From 5ecbb2740640951a56eb08f2ff1dfa241a62f1ba Mon Sep 17 00:00:00 2001 From: Erin Shaben Date: Fri, 6 Oct 2023 17:43:25 -0400 Subject: [PATCH] update code snippets --- .../get-started/networks/moonbase/connect.md | 5 +- .../get-started/networks/moonbeam/connect.md | 6 +- .../get-started/networks/moonriver/connect.md | 8 +- .../xcm/xcm-precompile-multilocation.md | 4 +- builders/build/eth-api/dev-env/brownie.md | 18 +- builders/build/eth-api/dev-env/foundry.md | 2 +- builders/build/eth-api/dev-env/hardhat.md | 67 ++- .../build/eth-api/dev-env/scaffold-eth.md | 12 +- builders/build/eth-api/dev-env/waffle-mars.md | 105 ++-- builders/build/eth-api/libraries/ethersjs.md | 48 +- builders/build/eth-api/libraries/ethersrs.md | 8 +- builders/build/eth-api/libraries/web3js.md | 38 +- builders/build/eth-api/libraries/web3py.md | 8 +- builders/build/eth-api/pubsub.md | 95 ++-- .../verify-contracts/api-verification.md | 509 ++++++++++-------- .../verify-contracts/etherscan-plugins.md | 10 +- builders/build/moonbeam-custom-api.md | 34 +- .../build/substrate-api/polkadot-js-api.md | 143 +++-- .../substrate-api/py-substrate-interface.md | 142 +++-- builders/get-started/eth-compare/security.md | 4 +- .../get-started/eth-compare/transfers-api.md | 8 +- builders/get-started/eth-compare/tx-fees.md | 4 +- builders/get-started/networks/moonbeam-dev.md | 4 +- builders/integrations/indexers/covalent.md | 107 ++-- builders/integrations/indexers/subquery.md | 4 +- builders/integrations/indexers/subsquid.md | 38 +- builders/integrations/indexers/thegraph.md | 2 +- .../integrations/oracles/band-protocol.md | 24 +- builders/integrations/oracles/chainlink.md | 4 +- builders/integrations/relayers/gelato.md | 128 +++-- builders/integrations/wallets/metamask.md | 133 ++--- .../integrations/wallets/walletconnect.md | 166 +++--- .../interoperability/protocols/wormhole.md | 96 ++-- .../xcm/xcm-sdk/v0/xcm-sdk.md | 139 ++--- .../xcm/xcm-sdk/v1/xcm-sdk.md | 23 +- .../pallets-precompiles/precompiles/batch.md | 33 +- .../precompiles/eth-mainnet.md | 42 +- .../precompiles/registry.md | 2 +- node-operators/oracle-nodes/node-chainlink.md | 72 +-- tokens/staking/stake.md | 38 +- tutorials/eth-api/call-permit-gasless-txs.md | 15 +- tutorials/eth-api/hardhat-start-to-end.md | 58 +- tutorials/eth-api/how-to-build-a-dapp.md | 26 +- tutorials/eth-api/randomness-lottery.md | 23 +- tutorials/integrations/local-subsquid.md | 114 ++-- tutorials/integrations/nft-subsquid.md | 6 +- 46 files changed, 1424 insertions(+), 1151 deletions(-) diff --git a/.snippets/text/builders/get-started/networks/moonbase/connect.md b/.snippets/text/builders/get-started/networks/moonbase/connect.md index 0ea985c9..cdb7bdf3 100644 --- a/.snippets/text/builders/get-started/networks/moonbase/connect.md +++ b/.snippets/text/builders/get-started/networks/moonbase/connect.md @@ -1,4 +1,4 @@ -## 网络端点 {: #network-endpoints } +## 网络端点 {: #network-endpoints } Moonbase Alpha有两类端点供用户使用:HTTPS和WSS。 @@ -18,6 +18,7 @@ const Web3 = require('web3'); // Load Web3 library // Create local Web3 instance - set Moonbase Alpha as provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); ``` + 如果使用的是[Ethers.js库](/builders/build/eth-api/libraries/ethersjs){target=_blank},您可以使用`ethers.JsonRpcProvider(providerURL, {object})` 来定义开发者,并且将provider(提供者)URL设定至Moonbase Alpha: ```js @@ -34,6 +35,6 @@ const provider = new ethers.JsonRpcProvider(providerURL, { 任何以太坊钱包都应当能够生成可以使用Moonbeam的地址(例如:[MetaMask](https://metamask.io/){target=_blank})。 -## Chain ID {: #chain-id } +## Chain ID {: #chain-id } Moonbase Alpha测试网的Chain ID为:`1287`,hex:`0x507`。 diff --git a/.snippets/text/builders/get-started/networks/moonbeam/connect.md b/.snippets/text/builders/get-started/networks/moonbeam/connect.md index 39fad013..7336734d 100644 --- a/.snippets/text/builders/get-started/networks/moonbeam/connect.md +++ b/.snippets/text/builders/get-started/networks/moonbeam/connect.md @@ -16,7 +16,7 @@ const Web3 = require('web3'); // Load Web3 library . . // Create local Web3 instance - set Moonbeam as provider -const web3 = new Web3("RPC-API-ENDPOINT-HERE"); // Insert your RPC URL here +const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` 如果使用的是[Ethers.js库](/builders/build/eth-api/libraries/ethersjs){target=_blank},您可以使用`ethers.JsonRpcProvider(providerURL, {object})`来定义提供者,并且将提供者URL设定至Moonbeam: @@ -24,7 +24,7 @@ const web3 = new Web3("RPC-API-ENDPOINT-HERE"); // Insert your RPC URL here ```js const ethers = require('ethers'); // Load Ethers library -const providerURL = "https://rpc.api.moonbeam.network"; +const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1284, @@ -34,6 +34,6 @@ const provider = new ethers.JsonRpcProvider(providerURL, { 任何以太坊钱包都应当能够为Moonbeam生成有效地址(例如:[MetaMask](https://metamask.io/){target=_blank})。 -## Chain ID {: #chain-id } +## Chain ID {: #chain-id } Moonbeam的Chain ID为`1284`,hex为`0x504`。 diff --git a/.snippets/text/builders/get-started/networks/moonriver/connect.md b/.snippets/text/builders/get-started/networks/moonriver/connect.md index f59f728c..d71c6872 100644 --- a/.snippets/text/builders/get-started/networks/moonriver/connect.md +++ b/.snippets/text/builders/get-started/networks/moonriver/connect.md @@ -1,4 +1,4 @@ -## 网络端点 {: #network-endpoints } +## 网络端点 {: #network-endpoints } Moonriver有两类端点供用户使用:HTTPS和WSS。 @@ -16,7 +16,7 @@ const Web3 = require('web3'); // Load Web3 library . . // Create local Web3 instance - set Moonriver as provider -const web3 = new Web3("RPC-API-ENDPOINT-HERE"); // Insert your RPC URL here +const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` 如果使用的是[Ethers.js库](/builders/build/eth-api/libraries/ethersjs){target=_blank},您可以使用`ethers.JsonRpcProvider(providerURL, {object})` 来定义开发者,并且将provider(提供者)URL设定至Moonriver: @@ -25,7 +25,7 @@ const web3 = new Web3("RPC-API-ENDPOINT-HERE"); // Insert your RPC URL here const ethers = require('ethers'); // Load Ethers library -const providerURL = "RPC-API-ENDPOINT-HERE"; // Insert your RPC URL here +const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Insert your RPC URL here // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1285, @@ -35,6 +35,6 @@ const provider = new ethers.JsonRpcProvider(providerURL, { 任何以太坊钱包都应当能够生成可以使用Moonbeam的地址(例如:[MetaMask](https://metamask.io/){target=_blank})。 -## Chain ID {: #chain-id } +## Chain ID {: #chain-id } Moonriver的Chain ID为: `1285`,hex:`0x505`。 diff --git a/.snippets/text/builders/interoperability/xcm/xcm-precompile-multilocation.md b/.snippets/text/builders/interoperability/xcm/xcm-precompile-multilocation.md index ed54b29d..c17cc3b5 100644 --- a/.snippets/text/builders/interoperability/xcm/xcm-precompile-multilocation.md +++ b/.snippets/text/builders/interoperability/xcm/xcm-precompile-multilocation.md @@ -1,5 +1,5 @@ -```js - struct Multilocation { +```solidity +struct Multilocation { uint8 parents; bytes[] interior; } diff --git a/builders/build/eth-api/dev-env/brownie.md b/builders/build/eth-api/dev-env/brownie.md index edaf7cc1..2aa4752f 100644 --- a/builders/build/eth-api/dev-env/brownie.md +++ b/builders/build/eth-api/dev-env/brownie.md @@ -248,13 +248,8 @@ cd scripts && touch deploy.py from brownie import Box, accounts def main(): - account = accounts.load('alice') - return Box.deploy( - { - 'from': account, - 'gas_limit': '200000' - } - ) + account = accounts.load("alice") + return Box.deploy({"from": account, "gas_limit": "200000"}) ``` 您可以使用`run`命令并指定网络来部署`Box.sol`合约: @@ -373,13 +368,10 @@ cd scripts && touch store-and-retrieve.py from brownie import Box, accounts def main(): - account = accounts.load('alice') + account = accounts.load("alice") box = Box[0] - store = box.store(5, {'from': accounts.load('alice'), 'gas_limit': '50000'}) - retrieve = box.retrieve({'from': accounts.load('alice')}) - - print("Transaction hash for updating the stored value: " + store) - print("Stored value: " + retrieve) + store = box.store(5, {"from": accounts.load("alice"), "gas_limit": "50000"}) + retrieve = box.retrieve({"from": accounts.load("alice")}) ``` 要运行脚本,您可以使用以下命令: diff --git a/builders/build/eth-api/dev-env/foundry.md b/builders/build/eth-api/dev-env/foundry.md index 916e45f3..b45800f4 100644 --- a/builders/build/eth-api/dev-env/foundry.md +++ b/builders/build/eth-api/dev-env/foundry.md @@ -284,7 +284,7 @@ curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H 从这里,您可以将新合约部署到您的Moonbeam的分叉实例或与已部署的合约进行交互。在本教程的上述示例的基础上,您可以使用Cast进行调用,来检查您部署合约的帐户中铸造的MYTOK Token的余额: ```bash -cast call INSERT-CONTRACT-ADDRESS "balanceOf(address)(uint256)" INSERT-YOUR-ADDRESS --rpc-url http://localhost:8545 +cast call INSERT_CONTRACT_ADDRESS "balanceOf(address)(uint256)" INSERT_YOUR_ADDRESS --rpc-url http://localhost:8545 ``` ## 使用Chisel {: #using-chisel } diff --git a/builders/build/eth-api/dev-env/hardhat.md b/builders/build/eth-api/dev-env/hardhat.md index 222a5e0f..6e70c4d7 100644 --- a/builders/build/eth-api/dev-env/hardhat.md +++ b/builders/build/eth-api/dev-env/hardhat.md @@ -211,26 +211,26 @@ touch deploy.js ```js // scripts/deploy.js async function main() { - // 1. Get the contract to deploy - const Box = await ethers.getContractFactory('Box'); - console.log('Deploying Box...'); + // 1. Get the contract to deploy + const Box = await ethers.getContractFactory('Box'); + console.log('Deploying Box...'); - // 2. Instantiating a new Box smart contract - const box = await Box.deploy(); + // 2. Instantiating a new Box smart contract + const box = await Box.deploy(); - // 3. Waiting for the deployment to resolve - await box.waitForDeployment(); + // 3. Waiting for the deployment to resolve + await box.waitForDeployment(); - // 4. Use the contract instance to get the contract address - console.log('Box deployed to:', box.target); + // 4. Use the contract instance to get the contract address + console.log('Box deployed to:', box.target); } main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); ``` 您现在可以使用`run`命令并指定`moonbase`作为网络来部署`Box.sol`合约: @@ -272,7 +272,7 @@ npx hardhat console --network moonbase 3. 与此合约交互。在本示例中,您可以调用`store`方法并存储一个简单的值 ```js - await box.store(5) + await box.store(5); ``` 交易将通过您的Moonbase账户进行签署并传送至网络。后台输出将如下所示: @@ -434,12 +434,12 @@ npx patch-package hardhat ```js ... networks: { - hardhat: { - forking: { - url: "{{ networks.moonbeam.rpc_url }}", - } - } - } + hardhat: { + forking: { + url: '{{ networks.moonbeam.rpc_url }}', + }, + }, + }, ... ``` @@ -448,12 +448,12 @@ npx patch-package hardhat ```js ... networks: { - hardhat: { - forking: { - url: "{{ networks.moonriver.rpc_url }}", - } - } - } + hardhat: { + forking: { + url: '{{ networks.moonriver.rpc_url }}', + }, + }, + }, ... ``` @@ -462,12 +462,12 @@ npx patch-package hardhat ```js ... networks: { - hardhat: { - forking: { - url: "{{ networks.moonbase.rpc_url }}", - } - } - } + hardhat: { + forking: { + url: '{{ networks.moonbase.rpc_url }}', + }, + }, + }, ... ``` @@ -494,7 +494,6 @@ async function main() { const provider = new ethers.providers.StaticJsonRpcProvider( 'http://127.0.0.1:8545/' ); - const contract = new ethers.Contract( 'INSERT_CONTRACT_ADDRESS', 'INSERT_CONTRACT_ABI', diff --git a/builders/build/eth-api/dev-env/scaffold-eth.md b/builders/build/eth-api/dev-env/scaffold-eth.md index e199b78a..00079894 100644 --- a/builders/build/eth-api/dev-env/scaffold-eth.md +++ b/builders/build/eth-api/dev-env/scaffold-eth.md @@ -56,25 +56,25 @@ yarn install === "Moonbeam" ```js - defaultNetwork = "moonbeam"; + defaultNetwork = 'moonbeam'; ``` === "Moonriver" ```js - defaultNetwork = "moonriver"; + defaultNetwork = 'moonriver'; ``` === "Moonbase Alpha" ```js - defaultNetwork = "moonbaseAlpha"; + defaultNetwork = 'moonbaseAlpha'; ``` === "Moonbeam开发节点" ```js - defaultNetwork = "moonbeamDevNode"; + defaultNetwork = 'moonbeamDevNode'; ``` 2. 在同一个文件的`module.exports/etherscan/apiKey`部分,为[Moonscan](https://moonscan.io/){target=_blank}添加API密钥,用于验证已部署的智能合约。了解如何生成Moonscan API密钥,请查看[Etherscan Plugins](/builders/build/eth-api/verify-contracts/etherscan-plugins/#generating-a-moonscan-api-key){target=_blank}部分。 @@ -82,7 +82,7 @@ yarn install 3. (可选)在`function mnemonic()`部分,注释当网络未设置为`localhost`时控制台发出警告 ```js - if (defaultNetwork !== "localhost") { + if (defaultNetwork !== 'localhost') { //console.log( // "☢️ WARNING: No mnemonic file created for a deploy account. Try `yarn run generate` and then `yarn run account`." //); @@ -205,7 +205,7 @@ yarn install 2. 在同一个文件`App.jsx`中,将`networkOptions`设置为您的DApp所支持的网络,例如: ```js - const networkOptions = [initialNetwork.name, "moonbeam", "moonriver"]; + const networkOptions = [initialNetwork.name, 'moonbeam', 'moonriver']; ``` ## 部署并启动DApp {: #deploy-and-launch-the-dapp } diff --git a/builders/build/eth-api/dev-env/waffle-mars.md b/builders/build/eth-api/dev-env/waffle-mars.md index b8383335..5d91183c 100644 --- a/builders/build/eth-api/dev-env/waffle-mars.md +++ b/builders/build/eth-api/dev-env/waffle-mars.md @@ -72,18 +72,18 @@ Mars提供了一个简单的、与TypeScript兼容的框架,用于创建高级 ```json { - "compilerOptions": { - "strict": true, - "target": "ES2019", - "moduleResolution": "node", - "resolveJsonModule": true, - "esModuleInterop": true, - "module": "CommonJS", - "composite": true, - "sourceMap": true, - "declaration": true, - "noEmit": true - } + "compilerOptions": { + "strict": true, + "target": "ES2019", + "moduleResolution": "node", + "resolveJsonModule": true, + "esModuleInterop": true, + "module": "CommonJS", + "composite": true, + "sourceMap": true, + "declaration": true, + "noEmit": true + } } ``` @@ -133,17 +133,17 @@ Mars提供了一个简单的、与TypeScript兼容的框架,用于创建高级 ```json { - "compilerType": "solcjs", // Specifies compiler to use - "compilerVersion": "0.8.0", // Specifies version of the compiler - "compilerOptions": { - "optimizer": { // Optional optimizer settings - "enabled": true, // Enable optimizer - "runs": 20000 // Optimize how many times you want to run the code - } - }, - "sourceDirectory": "./contracts", // Path to directory containing smart contracts - "outputDirectory": "./build", // Path to directory where Waffle saves compiler output - "typechainEnabled": true // Enable typed artifact generation + "compilerType": "solcjs", + "compilerVersion": "0.8.0", + "compilerOptions": { + "optimizer": { + "enabled": true, + "runs": 20000 + } + }, + "sourceDirectory": "./contracts", + "outputDirectory": "./build", + "typechainEnabled": true } ``` @@ -151,7 +151,7 @@ Mars提供了一个简单的、与TypeScript兼容的框架,用于创建高级 ```json "scripts": { - "build": "waffle" + "build": "waffle" }, ``` @@ -176,6 +176,7 @@ npm run build 由于您将针对测试网运行测试,因此可能需要花费几分钟才能运行所有测试。如果您想获得更有效的测试体验,您可以使用[`instant seal`](/builders/get-started/networks/moonbeam-dev/#node-options){target=_blank}[设置Moonbeam开发节点](/builders/get-started/networks/moonbeam-dev/){target=_blank}。运行具有`instant seal`功能的Moonbeam本地开发节点与使用[Ganache](https://www.trufflesuite.com/ganache){target=_blank}可获得的快速迭代体验相似。 1. 创建一个目录来包含您的测试,并创建一个文件来测试您的`MyToken`合约 + ```bash mkdir test && cd test && touch MyToken.test.ts ``` @@ -214,9 +215,9 @@ npm run build ```typescript beforeEach(async () => { // This is for demo purposes only. Never store your private key in a JavaScript/TypeScript file - const PRIVATE_KEY = '' + const privateKey = 'INSERT_PRIVATE_KEY' // Create a wallet instance using your private key & connect it to the provider - wallet = new Wallet(PRIVATE_KEY).connect(provider); + wallet = new Wallet(privateKey).connect(provider); // Create a random account to transfer tokens to & connect it to the provider walletTo = Wallet.createRandom().connect(provider); @@ -233,6 +234,7 @@ npm run build ``` 4. 现在您可以创建您的第一个测试用例。第一次测试用例将检查您的初始余额,以确保您收到了10个代币的初始供应量。请注意测试用例应考虑成功和失败的情况,为了遵循测试结果,需先编写失败的测试的代码: + ```typescript it('Mints the correct initial balance', async () => { expect(await token.balanceOf(wallet.address)).to.equal(1); // This should fail @@ -240,24 +242,27 @@ npm run build ``` 5. 在运行第一个测试用例之前,您需要回到根方向并添加一个`.mocharc.json` Mocha配置文件: + ```bash cd .. && touch .mocharc.json ``` 6. 现在,您可以编辑`.mocharc.json`文件来配置Mocha: + ```json { - "require": "ts-node/register/transpile-only", // Use ts-node to transpile the code for tests - "timeout": 600000, // Set timeout to 10 minutes - "extension": "test.ts" // Specify extension for test files + "require": "ts-node/register/transpile-only", + "timeout": 600000, + "extension": "test.ts" } ``` 7. 您还需要在`package.json`中添加一个脚本来运行你的测试用例: + ```json "scripts": { - "build": "waffle", - "test": "mocha", + "build": "waffle", + "test": "mocha" }, ``` @@ -267,7 +272,7 @@ npm run build npm run test ``` -请注意,因为测试是针对Moonbase Alpha运行的,所以处理可能需要几分钟时间。但如果一切都按预期进行,您应该会有一个失败的测试。 + 请注意,因为测试是针对Moonbase Alpha运行的,所以处理可能需要几分钟时间。但如果一切都按预期进行,您应该会有一个失败的测试。 9. 接下来,您可以返回并编辑测试,检查10个代币: @@ -306,7 +311,7 @@ import { MyToken, MyTokenFactory } from '../build/types'; use(solidity); -describe ('MyToken', () => { +describe('MyToken', () => { let provider: Provider = new ethers.providers.JsonRpcProvider( '{{ networks.moonbase.rpc_url }}' ); @@ -316,8 +321,8 @@ describe ('MyToken', () => { beforeEach(async () => { // This is for demo purposes only. Never store your private key in a JavaScript/TypeScript file - const PRIVATE_KEY = '' - wallet = new Wallet(PRIVATE_KEY).connect(provider); + const privateKey = 'INSERT_PRIVATE_KEY'; + wallet = new Wallet(privateKey).connect(provider); walletTo = Wallet.createRandom().connect(provider); token = await new MyTokenFactory(wallet).deploy(); let contractTransaction = await token.initialize(10); @@ -332,7 +337,7 @@ describe ('MyToken', () => { await (await token.transfer(walletTo.address, 7)).wait(); expect(await token.balanceOf(walletTo.address)).to.equal(7); }); -}) +}); ``` 如果您想自己编写更多测试用例,您可以考虑测试从没有任何资金的账户转账或从没有足够资金的账户转账。 @@ -354,8 +359,8 @@ describe ('MyToken', () => { ```json "scripts": { - "build": "waffle && mars", - "test": "mocha", + "build": "waffle && mars", + "test": "mocha", }, ``` @@ -376,38 +381,45 @@ describe ('MyToken', () => { 在此步骤中,您将创建部署脚本,该脚本将定义应如何部署合约。Mars提供了一个`deploy`功能,您可以向它传递选项,例如用于部署合约的帐户私钥、所要部署的网络等。`deploy`函数内部用于定义要部署的合约的地方。 Mars有一个`contract`函数,用来接受`name`、`artifact`和 `constructorArgs`。此函数将用于部署`MyToken`合约,初始供应量为10个MYTOK。 1. 创建一个`src`目录来包含你的部署脚本并创建脚本来部署`MyToken`合约: + ```bash mkdir src && cd src && touch deploy.ts ``` 2. 在`deploy.ts`中,使用Mars的`deploy`函数创建一个脚本,使用您账户的私钥部署至 Moonbase Alpha: + ```javascript import { deploy } from 'ethereum-mars'; // This is for demo purposes only. Never store your private key in a JavaScript/TypeScript file - const privateKey = ""; - deploy({network: '{{ networks.moonbase.rpc_url }}', privateKey},(deployer) => { - // Deployment logic will go here - }); + const privateKey = 'INSERT_PRIVATE_KEY'; + deploy( + { network: '{{ networks.moonbase.rpc_url }}', privateKey }, + (deployer) => { + // Deployment logic will go here + } + ); ``` 3. 设置`deploy`函数来部署在上述步骤中创建的`MyToken`合约: + ```javascript import { deploy, contract } from 'ethereum-mars'; import { MyToken } from '../build/artifacts'; // This is for demo purposes only. Never store your private key in a JavaScript/TypeScript file - const privateKey = ""; - deploy({network: '{{ networks.moonbase.rpc_url }}', privateKey}, () => { + const privateKey = 'INSERT_PRIVATE_KEY'; + deploy({ network: '{{ networks.moonbase.rpc_url }}', privateKey }, () => { contract('myToken', MyToken, [10]); }); ``` 4. 将部署脚本添加到`package.json`中的`scripts`对象: + ```json - "scripts": { + "scripts": { "build": "waffle && mars", "test": "mocha", "deploy": "ts-node src/deploy.ts" - }, + }, ``` 到目前为止,您应该已经在`deploy.ts`中创建了一个部署脚本,用于将`MyToken`合约部署至Moonbase Alpha,并添加了轻松调用脚本和部署合约的功能。 @@ -417,6 +429,7 @@ describe ('MyToken', () => { 若您已配置了部署,现在可以真正部署至Moonbase Alpha了。 1. 使用您刚刚创建的脚本部署合约: + ```bash npm run deploy ``` diff --git a/builders/build/eth-api/libraries/ethersjs.md b/builders/build/eth-api/libraries/ethersjs.md index ce589599..2770f0ea 100644 --- a/builders/build/eth-api/libraries/ethersjs.md +++ b/builders/build/eth-api/libraries/ethersjs.md @@ -72,13 +72,10 @@ mkdir ethers-examples && cd ethers-examples && npm init --y }, }; // 3. Create ethers provider - const provider = new ethers.JsonRpcProvider( - providerRPC.moonbeam.rpc, - { - chainId: providerRPC.moonbeam.chainId, - name: providerRPC.moonbeam.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { + chainId: providerRPC.moonbeam.chainId, + name: providerRPC.moonbeam.name, + }); ``` === "Moonriver" @@ -96,13 +93,10 @@ mkdir ethers-examples && cd ethers-examples && npm init --y }, }; // 3. Create ethers provider - const provider = new ethers.JsonRpcProvider( - providerRPC.moonriver.rpc, - { - chainId: providerRPC.moonriver.chainId, - name: providerRPC.moonriver.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonriver.rpc, { + chainId: providerRPC.moonriver.chainId, + name: providerRPC.moonriver.name, + }); ``` === "Moonbase Alpha" @@ -120,13 +114,10 @@ mkdir ethers-examples && cd ethers-examples && npm init --y }, }; // 3. Create ethers provider - const provider = new ethers.JsonRpcProvider( - providerRPC.moonbase.rpc, - { - chainId: providerRPC.moonbase.chainId, - name: providerRPC.moonbase.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { + chainId: providerRPC.moonbase.chainId, + name: providerRPC.moonbase.name, + }); ``` === "Moonbeam开发节点" @@ -144,13 +135,10 @@ mkdir ethers-examples && cd ethers-examples && npm init --y }, }; // 3. Create ethers provider - const provider = new ethers.JsonRpcProvider( - providerRPC.dev.rpc, - { - chainId: providerRPC.dev.chainId, - name: providerRPC.dev.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.dev.rpc, { + chainId: providerRPC.dev.chainId, + name: providerRPC.dev.name, + }); ``` ## 发送交易 {: #send-a-transaction } @@ -531,7 +519,9 @@ const incrementer = new ethers.Contract(contractAddress, abi, wallet); // 6. Create reset function const reset = async () => { - console.log(`Calling the reset function in contract at address: ${contractAddress}`); + console.log( + `Calling the reset function in contract at address: ${contractAddress}` + ); // 7. sign and send tx and wait for receipt const createReceipt = await incrementer.reset(); diff --git a/builders/build/eth-api/libraries/ethersrs.md b/builders/build/eth-api/libraries/ethersrs.md index 3965691f..07174387 100644 --- a/builders/build/eth-api/libraries/ethersrs.md +++ b/builders/build/eth-api/libraries/ethersrs.md @@ -92,7 +92,7 @@ solc-select install 0.8.17 && solc-select use 0.8.17 // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key - let wallet: LocalWallet = "YOUR PRIVATE KEY" + let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbeam); @@ -122,7 +122,7 @@ solc-select install 0.8.17 && solc-select use 0.8.17 // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key - let wallet: LocalWallet = "YOUR PRIVATE KEY" + let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonriver); @@ -152,7 +152,7 @@ solc-select install 0.8.17 && solc-select use 0.8.17 // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key - let wallet: LocalWallet = "YOUR PRIVATE KEY" + let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); @@ -182,7 +182,7 @@ solc-select install 0.8.17 && solc-select use 0.8.17 // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key - let wallet: LocalWallet = "YOUR PRIVATE KEY" + let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::MoonbeamDev); diff --git a/builders/build/eth-api/libraries/web3js.md b/builders/build/eth-api/libraries/web3js.md index 779c1377..e19b66cd 100644 --- a/builders/build/eth-api/libraries/web3js.md +++ b/builders/build/eth-api/libraries/web3js.md @@ -125,8 +125,14 @@ const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create balances function const balances = async () => { // 4. Fetch balance info - const balanceFrom = web3.utils.fromWei(await web3.eth.getBalance(addressFrom), 'ether'); - const balanceTo = web3.utils.fromWei(await web3.eth.getBalance(addressTo), 'ether'); + const balanceFrom = web3.utils.fromWei( + await web3.eth.getBalance(addressFrom), + 'ether' + ); + const balanceTo = web3.utils.fromWei( + await web3.eth.getBalance(addressTo), + 'ether' + ); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); @@ -180,7 +186,9 @@ const addressTo = 'INSERT_TO_ADDRESS'; // Change addressTo // 3. Create send function const send = async () => { - console.log(`Attempting to send transaction from ${accountFrom.address} to ${addressTo}`); + console.log( + `Attempting to send transaction from ${accountFrom.address} to ${addressTo}` + ); // 4. Sign tx with PK const createTransaction = await web3.eth.accounts.signTransaction( @@ -193,8 +201,12 @@ const send = async () => { ); // 5. Send tx and wait for receipt - const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction); - console.log(`Transaction successful with hash: ${createReceipt.transactionHash}`); + const createReceipt = await web3.eth.sendSignedTransaction( + createTransaction.rawTransaction + ); + console.log( + `Transaction successful with hash: ${createReceipt.transactionHash}` + ); }; // 6. Call send function @@ -293,7 +305,9 @@ const deploy = async () => { ); // 9. Send tx and wait for receipt - const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction); + const createReceipt = await web3.eth.sendSignedTransaction( + createTransaction.rawTransaction + ); console.log(`Contract deployed at address: ${createReceipt.contractAddress}`); }; @@ -435,7 +449,9 @@ const increment = async () => { ); // 8. Send tx and wait for receipt - const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction); + const createReceipt = await web3.eth.sendSignedTransaction( + createTransaction.rawTransaction + ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; @@ -492,7 +508,9 @@ const resetTx = incrementer.methods.reset(); // 6. Create reset function const reset = async () => { - console.log(`Calling the reset function in contract at address: ${contractAddress}`); + console.log( + `Calling the reset function in contract at address: ${contractAddress}` + ); // 7. Sign tx with PK const createTransaction = await web3.eth.accounts.signTransaction( @@ -505,7 +523,9 @@ const reset = async () => { ); // 8. Send tx and wait for receipt - const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction); + const createReceipt = await web3.eth.sendSignedTransaction( + createTransaction.rawTransaction + ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; diff --git a/builders/build/eth-api/libraries/web3py.md b/builders/build/eth-api/libraries/web3py.md index 62238a19..eee42874 100644 --- a/builders/build/eth-api/libraries/web3py.md +++ b/builders/build/eth-api/libraries/web3py.md @@ -49,7 +49,7 @@ pip3 install web3 py-solc-x ```python from web3 import Web3 - web3 = Web3(Web3.HTTPProvider('{{ networks.moonbeam.rpc_url }}')) # Insert your RPC URL here + web3 = Web3(Web3.HTTPProvider("{{ networks.moonbeam.rpc_url }}")) # Insert your RPC URL here ``` === "Moonriver" @@ -57,7 +57,7 @@ pip3 install web3 py-solc-x ```python from web3 import Web3 - web3 = Web3(Web3.HTTPProvider('{{ networks.moonriver.rpc_url }}')) # Insert your RPC URL here + web3 = Web3(Web3.HTTPProvider("{{ networks.moonriver.rpc_url }}")) # Insert your RPC URL here ``` === "Moonbase Alpha" @@ -65,7 +65,7 @@ pip3 install web3 py-solc-x ```python from web3 import Web3 - web3 = Web3(Web3.HTTPProvider('{{ networks.moonbase.rpc_url }}')) + web3 = Web3(Web3.HTTPProvider("{{ networks.moonbase.rpc_url }}")) ``` === "Moonbeam开发节点" @@ -73,7 +73,7 @@ pip3 install web3 py-solc-x ```python from web3 import Web3 - web3 = Web3(Web3.HTTPProvider('{{ networks.development.rpc_url }}')) + web3 = Web3(Web3.HTTPProvider("{{ networks.development.rpc_url }}")) ``` ## 发送交易 {: #send-a-transaction } diff --git a/builders/build/eth-api/pubsub.md b/builders/build/eth-api/pubsub.md index 6047d0d0..4f632354 100644 --- a/builders/build/eth-api/pubsub.md +++ b/builders/build/eth-api/pubsub.md @@ -5,7 +5,7 @@ description: 使用类似于以太坊的pubsub功能来订阅Moonbeam上的以 # 事件订阅 -## 概览 {: #introduction } +## 概览 {: #introduction } Moonbeam支持以太坊式事件的事件订阅。这允许您订阅事件并进行相应处理,而不需轮询。 @@ -13,12 +13,13 @@ Moonbeam支持以太坊式事件的事件订阅。这允许您订阅事件并进 在本指南中,您将学习如何在Moonbase Alpha上订阅事件日志、待处理交易和新的区块。本指南也适用于Moonbeam或Moonriver。 -## 查看先决条件 {: #checking-prerequisites } +## 查看先决条件 {: #checking-prerequisites } + 本教程所使用的示例基于Ubuntu 18.04的环境。除此之外,还需要进行以下操作: - 安装MetaMask并[连接到Moonbase](/tokens/connect/metamask/){target=_blank} - - 具有拥有一定数量资金的账户。 - --8<-- 'text/_common/faucet/faucet-list-item.md' + - 具有拥有一定数量资金的账户。 + --8<-- 'text/_common/faucet/faucet-list-item.md' - 在Moonbase上部署您的ERC-20代币。您可以根据我们的[Remix教程](/builders/build/eth-api/dev-env/remix/){target=_blank}进行操作,但首先要确保MetaMask指向Moonbase --8<-- 'text/_common/install-nodejs.md' @@ -37,26 +38,32 @@ npm ls web3 在撰写本教程时,所用版本为1.3.0版本。 -## 订阅事件日志 {: #subscribe-to-event-logs } +## 订阅事件日志 {: #subscribe-to-event-logs } 每个采用ERC-20代币标准的合约都会发送与代币转移相关的事件信息,即`event Transfer(address indexed from, address indexed to, uint256 value)`。在以下示例中,您将了解如何订阅这些事件日志。请执行以下代码调用Web3.js库: ```js const Web3 = require('web3'); const web3 = new Web3('wss://wss.api.moonbase.moonbeam.network'); -web3.eth.subscribe('logs', { - address: 'ContractAddress', - topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'] -}, (error, result) => { - if (error) - console.error(error); -}) - .on("connected", function (subscriptionId) { - console.log(subscriptionId); - }) - .on("data", function (log) { - console.log(log); - }); +web3.eth + .subscribe( + 'logs', + { + address: 'INSERT_CONTRACT_ADDRESS', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + ], + }, + (error, result) => { + if (error) console.error(error); + } + ) + .on('connected', function (subscriptionId) { + console.log(subscriptionId); + }) + .on('data', function (log) { + console.log(log); + }); ``` 请注意,您需连接到Moonbase Alpha的WebSocket终端。调用`web3.eth.subscribe(‘logs’, options [, callback])`方法订阅过滤后的事件日志。在本示例中,过滤选项有:事件发出的合约地址,以及用于描述事件的主题。更多关于事件主题的信息可以在[了解以太坊事件日志](https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378){target=_blank}这篇Medium文章中找到。如果事件没有主题,用户将订阅该合约发出的所有事件信息。如果仅过滤`Transfer`(代币转帐)事件,需要包含通过以下方式计算的事件签名: @@ -89,7 +96,7 @@ EventSignature = keccak256(Transfer(address,address,uint256)) 如果事件返回了多个无索引数据,这些数据将根据事件发出顺序,依次附在前一个数据之后。因此每个数据值都会被解码成32字节(或64 hex character长度)的小片段。 -### 使用通配符和条件格式 {: #using-wildcards-and-conditional-formatting } +### 使用通配符和条件格式 {: #using-wildcards-and-conditional-formatting } 考虑到通配符和条件格式的应用,v2版本新增的日志订阅功能在用于主题方面还有一些局限。但在[Moonbase Alpha v3](https://moonbeam.network/announcements/moonbeam-network-upgrades-account-structure-to-match-ethereum/){target=_blank}版本中,这些局限已经得到解决。 @@ -100,28 +107,28 @@ const Web3 = require('web3'); const web3 = new Web3('wss://wss.api.moonbase.moonbeam.network'); web3.eth - .subscribe( - 'logs', - { - address: 'ContractAddress', - topics: [ - null, - [ - '0x00000000000000000000000044236223aB4291b93EEd10E4B511B37a398DEE55', - '0x0000000000000000000000008841701Dba3639B254D9CEe712E49D188A1e941e', - ], - ], - }, - (error, result) => { - if (error) console.error(error); - } - ) - .on('connected', function (subscriptionId) { - console.log(subscriptionId); - }) - .on('data', function (log) { - console.log(log); - }); + .subscribe( + 'logs', + { + address: 'INSERT_CONTRACT_ADDRESS', + topics: [ + null, + [ + '0x00000000000000000000000044236223aB4291b93EEd10E4B511B37a398DEE55', + '0x0000000000000000000000008841701Dba3639B254D9CEe712E49D188A1e941e', + ], + ], + }, + (error, result) => { + if (error) console.error(error); + } + ) + .on('connected', function (subscriptionId) { + console.log(subscriptionId); + }) + .on('data', function (log) { + console.log(log); + }); ``` 在这里使用通配符`null`代替事件签名,可以进行过滤并接收所有订阅合约发送的事件信息。但在这一设置下,您还可以使用另一个(`topic_1`)输入值来定义此前提到的地址过滤器。例如在这个例子中,您要得到的效果是只在当`topic_1`是我们所提供的地址之一时,才接收事件信息。请注意,地址需要以H256形式输入。例如,地址`0x44236223aB4291b93EEd10E4B511B37a398DEE55`需要输入为`0x00000000000000000000000044236223aB4291b93EEd10E4B511B37a398DEE55`。和此前一样,订阅的输出值将在`topic_0`处显示事件签名,告诉您该合约发出的事件。 @@ -132,7 +139,7 @@ web3.eth 这个例子说明,您可以仅订阅某个特定合约的事件日志。但是,Web3.js库也提供其他订阅类型,将在下节展开介绍。 -## 订阅收到的待处理交易信息 {: #subscribe-to-incoming-pending-transactions } +## 订阅收到的待处理交易信息 {: #subscribe-to-incoming-pending-transactions } 您可以调用`web3.eth.subscribe(‘pendingTransactions’, [, callback])`方法订阅待处理交易信息,并用相同的回调函数来检查返回值。这种方法比此前例子中的方法要简单很多,它返回的是待处理交易的哈希值。 @@ -140,7 +147,7 @@ web3.eth 您可以验证,该笔交易的哈希值与MetaMask(或Remix)上显示的一致。 -## 订阅收到的区块头 {: #subscribe-to-incoming-block-headers } +## 订阅收到的区块头 {: #subscribe-to-incoming-block-headers } 使用Web3.js库还可以订阅新区块头。您可以调用`web3.eth.subscribe('newBlockHeaders' [, callback])`方法进行订阅,并调用同样的回调函数检查返回值。通过这种方法,可以订阅刚收到的区块头,也可以追踪区块链的变化。 @@ -148,7 +155,7 @@ web3.eth 请注意,图片中只显示了一个区块头,但在实际操作过程中,会显示所有产生区块的相关信息,所以区块信息很快会占满整个终端屏幕。 -## 检查节点是否与网络同步 {: #check-if-a-node-is-synchronized-with-the-network } +## 检查节点是否与网络同步 {: #check-if-a-node-is-synchronized-with-the-network } 通过发布/订阅功能,还可以检查某个订阅的特定节点是否与网络同步。可以调用[`web3.eth.subscribe(‘syncing' [, callback])`](https://web3js.readthedocs.io/en/v1.2.11/web3-eth-subscribe.html#subscribe-syncing){target=_blank}方法,并通过相同的回调函数检查返回值。当节点没有在同步时,此订阅将返回一个为`false`的布尔值,或节点在同步时,则返回一个描述同步进度的对象,如下图所示。 diff --git a/builders/build/eth-api/verify-contracts/api-verification.md b/builders/build/eth-api/verify-contracts/api-verification.md index c200d49d..9bf978e6 100644 --- a/builders/build/eth-api/verify-contracts/api-verification.md +++ b/builders/build/eth-api/verify-contracts/api-verification.md @@ -49,137 +49,191 @@ Moonbeam相关网络的Moonscan API URL如下: 要使用Moonscan API验证合约源代码,您需要拟定一个包含所有相关合约创建信息的POST请求,并将其请求传送至Moonscan的REST API。以下为使用JavaScript和[Axios](https://axios-http.com/docs/intro){target=_blank}(HTTP用户端)的范例代码: === "Moonbeam" + ```javascript // Submit Source Code for Verification - const response = await axios.post("https://api-moonbeam.moonscan.io/api", { - apikey: "INSERT-API-KEY-HERE", - module: "contract", - action: "verifysourcecode", - contractAddress: "INSERT-CONTRACT-ADDRESS-HERE", - sourceCode: "INSERT-SOURCE-CODE-HERE", // flattened if necessary - codeformat: "solidity-single-file" // or you can use "solidity-standard-json-input" - contractname: "INSERT-CONTRACT-NAME-HERE", // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 - compilerversion: "INSERT-COMPILER-VERSION-HERE" // see https://etherscan.io/solcversions for list of support versions - optimizationUsed: 0 // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) - runs: 200 // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) - constructorArguements: "INSERT-CONSTRUCTOR-ARGUMENTS-HERE" // if applicable - evmversion: "INSERT-EVM-VERSION-HERE", // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) + const response = await axios.post( + 'https://api-moonbeam.moonscan.io/api', + { + apikey: 'INSERT_API_KEY', + module: 'contract', + action: 'verifysourcecode', + contractAddress: 'INSERT_CONTRACT_ADDRESS', + sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary + codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" + contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 + compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions + optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) + runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) + constructorArguements: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable + evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types - libraryname1: "INSERT-LIBRARY-NAME-HERE" // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) - libraryaddress1: "INSERT-LIBRARY-ADDRESS-HERE" // if applicable, enter the address of the first library used - libraryname2: "INSERT-LIBRARY-NAME-HERE", // if applicable, enter the name of the second library used - libraryaddress2: "INSERT-LIBRARY-ADDRESS-HERE", // if applicable, enter the address of the second library used + libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) + libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used + libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used + libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... - }, headers: { "Content-Type": "application/x-www-form-urlencoded" }) - - if (response.data.status == "1") { - // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission - // average time of processing is 30-60 seconds - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) - // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status + }, + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } + ); + + if (response.data.status == '1') { + // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission + // average time of processing is 30-60 seconds + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); + // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status } else { - // 0 = error - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) + // 0 = error + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); } ``` === "Moonriver" + ```javascript // Submit Source Code for Verification - const response = await axios.post("https://api-moonriver.moonscan.io/api", { - apikey: "INSERT-API-KEY-HERE", - module: "contract", - action: "verifysourcecode", - contractAddress: "INSERT-CONTRACT-ADDRESS-HERE", - sourceCode: "INSERT-SOURCE-CODE-HERE", // flattened if necessary - codeformat: "solidity-single-file" // or you can use "solidity-standard-json-input" - contractname: "INSERT-CONTRACT-NAME-HERE", // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 - compilerversion: "INSERT-COMPILER-VERSION-HERE" // see https://etherscan.io/solcversions for list of support versions - optimizationUsed: 0 // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) - runs: 200 // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) - constructorArguements: "INSERT-CONSTRUCTOR-ARGUMENTS-HERE" // if applicable - evmversion: "INSERT-EVM-VERSION-HERE", // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) + const response = await axios.post( + 'https://api-moonriver.moonscan.io/api', + { + apikey: 'INSERT_API_KEY', + module: 'contract', + action: 'verifysourcecode', + contractAddress: 'INSERT_CONTRACT_ADDRESS', + sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary + codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" + contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 + compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions + optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) + runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) + constructorArguements: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable + evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types - libraryname1: "INSERT-LIBRARY-NAME-HERE" // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) - libraryaddress1: "INSERT-LIBRARY-ADDRESS-HERE" // if applicable, enter the address of the first library used - libraryname2: "INSERT-LIBRARY-NAME-HERE", // if applicable, enter the name of the second library used - libraryaddress2: "INSERT-LIBRARY-ADDRESS-HERE", // if applicable, enter the address of the second library used + libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) + libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used + libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used + libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... - }, headers: { "Content-Type": "application/x-www-form-urlencoded" }) - - if (response.data.status == "1") { - // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission - // average time of processing is 30-60 seconds - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) - // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status + }, + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } + ); + + if (response.data.status == '1') { + // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission + // average time of processing is 30-60 seconds + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); + // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status } else { - // 0 = error - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) + // 0 = error + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); } ``` -=== "Moonbase" +=== "Moonbase Alpha" + ```javascript // Submit Source Code for Verification - const response = await axios.post("https://api-moonbase.moonscan.io/api", { - apikey: "INSERT-API-KEY-HERE", - module: "contract", - action: "verifysourcecode", - contractAddress: "INSERT-CONTRACT-ADDRESS-HERE", - sourceCode: "INSERT-SOURCE-CODE-HERE", // flattened if necessary - codeformat: "solidity-single-file" // or you can use "solidity-standard-json-input" - contractname: "INSERT-CONTRACT-NAME-HERE", // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 - compilerversion: "INSERT-COMPILER-VERSION-HERE" // see https://etherscan.io/solcversions for list of support versions - optimizationUsed: 0 // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) - runs: 200 // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) - constructorArguements: "INSERT-CONSTRUCTOR-ARGUMENTS-HERE" // if applicable - evmversion: "INSERT-EVM-VERSION-HERE", // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) + const response = await axios.post( + 'https://api-moonbase.moonscan.io/api', + { + apikey: 'INSERT_API_KEY', + module: 'contract', + action: 'verifysourcecode', + contractAddress: 'INSERT_CONTRACT_ADDRESS', + sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary + codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" + contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 + compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions + optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) + runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) + constructorArguements: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable + evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types - libraryname1: "INSERT-LIBRARY-NAME-HERE" // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) - libraryaddress1: "INSERT-LIBRARY-ADDRESS-HERE" // if applicable, enter the address of the first library used - libraryname2: "INSERT-LIBRARY-NAME-HERE", // if applicable, enter the name of the second library used - libraryaddress2: "INSERT-LIBRARY-ADDRESS-HERE", // if applicable, enter the address of the second library used + libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) + libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used + libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used + libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... - }, headers: { "Content-Type": "application/x-www-form-urlencoded" }) - - if (response.data.status == "1") { - // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission - // average time of processing is 30-60 seconds - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) - // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status + }, + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } + ); + + if (response.data.status == '1') { + // 1 = submission success, use the guid returned (response.data.response.data) to check the status of your submission + // average time of processing is 30-60 seconds + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); + // response.data.response.data is the GUID receipt for the submission, you can use this guid for checking the verification status } else { - // 0 = error - console.log(response.data.status + "; " + response.data.message + "; " + response.data.result) + // 0 = error + console.log( + response.data.status + + '; ' + + response.data.message + + '; ' + + response.data.result + ); } ``` 在成功提交后,将会获得一个GUID作为结果。此GUID将会用于查看提交状态。 === "Moonbeam" + ```bash curl https://api-moonbeam.moonscan.io/api - ?module=contract - &action=checkverifystatus - &guid=INSERT-GUID-FROM-RESPONSE-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=checkverifystatus + &guid=INSERT_GUID_FROM_RESPONSE + &apikey=INSERT_API_KEY ``` === "Moonriver" + ```bash curl https://api-moonriver.moonscan.io/api - ?module=contract - &action=checkverifystatus - &guid=INSERT-GUID-FROM-RESPONSE-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=checkverifystatus + &guid=INSERT_GUID_FROM_RESPONSE + &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" + ```bash curl https://api-moonbase.moonscan.io/api - ?module=contract - &action=checkverifystatus - &guid=INSERT-GUID-FROM-RESPONSE-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=checkverifystatus + &guid=INSERT_GUID_FROM_RESPONSE + &apikey=INSERT_API_KEY ``` ### 检索验证合约的ABI {: #retrieve-contract-abi-for-verified-contracts } @@ -187,30 +241,33 @@ Moonbeam相关网络的Moonscan API URL如下: 当您合约已在Moonscan上获得验证,您可以使用以下端点检索合约ABI: === "Moonbeam" + ```bash curl https://api-moonbeam.moonscan.io/api - ?module=contract - &action=getabi - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getabi + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` === "Moonriver" + ```bash curl https://api-moonriver.moonscan.io/api - ?module=contract - &action=getabi - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getabi + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" + ```bash curl https://api-moonbase.moonscan.io/api - ?module=contract - &action=getabi - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getabi + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` ### 检索验证合约的源代码 {: #retrieve-contract-source-code-for-verified-contracts } @@ -218,30 +275,33 @@ Moonbeam相关网络的Moonscan API URL如下: 当您的合约已在Moonscan上获得验证,您可以使用以下端点检索合约源代码: === "Moonbeam" + ```bash curl https://api-moonbeam.moonscan.io/api - ?module=contract - &action=getsourcecode - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getsourcecode + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` === "Moonriver" + ```bash curl https://api-moonriver.moonscan.io/api - ?module=contract - &action=getsourcecode - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getsourcecode + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" + ```bash curl https://api-moonbase.moonscan.io/api - ?module=contract - &action=getsourcecode - &address=INSERT-CONTRACT-ADDRESS-HERE - &apikey=INSERT-API-KEY-TOKEN-HERE + ?module=contract + &action=getsourcecode + &address=INSERT_CONTRACT_ADDRESS + &apikey=INSERT_API_KEY ``` ## 使用Sourcify API {: #using-sourcify-api } @@ -254,12 +314,13 @@ Sourcify API端点可通过以下公共服务器访问: === "Production" - ```bash + ```text https://sourcify.dev/server ``` === "Staging" - ```bash + + ```text https://staging.sourcify.dev/server ``` @@ -268,17 +329,20 @@ Sourcify API端点可通过以下公共服务器访问: Sourcify使用链ID验证请求的目标网络。Moonbeam相关网络的链ID如下: === "Moonbeam" - ```bash + + ```text {{ networks.moonbeam.chain_id }} ``` === "Moonriver" - ```bash + + ```text {{ networks.moonriver.chain_id }} ``` === "Moonbase" - ```bash + + ```text {{ networks.moonbase.chain_id }} ``` @@ -295,86 +359,89 @@ Sourcify支持两种验证匹配结果。 您可以使用POST请求在Sourcify验证合约,以下为使用JavaScript撰写的范例代码: === "Moonbeam" + ```javascript // Submit Contract Source Code and Metadata for Verification - const response = await axios.post("https://sourcify.dev/server/verify", { - "address": "INSERT-CONTRACT-ADDRESS-HERE" - "chain": {{ networks.moonbeam.chain_id }}, // chain ID of Moonbeam - "files": { - "metadata-1.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 1 - "metadata-2.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 2 - "file1-name.sol": "INSERT-SOL-FILE-HERE", // contract source file 1 - "file2-name.sol": "INSERT-SOL-FILE-HERE" // contract source file 2 - //... - }, - "chosenContract": 1 // (optional) index of the contract, if the provided files contain multiple metadata files - }) - - if (result.status == "perfect") { - // perfect match - console.log(result.status + ";" + result.address); - } elseif (result.status == "partial") { - // partial match - console.log(result.status + ";" + result.address); + const response = await axios.post('https://sourcify.dev/server/verify', { + address: 'INSERT_CONTRACT_ADDRESS', + chain: {{ networks.moonbeam.chain_id }}, // chain ID of Moonbeam + files: { + 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 + 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 + 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 + 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 + //... + }, + chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files + }); + + if (result.status == 'perfect') { + // perfect match + console.log(result.status + ';' + result.address); + } else if (result.status == 'partial') { + // partial match + console.log(result.status + ';' + result.address); } else { - // non-matching - console.log(result.status + ";" + result.address); + // non-matching + console.log(result.status + ';' + result.address); } ``` === "Moonriver" + ```javascript // Submit Contract Source Code and Metadata for Verification - const response = await axios.post("https://sourcify.dev/server/verify", { - "address": "INSERT-CONTRACT-ADDRESS-HERE" - "chain": {{ networks.moonriver.chain_id }}, // chain ID of Moonriver - "files": { - "metadata-1.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 1 - "metadata-2.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 2 - "file1-name.sol": "INSERT-SOL-FILE-HERE", // contract source file 1 - "file2-name.sol": "INSERT-SOL-FILE-HERE" // contract source file 2 - //... - }, - "chosenContract": 1 // (optional) index of the contract, if the provided files contain multiple metadata files - }) - - if (result.status == "perfect") { - // perfect match - console.log(result.status + ";" + result.address); - } elseif (result.status == "partial") { - // partial match - console.log(result.status + ";" + result.address); + const response = await axios.post('https://sourcify.dev/server/verify', { + address: 'INSERT_CONTRACT_ADDRESS', + chain: {{ networks.moonriver.chain_id }}, // chain ID of Moonriver + files: { + 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 + 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 + 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 + 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 + //... + }, + chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files + }); + + if (result.status == 'perfect') { + // perfect match + console.log(result.status + ';' + result.address); + } else if (result.status == 'partial') { + // partial match + console.log(result.status + ';' + result.address); } else { - // non-matching - console.log(result.status + ";" + result.address); + // non-matching + console.log(result.status + ';' + result.address); } ``` -=== "Moonbase" +=== "Moonbase Alpha" + ```javascript // Submit Contract Source Code and Metadata for Verification - const response = await axios.post("https://sourcify.dev/server/verify", { - "address": "INSERT-CONTRACT-ADDRESS-HERE" - "chain": {{ networks.moonbase.chain_id }}, // chain ID of Moonbase Alpha - "files": { - "metadata-1.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 1 - "metadata-2.json": "INSERT-JSON-FILE-HERE", // metadata file for contract file 2 - "file1-name.sol": "INSERT-SOL-FILE-HERE", // contract source file 1 - "file2-name.sol": "INSERT-SOL-FILE-HERE" // contract source file 2 - //... - }, - "chosenContract": 1 // (optional) index of the contract, if the provided files contain multiple metadata files - }) - - if (result.status == "perfect") { - // perfect match - console.log(result.status + ";" + result.address); - } elseif (result.status == "partial") { - // partial match - console.log(result.status + ";" + result.address); + const response = await axios.post('https://sourcify.dev/server/verify', { + address: 'INSERT_CONTRACT_ADDRESS', + chain: {{ networks.moonbase.chain_id }}, // chain ID of Moonbase Alpha + files: { + 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 + 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 + 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 + 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 + //... + }, + chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files + }); + + if (result.status == 'perfect') { + // perfect match + console.log(result.status + ';' + result.address); + } else if (result.status == 'partial') { + // partial match + console.log(result.status + ';' + result.address); } else { - // non-matching - console.log(result.status + ";" + result.address); + // non-matching + console.log(result.status + ';' + result.address); } ``` @@ -390,37 +457,37 @@ Sourcify提供开发者端点以同时查看多个EVM链上合约的验证状态 ```bash curl https://sourcify.dev/server/check-by-addresses - ?addresses={INSERT-ADDRESS-1-HERE, INSERT-ADDRESS-2-HERE, ...} - &chainIds={INSERT-CHAIN-ID-1, INSERT-CHAIN-ID-2, ...} + ?addresses={INSERT_ADDRESS_1, INSERT_ADDRESS_2, ...} + &chainIds={INSERT_CHAIN_ID_1, INSERT_CHAIN_ID_2, ...} ``` === "部分匹配" ```bash curl https://sourcify.dev/server/check-all-by-addresses - ?addresses={INSERT-ADDRESS-1-HERE, INSERT-ADDRESS-2-HERE, ...} - &chainIds={INSERT-CHAIN-ID-1, INSERT-CHAIN-ID-2, ...} + ?addresses={INSERT_ADDRESS_1, INSERT_ADDRESS_2, ...} + &chainIds={INSERT_CHAIN_ID_1, INSERT_CHAIN_ID_2, ...} ``` 您将会获得一个JSON对象的响应,结构如下所示: ```json [ - { - "address": "address1", - "status": "perfect", - "chainIds": [ - "chainId1", - "chaindId2" - ] - }, - { - "address": "address2", - "status": "partial", - "chainIds": [ - "chaindId2" - ] - } + { + "address": "address1", + "status": "perfect", + "chainIds": [ + "chainId1", + "chaindId2" + ] + }, + { + "address": "address2", + "status": "partial", + "chainIds": [ + "chaindId2" + ] + } ] ``` @@ -431,31 +498,41 @@ Sourcify提供开发者端点以同时查看多个EVM链上合约的验证状态 此终端有两种变化,其中之一为完美匹配的源文件: === "Moonbeam" + ```bash - curl https://sourcify.dev/server/files/{{ networks.moonbeam.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/{{ networks.moonbeam.chain_id }}/INSERT_CONTRACT_ADDRESS ``` + === "Moonriver" + ```bash - curl https://sourcify.dev/server/files/{{ networks.moonriver.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/{{ networks.moonriver.chain_id }}/INSERT_CONTRACT_ADDRESS ``` + === "Moonbase" + ```bash - curl https://sourcify.dev/server/files/{{ networks.moonbase.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/{{ networks.moonbase.chain_id }}/INSERT_CONTRACT_ADDRESS ``` 另外一个为完美匹配和部分匹配的源文件: === "Moonbeam" + ```bash - curl https://sourcify.dev/server/files/any/{{ networks.moonbeam.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/any/{{ networks.moonbeam.chain_id }}/INSERT_CONTRACT_ADDRESS ``` + === "Moonriver" + ```bash - curl https://sourcify.dev/server/files/any/{{ networks.moonriver.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/any/{{ networks.moonriver.chain_id }}/INSERT_CONTRACT_ADDRESS ``` + === "Moonbase" + ```bash - curl https://sourcify.dev/server/files/any/{{ networks.moonbase.chain_id }}/INSERT-YOUR-CONTRACT-ADDRESS-HERE + curl https://sourcify.dev/server/files/any/{{ networks.moonbase.chain_id }}/INSERT_CONTRACT_ADDRESS ``` ### 在Foundry中使用Sourcify {: #using-sourcify-with-foundry } @@ -483,7 +560,7 @@ cast abi-encode "constructor(uint256)" 100 ```bash forge verify-contract --chain-id {{ networks.moonbeam.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ - --verifier sourcify YOUR_CONTRACT_ADDRESS src/MyToken.sol:MyToken + --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` === "Moonriver" @@ -491,7 +568,7 @@ cast abi-encode "constructor(uint256)" 100 ```bash forge verify-contract --chain-id {{ networks.moonriver.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ - --verifier sourcify YOUR_CONTRACT_ADDRESS src/MyToken.sol:MyToken + --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` === "Moonbase Alpha" @@ -499,7 +576,7 @@ cast abi-encode "constructor(uint256)" 100 ```bash forge verify-contract --chain-id {{ networks.moonbase.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ - --verifier sourcify YOUR_CONTRACT_ADDRESS src/MyToken.sol:MyToken + --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` ![Foundry Verify](/images/builders/build/eth-api/verify-contracts/api-verification/api-1.png) @@ -512,7 +589,7 @@ cast abi-encode "constructor(uint256)" 100 forge create --rpc-url {{ networks.moonbeam.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ - --private-key YOUR_PRIVATE_KEY \ + --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` @@ -522,7 +599,7 @@ cast abi-encode "constructor(uint256)" 100 forge create --rpc-url {{ networks.moonriver.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ - --private-key YOUR_PRIVATE_KEY \ + --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` @@ -532,8 +609,8 @@ cast abi-encode "constructor(uint256)" 100 forge create --rpc-url {{ networks.moonbase.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ - --private-key YOUR_PRIVATE_KEY \ + --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` -![Foundry Contract Deploy and Verify](/images/builders/build/eth-api/verify-contracts/api-verification/api-2.png) \ No newline at end of file +![Foundry Contract Deploy and Verify](/images/builders/build/eth-api/verify-contracts/api-verification/api-2.png) diff --git a/builders/build/eth-api/verify-contracts/etherscan-plugins.md b/builders/build/eth-api/verify-contracts/etherscan-plugins.md index 75727c76..84443d1c 100644 --- a/builders/build/eth-api/verify-contracts/etherscan-plugins.md +++ b/builders/build/eth-api/verify-contracts/etherscan-plugins.md @@ -72,8 +72,8 @@ module.exports = { moonbeam: 'INSERT_MOONSCAN_API_KEY', // Moonbeam Moonscan API Key moonriver: 'INSERT_MOONSCAN_API_KEY', // Moonriver Moonscan API Key moonbaseAlpha: 'INSERT_MOONSCAN_API_KEY', // Moonbeam Moonscan API Key - } - } + }, + }, }; ``` @@ -119,9 +119,9 @@ module.exports = { compilers: { ... }, plugins: ['moonbeam-truffle-plugin', 'truffle-plugin-verify'], api_keys: { - moonscan: 'INSERT_YOUR_MOONSCAN_API_KEY' - } -} + moonscan: 'INSERT_YOUR_MOONSCAN_API_KEY', + }, +}; ``` 要验证合约,您需要运行`run verify`命令并传入已部署合约的名称及其部署的网络: diff --git a/builders/build/moonbeam-custom-api.md b/builders/build/moonbeam-custom-api.md index ceede1a2..ab124cc0 100644 --- a/builders/build/moonbeam-custom-api.md +++ b/builders/build/moonbeam-custom-api.md @@ -30,25 +30,27 @@ Moonbeam节点现已添加对两个自定义JSON RPC端点`moon_isBlockFinalized === "moon_isBlockFinalized" ```bash - curl -H "Content-Type: application/json" -X POST --data - '[{ - "jsonrpc":"2.0", - "id":"1", - "method":"moon_isBlockFinalized", - "params":["Put-Block-Hash-Here" - ]}]' - {{ networks.moonbase.rpc_url }} + curl -H "Content-Type: application/json" -X POST --data '[ + { + "jsonrpc": "2.0", + "id": "1", + "method": "moon_isBlockFinalized", + "params": ["INSERT_BLOCK_HASH"] + } + ]' + {{ networks.moonbase.rpc_url }} ``` === "moon_isTxFinalized" ```bash - curl -H "Content-Type: application/json" -X POST --data - '[{ - "jsonrpc":"2.0", - "id":"1", - "method":"moon_isTxFinalized", - "params":["Put-Tx-Hash-Here" - ]}]' - {{ networks.moonbase.rpc_url }} + curl -H "Content-Type: application/json" -X POST --data '[ + { + "jsonrpc": "2.0", + "id": "1", + "method": "moon_isTxFinalized", + "params": ["INSERT_TX_HASH"] + } + ]' + {{ networks.moonbase.rpc_url }} ``` diff --git a/builders/build/substrate-api/polkadot-js-api.md b/builders/build/substrate-api/polkadot-js-api.md index e8b60e9d..914a6077 100644 --- a/builders/build/substrate-api/polkadot-js-api.md +++ b/builders/build/substrate-api/polkadot-js-api.md @@ -38,43 +38,75 @@ yarn add @polkadot/api --8<-- 'text/_common/endpoint-examples.md' === "Moonbeam" + ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; + const main = async () => { + // Construct API provider + const wsProvider = new WsProvider('{{ networks.moonbeam.wss_url }}'); + const api = await ApiPromise.create({ provider: wsProvider }); + + // Code goes here + + await api.disconnect(); + } - // Construct API provider - const wsProvider = new WsProvider('{{ networks.moonbeam.wss_url }}'); - const api = await ApiPromise.create({ provider: wsProvider }); + main(); ``` === "Moonriver" + ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; + const main = async () => { + // Construct API provider + const wsProvider = new WsProvider('{{ networks.moonriver.wss_url }}'); + const api = await ApiPromise.create({ provider: wsProvider }); + + // Code goes here - // Construct API provider - const wsProvider = new WsProvider('{{ networks.moonriver.wss_url }}'); - const api = await ApiPromise.create({ provider: wsProvider }); + await api.disconnect(); + } + + main(); ``` === "Moonbase Alpha" + ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; + const main = async () => { + // Construct API provider + const wsProvider = new WsProvider('{{ networks.moonbase.wss_url }}'); + const api = await ApiPromise.create({ provider: wsProvider }); + + // Code goes here + + await api.disconnect(); + } - // Construct API provider - const wsProvider = new WsProvider('{{ networks.moonbase.wss_url }}'); - const api = await ApiPromise.create({ provider: wsProvider }); + main(); ``` === "Moonbeam开发节点" + ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; + const main = async () => { + // Construct API provider + const wsProvider = new WsProvider('{{ networks.dev.wss_url }}'); + const api = await ApiPromise.create({ provider: wsProvider }); + + // Code goes here - // Construct API provider - const wsProvider = new WsProvider('{{ networks.development.wss_url }}'); - const api = await ApiPromise.create({ provider: wsProvider }); + await api.disconnect(); + } + + main(); ``` ### 元数据和动态API修饰 {: #metadata-and-dynamic-api-decoration } @@ -100,7 +132,7 @@ yarn add @polkadot/api ... // Define wallet address -const addr = 'MOONBEAM-WALLET-ADDRESS-HERE'; +const addr = 'INSERT_ADDRESS'; // Retrieve the last timestamp const now = await api.query.timestamp.now(); @@ -111,7 +143,9 @@ const { nonce, data: balance } = await api.query.system.account(addr); // Retrieve the given account's next index/nonce, taking txs in the pool into account const nextNonce = await api.rpc.system.accountNextIndex(addr); -console.log(`${now}: balance of ${balance.free} and a current nonce of ${nonce} and next nonce of ${nextNonce}`); +console.log( + `${now}: balance of ${balance.free} and a current nonce of ${nonce}` +); // Disconnect the API api.disconnect(); @@ -140,7 +174,9 @@ const chain = await api.rpc.system.chain(); const lastHeader = await api.rpc.chain.getHeader(); // Log the information -console.log(`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`); +console.log( + `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` +); // Disconnect the API api.disconnect(); @@ -165,7 +201,9 @@ const chain = await api.rpc.system.chain(); // Subscribe to the new headers await api.rpc.chain.subscribeNewHeads((lastHeader) => { - console.log(`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`); + console.log( + `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` + ); }); // Disconnect the API @@ -181,11 +219,13 @@ api.disconnect(); ... // Define wallet address -const addr = 'MOONBEAM-WALLET-ADDRESS-HERE'; +const addr = 'INSERT_ADDRESS'; // Subscribe to balance changes for a specified account await api.query.system.account(addr, ({ nonce, data: balance }) => { - console.log(`free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}`); + console.log( + `Free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}` + ); }); // Disconnect the API @@ -238,20 +278,20 @@ const keyring = new Keyring({ type: 'ethereum' }); ... // Initialize wallet key pairs -const alice = keyring.addFromUri('ALICE-ACCOUNT-PRIVATE-KEY'); -const bob = 'BOB-ACCOUNT-PUBLIC-KEY'; +const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY'); +const bob = 'INSERT_BOBS_ADDRESS'; // Form the transaction const tx = await api.tx.balances - .transfer(bob, 12345n) + .transfer(bob, 12345n); // Retrieve the encoded calldata of the transaction -const encodedCalldata = tx.method.toHex() -console.log(encodedCallData) +const encodedCalldata = tx.method.toHex(); +console.log(encodedCallData); // Sign and send the transaction const txHash = await tx - .signAndSend(alice); + .signAndSend(alice); // Show the transaction hash console.log(`Submitted with hash ${txHash}`); @@ -291,32 +331,27 @@ Polkadot.js API允许通过`api.tx.utility.batch`函数批处理事务。这些 ... // Construct a list of transactions to batch -const collator = 'COLLATOR-ACCOUNT-PUBLIC-KEY'; +const collator = 'INSERT_COLLATORS_ADDRESS'; const txs = [ api.tx.balances.transfer(bob, 12345n), api.tx.balances.transfer(charlie, 12345n), - api.tx.parachainStaking.scheduleDelegatorBondLess(collator, 12345n) + api.tx.parachainStaking.scheduleDelegatorBondLess(collator, 12345n), ]; // Estimate the fees as RuntimeDispatchInfo, using the signer (either // address or locked/unlocked keypair) -const info = await api.tx.utility - .batch(txs) - .paymentInfo(alice); +const info = await api.tx.utility.batch(txs).paymentInfo(alice); console.log(`estimated fees: ${info}`); // Construct the batch and send the transactions -api.tx.utility - .batch(txs) - .signAndSend(alice, ({ status }) => { - if (status.isInBlock) { - console.log(`included in ${status.asInBlock}`); - } - }); +api.tx.utility.batch(txs).signAndSend(alice, ({ status }) => { + if (status.isInBlock) { + console.log(`included in ${status.asInBlock}`); -// Disconnect the API -api.disconnect(); + // Disconnect API here! + } +}); ``` ??? code "查看完整脚本" @@ -397,28 +432,26 @@ import { numberToHex } from '@polkadot/util'; // Define the raw signed transaction const txData = { - nonce: numberToHex(1), - gasPrice: numberToHex(21000000000), - gasLimit: numberToHex(21000), - to: '0xc390cC49a32736a58733Cf46bE42f734dD4f53cb', - value: numberToHex(1000000000000000000), - data: '', - v: "0507", - r: "0x5ab2f48bdc6752191440ce62088b9e42f20215ee4305403579aa2e1eba615ce8", - s: "0x3b172e53874422756d48b449438407e5478c985680d4aaa39d762fe0d1a11683" -} - + nonce: numberToHex(1), + gasPrice: numberToHex(21000000000), + gasLimit: numberToHex(21000), + to: '0xc390cC49a32736a58733Cf46bE42f734dD4f53cb', + value: numberToHex(1000000000000000000), + data: '', + v: '0507', + r: '0x5ab2f48bdc6752191440ce62088b9e42f20215ee4305403579aa2e1eba615ce8', + s: '0x3b172e53874422756d48b449438407e5478c985680d4aaa39d762fe0d1a11683', +}; // Extract the values to an array -var txDataArray = Object.keys(txData) - .map(function (key) { - return txData[key]; - }); +var txDataArray = Object.keys(txData).map(function (key) { + return txData[key]; +}); // Calculate the RLP encoded transaction -var encoded_tx = encode(txDataArray) +var encoded_tx = encode(txDataArray); // Hash the encoded transaction using keccak256 -console.log(keccakAsHex(encoded_tx)) +console.log(keccakAsHex(encoded_tx)); ``` 您可以查看相应的[NPM存储库页面](https://www.npmjs.com/package/@polkadot/util-crypto/v/0.32.19){target=_blank}以获取其中的可用方法列表库及其相关文档。 diff --git a/builders/build/substrate-api/py-substrate-interface.md b/builders/build/substrate-api/py-substrate-interface.md index 5f202963..bab230d6 100644 --- a/builders/build/substrate-api/py-substrate-interface.md +++ b/builders/build/substrate-api/py-substrate-interface.md @@ -45,7 +45,7 @@ pip install substrate-interface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbeam.wss_url }}", - ) + ) ``` === "Moonriver" @@ -57,7 +57,7 @@ pip install substrate-interface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonriver.wss_url }}", - ) + ) ``` === "Moonbase Alpha" @@ -69,7 +69,7 @@ pip install substrate-interface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", - ) + ) ``` === "Moonbeam开发节点" @@ -110,8 +110,8 @@ print(constant_list) # Retrieve the Existential Deposit constant on Moonbeam, which is 0 constant = ws_provider.get_constant("Balances", "ExistentialDeposit") print(constant.value) - ``` + ### 检索区块和Extrinsics {: #retrieving-blocks-and-extrinsics } 您可以使用Python Substrate Interface API检索Moonbeam网络的基本信息,如区块和extrinsics。 @@ -127,29 +127,31 @@ from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", -) +) # Retrieve the latest block block = ws_provider.get_block() # Retrieve the latest finalized block -block = ws_provider.get_block_header(finalized_only = True) +block = ws_provider.get_block_header(finalized_only=True) # Retrieve a block given its Substrate block hash block_hash = "0xa499d4ebccdabe31218d232460c0f8b91bd08f72aca25f9b25b04b6dfb7a2acb" block = ws_provider.get_block(block_hash=block_hash) # Iterate through the extrinsics inside the block -for extrinsic in block['extrinsics']: - if 'address' in extrinsic: - signed_by_address = extrinsic['address'].value +for extrinsic in block["extrinsics"]: + if "address" in extrinsic: + signed_by_address = extrinsic["address"].value else: signed_by_address = None - print('\nPallet: {}\nCall: {}\nSigned by: {}'.format( - extrinsic["call"]["call_module"].name, - extrinsic["call"]["call_function"].name, - signed_by_address - )) + print( + "\nPallet: {}\nCall: {}\nSigned by: {}".format( + extrinsic["call"]["call_module"].name, + extrinsic["call"]["call_function"].name, + signed_by_address, + ) + ) ``` !!! 注意事项 @@ -166,14 +168,17 @@ from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", -) +) -def subscription_handler(obj, update_nr, subscription_id): +def subscription_handler(obj, update_nr, subscription_id): print(f"New block #{obj['header']['number']}") if update_nr > 10: - return {'message': 'Subscription will cancel when a value is returned', 'updates_processed': update_nr} + return { + "message": "Subscription will cancel when a value is returned", + "updates_processed": update_nr, + } result = ws_provider.subscribe_block_headers(subscription_handler) @@ -194,7 +199,7 @@ from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", -) +) # List of available storage functions in the metadata method_list = ws_provider.get_metadata_storage_functions() @@ -202,20 +207,18 @@ print(method_list) # Query basic account information account_info = ws_provider.query( - module='System', - storage_function='Account', - params=['0x578002f699722394afc52169069a1FfC98DA36f1'] + module="System", + storage_function="Account", + params=["0x578002f699722394afc52169069a1FfC98DA36f1"], ) # Log the account nonce -print(account_info.value['nonce']) +print(account_info.value["nonce"]) # Log the account free balance -print(account_info.value['data']['free']) +print(account_info.value["data"]["free"]) # Query candidate pool information from Moonbeam's Parachain Staking module candidate_pool_info = ws_provider.query( - module='ParachainStaking', - storage_function='CandidatePool', - params=[] + module="ParachainStaking", storage_function="CandidatePool", params=[] ) print(candidate_pool_info) ``` @@ -233,10 +236,10 @@ Python Substrate Interface中的密钥对是用于任何数据的签署,包括 from substrateinterface import Keypair, KeypairType # Define the shortform private key -privatekey = bytes.fromhex("enter-shortform-private-key-without-0x-prefix") +privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") # Define the account mnenomic -mnemonic = "enter-account-mnemonic" +mnemonic = "INSERT_MNEMONIC" # Generate the keypair from shortform private key keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) @@ -258,7 +261,6 @@ keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ECDSA) 以下示例代码将显示发送交易的一个完整示例。 ```python - # Imports from substrateinterface import SubstrateInterface, Keypair, KeypairType from substrateinterface.exceptions import SubstrateRequestException @@ -266,22 +268,22 @@ from substrateinterface.exceptions import SubstrateRequestException # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", -) +) # Define the shortform private key of the sending account -privatekey = bytes.fromhex("enter-shortform-private-key-without-0x-prefix") +privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") # Generate the keypair keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) # Form a transaction call call = ws_provider.compose_call( - call_module='Balances', - call_function='transfer', + call_module="Balances", + call_function="transfer", call_params={ - 'dest': '0x44236223aB4291b93EEd10E4B511B37a398DEE55', - 'value': 1 * 10**18 - } + "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", + "value": 1 * 10**18, + }, ) # Form a signed extrinsic @@ -290,13 +292,14 @@ extrinsic = ws_provider.create_signed_extrinsic(call=call, keypair=keypair) # Submit the extrinsic try: receipt = ws_provider.submit_extrinsic(extrinsic, wait_for_inclusion=True) - print("Extrinsic '{}' sent and included in block '{}'".format(receipt.extrinsic_hash, receipt.block_hash)) -except SubstrateRequestException as e: - print("Failed to send: {}".format(e)) - + print( + "Extrinsic '{}' sent and included in block '{}'".format( + receipt.extrinsic_hash, receipt.block_hash + ) + ) ``` -### 离线签署 {: #offline-signing } +### 离线签署 {: #offline-signing } 您可以通过[`sign`](https://polkascan.github.io/py-substrate-interface/#substrateinterface.Keypair.sign){target=_blank}函数使用密钥对签署交易负载或任何数据。这方式可用于离线签署交易。 @@ -309,22 +312,22 @@ except SubstrateRequestException as e: # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", - ) + ) # Construct a transaction call call = ws_provider.compose_call( - call_module='Balances', - call_function='transfer', + call_module="Balances", + call_function="transfer", call_params={ - 'dest': '0x44236223aB4291b93EEd10E4B511B37a398DEE55', - 'value': 1 * 10**18 - } + "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", + "value": 1 * 10**18, + }, ) # Generate the signature payload signature_payload = ws_provider.generate_signature_payload(call=call) ``` - + 2. 在离线设备使用发送账户的私钥创建一个密钥对,并签署签名负载: ```python @@ -332,22 +335,21 @@ except SubstrateRequestException as e: from substrateinterface import Keypair, KeypairType # Define the signature payload from the offline machine - signature_payload = "signature payload from offline machine" - + signature_payload = "INSERT_SIGNATURE_PAYLOAD" + # Define the shortform private key of the sender account - privatekey = bytes.fromhex("enter-shortform-private-key-without-0x-prefix") - + privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") + # Generate the keypair from shortform private key keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) # Sign the signature_payload signature = keypair.sign(signature_payload) ``` - + 3. 在线上设备使用发送账户的公钥创建一个密钥对,并使用离线设备生成的签名提交extrinsic: ```python - # Imports from substrateinterface import SubstrateInterface, Keypair, KeypairType @@ -357,33 +359,29 @@ except SubstrateRequestException as e: ) # Define the signature from the offline machine - signature = "generated signature from offline machine" - + signature_payload = "INSERT_SIGNATURE_PAYLOAD" + # Construct a keypair with the Ethereum style wallet address of the sending account - keypair = Keypair(public_key="enter-sender-wallet-address-without-0x", crypto_type=KeypairType.ECDSA) - + keypair = Keypair(public_key="INSERT_ADDRESS_WITHOUT_0X", crypto_type=KeypairType.ECDSA) + # Construct the same transaction call that was signed call = ws_provider.compose_call( - call_module='Balances', - call_function='transfer', + call_module="Balances", + call_function="transfer", call_params={ - 'dest': '0x44236223aB4291b93EEd10E4B511B37a398DEE55', - 'value': 1 * 10**18 - } + "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", + "value": 1 * 10**18, + }, ) - + # Construct the signed extrinsic with the generated signature extrinsic = substrate.create_signed_extrinsic( - call=call, - keypair=keypair, - signature=signature + call=call, keypair=keypair, signature=signature ) - + # Submit the signed extrinsic - result = substrate.submit_extrinsic( - extrinsic=extrinsic - ) - + result = substrate.submit_extrinsic(extrinsic=extrinsic) + # Print the execution result print(result.extrinsic_hash) ``` diff --git a/builders/get-started/eth-compare/security.md b/builders/get-started/eth-compare/security.md index 2d1a0e11..b195342b 100644 --- a/builders/get-started/eth-compare/security.md +++ b/builders/get-started/eth-compare/security.md @@ -78,7 +78,7 @@ function makeArbitraryCall(address _target, bytes calldata _bytes) public { } // Ensure the call data calls an approved and safe function - require(selector == INSERT-WHITELISTED-FUNCTION-SELECTOR); + require(selector == INSERT_WHITELISTED_FUNCTION_SELECTOR); // Arbitrary call (bool success,) = _target.call(_bytes); @@ -97,7 +97,7 @@ function makeArbitraryCall(address _target, bytes calldata _bytes) public { ```solidity function makeArbitraryCall(address _target, bytes calldata _bytes) public { // Ensure the contract address is safe - require(_target == INSERT-CONTRACT-ADDRESS); + require(_target == INSERT_CONTRACT_ADDRESS); // Arbitrary call (bool success,) = _target.call(_bytes); diff --git a/builders/get-started/eth-compare/transfers-api.md b/builders/get-started/eth-compare/transfers-api.md index 39bf84b9..05868d37 100644 --- a/builders/get-started/eth-compare/transfers-api.md +++ b/builders/get-started/eth-compare/transfers-api.md @@ -49,7 +49,9 @@ Token持有者有两种方式来启动Moonbeam上的余额转账功能。一方 以下代码片段使用[`subscribeFinalizedHeads`](https://polkadot.js.org/docs/substrate/rpc/#subscribefinalizedheads-header){target=_blank}订阅最新确认的区块头,并循环访问之中的每个事件。然后,检查是否与一个`balances.Transfer`事件对应。如果是,这将提取一个转账的`from`、`to`以及`amount`并显示在控制台上。请注意,`amount`是以最小的单位(Wei)来显示的。您可以在他们的[官方文档网站](https://polkadot.js.org/docs/substrate/rpc){target=_blank}找到关于Polkadot.js和Substrate JSON RPC的所有可用信息。 ---8<-- 'code/builders/get-started/eth-compare/transfers-api/balance-event.md' +```ts +--8<-- 'code/builders/get-started/eth-compare/transfers-api/balance-event.ts' +``` 此外,您可以在[此脚本](https://gist.github.com/crystalin/b2ce44a208af60d62b5ecd1bad513bce){target=_blank}中找到更多余额转账相关具体案例的代码片段。 @@ -59,6 +61,8 @@ Token持有者有两种方式来启动Moonbeam上的余额转账功能。一方 以下代码片段使用Axios HTTP客户端查询Sidecar端点`/blocks/head`(https://paritytech.github.io/substrate-api-sidecar/dist/){target=_blank}以获取最新确认的区块头。然后,在EVM和Substrate API级别解码原生Token转账的`from`、`to`、`value`、`tx hash`、和`transaction status` 区块。 ---8<-- 'code/builders/get-started/eth-compare/transfers-api/sidecar-transfer.md' +```js +--8<-- 'code/builders/get-started/eth-compare/transfers-api/sidecar-transfer.js' +``` 关于安装和运行Sidecar服务实例,以及如何解码Moonbeam交易的Sidecar区块等更多信息,请参考[Substrate API Sidecar页面](/builders/build/substrate-api/sidecar/){target=_blank}。 diff --git a/builders/get-started/eth-compare/tx-fees.md b/builders/get-started/eth-compare/tx-fees.md index 40300c08..86307434 100644 --- a/builders/get-started/eth-compare/tx-fees.md +++ b/builders/get-started/eth-compare/tx-fees.md @@ -285,6 +285,8 @@ Moonbeam网络实施[`eth_feeHistory`](https://docs.alchemy.com/reference/eth-fe 您可以将以下代码片段用于任何基于Moonbeam的网络,但您需要相应地修改`baseFee`。您可以参考[基本费用](#base-fee)部分以获取每个网络的计算结果。 ---8<-- 'code/builders/get-started/eth-compare/tx-fees/tx-fees-block-dynamic.md' +```js +--8<-- 'code/builders/get-started/eth-compare/tx-fees/tx-fees-block-dynamic.js' +``` --8<-- 'text/_disclaimers/third-party-content.md' diff --git a/builders/get-started/networks/moonbeam-dev.md b/builders/get-started/networks/moonbeam-dev.md index dfecf46c..8cca09a2 100644 --- a/builders/get-started/networks/moonbeam-dev.md +++ b/builders/get-started/networks/moonbeam-dev.md @@ -205,7 +205,9 @@ import { ethers } from 'ethers'; const produceBlock = async () => { // Connect to the Ethereum node (if applicable, replace the URL with your node's address) - const provider = new ethers.JsonRpcProvider('{{ networks.development.rpc_url }}'); + const provider = new ethers.JsonRpcProvider( + '{{ networks.development.rpc_url }}' + ); // Set the custom JSON-RPC method and parameters const method = 'engine_createBlock'; diff --git a/builders/integrations/indexers/covalent.md b/builders/integrations/indexers/covalent.md index 38bea999..1ce60386 100644 --- a/builders/integrations/indexers/covalent.md +++ b/builders/integrations/indexers/covalent.md @@ -41,6 +41,7 @@ Covalent API有两类终端: - **B类** —— 专门为特定区块链上的特定协议而设置的终端,例如Uniswap就是仅适用于以太坊的终端,无法在其他区块链网络上使用 ## Covalent API基础知识 {: #fundamentals-of-the-covalent-api } + - Covalent API是RESTful,围绕网页端界面主要资源进行开发 - 当前的Covalent API版本为版本1 - 所有终端的默认返回形式为JSON @@ -50,6 +51,7 @@ Covalent API有两类终端: - Covalent API采用实时刷新方式,刷新率为30秒或2个区块,每批次为10分钟或40个区块 ## 支持终端 {: #supported-endpoints } + - **Balances** —— 获取某一地址的代币余额。这一函数将返回一个包含所有ERC-20和NFT代币余额(包括ERC-721 和ERC-1155)的列表,以及这些代币目前的现货价格(若有) - **Transactions** —— 返回某一地址的所有交易记录,包括解码的日志事件。这一函数将深度抓取区块链并返回索引到这一地址的所有交易 - **Transfers** —— 获取某一地址的ERC-20代币转移记录以及历史代币价格(若有)) @@ -57,16 +59,16 @@ Covalent API有两类终端: - **Log Events (Smart Contract)** —— 返回特定智能合约发出的已解码日志事件,并标有页码 - **Log Events (Topic Hash)** —— 返回已解码日志事件,各个事件主题的哈希值之间用逗号分开,并标有页码 - ### 请求格式 {: #request-formatting } -| 终端 | | 格式 | -| :---------- | :-: | :------------------- | -| Balances | | api.covalenthq.com/v1/1287/address/{address}/balances_v2/ | -| Transactions | | api.covalenthq.com/v1/1287/address/{address}/transactions_v2/| -| Transfers | | api.covalenthq.com/v1/1287/address/{address}/transfers_v2/ | -| Token Holders | | api.covalenthq.com/v1/1287/tokens/{contract_address}/token_holders/ | -| Log Events (Smart Contract) | | api.covalenthq.com/v1/1287/events/address/{contract_address}/ | -| Log Events (Topic Hash) | | api.covalenthq.com/v1/1287/events/topics/{topic}/ | + +| 终端 | 格式 | +|:---------------------------:|:-------------------------------------------------------------------:| +| Balances | api.covalenthq.com/v1/1287/address/{address}/balances_v2/ | +| Transactions | api.covalenthq.com/v1/1287/address/{address}/transactions_v2/ | +| Transfers | api.covalenthq.com/v1/1287/address/{address}/transfers_v2/ | +| Token Holders | api.covalenthq.com/v1/1287/tokens/{contract_address}/token_holders/ | +| Log Events (Smart Contract) | api.covalenthq.com/v1/1287/events/address/{contract_address}/ | +| Log Events (Topic Hash) | api.covalenthq.com/v1/1287/events/topics/{topic}/ | ## 查看先决条件 {: #checking-prerequisites } @@ -77,6 +79,7 @@ Covalent API有两类终端: --8<-- 'text/_common/faucet/faucet-list-item.md' ## Covalent API使用测试 {: #try-it-out } + 首先确保您已获得以“ckey_”开头的[API密钥](https://www.covalenthq.com/platform/#/auth/register/){target=_blank}。Token Holders终端将返回某一特定代币所有持有者的列表,调用这个API需要执行以下操作: - 您的API密钥 @@ -84,10 +87,11 @@ Covalent API有两类终端: - 智能合约(此示例中为ERTH代币):0x08B40414525687731C23F430CEBb424b332b3d35 ### 使用Curl {: #using-curl } + 将占位符替换为您的API密钥,然后在终端窗口运行以下指令。 ```bash -curl https://api.covalenthq.com/v1/1287/tokens/\ +curl https://api.covalenthq.com/v1/1287/tokens/ \ 0x08B40414525687731C23F430CEBb424b332b3d35/token_holders/ \ -u INSERT_YOUR_API_KEY: ``` @@ -105,50 +109,50 @@ Covalent API将返回ERTH代币持有者名单。如果您未持有ERTH代币, ```js // set your API key - const apiKey = INSERT_YOUR_API_KEY; - - function getData() { - const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; //example - const chainId = '{{ networks.moonbase.chain_id }}'; //Moonbeam Testnet (Moonbase Alpha Chain ID) - const url = new URL(`https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/`); - - url.search = new URLSearchParams({ - key: apiKey - }) - - // use fetch API to get Covalent data - fetch(url) - .then((resp) => resp.json()) - .then(function(data) { - const result = data.data; - - console.log(result) - return result - } - )} - - getData(); - ``` + const apiKey = INSERT_YOUR_API_KEY; + + function getData() { + const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; // example + const chainId = '{{ networks.moonbase.chain_id }}'; // Moonbeam Testnet (Moonbase Alpha Chain ID) + const url = new URL(`https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/`); + + url.search = new URLSearchParams({ + key: apiKey, + }); + + // use fetch API to get Covalent data + fetch(url) + .then((resp) => resp.json()) + .then(function(data) { + const result = data.data; + + console.log(result); + return result; + } + )} + + getData(); + ``` === "Using Async" ```js // set your API key const apiKey = INSERT_YOUR_API_KEY; - const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; //example - const chainId = '{{ networks.moonbase.chain_id }}'; //Moonbeam Testnet (Moonbase Alpha Chain ID) - const url = new URL(`https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/`); + const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; // example + const chainId = '{{ networks.moonbase.chain_id }}'; // Moonbeam Testnet (Moonbase Alpha Chain ID) + const url = new URL(`https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/`); url.search = new URLSearchParams({ - key: apiKey - }) + key: apiKey, + }); async function getData() { - const response = await fetch(url); - const result = await response.json(); - console.log(result) - return result; - } + const response = await fetch(url); + const result = await response.json(); + console.log(result); + return result; + }; getData(); ``` @@ -158,21 +162,22 @@ Covalent API将返回ERTH代币持有者名单。如果您未持有ERTH代币, ![Javascript Console Output](/images/builders/integrations/indexers/covalent/covalent-2.png) ## Python示例 {: #python-example } + Covalent没有官方的API包装器,用户需要使用Python [请求库](https://pypi.org/project/requests/){target=_blank}才能直接调用API。通过`pip install requests`从指令行中将请求安装到运行环境中,然后将其导入,并在您的代码中使用。使用HTTP verbs get方法从API中返回相关信息。复制粘贴以下代码块到您选择的环境并运行。输出内容将与以上截图相似,但形式可能有所不同,这取决于运行环境。 ```python import requests def fetch_wallet_balance(address): - api_url = 'https://api.covalenthq.com' - endpoint = f'/v1/1287/address/{address}/balances_v2/' + api_url = "https://api.covalenthq.com" + endpoint = f"/v1/{{ networks.moonbase.chain_id }}/address/{address}/balances_v2/" url = api_url + endpoint - r = requests.get(url, auth=(INSERT_YOUR_API_KEY,'')) - print(r.json()) - return(r.json()) + response = requests.get(url, auth=("INSERT_YOUR_API_KEY", "")) + print(response.json()) + return response.json() -#Example address request -fetch_wallet_balance('0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8') +# Example address request +fetch_wallet_balance("0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8") ``` !!! 注意事项 diff --git a/builders/integrations/indexers/subquery.md b/builders/integrations/indexers/subquery.md index 0f83bdb8..71dd0a1e 100644 --- a/builders/integrations/indexers/subquery.md +++ b/builders/integrations/indexers/subquery.md @@ -83,9 +83,9 @@ SubQuery支持索引任意Moonbeam网络的以太坊虚拟机(EVM)和Substra 如果您查看`package.json`文件,您将会发现`chaintypes`已经导出在该文件中。如果未发现此情况,或者您正在扩展现有Substrate项目以添加Moonbeam网络支持,您将需要包含以下代码段: ```json - "exports": { +"exports": { "chaintypes": "src/chaintypes.ts" - } +} ``` ## 更新网络配置 {: #updating-the-network-configuration } diff --git a/builders/integrations/indexers/subsquid.md b/builders/integrations/indexers/subsquid.md index de341988..c4f6ea06 100644 --- a/builders/integrations/indexers/subsquid.md +++ b/builders/integrations/indexers/subsquid.md @@ -33,7 +33,7 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 1. 通过运行以下命令创建基于Substrate模板的Subsquid项目: ```bash - sqd init --template substrate + sqd init INSERT_SQUID_NAME --template substrate ``` 有关开始使用此模板的更多信息,请查看Subsquid文档网站上的[快速入门:Substrate链](https://docs.subsquid.io/quickstart/quickstart-substrate/){target=_blank}指南。 @@ -66,8 +66,8 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonbeam.rpc_url }}, - // Resolves to "https://moonbeam.archive.subsquid.io" - archive: lookupArchive("moonbeam", { type: "Substrate" }), + // Resolves to 'https://moonbeam.archive.subsquid.io' + archive: lookupArchive('moonbeam', { type: 'Substrate' }), }); ``` @@ -77,8 +77,8 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonriver.rpc_url }}, - // Resolves to "https://moonriver.archive.subsquid.io" - archive: lookupArchive("moonriver", { type: "Substrate" }), + // Resolves to 'https://moonriver.archive.subsquid.io' + archive: lookupArchive('moonriver', { type: 'Substrate' }), }); ``` @@ -88,8 +88,8 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonbase.rpc_url }}, - // Resolves to "https://moonbase.archive.subsquid.io" - archive: lookupArchive("moonbase", { type: "Substrate" }), + // Resolves to 'https://moonbase.archive.subsquid.io' + archive: lookupArchive('moonbase', { type: 'Substrate' }), }); ``` @@ -104,13 +104,13 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 === "EVM" ```bash - sqd init --template evm + sqd init INSERT_SQUID_NAME --template evm ``` === "ABI" ```bash - sqd init --template abi + sqd init INSERT_SQUID_NAME --template abi ``` 有关开始使用这两个模板的更多信息,请查看以下Subsquid文档: @@ -140,25 +140,25 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 3. 修改`src/processor.ts`文件,squid在该文件中实例化处理器、配置处理器并附加处理函数。处理器从[Archive](https://docs.subsquid.io/archives/overview/){target=_blank}(一个专门的数据湖)中获取历史链上数据。您需要将处理器配置为从与您索引数据的网络相对应的Archive(存档)中提取数据: - === "Moonbea - m" + === "Moonbeam" + ```js const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonbeam.rpc_url }}, - // Resolves to "https://moonbeam-evm.archive.subsquid.io" - archive: lookupArchive("moonbeam", { type: "EVM" }) + // Resolves to 'https://moonbeam-evm.archive.subsquid.io' + archive: lookupArchive('moonbeam', { type: 'EVM' }) }); ``` - === "Moonriv - er" + === "Moonriver" + ```js const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonriver.rpc_url }}, - // Resolves to "https://moonriver-evm.archive.subsquid.io" - archive: lookupArchive("moonriver", { type: "EVM" }), + // Resolves to 'https://moonriver-evm.archive.subsquid.io' + archive: lookupArchive('moonriver', { type: 'EVM' }), }); ``` @@ -168,8 +168,8 @@ Subsquid为以太坊虚拟机(EVM)和Substrate数据均提供原生的完整 const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: {{ networks.moonbase.rpc_url }}, - // Resolves to "https://moonbase-evm.archive.subsquid.io" - archive: lookupArchive("moonbase", { type: "EVM" }), + // Resolves to 'https://moonbase-evm.archive.subsquid.io' + archive: lookupArchive('moonbase', { type: 'EVM' }), }); ``` diff --git a/builders/integrations/indexers/thegraph.md b/builders/integrations/indexers/thegraph.md index ccc2cf54..4e42e08e 100644 --- a/builders/integrations/indexers/thegraph.md +++ b/builders/integrations/indexers/thegraph.md @@ -251,7 +251,7 @@ export function handlePlayerJoined(event: PlayerJoined): void { ticket.isGifted = event.params.isGifted; ticket.isWinner = false; - ticket.save(); + ticket.save(); } ``` diff --git a/builders/integrations/oracles/band-protocol.md b/builders/integrations/oracles/band-protocol.md index a2897f38..ab132a72 100644 --- a/builders/integrations/oracles/band-protocol.md +++ b/builders/integrations/oracles/band-protocol.md @@ -6,17 +6,19 @@ description: 如何通过智能合约或者Javascript在Moonbeam以太坊DApp使 # Band Protocol预言机 ## 概览 {: #introduction } + 开发者可通过两种方法从Band预言机获取价格。第一,可以通过Moonbeam上的Band智能合约在固定时间段或价格滑点大于目标值(不同代币的目标值不同)时获取链上最新数据。第二,使用JavaScript辅助库,该库绕过区块链直接从Band Protocol API(与智能合约相似的函数)中获取数据。如果DApp前端需要直接获取数据,则可以使用这种方法。 聚合合约地址可以在以下列表找到: -| 网络 | | 聚合合约地址 | -| :------------: | ---- | :----------------------------------------: | -| Moonbase Alpha | | 0xDA7a001b254CD22e46d3eAB04d937489c93174C3 | +| 网络 | 聚合合约地址 | +|:--------------:|:------------------------------------------:| +| Moonbase Alpha | 0xDA7a001b254CD22e46d3eAB04d937489c93174C3 | --8<-- 'text/_disclaimers/third-party-content-intro.md' ## 支持的代币 {: #supported-token } + 只要是平台支持的基础货币和报价货币(_报价对显示方式:基础货币代码_/_报价货币代码_),您都可以获取其报价。例如: - `BTC/USD` @@ -26,6 +28,7 @@ description: 如何通过智能合约或者Javascript在Moonbeam以太坊DApp使 您可通过此[Band标准数据集](https://data.bandprotocol.com){target=_blank}查看平台已支持的代币种类。撰写本文时,已有超过146对货币对可查询。 ## 获取报价 {: #querying-prices } + 如上所述,开发者可以通过两种方法从Band预言机获取报价: - Moonbeam上的Band智能合约(目前已部署在Moonbase Alpha测试网上) @@ -44,9 +47,9 @@ Moonbeam上的Band Protocol智能合约可通过实现`StdReference`合约接口 ```solidity struct ReferenceData { - uint256 rate; - uint256 lastUpdatedBase; - uint256 lastUpdatedQuote; + uint256 rate; + uint256 lastUpdatedBase; + uint256 lastUpdatedQuote; } ``` @@ -85,6 +88,7 @@ interface IStdReference { returns (ReferenceData[] memory); } ``` + 接下来可以使用`DemoOracle`脚本。该脚本含有4个函数: - **getPrice**(*string[]* base, *string[]* quotes) - 请求单一基础货币报价的_视图_函数。在此示例中,`BTC`以`USD`为报价单位 @@ -212,7 +216,7 @@ getReferenceData(['BTC/USD', 'BTC/ETH', 'ETH/EUR']) pair: 'ETH/EUR', rate: rate, updated: { base: lastUpdatedBase, quote: lastUpdatedQuote} - } + }, ] ``` @@ -229,7 +233,11 @@ const queryData = async () => { const endpoint = 'https://poa-api.bandchain.org'; const bandchain = new BandChain(endpoint); - const dataQuery = await bandchain.getReferenceData(['BTC/USD', 'BTC/ETH', 'ETH/EUR']); + const dataQuery = await bandchain.getReferenceData([ + 'BTC/USD', + 'BTC/ETH', + 'ETH/EUR', + ]); console.log(dataQuery); }; diff --git a/builders/integrations/oracles/chainlink.md b/builders/integrations/oracles/chainlink.md index f0596ee2..96c16c83 100644 --- a/builders/integrations/oracles/chainlink.md +++ b/builders/integrations/oracles/chainlink.md @@ -434,8 +434,8 @@ contract Client is ChainlinkClient { */ constructor() { setChainlinkToken(address(0xa36085F69e2889c224210F603D836748e7dC0088)); - oracle = {INSERT-YOUR-ORACLE-NODE-ADDRESS}; - jobId = "{INSERT-YOUR-JOB-ID}"; + oracle = INSERT_YOUR_ORACLE_NODE_ADDRESS; + jobId = "INSERT_YOUR_JOB_ID"; fee = 0; } diff --git a/builders/integrations/relayers/gelato.md b/builders/integrations/relayers/gelato.md index 76fe3431..6d32f0c9 100644 --- a/builders/integrations/relayers/gelato.md +++ b/builders/integrations/relayers/gelato.md @@ -95,8 +95,8 @@ touch hello-world.js 现在您已经完成事前准备。接着,您需要导入Gelato Relay SDK和Ethers.js: ```js - import { Wallet, utils } from "ethers"; - import { GelatoRelaySDK } from "@gelatonetwork/gelato-relay-sdk"; +import { Wallet, utils } from 'ethers'; +import { GelatoRelaySDK } from '@gelatonetwork/gelato-relay-sdk'; ``` 接着,创建一个包含脚本逻辑的函数: @@ -104,15 +104,15 @@ touch hello-world.js ```js const forwardRequestExample = async () => { -} +}; ``` 在`forwardRequestExample`函数中,定义链ID以及您希望交互的[`HelloWorld.sol` 合约](https://moonscan.io/address/0x3456E168d2D7271847808463D6D383D079Bd5Eaa#code){target=_blank}。 ```js - const chainId = {{ networks.moonbeam.chain_id }}; - // `HelloWorld.sol` contract on Moonbeam - const target = "0x3456E168d2D7271847808463D6D383D079Bd5Eaa"; +const chainId = {{ networks.moonbeam.chain_id }}; +// `HelloWorld.sol` contract on Moonbeam +const target = '0x3456E168d2D7271847808463D6D383D079Bd5Eaa'; ``` [`HelloWorld.sol`合约](https://moonscan.io/address/0x3456E168d2D7271847808463D6D383D079Bd5Eaa#code){target=_blank}将会在生产以下内容,以支持无需Gas费用的交易。 @@ -150,12 +150,12 @@ contract HelloWorld is ERC2771Context { 接着,您可以创建一个新的测试账户以提交无需Gas费用的交易。此账户不安全且不应当被用于生产环境。本示例使用预设数值定义`test_token`作为展示,但您可以依据需求制定任何Token。 ```js - const test_token = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; - // Create mock wallet - const wallet = Wallet.createRandom(); - const sponsor = await wallet.getAddress(); - console.log(`Mock PK: ${await wallet._signingKey().privateKey}`); - console.log(`Mock wallet address: ${sponsor}`); +const test_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; +// Create mock wallet +const wallet = Wallet.createRandom(); +const sponsor = await wallet.getAddress(); +console.log(`Mock PK: ${await wallet._signingKey().privateKey}`); +console.log(`Mock wallet address: ${sponsor}`); ``` ### 添加请求数据 {: #add-request-data } @@ -176,35 +176,35 @@ contract HelloWorld is ERC2771Context { 此ABI编码调用数据制定了调用的合约函数以及任何相关参数,并可以通过MetaMask或Remix获取。另外,您或许可以通过Ether.js或是Web3.js获取ABI编码调用数据。有一些额外的参数在以下示例中定义,如`paymentType`、`maxFee`以及`gas`。您可以选取不同可用的支付类型。为简单起见,重复播放保护未包含在此示例中。 ```js - // ABI encode for HelloWorld.sayHiVanilla(address _feeToken) - const data = `0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee`; - const paymentType = 1; - // Maximum fee that sponsor is willing to pay worth of test_token - const maxFee = "1000000000000000000"; - // Gas limit - const gas = "200000"; - - // Smart contract nonces are not enforced to simplify the example. - // In reality, this decision depends whether or not target - // address already implements replay protection. (More info in the docs) - const sponsorNonce = 0; - const enforceSponsorNonce = false; - // Only relevant when enforceSponsorNonce = true - const enforceSponsorNonceOrdering = false; - - // Build ForwardRequest object - const forwardRequest = GelatoRelaySDK.forwardRequest( - chainId, - target, - data, - test_token, - paymentType, - maxFee, - gas, - sponsorNonce, - enforceSponsorNonce, - sponsor - ); +// ABI encode for HelloWorld.sayHiVanilla(address _feeToken) +const data = '0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee'; +const paymentType = 1; +// Maximum fee that sponsor is willing to pay worth of test_token +const maxFee = '1000000000000000000'; +// Gas limit +const gas = '200000'; + +// Smart contract nonces are not enforced to simplify the example. +// In reality, this decision depends whether or not target +// address already implements replay protection. (More info in the docs) +const sponsorNonce = 0; +const enforceSponsorNonce = false; +// Only relevant when enforceSponsorNonce = true +const enforceSponsorNonceOrdering = false; + +// Build ForwardRequest object +const forwardRequest = GelatoRelaySDK.forwardRequest( + chainId, + target, + data, + test_token, + paymentType, + maxFee, + gas, + sponsorNonce, + enforceSponsorNonce, + sponsor +); ``` 最后,`forwardRequest`对象将被创建,且具有先前步骤中定义的所有相关函数。在最终步骤,`forwardRequest`对象将会与所需的签名被传送至Gelato Relay API。 @@ -214,18 +214,18 @@ contract HelloWorld is ERC2771Context { 最后的几个步骤包含散列请求对象以及签署结果的哈希。最后一步为提交请求和签名至Gelato Relay API。您可以在`forwardRequest`对象后复制并粘贴以下代码: ```js - // Get EIP-712 hash (aka digest) of forwardRequest - const digest = GelatoRelaySDK.getForwardRequestDigestToSign(forwardRequest); +// Get EIP-712 hash (aka digest) of forwardRequest +const digest = GelatoRelaySDK.getForwardRequestDigestToSign(forwardRequest); - // Sign digest using mock private key - const sponsorSignature = utils.BytesLike = utils.joinSignature( - await wallet._signingKey().signDigest(digest) - ); +// Sign digest using mock private key +const sponsorSignature = utils.BytesLike = utils.joinSignature( + await wallet._signingKey().signDigest(digest) +); - // Send forwardRequest and its sponsorSignature to Gelato Relay API - await GelatoRelaySDK.sendForwardRequest(forwardRequest, sponsorSignature); +// Send forwardRequest and its sponsorSignature to Gelato Relay API +await GelatoRelaySDK.sendForwardRequest(forwardRequest, sponsorSignature); - console.log("ForwardRequest submitted!"); +console.log('ForwardRequest submitted!'); ``` [EIP-712标准](https://eips.ethereum.org/EIPS/eip-712){target=_blank}为用户提供他们授权动作的重要内容。[EIP-712](https://eips.ethereum.org/EIPS/eip-712){target=_blank}并非签署一个长的、无法识别的字节串(该字符串危险且可能被恶意用户利用),而是提供了一个以可读方式编码和显示消息内容的框架,使终端用户更加安全。 @@ -243,32 +243,31 @@ node hello-world.js 完整的`hello-world.js`文件应包含以下内容: ```js -import { Wallet, utils } from "ethers"; -import { GelatoRelaySDK } from "@gelatonetwork/gelato-relay-sdk"; +import { Wallet, utils } from 'ethers'; +import { GelatoRelaySDK } from '@gelatonetwork/gelato-relay-sdk'; const forwardRequestExample = async () => { - const chainId = {{ networks.moonbeam.chain_id }}; // `HelloWorld.sol` contract on Moonbeam - const target = "0x3456E168d2D7271847808463D6D383D079Bd5Eaa"; - const test_token = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; - + const target = '0x3456E168d2D7271847808463D6D383D079Bd5Eaa'; + const test_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; + // Create mock wallet const wallet = Wallet.createRandom(); const sponsor = await wallet.getAddress(); console.log(`Mock PK: ${await wallet._signingKey().privateKey}`); console.log(`Mock wallet address: ${sponsor}`); - + // ABI encode for HelloWorld.sayHiVanilla(address _feeToken) const data = `0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee`; const paymentType = 1; // Maximum fee that sponsor is willing to pay worth of test_token - const maxFee = "1000000000000000000"; + const maxFee = '1000000000000000000'; // Gas limit - const gas = "200000"; - + const gas = '200000'; + // Smart contract nonces are not enforced to simplify the example. - // In reality, this decision depends whether or not target + // In reality, this decision depends whether or not target // address already implements replay protection. (More info in the docs) const sponsorNonce = 0; const enforceSponsorNonce = false; @@ -293,15 +292,14 @@ const forwardRequestExample = async () => { const digest = GelatoRelaySDK.getForwardRequestDigestToSign(forwardRequest); // Sign digest using mock private key - const sponsorSignature = utils.BytesLike = utils.joinSignature( + const sponsorSignature = (utils.BytesLike = utils.joinSignature( await wallet._signingKey().signDigest(digest) - ); + )); // Send forwardRequest and its sponsorSignature to Gelato Relay API await GelatoRelaySDK.sendForwardRequest(forwardRequest, sponsorSignature); - console.log("ForwardRequest submitted!"); - + console.log('ForwardRequest submitted!'); }; forwardRequestExample(); diff --git a/builders/integrations/wallets/metamask.md b/builders/integrations/wallets/metamask.md index 0eecf488..7581dd52 100644 --- a/builders/integrations/wallets/metamask.md +++ b/builders/integrations/wallets/metamask.md @@ -48,33 +48,33 @@ npm install @metamask/detect-provider ```javascript import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { - const provider = await detectEthereumProvider({ mustBeMetaMask: true }); - if (provider) { - // Logic will go here - } else { - console.error("Please install MetaMask"); - } - } + const provider = await detectEthereumProvider({ mustBeMetaMask: true }); + if (provider) { + // Logic will go here + } else { + console.error('Please install MetaMask'); + } + }; ``` - + 2. 通过调用`eth_requestAccounts`函数来请求获取用户的账户。这将提示MetaMask跳出弹窗,要求用户选择想要连接的账户。在后台,通过调用`wallet_requestPermissions`函数来检查账户的权限。目前仅限于`eth_accounts`可用于连接。因此,您最终要验证您是否有权访问从`eth_accounts`返回的用户地址。如果您有兴趣了解更多权限系统的相关信息,请查看[EIP-2255](https://eips.ethereum.org/EIPS/eip-2255){target=_blank} ```javascript -import detectEthereumProvider from '@metamask/detect-provider'; + import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { - const provider = await detectEthereumProvider({ mustBeMetaMask: true }); - if (provider) { - try { - await provider.request({ method: "eth_requestAccounts"}); - } catch(e) { - console.error(e); - } - } else { - console.error("Please install MetaMask"); + const provider = await detectEthereumProvider({ mustBeMetaMask: true }); + if (provider) { + try { + await provider.request({ method: 'eth_requestAccounts' }); + } catch (e) { + console.error(e); } - } + } else { + console.error('Please install MetaMask'); + } + }; ``` - + ![Add accounts to MetaMask](/images/builders/integrations/wallets/metamask/metamask-1.png) 3. 通过调用`wallet_addEthereumChain`函数将Moonbase Alpha添加为新的网络。这将提示用户提供将Moonbase Alpha添加为自定义网络的权限。成功添加网络后,将提示用户切换网络至Moonbase Alpha @@ -82,35 +82,36 @@ import detectEthereumProvider from '@metamask/detect-provider'; ```javascript import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { - const provider = await detectEthereumProvider({ mustBeMetaMask: true }); - if (provider) { - try { - await provider.request({ method: "eth_requestAccounts"}); - await provider.request({ - method: "wallet_addEthereumChain", - params: [ - { - chainId: "{{ networks.moonbase.hex_chain_id }}", // Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex - chainName: "Moonbase Alpha", - nativeCurrency: { - name: 'DEV', - symbol: 'DEV', - decimals: 18 - }, - rpcUrls: ["{{ networks.moonbase.rpc_url }}"], - blockExplorerUrls: ["{{ networks.moonbase.block_explorer }}"] - }, - ] - }) - } catch(e) { - console.error(e); - } - } else { - console.error("Please install MetaMask"); + const provider = await detectEthereumProvider({ mustBeMetaMask: true }); + if (provider) { + try { + await provider.request({ method: 'eth_requestAccounts' }); + await provider.request({ + method: 'wallet_addEthereumChain', + params: [ + { + // Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex + chainId: '{{ networks.moonbase.hex_chain_id }}', + chainName: 'Moonbase Alpha', + nativeCurrency: { + name: 'DEV', + symbol: 'DEV', + decimals: 18, + }, + rpcUrls: ['{{ networks.moonbase.rpc_url }}'], + blockExplorerUrls: ['{{ networks.moonbase.block_explorer }}'], + }, + ], + }); + } catch (e) { + console.error(e); } - } + } else { + console.error('Please install MetaMask'); + } + }; ``` - + ![Add and switch networks in MetaMask](/images/builders/integrations/wallets/metamask/metamask-2.png) 现在,您应该已经完成按钮创建,用户只需点击按钮,根据操作指示即可将MetaMask账户连接至Moonbase Alpha。 @@ -120,15 +121,15 @@ import detectEthereumProvider from '@metamask/detect-provider'; 您可能会有知道用户是否将其MetaMask连接至Moonbase Alpha的逻辑。如果用户已经连接,您也可以禁用此按钮。要确认用户是否已经连接至Moonbase Alpha,您可以调用`eth_chainId`函数,它将返回用户当前chain ID: ```javascript - const chainId = await provider.request({ - method: 'eth_chainId' - }) - // Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex - if (chainId === "{{ networks.moonbase.hex_chain_id }}"){ - // At this point, you might want to disable the "Connect" button - // or inform the user that they are already connected to the - // Moonbase Alpha testnet - } +const chainId = await provider.request({ + method: 'eth_chainId', +}); +// Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex +if (chainId === '{{ networks.moonbase.hex_chain_id }}') { + // At this point, you might want to disable the "Connect" button + // or inform the user that they are already connected to the + // Moonbase Alpha testnet +} ``` ## 监听账户变化 {: #listen-to-account-changes } @@ -136,12 +137,12 @@ import detectEthereumProvider from '@metamask/detect-provider'; 为了确保您的项目或dApp与最新的账户信息保持同步,您可以添加MetaMask提供的`accountsChanged`事件监听器。当`eth_accounts`返回的值发生变化时,MetaMask将发出此事件。如果返回地址,则它是您的用户最近提供访问权限的帐户。如果没有返回地址,则表示用户没有提供任何具有访问权限的帐户。 ```javascript - provider.on("accountsChanged", (accounts) => { - if (accounts.length === 0) { - // MetaMask is locked or the user doesn't have any connected accounts - console.log('Please connect to MetaMask.'); - } - }) +provider.on('accountsChanged', (accounts) => { + if (accounts.length === 0) { + // MetaMask is locked or the user doesn't have any connected accounts + console.log('Please connect to MetaMask.'); + } +}); ``` ## 监听链变化 {: #listen-to-chain-changes } @@ -149,10 +150,10 @@ import detectEthereumProvider from '@metamask/detect-provider'; 为了使您的项目或dApp与连接链的变化保持同步,您可以订阅`chainChanged`事件。当连接的链发生变化时,MetaMask将发出此事件。 ```javascript - provider.on("chainChanged", () => { - // MetaMask recommends reloading the page unless you have good reason not to - window.location.reload(); - }) +provider.on('chainChanged', () => { + // MetaMask recommends reloading the page unless you have good reason not to + window.location.reload(); +}); ``` 若非必要情况,MetaMask建议在链变化时重新加载页面,因为与链更改保持一致至关重要。 \ No newline at end of file diff --git a/builders/integrations/wallets/walletconnect.md b/builders/integrations/wallets/walletconnect.md index d79730e6..a9570cc7 100644 --- a/builders/integrations/wallets/walletconnect.md +++ b/builders/integrations/wallets/walletconnect.md @@ -122,11 +122,14 @@ Moonbeam WalletConnect范本提供了所有您目前为止需要的内容,为 3. 查看连接是否已成功建立,如果并未成功建立即创建一个新的连接要求 ```js -const connect = async () => { +const connect = async () => { setFetching(true); // 1. Create connector - const connector = new WalletConnect({ bridge: "https://bridge.walletconnect.org", qrcodeModal: QRCodeModal }); + const connector = new WalletConnect({ + bridge: 'https://bridge.walletconnect.org', + qrcodeModal: QRCodeModal, + }); // 2. Update the connector state setConnector(connector); @@ -206,11 +209,13 @@ const killSession = () => { 现在您已经具有了所有的逻辑以处理解除连接的操作,您将会需要一个**Disconnect**按纽包含`onClick` 以触发 `killSession` 函数。由于您仅希望在用户已连接时显示**Disconnect**按钮,您可以使用 [conditional renderering](https://reactjs.org/docs/conditional-rendering.html){target=_blank}。条件渲染(Conditional renderering)使您能够查看指定的参数,如果当前条件符合您的设定您将可以渲染一个元件或是其他元件。在此例当中,如果您获取的并不是先前连接和连接器的存在,您可以渲染**Disconnect**按钮,否则渲染**Connect Wallet**按钮。您可以使用以下部分取代已存在的` -)} +{ + connector && !fetching ? ( + Disconnect + ) : ( + + ); +} ``` 如果您在测试解除连接逻辑的时候发现您点击**Connect Wallet**的时候不会出现任何反应或是弹窗,请确认您是否手动在MetaMask行动钱包解除了任何先前存在的连接。如果您仍遇到问题,请重新刷新您的浏览器。 @@ -226,7 +231,7 @@ const killSession = () => { 在`disconnect`获得响应后,您可以新增`resetApp`函数。如此一来,当任何`disconnect`事件被发出,您将能够重置您DApp的状态。 ```js -connector.on("disconnect", async (error) => { +connector.on('disconnect', async (error) => { if (error) { // Handle errors as you see fit console.error(error); @@ -263,7 +268,9 @@ const onConnect = async (chainId, connectedAccount) => { setChainId(chainId); // get chain data - const networkData = SUPPORTED_NETWORKS.filter((chain) => chain.chain_id === chainId)[0]; + const networkData = SUPPORTED_NETWORKS.filter( + (chain) => chain.chain_id === chainId + )[0]; if (!networkData) { setSupported(false); @@ -294,33 +301,36 @@ useEffect(() => { 接着在页面上渲染状态变量,您可以在**Disconnect**按钮包含额外的UI元素。同样,您可以使用条件渲染以显示具体详情或是在连接至错误网络时显示错误信息: ```js -{connector && !fetching ? ( - - - Connected Account: - {account} - - - Chain ID: - {chainId} - - {supported ? ( - <> - - Network: - {network} - - - ) : ( - - Network not supported. Please disconnect, switch networks, and connect again. - - )} - Disconnect - -) : ( - -)} +{ + connector && !fetching ? ( + + + Connected Account: + {account} + + + Chain ID: + {chainId} + + {supported ? ( + <> + + Network: + {network} + + + ) : ( + + Network not supported. Please disconnect, switch networks, and connect + again. + + )} + Disconnect + + ) : ( + + ); +} ``` 您可以调整以上代码段以更好地处理错误。 @@ -368,9 +378,11 @@ const [balance, setBalance] = useState(null); const onConnect = async (chainId, address) => { setAccount(address); - const networkData = SUPPORTED_NETWORKS.filter((network) => network.chain_id === chainId)[0]; + const networkData = SUPPORTED_NETWORKS.filter( + (network) => network.chain_id === chainId + )[0]; - if (!networkData){ + if (!networkData) { setSupported(false); } else { setSupported(true); @@ -381,7 +393,7 @@ const onConnect = async (chainId, address) => { // 1. Create an Ethers provider const provider = new ethers.JsonRpcProvider(networkData.rpc_url, { chainId, - name: networkData.name + name: networkData.name, }); // 2. Get the account balance @@ -408,20 +420,25 @@ if ((!chainId || !account || !balance) && connector.connected) { 最后,您可以在用户连接至支持网络时显示账户余额。您可以使用先前创建的`symbol`状态变量在Moonbase Alpha显示**DEV**余额。 ```js -{supported ? ( - <> - - Network: - {network} - - - Balance: - {balance} {symbol} - - -) : ( - Network not supported. Please disconnect, switch networks, and connect again. -)} +{ + supported ? ( + <> + + Network: + {network} + + + Balance: + {balance} {symbol} + + + ) : ( + + Network not supported. Please disconnect, switch networks, and connect + again. + + ); +} ``` 此示例可以修改为从Ethers获取其他所需数据。 @@ -435,7 +452,11 @@ if ((!chainId || !account || !balance) && connector.connected) { ```js const sendTransaction = async () => { try { - await connector.sendTransaction({ from: account, to: account, value: "0x1BC16D674EC80000" }); + await connector.sendTransaction({ + from: account, + to: account, + value: '0x1BC16D674EC80000', + }); } catch (e) { // Handle the error as you see fit console.error(e); @@ -446,21 +467,28 @@ const sendTransaction = async () => { 要在DApp中发起交易,您需要创建一个按钮包含`onClick`以触发`sendTransaction`函数。此动作仅会在连接至支持网络时被执行。 ```js -{supported ? ( - <> - - Network: - {network} - - - Balance: - {balance} {symbol} - - Send Transaction - -) : ( - Network not supported. Please disconnect, switch networks, and connect again. -)} +{ + supported ? ( + <> + + Network: + {network} + + + Balance: + {balance} {symbol} + + + Send Transaction + + + ) : ( + + Network not supported. Please disconnect, switch networks, and connect + again. + + ); +} ``` 当您点击**Send Transaction**,MetaMask移动端钱包将会跳出弹窗显示交易细节: diff --git a/builders/interoperability/protocols/wormhole.md b/builders/interoperability/protocols/wormhole.md index 6ba0093e..035d9a1f 100644 --- a/builders/interoperability/protocols/wormhole.md +++ b/builders/interoperability/protocols/wormhole.md @@ -67,13 +67,13 @@ Wormhole由多个模块化的交换组件组成,这些组件可以独立使用 如需在每条链上部署,您将需要Wormhole核心桥接的本地实例以及每条对应链的chain ID。如下所示为选定的几个测试网提供了这些数据。您可以在Wormhole的[文档网站](https://book.wormhole.com/reference/contracts.html#testnet){target=_blank}找到其他网络的端点。请注意,为本文设计的智能合约和中继器仅支持EVM,因此在本次演示只能使用EVM。 -| 网络 & 水龙头 | 核心桥地址 | Wormhole 链ID | -|:-------------------------------------------------------------------:|:------------------------------------------:|:-----------------:| -| [Polygon Mumbai](https://faucet.polygon.technology/){target=_blank} | 0x0CBE91CF822c73C2315FB05100C2F714765d5c20 | 5 | -| [Avalanche Fuji](https://faucet.avax.network/){target=_blank} | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | 6 | -| [Fantom TestNet](https://faucet.fantom.network/){target=_blank} | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | 10 | -| [Goerli](https://goerlifaucet.com/){target=_blank} | 0x706abc4E45D419950511e474C7B9Ed348A4a716c | 2 | -| [Moonbase Alpha](https://docs.moonbeam.network/builders/get-started/networks/moonbase/#moonbase-alpha-faucet){target=_blank} | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | 16 | +| 网络 & 水龙头 | 核心桥地址 | Wormhole 链ID | +|:----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:|:-------------:| +| [Polygon Mumbai](https://faucet.polygon.technology/){target=_blank} | 0x0CBE91CF822c73C2315FB05100C2F714765d5c20 | 5 | +| [Avalanche Fuji](https://faucet.avax.network/){target=_blank} | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | 6 | +| [Fantom TestNet](https://faucet.fantom.network/){target=_blank} | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | 10 | +| [Goerli](https://goerlifaucet.com/){target=_blank} | 0x706abc4E45D419950511e474C7B9Ed348A4a716c | 2 | +| [Moonbase Alpha](https://docs.moonbeam.network/builders/get-started/networks/moonbase/#moonbase-alpha-faucet){target=_blank} | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | 16 | 1. 确保选择的合约为**SimpleGeneralMessage** 2. 点击箭头按钮打开部署菜单 @@ -177,21 +177,19 @@ npm run testnet-spy 请确保编辑`spyServiceFilters`数组以便中继器监听您部署的两个合约。 - -```javascript - "spyServiceFilters": [ - { - "chainId": 16, - "emitterAddress": "0x428097dCddCB00Ab65e63AB9bc56Bb48d106ECBE" - }, - { - "chainId": 10, - "emitterAddress": "0x5017Fd40aeA8Ab94693bE41b3bE4e90F45860bA4" - } - ] +```json +"spyServiceFilters": [ + { + "chainId": 16, + "emitterAddress": "0x428097dCddCB00Ab65e63AB9bc56Bb48d106ECBE" + }, + { + "chainId": 10, + "emitterAddress": "0x5017Fd40aeA8Ab94693bE41b3bE4e90F45860bA4" + } +] ``` - 在`simplegeneralmessage_plugin`文件夹中,打开`src/plugin.ts`。该文件包含中继器的监听器和执行器两个组件的插件代码,但注释已明确说明哪些函数与哪个组件相关。该文件的片段如下所示,请遵循教程操作。若没有执行操作,您可以在[它的Github repository](https://github.com/jboetticher/relayer-engine-docs-example/blob/main/plugins/simplegeneralmessage_plugin/src/plugin.ts){target=_blank}获取整个文件。 接下来看下方的`getFilters()`函数。`spyServiceFilters`对象被注入至`getFilters()`所属的插件类别中。注意该过程中没有发生任何过滤,这仅仅是过滤器的准备工作。VAA的真正过滤发生在`relayer-engine`包中,使用此`getFilters()`函数来了解要过滤的内容。 @@ -238,7 +236,6 @@ npm run testnet-spy } ``` - 这就是所有关于监听器组件的所需内容。大部分代码藏于`relayer-engine`包中,对用户不可见。 如果您还记得组件列表的话,第三个是Redis数据库组件。与数据库相关的大部分代码对用户隐藏,因为`relayer-engine`包会从其写入和阅读,并将任何相关数据注入插件代码。要运行Redis数据库,只需在父目录中运行以下命令: @@ -259,7 +256,7 @@ npm run redis 泄露密钥可能导致资金流失,因此请妥善保管您的密钥。虽然`executor.json`在存储库中被git忽略,请确保您在测试网使用的钱包中没有任何主网资金。 -```javascript +```json { "privateKeys": { "16": [ @@ -277,7 +274,6 @@ npm run redis "10": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], - } } ``` @@ -286,9 +282,9 @@ npm run redis 如果您正在使用一条并未在上方EVM测试网列表中列出的链,您将需要添加您自己的数组。该数组的密钥应该在另一个您之前决定部署的EVM的Wormhole chain ID。例如,如果您在Fantom TestNet上部署,您将添加以下对象,因为Fantom TestNet的Wormhole chain ID是10。 -```javascript +```json "10": [ - "YOUR PRIVATE KEY" + "INSERT_YOUR_PRIVATE_KEY" ] ``` @@ -304,7 +300,6 @@ npm run redis 有了Ethers解码的数据,我们可以知道负载所传送至的目标合约以及目标链,因为数据被打包至消息中了。该函数检查指定的目标chain ID是否属于一个EVM,并将使用上述的`execute.onEVM(options)`函数执行。否则,它将记录一个错误,因为系统会因简单起见而不与非EVM链交互。 - ```javascript // Consumes a workflow for execution async handleWorkflow( @@ -319,17 +314,24 @@ async handleWorkflow( this.logger.info(`Parsed VAA. seq: ${parsed.sequence}`); // Here we are parsing the payload so that we can send it to the right recipient - const hexPayload = parsed.payload.toString("hex"); - let [recipient, destID, sender, message] = ethers.utils.defaultAbiCoder.decode(["bytes32", "uint16", "bytes32", "string"], "0x" + hexPayload); + const hexPayload = parsed.payload.toString('hex'); + let [recipient, destID, sender, message] = + ethers.utils.defaultAbiCoder.decode( + ['bytes32', 'uint16', 'bytes32', 'string'], + '0x' + hexPayload + ); recipient = this.formatAddress(recipient); sender = this.formatAddress(sender); const destChainID = destID as ChainId; - this.logger.info(`VAA: ${sender} sent "${message}" to ${recipient} on chain ${destID}.`); + this.logger.info( + `VAA: ${sender} sent "${message}" to ${recipient} on chain ${destID}.` + ); // Execution logic if (wh.isEVMChain(destChainID)) { // This is where you do all of the EVM execution. - // Add your own private wallet for the executor to inject in relayer-engine-config/executor.json + // Add your own private wallet for the executor to inject in + // relayer-engine-config/executor.json await execute.onEVM({ chainId: destChainID, f: async (wallet, chainId) => { @@ -338,14 +340,16 @@ async handleWorkflow( this.logger.info(result); }, }); + } else { + // The relayer plugin has a built-in Solana wallet handler, which you could use + // here. NEAR & Algorand are supported by Wormhole, but they're not supported by + // the relayer plugin. If you want to interact with NEAR or Algorand you'd have + // to make your own wallet management system, that's all + this.logger.error( + 'Requested chainID is not an EVM chain, which is currently unsupported.' + ); } - else { - // The relayer plugin has a built-in Solana wallet handler, which you could use here. - // NEAR & Algorand are supported by Wormhole, but they're not supported by the relayer plugin. - // If you want to interact with NEAR or Algorand you'd have to make your own wallet management system, that's all. - this.logger.error("Requested chainID is not an EVM chain, which is currently unsupported."); - } -} +}; ``` 在回调函数中,使用Ethers包创建一个[合约对象](https://docs.ethers.org/v6/api/contract/#Contract){target=_blank}。其导入的ABI从`SimpleGeneralMessage`合约的编译中导出,所以该代码假设VAA中指定的消息接收者是或从`SimpleGeneralMessage`合约继承。 @@ -367,21 +371,19 @@ await execute.onEVM({ 该中继器还有许多其他配置。例如,`mode`字符串设置为`“BOTH”`以确保使用监听器和执行器插件,也可根据开发者需求选择只运行其中一个。此外,还有多个日志级别可供指定,如`“error”`可用来只记录错误消息。然而,在本次演示中只需保留配置设置即可。 - -```javascript +```json "mode": "BOTH", "logLevel": "debug", ... - { - "chainId": 16, - "chainName": "Moonbase Alpha", - "nodeUrl": "https://rpc.api.moonbase.moonbeam.network", - "bridgeAddress": "0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901", - "tokenBridgeAddress": "0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96" - }, + { + "chainId": 16, + "chainName": "Moonbase Alpha", + "nodeUrl": "https://rpc.api.moonbase.moonbeam.network", + "bridgeAddress": "0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901", + "tokenBridgeAddress": "0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96" + }, ``` - 配置这样就行了!现在需要运行它。在您的终端实例(未运行间谍节点的实例),导航至父文件夹。运行下列命令: ```bash diff --git a/builders/interoperability/xcm/xcm-sdk/v0/xcm-sdk.md b/builders/interoperability/xcm/xcm-sdk/v0/xcm-sdk.md index fd868ddb..f5ad7b6d 100644 --- a/builders/interoperability/xcm/xcm-sdk/v0/xcm-sdk.md +++ b/builders/interoperability/xcm/xcm-sdk/v0/xcm-sdk.md @@ -57,7 +57,7 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto === "Moonbeam" ```js - import { ethers } from "ethers"; + import { ethers } from 'ethers'; import { Keyring } from '@polkadot/api'; // Set up Ethers provider and signer @@ -68,24 +68,21 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto chainId: {{ networks.moonbeam.chain_id }}, // {{ networks.moonbeam.hex_chain_id }} in hex, }, }; - const provider = new ethers.JsonRpcProvider( - providerRPC.moonbeam.rpc, - { - chainId: providerRPC.moonbeam.chainId, - name: providerRPC.moonbeam.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { + chainId: providerRPC.moonbeam.chainId, + name: providerRPC.moonbeam.name, + }); const ethersSigner = new ethers.Wallet('INSERT_PRIVATE_KEY', provider); // Set up Polkadot keyring const keyring = new Keyring({ type: 'sr25519' }); - const polkadotKeyring = keyring.addFromUri(mnemonic); + const polkadotKeyring = keyring.addFromUri('INSERT_MNEMONIC'); ``` === "Moonriver" ```js - import { ethers } from "ethers"; + import { ethers } from 'ethers'; import { Keyring } from '@polkadot/api'; // Set up Ethers provider and signer @@ -96,13 +93,10 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto chainId: {{ networks.moonriver.chain_id }}, // {{ networks.moonriver.hex_chain_id }} in hex, }, }; - const provider = new ethers.JsonRpcProvider( - providerRPC.moonriver.rpc, - { - chainId: providerRPC.moonriver.chainId, - name: providerRPC.moonriver.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonriver.rpc, { + chainId: providerRPC.moonriver.chainId, + name: providerRPC.moonriver.name, + }); const ethersSigner = new ethers.Wallet('INSERT_PRIVATE_KEY', provider); // Set up Polkadot keyring @@ -113,7 +107,7 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto === "Moonbase Alpha" ```js - import { ethers } from "ethers"; + import { ethers } from 'ethers'; import { Keyring } from '@polkadot/api'; // Set up Ethers provider and signer @@ -124,18 +118,15 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto chainId: {{ networks.moonbase.chain_id }}, // {{ networks.moonbase.hex_chain_id }} in hex, }, }; - const provider = new ethers.JsonRpcProvider( - providerRPC.moonbase.rpc, - { - chainId: providerRPC.moonbase.chainId, - name: providerRPC.moonbase.name, - } - ); + const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { + chainId: providerRPC.moonbase.chainId, + name: providerRPC.moonbase.name, + }); const ethersSigner = new ethers.Wallet('INSERT_PRIVATE_KEY', provider); // Set up Polkadot keyring const keyring = new Keyring({ type: 'sr25519' }); - const polkadotKeyring = keyring.addFromUri(mnemonic); + const polkadotKeyring = keyring.addFromUri('INSERT_MNEMONIC'); ``` ### 初始化 {: #initializing } @@ -146,21 +137,21 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto ```js import { init } from '@moonbeam-network/xcm-sdk'; - const { moonbeam } = init() + const { moonbeam } = init(); ``` === "Moonriver" ```js import { init } from '@moonbeam-network/xcm-sdk'; - const { moonriver } = init() + const { moonriver } = init(); ``` === "Moonbase Alpha" ```js import { init } from '@moonbeam-network/xcm-sdk'; - const { moonbase } = init() + const { moonbase } = init(); ``` 如果您希望支持某个特定钱包,您可以直接将签署者传递至`init`函数。否则,您仅能在为存款或提现构建转移数据时直接传递签署者。要为[Ethers](/builders/build/eth-api/libraries/ethersjs){target=_blank}和[波卡](/builders/build/substrate-api/polkadot-js-api){target=_blank}传递签署者,您可以使用以下代码段: @@ -171,8 +162,8 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto import { init } from '@moonbeam-network/xcm-sdk'; const { moonbeam } = init({ ethersSigner: 'INSERT_ETHERS_SIGNER', - polkadotSigner: 'INSERT_POLKADOT_SIGNER' - }) + polkadotSigner: 'INSERT_POLKADOT_SIGNER', + }); ``` === "Moonriver" @@ -181,8 +172,8 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto import { init } from '@moonbeam-network/xcm-sdk'; const { moonriver } = init({ ethersSigner: 'INSERT_ETHERS_SIGNER', - polkadotSigner: 'INSERT_POLKADOT_SIGNER' - }) + polkadotSigner: 'INSERT_POLKADOT_SIGNER', + }); ``` === "Moonbase Alpha" @@ -191,8 +182,8 @@ npm i @polkadot/api-augment @polkadot/types @polkadot/util @polkadot/util-crypto import { init } from '@moonbeam-network/xcm-sdk'; const { moonbase } = init({ ethersSigner: 'INSERT_ETHERS_SIGNER', - polkadotSigner: 'INSERT_POLKADOT_SIGNER' - }) + polkadotSigner: 'INSERT_POLKADOT_SIGNER', + }); ``` ## 使用SDK接口 {: #using-the-api } @@ -383,15 +374,17 @@ async function deposit() { const { asset, sourceBalance, source, min, send } = await from(polkadot).get( 'INSERT_MOONBEAM_ADDRESS', - polkadotKeyring, // See the Get section for other accepted arguments + polkadotKeyring // See the Get section for other accepted arguments ); console.log( `Your ${asset.originSymbol} balance in ${source.name}: ${toDecimal( sourceBalance, - asset.decimals, - ).toFixed()}. Minimum transferable amount is: ${toDecimal(min, asset.decimals).toFixed()}`, - ); + asset.decimals + ).toFixed()}. Minimum transferable amount is: ${toDecimal( + min, + asset.decimals + ).toFixed()}` await send('INSERT_AMOUNT', (event) => console.log(event)); } @@ -484,7 +477,7 @@ const { from } = moonbeam.deposit(dot); const response = await from(polkadot).get( 'INSERT_MOONBEAM_ADDRESS', polkadotKeyring, -) +); ``` 以下为调用`get`以从波卡传送DOT至Moonbeam的范例: @@ -572,11 +565,16 @@ async function getDepositFee() { const { from } = moonbeam.deposit(dot); const { asset, getFee } = await from(polkadot).get( 'INSERT_MOONBEAM_ADDRESS', - polkadotKeyring, // See the Get section for other accepted arguments + polkadotKeyring // See the Get section for other accepted arguments ); - const fee = await getFee('INSERT_AMOUNT')); - console.log(`Fee to deposit is estimated to be: ${toDecimal(fee, asset.decimals).toFixed()} ${dot}`); + const fee = await getFee('INSERT_AMOUNT'); + console.log( + `Fee to deposit is estimated to be: ${toDecimal( + fee, + asset.decimals + ).toFixed()} ${dot}` + ); } getDepositFee(); @@ -606,11 +604,11 @@ async function withdraw() { console.log( `\nYou can withdraw ${dot} to these chains: `, - chains.map((chain) => chain.name), + chains.map((chain) => chain.name) ); const { asset, destination, destinationBalance, min, send } = await to( - polkadot, + polkadot ).get('INSERT_POLKADOT_ADDRESS', { ethersSigner: signer, // Only required if you didn't pass the signer in on initialization }); @@ -618,8 +616,11 @@ async function withdraw() { console.log( `Your ${asset.originSymbol} balance in ${destination.name}: ${toDecimal( destinationBalance, - asset.decimals, - ).toFixed()}. Minimum transferable amount is: ${toDecimal(min, asset.decimals).toFixed()}`, + asset.decimals + ).toFixed()}. Minimum transferable amount is: ${toDecimal( + min, + asset.decimals + ).toFixed()}` ); await send('INSERT_AMOUNT', (event) => console.log(event)); @@ -674,8 +675,8 @@ const dot = AssetSymbol.DOT; const polkadot = ChainKey.Polkadot; const { to } = moonbeam.deposit(dot); -const response = await to( - polkadot, +const response = await to( + polkadot ).get('INSERT_POLKADOT_ADDRESS', { ethersSigner: signer } // Only required if you didn't pass the signer in on initialization ) @@ -767,11 +768,16 @@ async function getWithdrawFee() { const { to } = moonbeam.withdraw(dot); const { asset, getFee } = await from(polkadot).get( 'INSERT_POLKADOT_ADDRESS', - { ethersSigner }, // Only required if you didn't pass the signer in on initialization + { ethersSigner } // Only required if you didn't pass the signer in on initialization ); const fee = await getFee('INSERT_AMOUNT'); - console.log(`Fee to deposit is estimated to be: ${toDecimal(fee, moonbeam.moonChain.decimals).toFixed()} ${moonbeam.moonAsset.originSymbol}`); + console.log( + `Fee to deposit is estimated to be: ${toDecimal( + fee, + moonbeam.moonChain.decimals + ).toFixed()} ${moonbeam.moonAsset.originSymbol}` + ); } getWithdrawFee(); @@ -784,19 +790,19 @@ getWithdrawFee(); === "Moonbeam" ```js - moonbeam.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb) + moonbeam.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb); ``` === "Moonriver" ```js - moonriver.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb) + moonriver.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb); ``` === "Moonbase Alpha" ```js - moonbase.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb) + moonbase.subscribeToAssetsBalanceInfo('INSERT_ADDRESS', cb); ``` 以下范例检索Moonbeam上给定帐户的余额信息,并将每个支持资产的余额输出到控制台: @@ -807,12 +813,13 @@ const unsubscribe = await moonbeam.subscribeToAssetsBalanceInfo( (balances) => { balances.forEach(({ asset, balance, origin }) => { console.log( - `${balance.symbol}: ${toDecimal(balance.balance, balance.decimals).toFixed()} (${ - origin.name - } ${asset.originSymbol})`, + `${balance.symbol}: ${toDecimal( + balance.balance, + balance.decimals + ).toFixed()} (${origin.name} ${asset.originSymbol})` ); }); - }, + } ); unsubscribe(); @@ -842,8 +849,8 @@ import { init, isXcmSdkDeposit } from '@moonbeam-network/xcm-sdk'; ... -const deposit = moonbeam.deposit(moonbeam.symbols[0]) -console.log(isXcmSdkDeposit(deposit)) // Returns true +const deposit = moonbeam.deposit(moonbeam.symbols[0]); +console.log(isXcmSdkDeposit(deposit)); // Returns true ``` ```js @@ -851,8 +858,8 @@ import { init, isXcmSdkDeposit } from '@moonbeam-network/xcm-sdk'; ... -const withdraw = moonbeam.withdraw(moonbeam.symbols[0]) -console.log(isXcmSdkDeposit(withdraw)) // Returns false +const withdraw = moonbeam.withdraw(moonbeam.symbols[0]); +console.log(isXcmSdkDeposit(withdraw)); // Returns false ``` #### 查看转移数据是否用于取出 {: #withdraw-check } @@ -866,8 +873,8 @@ import { init, isXcmSdkWithdraw } from '@moonbeam-network/xcm-sdk'; ... -const withdraw = moonbeam.withdraw(moonbeam.symbols[0]) -console.log(isXcmSdkWithdraw(withdraw)) // Returns true +const withdraw = moonbeam.withdraw(moonbeam.symbols[0]); +console.log(isXcmSdkWithdraw(withdraw)); // Returns true ``` ```js @@ -875,8 +882,8 @@ import { init, isXcmSdkWithdraw } from '@moonbeam-network/xcm-sdk'; ... -const deposit = moonbeam.deposit(moonbeam.symbols[0]) -console.log(isXcmSdkDeposit(deposit)) // Returns false +const deposit = moonbeam.deposit(moonbeam.symbols[0]); +console.log(isXcmSdkDeposit(deposit)); // Returns false ``` #### 将余额转换为十进制或BigInt {: #decimals } diff --git a/builders/interoperability/xcm/xcm-sdk/v1/xcm-sdk.md b/builders/interoperability/xcm/xcm-sdk/v1/xcm-sdk.md index cea03d9b..23cf8a73 100644 --- a/builders/interoperability/xcm/xcm-sdk/v1/xcm-sdk.md +++ b/builders/interoperability/xcm/xcm-sdk/v1/xcm-sdk.md @@ -182,8 +182,7 @@ const { assets, getTransferData } = Sdk(); ```js import { Sdk } from '@moonbeam-network/xcm-sdk'; -const fromPolkadot = async() => { - +const fromPolkadot = async () => { const { assets, asset } = Sdk.assets(); console.log( `The supported assets are: ${assets.map((asset) => asset.originSymbol)}` @@ -191,12 +190,18 @@ const fromPolkadot = async() => { const { sourceChains, source } = Sdk.assets().asset('dot'); console.log( - `The supported source chains are: ${sourceChains.map((chain) => chain.name)}` + `The supported source chains are: ${sourceChains.map( + (chain) => chain.name + )}` ); - const { destinationChains, destination } = Sdk.assets().asset('dot').source('polkadot'); + const { destinationChains, destination } = Sdk.assets() + .asset('dot') + .source('polkadot'); console.log( - `The supported destination chains are: ${destinationChains.map((chain) => chain.name)}` + `The supported destination chains are: ${destinationChains.map( + (chain) => chain.name + )}` ); const data = await Sdk() @@ -204,10 +209,10 @@ const fromPolkadot = async() => { .asset('dot') .source('polkadot') .destination('moonbeam') - .accounts(pair.address, ethersSigner.address { + .accounts(pair.address, ethersSigner.address, { pair, }); -} +}; fromPolkadot(); ``` @@ -220,7 +225,7 @@ fromPolkadot(); ```js import { Sdk } from '@moonbeam-network/xcm-sdk'; -const fromPolkadot = async() => { +const fromPolkadot = async () => { const data = await Sdk().getTransferData({ destinationAddress: ethersSigner.address, destinationKeyOrChain: 'moonbeam', @@ -229,7 +234,7 @@ const fromPolkadot = async() => { sourceAddress: pair.address, sourceKeyOrChain: 'polkadot', }); -} +}; fromPolkadot(); ``` diff --git a/builders/pallets-precompiles/precompiles/batch.md b/builders/pallets-precompiles/precompiles/batch.md index c2ef3ef7..a58df10b 100644 --- a/builders/pallets-precompiles/precompiles/batch.md +++ b/builders/pallets-precompiles/precompiles/batch.md @@ -68,7 +68,9 @@ Moonbeam上的批量预编译合约允许开发者同时执行多个EVM调用。 此`SimpleContract.sol`合约将会作为批量合约交互的范例,但在实际操作上所有合约皆可以进行交互。 - --8<-- 'code/builders/pallets-precompiles/precompiles/batch/simple-contract.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/batch/simple-contract.sol' +``` ### 设置Remix {: #remix-set-up } @@ -130,7 +132,7 @@ Moonbeam上的批量预编译合约允许开发者同时执行多个EVM调用。 1. 确保您连接的钱包中至少有0.5个DEV 2. 在**Deployed Contracts**中展开批量预编译合约 3. 展开**batchAll**函数 -4. 在**to**输入栏中,根据以下格式输入您的地址:`["ADDRESS-1-HERE", "ADDRESS-2-HERE"]`,其中第一个地址代表您希望传送资产的第一个地址,而第二个地址为您希望传送资产的第二个地址 +4. 在**to**输入栏中,根据以下格式输入您的地址:`["INSERT_ADDRESS_1", "INSERT_ADDRESS_2"]`,其中第一个地址代表您希望传送资产的第一个地址,而第二个地址为您希望传送资产的第二个地址 5. 在**value**输入栏中,输入您希望转移至个别地址以Wei为单位的数量。举例而言,`["100000000000000000", "200000000000000000"]`将会转移0.1 DEV至第一个地址和0.2 DEV至第二个地址 6. 在剩下的**callData**和**gasLimit**输入栏中输入`[]`,调用数据和Gas限制在传送原生资产时不需要考虑 7. 点击**transact** @@ -158,7 +160,9 @@ Moonbeam上的批量预编译合约允许开发者同时执行多个EVM调用。 现在您已经拥有该交易的调用数据!根据范例数据的`1` 和`"moonbeam"`,我们可以在调用数据中查找这些被编码的数据: - --8<-- 'code/builders/pallets-precompiles/precompiles/batch/simple-message-call-data.md' +```text +--8<-- 'code/builders/pallets-precompiles/precompiles/batch/simple-message-call-data.md' +``` 调用数据可以被拆分为五行: @@ -179,9 +183,9 @@ Moonbeam上的批量预编译合约允许开发者同时执行多个EVM调用。 1. 在`SimpleContract.sol`标题右方的复制按钮复制其合约地址,请确保您拥有来自[先前部分教程的调用数据](#finding-a-contract-interactions-call-data) 2. 在**Deployed Contracts**下方展开批量预编译合约 3. 展开**batchAll**函数 -4. 在**to**输入栏中,以下述格式插入您先前复制的`SimpleContract.sol`合约地址:`["SIMPLE-CONTRACT-ADDRESS-HERE"]` -5. 在数值输入栏中,由于`["SIMPLE-CONTRACT-ADDRESS-HERE"]`并不需要支付任何原生资产,输入`["0"]`代表0 Wei -6. 在**callData**输入栏位中,以下格式插入您在先前部分教程获得的函数数据:`["CALL-DATA-HERE"]` +4. 在**to**输入栏中,以下述格式插入您先前复制的`SimpleContract.sol`合约地址:`["INSERT_SIMPLE_CONTRACT_ADDRESS"]` +5. 在数值输入栏中,由于`["INSERT_SIMPLE_CONTRACT_ADDRESS"]`并不需要支付任何原生资产,输入`["0"]`代表0 Wei +6. 在**callData**输入栏位中,以下格式插入您在先前部分教程获得的函数数据:`["INSERT_CALL_DATA"]` 7. 在**gasLimit**输入栏中,插入`[]`。您也可以输入Gas限制的数据,依据您的需求决定 8. 点击**transact** 9. 在MetaMask跳出的弹窗中点击**Confirm**以确认交易 @@ -247,13 +251,22 @@ Moonbeam上的批量预编译合约允许开发者同时执行多个EVM调用。 !!! 注意事项 以下部分显示的代码段并非用于生产环境,请确保您根据用例修改。 +=== "Ethers.js" + + ```js + --8<-- 'code/builders/pallets-precompiles/precompiles/batch/ethers-batch.js' + ``` + === "Web3.js" - --8<-- 'code/builders/pallets-precompiles/precompiles/batch/web3js-batch.md' -=== "Ethers.js" - --8<-- 'code/builders/pallets-precompiles/precompiles/batch/ethers-batch.md' + ```js + --8<-- 'code/builders/pallets-precompiles/precompiles/batch/web3js-batch.js' + ``` === "Web3.py" - --8<-- 'code/builders/pallets-precompiles/precompiles/batch/web3py-batch.md' + + ```py + --8<-- 'code/builders/pallets-precompiles/precompiles/batch/web3py-batch.py' + ``` 最后,您应当已经了解如何与批量预编译进行交互,如同您与[Ethers](/builders/build/eth-api/libraries/ethersjs){target=_blank}中的合约进行交互一样。 diff --git a/builders/pallets-precompiles/precompiles/eth-mainnet.md b/builders/pallets-precompiles/precompiles/eth-mainnet.md index f695fd30..d92a8d22 100644 --- a/builders/pallets-precompiles/precompiles/eth-mainnet.md +++ b/builders/pallets-precompiles/precompiles/eth-mainnet.md @@ -40,15 +40,21 @@ npm ls web3 我们用一个简单的例子来说明如何利用这一预编译功能。我们需要进行签名,然后获取包含这些数值的已签名消息,从而获得交易签名值(v, r, s): ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ecrecover.md' +```js +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ecrecover.js' +``` 这一代码将在终端返回以下对象: +```text --8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ecrecoverresult.md' +``` 有了这些必要数值,我们就可以到Remix测试预编译合约。请注意,签名验证也可以通过Web3.js库来实现,但在本示例中,我们将会使用Remix,以确保它使用的是区块链上的预编译合约。我们可以使用以下Solidity代码进行签名验证: ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ecrecoverremix.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ecrecoverremix.sol' +``` 使用[Remix编译器部署](/builders/build/eth-api/dev-env/remix/)并将[MetaMask连接至Moonbase Alpha](/tokens/connect/metamask/)即可部署合约。调用`verify()`方法进行验证,如果`ecrecover`返回的地址与消息签名所使用的地址(与密钥相关,需在合约中手动设置)一致,即返回*true*。 @@ -56,7 +62,9 @@ npm ls web3 向这一函数输入数据可返回其SHA256哈希值。测试这一预编译合约,可以使用此[在线工具](https://md5calc.com/hash/sha256)来计算任何字符串的SHA256哈希值。在本示例中,我们将使用`Hello World!`。直接进入Remix并部署以下代码,计算出来的哈希值将在`expectedHash`变量中显示: ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/sha256.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/sha256.sol' +``` 合约部署后,就可以调用`checkHash()`方法进行验证。如果`calculateHash()`返回的哈希值与所提供的哈希值一致,即返回*true* 。 @@ -66,7 +74,9 @@ SHA3-256是SHA-3安全散列算法(遵循[FIPS202](https://nvlpubs.nist.gov/ni 目前Solidity暂不支持SHA3-256,因此需要使用内联汇编的方式调用这一函数。您可使用以下代码调用这个预编译合约。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/sha3fips.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/sha3fips.sol' +``` 使用[Remix编译器部署](/builders/build/eth-api/dev-env/remix/)并将[MetaMask连接至Moonbase Alpha](/tokens/connect/metamask/)即可部署合约。调用`sha3fips(bytes memory data)`方法返回数据参数的编码字符串。 @@ -74,7 +84,9 @@ SHA3-256是SHA-3安全散列算法(遵循[FIPS202](https://nvlpubs.nist.gov/ni 向这一函数输入数据可返回其RIPEMD-160哈希值。测试这一预编译合约,可以使用这个[在线工具](https://md5calc.com/hash/ripemd160)来计算任何字符串的RIPEMD-160哈希值。在本示例中,我们仍使用`Hello World!`。我们将使用相同的代码,但使用另一个函数:`ripemd160`函数。请注意,这个函数返回的是`bytes20`类型的变量: ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ripemd160.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/ripemd160.sol' +``` 合约部署后,就可以调用`checkHash()`方法进行验证。如果`calculateHash()`返回的哈希值与所提供的哈希值一致,即返回*true* 。 @@ -84,7 +96,9 @@ BN128Add预编译实现了原生椭圆曲线点添加。它返回一个表示`(a 目前Solidity暂不支持BN128Add,因此需要使用内联汇编的方式调用这一函数。您可使用以下代码样本调用这个预编译合约。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128add.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128add.sol' +``` 使用[Remix编译器部署](/builders/build/eth-api/dev-env/remix/)并将[MetaMask连接至Moonbase Alpha](/tokens/connect/metamask/)即可部署合约。调用`callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by)`方法返回操作结果。 @@ -94,7 +108,9 @@ BN128Mul预编译实现了原生椭圆曲线的标量乘法。它返回一个椭 目前Solidity暂不支持BN128Mul,因此需要使用内联汇编的方式调用这一函数。您可使用以下代码调用这个预编译合约。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128mul.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128mul.sol' +``` 使用[Remix编译器部署](/builders/build/eth-api/dev-env/remix/)并将[MetaMask连接至Moonbase Alpha](/tokens/connect/metamask/)即可部署合约。调用`callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar)`方法返回操作结果。 @@ -104,7 +120,9 @@ BN128Pairing预编译通过椭圆曲线配对操作进行zkSNARK验证。更多 目前Solidity暂不支持BN128Pairing,因此需要使用内联汇编的方式调用这一函数。您可使用以下代码调用这个预编译合约。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128pairing.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/bn128pairing.sol' +``` 使用[Remix编译器部署](/builders/build/eth-api/dev-env/remix/)并将[MetaMask连接至Moonbase Alpha](/tokens/connect/metamask/)即可部署合约。调用`function callBn256Pairing(bytes memory input)`方法返回操作结果。 @@ -114,7 +132,9 @@ BN128Pairing预编译通过椭圆曲线配对操作进行zkSNARK验证。更多 目前Solidity暂不支持恒等函数,因此需要使用内联汇编的方式调用这一函数。您可以使用[以下代码](https://docs.klaytn.com/smart-contract/precompiled-contracts#address-0x-04-datacopy-data)(经修改已适应Solidity)调用这个预编译合约。我们可以使用此[在线工具](https://web3-type-converter.onbrn.com/)来获取任何字符串的字节码,因为它是`callDataCopy()`方法的输入值。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/identity.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/identity.sol' +``` 合约部署后,就可以调用`callDataCopy()`方法来验证`memoryStored`是否与您在函数中所输入的字节码相符。 @@ -124,6 +144,8 @@ BN128Pairing预编译通过椭圆曲线配对操作进行zkSNARK验证。更多 目前Solidity暂不支持模幂运算函数,因此需要使用内联汇编的方式调用这一函数。[以下代码](https://docs.klaytn.com/smart-contract/precompiled-contracts#address-0x05-bigmodexp-base-exp-mod)经过了简化,能更好地呈现这一预编译合约的功能。 ---8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/modularexp.md' +```solidity +--8<-- 'code/builders/pallets-precompiles/precompiles/eth-mainnet/modularexp.sol' +``` 您也可以在[Remix](/builders/build/eth-api/dev-env/remix/)环境中尝试使用这一合约。调用`verify()`函数,输入基数、指数和除数,结果将储存在函数的`checkResult`变量中。 diff --git a/builders/pallets-precompiles/precompiles/registry.md b/builders/pallets-precompiles/precompiles/registry.md index 7d80525b..8f569558 100644 --- a/builders/pallets-precompiles/precompiles/registry.md +++ b/builders/pallets-precompiles/precompiles/registry.md @@ -119,4 +119,4 @@ Registry Precompile位于以下地址: ```py --8<-- 'code/builders/pallets-precompiles/precompiles/registry/web3.py' - ``` \ No newline at end of file + ``` diff --git a/node-operators/oracle-nodes/node-chainlink.md b/node-operators/oracle-nodes/node-chainlink.md index 13d2d9fd..da1cf30e 100644 --- a/node-operators/oracle-nodes/node-chainlink.md +++ b/node-operators/oracle-nodes/node-chainlink.md @@ -208,28 +208,30 @@ Chainlink预言机配置的最后一步就是创建Job。请参阅[Chainlink官 ```json { - "initiators": [ - { - "type": "runlog", - "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } - } - ], - "tasks": [ - { - "type": "httpget", - "params": { "get": "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD" } - }, - { - "type": "jsonparse", - "params": { "path": [ "USD" ] } - }, - { - "type": "multiply", - "params": { "times": 100 } - }, - { "type": "ethuint256" }, - { "type": "ethtx" } - ] + "initiators": [ + { + "type": "runlog", + "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } + } + ], + "tasks": [ + { + "type": "httpget", + "params": { + "get": "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD" + } + }, + { + "type": "jsonparse", + "params": { "path": ["USD"] } + }, + { + "type": "multiply", + "params": { "times": 100 } + }, + { "type": "ethuint256" }, + { "type": "ethtx" } + ] } ``` @@ -249,19 +251,19 @@ Chainlink预言机配置的最后一步就是创建Job。请参阅[Chainlink官 ```json { - "initiators": [ - { - "type": "runlog", - "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } - } - ], - "tasks": [ - { "type": "httpget" }, - { "type": "jsonparse" }, - { "type": "multiply" }, - { "type": "ethuint256" }, - { "type": "ethtx" } - ] + "initiators": [ + { + "type": "runlog", + "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } + } + ], + "tasks": [ + { "type": "httpget" }, + { "type": "jsonparse" }, + { "type": "multiply" }, + { "type": "ethuint256" }, + { "type": "ethtx" } + ] } ``` diff --git a/tokens/staking/stake.md b/tokens/staking/stake.md index f05085b8..2caa6469 100644 --- a/tokens/staking/stake.md +++ b/tokens/staking/stake.md @@ -49,7 +49,7 @@ Token持有者可以向候选人质押自己的Token,这一过程称为委托 - **setAutoCompound**(*address* candidate, *uint8* value, *uint256* candidateAutoCompoundingDelegationCount, *uint256* delegatorDelegationCount) - 为现有委托设置一个自动复合数值 -## 获取质押数值 {: #retrieving-staking-parameters } +## 获取质押数值 {: #retrieving-staking-parameters } 您可以使用Polkadot.js Apps查看任何常量质押数值,例如最大委托数量、最低质押要求、委托请求的退出延迟等。 @@ -86,7 +86,7 @@ Token持有者可以向候选人质押自己的Token,这一过程称为委托 ![Staking Account](/images/tokens/staking/stake/stake-2.png) -### 获取候选人的委托数量 {: #get-the-candidate-delegation-count } +### 获取候选人的委托数量 {: #get-the-candidate-delegation-count } 首先,您需要获取`candidateInfo`,其中将包含委托人数量,因为您需要在以后的交易中提交此参数。要检索参数,请确保您仍在 **Developer** 页面的 **Chain State** 选项卡上,然后执行以下步骤: @@ -105,11 +105,12 @@ Token持有者可以向候选人质押自己的Token,这一过程称为委托 ```js // Simple script to get the number of auto-compounding delegations for a given candidate. -// Remember to replace CANDIDATE-ADDRESS-HERE with the candidate's address you want to delegate. -const candidateAccount = 'CANDIDATE-ADDRESS-HERE'; -const autoCompoundingDelegations = await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); +// Remember to replace INSERT_CANDIDATE_ADDRESS with the candidate's address you want to delegate. +const candidateAccount = 'INSERT_CANDIDATE_ADDRESS'; +const autoCompoundingDelegations = + await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); console.log(autoCompoundingDelegations.toHuman().length); -``` +``` 要运行该代码段,请确保您位于Polkadot.js Apps的 **JavaScript** 页面(可以从 **Developer** 下拉列表中选择),并执行以下步骤: @@ -126,15 +127,14 @@ console.log(autoCompoundingDelegations.toHuman().length); ```js // Simple script to get your number of existing delegations. -// Remember to replace YOUR-ADDRESS-HERE with your delegator address. -const yourDelegatorAccount = 'YOUR-ADDRESS-HERE'; +// Remember to replace INSERT_YOUR_ADDRESS with your delegator address. +const yourDelegatorAccount = 'INSERT_YOUR_ADDRESS'; const delegatorInfo = await api.query.parachainStaking.delegatorState(yourDelegatorAccount); - if (delegatorInfo.toHuman()) { - console.log(delegatorInfo.toHuman()["delegations"].length); + console.log(delegatorInfo.toHuman()['delegations'].length); } else { - console.log(0) + console.log(0); } ``` @@ -195,12 +195,16 @@ if (delegatorInfo.toHuman()) { ```js // Simple script to verify your auto-compounding percentage for a given candidate. -// Remember to replace CANDIDATE-ADDRESS-HERE with the candidate's address you want to delegate -// And replace DELEGATOR-ADDRESS-HERE with the address used to delegate with -const candidateAccount = 'CANDIDATE-ADDRESS-HERE'; -const delegationAccount = 'DELEGATOR-ADDRESS-HERE' -const autoCompoundingDelegations = await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); -const delegation = autoCompoundingDelegations.find(del => del.delegator == delegationAccount) +// Remember to replace INSERT_CANDIDATE_ADDRESS with the candidate's address you +// want to delegate and replace INSERT_DELEGATOR_ADDRESS with the address used to +// delegate with +const candidateAccount = 'INSERT_CANDIDATE_ADDRESS'; +const delegationAccount = 'INSERT_DELEGATOR_ADDRESS'; +const autoCompoundingDelegations = + await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); +const delegation = autoCompoundingDelegations.find( + (del) => del.delegator == delegationAccount +); console.log(`${delegation.value}%`); ``` diff --git a/tutorials/eth-api/call-permit-gasless-txs.md b/tutorials/eth-api/call-permit-gasless-txs.md index d9cbf3f8..122cc9a4 100644 --- a/tutorials/eth-api/call-permit-gasless-txs.md +++ b/tutorials/eth-api/call-permit-gasless-txs.md @@ -373,9 +373,9 @@ import abi from './callPermitABI.js' ... const callPermit = new ethers.Contract( - '{{ networks.moonbeam.precompiles.call_permit }}', - abi, - thirdPartyGasSigner + '{{ networks.moonbeam.precompiles.call_permit }}', + abi, + thirdPartyGasSigner, ); const nonce = await callPermit.nonces(userSigner.address); @@ -401,8 +401,8 @@ const nonce = await callPermit.nonces(userSigner.address); }); // Insert your own signer logic or use the following for testing purposes - const userSigner = new ethers.Wallet('INSERT-PRIVATE-KEY', provider); - const thirdPartyGasSigner = new ethers.Wallet('INSERT-PRIVATE-KEY', provider); + const userSigner = new ethers.Wallet('INSERT_PRIVATE_KEY', provider); + const thirdPartyGasSigner = new ethers.Wallet('INSERT_PRIVATE_KEY', provider); const domain = { name: 'Call Permit Precompile', @@ -439,7 +439,7 @@ const nonce = await callPermit.nonces(userSigner.address); const callPermit = new ethers.Contract( '{{ networks.moonbeam.precompiles.call_permit }}', abi, - thirdPartyGasSigner + thirdPartyGasSigner, ); const nonce = await callPermit.nonces(userSigner.address); @@ -483,7 +483,7 @@ sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message))) const signature = await signer.signTypedData( domain, // The domain separator types, // The typed data structure - message // The message data + message, // The message data ); console.log(`Signature hash: ${signature}`); ``` @@ -518,6 +518,7 @@ console.log(`Transaction hash: ${dispatch.hash}`); ``` ??? code "查看完整腳本" + ```js --8<-- 'code/builders/pallets-precompiles/precompiles/call-permit/dispatch-call-permit.js' ``` diff --git a/tutorials/eth-api/hardhat-start-to-end.md b/tutorials/eth-api/hardhat-start-to-end.md index 7eb8a82c..8abbc911 100644 --- a/tutorials/eth-api/hardhat-start-to-end.md +++ b/tutorials/eth-api/hardhat-start-to-end.md @@ -131,44 +131,40 @@ npm install --save-dev @nomicfoundation/hardhat-toolbox ```js moonbeam: { - url: '{{ networks.moonbeam.rpc_url }}', // Insert your RPC URL here - - chainId: {{ networks.moonbeam.chain_id }}, // (hex: {{ networks.moonbeam.hex_chain_id }}) - accounts: [privateKey] - }, + url: '{{ networks.moonbeam.rpc_url }}', // Insert your RPC URL here + chainId: {{ networks.moonbeam.chain_id }}, // (hex: {{ networks.moonbeam.hex_chain_id }}) + accounts: [privateKey] + }, ``` === "Moonriver" ```js moonriver: { - url: '{{ networks.moonriver.rpc_url }}', // Insert your RPC URL here - - chainId: {{ networks.moonriver.chain_id }}, // (hex: {{ networks.moonriver.hex_chain_id }}) - accounts: [privateKey] - }, + url: '{{ networks.moonriver.rpc_url }}', // Insert your RPC URL here + chainId: {{ networks.moonriver.chain_id }}, // (hex: {{ networks.moonriver.hex_chain_id }}) + accounts: [privateKey] + }, ``` === "Moonbase Alpha" ```js moonbase: { - url: '{{ networks.moonbase.rpc_url }}', - - chainId: {{ networks.moonbase.chain_id }}, // (hex: {{ networks.moonbase.hex_chain_id }}) - accounts: [privateKey] - }, + url: '{{ networks.moonbase.rpc_url }}', + chainId: {{ networks.moonbase.chain_id }}, // (hex: {{ networks.moonbase.hex_chain_id }}) + accounts: [privateKey] + }, ``` === "Moonbeam开发节点" ```js dev: { - url: '{{ networks.development.rpc_url }}', - - chainId: {{ networks.development.chain_id }}, // (hex: {{ networks.development.hex_chain_id }}) - accounts: [privateKey] - }, + url: '{{ networks.development.rpc_url }}', + chainId: {{ networks.development.chain_id }}, // (hex: {{ networks.development.hex_chain_id }}) + accounts: [privateKey] + }, ``` 5. 导入[Moonscan API密钥](/builders/build/eth-api/verify-contracts/etherscan-plugins/#generating-a-moonscan-api-key){target=_blank},用于本教程后续验证部分 @@ -214,8 +210,8 @@ module.exports = { apiKey: { moonbaseAlpha: moonscanAPIKey, // Moonbase Moonscan API Key moonbeam: moonscanAPIKey, // Moonbeam Moonscan API Key - } - } + }, + }, }; ``` @@ -311,7 +307,7 @@ describe('Dao contract', function () { // Return the deployed DAO and the first member of the DAO to allow the tests to // access and interact with them return { deployedDao, member1 }; - } + }; // The test cases should be added here @@ -367,7 +363,11 @@ it('should not allow non-admins to grant membership', async function () { // We use connect to call grant_member from member1's account instead of admin. // This test will succeed if the function call reverts and fails if the call succeeds - await expect(deployedDao.connect(member1).grant_member('0x0000000000000000000000000000000000000000')).to.be.reverted; + await expect( + deployedDao + .connect(member1) + .grant_member('0x0000000000000000000000000000000000000000') + ).to.be.reverted; }); ``` @@ -462,7 +462,10 @@ async function main() { // 4. Deploy the contract specifying two params: the desired collator to // delegate to and the address of the deployer (the initial DAO admin) - const deployedDao = await delegationDao.deploy(targetCollator, deployer.address); + const deployedDao = await delegationDao.deploy( + targetCollator, + deployer.address + ); await deployedDao.waitForDeployment(); // 5. Print out the address of the deployed staking DAO contract @@ -531,7 +534,10 @@ async function main() { // 4. Deploy the contract specifying two params: the desired collator to delegate // to and the address of the deployer (synonymous with initial DAO admin) - const deployedDao = await delegationDao.deploy(targetCollator, deployer.address); + const deployedDao = await delegationDao.deploy( + targetCollator, + deployer.address + ); await deployedDao.waitForDeployment(); console.log('DAO address:', deployedDao.address); diff --git a/tutorials/eth-api/how-to-build-a-dapp.md b/tutorials/eth-api/how-to-build-a-dapp.md index 9fd15022..afa00c31 100644 --- a/tutorials/eth-api/how-to-build-a-dapp.md +++ b/tutorials/eth-api/how-to-build-a-dapp.md @@ -43,10 +43,10 @@ _作者:Jeremy Boetticher_ ```json { - "jsonrpc": "2.0", - "id": 1, - "method": "eth_getBalance", - "params": ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac", "latest"] + "jsonrpc": "2.0", + "id": 1, + "method": "eth_getBalance", + "params": ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac", "latest"] } ``` @@ -87,7 +87,7 @@ npx hardhat init npm install --save-dev hardhat @nomicfoundation/hardhat-ethers ethers ``` -在我们开始编写智能合约之前,让我们先将JSON-RPC URL添加至配置之中,我们可以使用以下代码设置`hardhat.config.js`文件,并将`YOUR_PRIVATE_KEY`取代为您具有资金账户的私钥。 +在我们开始编写智能合约之前,让我们先将JSON-RPC URL添加至配置之中,我们可以使用以下代码设置`hardhat.config.js`文件,并将`INSERT_YOUR_PRIVATE_KEY`取代为您具有资金账户的私钥。 !!! 注意事项 这仅用于测试目的,**请勿将您具有真实资金的账户私钥以文字的方式储存**。 @@ -100,7 +100,7 @@ module.exports = { moonbase: { url: '{{ networks.moonbase.rpc_url }}', chainId: {{ networks.moonbase.chain_id }}, - accounts: ['YOUR_PRIVATE_KEY'] + accounts: ['INSERT_YOUR_PRIVATE_KEY'] } } }; @@ -472,14 +472,14 @@ function App() { #### 创建一个智能合约实例 {: #create-a-contract-instance } -让我们在`App.js`中导入JSON文件和Ethers `Contract`对象。我们可以使用地址和ABI创建一个合约对象实例,因此将`YOUR_CONTRACT_ADDRESS_HERE`替换为您[部署时](#deploying-smart-contracts)复制的合约地址: +让我们在`App.js`中导入JSON文件和Ethers `Contract`对象。我们可以使用地址和ABI创建一个合约对象实例,因此将`INSERT_CONTRACT_ADDRESS`替换为您[部署时](#deploying-smart-contracts)复制的合约地址: ```javascript // ... other imports import MintableERC20 from './MintableERC20.json'; import { Contract } from 'ethers'; -const contractAddress = 'YOUR_CONTRACT_ADDRESS_HERE'; +const contractAddress = 'INSERT_CONTRACT_ADDRESS'; function App() { const contract = new Contract(contractAddress, MintableERC20.abi); @@ -503,7 +503,7 @@ function App() { alignCenter: { textAlign: 'center' }, }; - const contractAddress = 'YOUR_CONTRACT_ADDRESS_HERE'; + const contractAddress = 'INSERT_CONTRACT_ADDRESS'; function App() { const contract = new Contract(contractAddress, MintableERC20.abi); @@ -611,7 +611,7 @@ function App() { card: { borderRadius: 4, padding: 4, maxWidth: '550px', width: '100%' }, alignCenter: { textAlign: 'center' }, }; - const contractAddress = 'YOUR_CONTRACT_ADDRESS_HERE'; + const contractAddress = 'INSERT_CONTRACT_ADDRESS'; function App() { const { activateBrowserWallet, deactivate, account } = useEthers(); @@ -817,7 +817,7 @@ function App() { import { Button, Grid, Card } from '@mui/material'; import { Box } from '@mui/system'; import { Contract } from 'ethers'; - import MintableERC20 from './MintableERC20.json'; + import MintableERC20 from './MintableERC20.json'; import SupplyComponent from './SupplyComponent'; import MintingComponent from './MintingComponent'; @@ -827,7 +827,7 @@ function App() { card: { borderRadius: 4, padding: 4, maxWidth: '550px', width: '100%' }, alignCenter: { textAlign: 'center' }, }; - const contractAddress = 'YOUR_CONTRACT_ADDRESS_HERE'; + const contractAddress = 'INSERT_CONTRACT_ADDRESS'; function App() { const { activateBrowserWallet, deactivate, account } = useEthers(); @@ -1055,7 +1055,7 @@ function App() { card: { borderRadius: 4, padding: 4, maxWidth: '550px', width: '100%' }, alignCenter: { textAlign: 'center' }, }; - const contractAddress = 'YOUR_CONTRACT_ADDRESS_HERE'; + const contractAddress = 'INSERT_CONTRACT_ADDRESS'; function App() { const { activateBrowserWallet, deactivate, account } = useEthers(); diff --git a/tutorials/eth-api/randomness-lottery.md b/tutorials/eth-api/randomness-lottery.md index 2484d56b..c005f6cb 100644 --- a/tutorials/eth-api/randomness-lottery.md +++ b/tutorials/eth-api/randomness-lottery.md @@ -466,19 +466,20 @@ touch participate.js ```js async function participate() { - const lottery = await ethers.getContractAt('Lottery', 'INSERT-CONTRACT-ADDRESS'); - - const participationFee = await lottery.PARTICIPATION_FEE(); - const tx = await lottery.participate({ value: participationFee }); - console.log('Participation transaction hash:', tx.hash); + const lottery = await ethers.getContractAt( + 'Lottery', + 'INSERT_CONTRACT_ADDRESS' + ); + const participationFee = await lottery.PARTICIPATION_FEE(); + const tx = await lottery.participate({ value: participationFee }); + console.log('Participation transaction hash:', tx.hash); } - participate() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); ``` 要运行此脚本,您可以使用以下命令: diff --git a/tutorials/integrations/local-subsquid.md b/tutorials/integrations/local-subsquid.md index 09a26525..c001e6c3 100644 --- a/tutorials/integrations/local-subsquid.md +++ b/tutorials/integrations/local-subsquid.md @@ -116,10 +116,12 @@ require('@nomicfoundation/hardhat-ethers'); module.exports = { solidity: "0.8.17", networks: { - dev: { - url: "{{ networks.development.rpc_url }}", + dev: { + url: '{{ networks.development.rpc_url }}', chainId: {{ networks.development.chain_id }}, // (hex: {{ networks.development.hex_chain_id }}), - accounts: ["0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133"], // Alith's private key + accounts: [ + '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133', + ], // Alith's private key }, }, }; @@ -239,38 +241,50 @@ npx hardhat compile // will compile your contracts, add the Hardhat Runtime Environment's members to the // global scope, and execute the script. const hre = require('hardhat'); - async function main() { // Get Contract ABI const MyTok = await hre.ethers.getContractFactory('MyTok'); - + // Plug ABI to Address - const myTok = await MyTok.attach('0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3'); - + const myTok = await MyTok.attach( + '0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3' + ); + const value = hre.ethers.utils.parseUnits('10', 'ether'); - + let tx; // Transfer to Baltathar - tx = await myTok.transfer('0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', value); + tx = await myTok.transfer( + '0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', + value + ); await tx.wait(); console.log(`Transfer to Baltathar with TxHash ${tx.hash}`); - + // Transfer to Charleth - tx = await myTok.transfer('0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc', value); + tx = await myTok.transfer( + '0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc', + value + ); await tx.wait(); console.log(`Transfer to Charleth with TxHash ${tx.hash}`); - + // Transfer to Dorothy - tx = await myTok.transfer('0x773539d4Ac0e786233D90A233654ccEE26a613D9', value); + tx = await myTok.transfer( + '0x773539d4Ac0e786233D90A233654ccEE26a613D9', + value + ); await tx.wait(); console.log(`Transfer to Dorothy with TxHash ${tx.hash}`); - + // Transfer to Ethan - tx = await myTok.transfer('0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB', value); + tx = await myTok.transfer( + '0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB', + value + ); await tx.wait(); console.log(`Transfer to Ethan with TxHash ${tx.hash}`); } - // We recommend this pattern to be able to use async/await everywhere // and properly handle errors. main().catch((error) => { @@ -374,17 +388,28 @@ volumes: { "$schema": "https://cdn.subsquid.io/schemas/commands.json", "commands": { - "archive-up": { - "description": "Start local Moonbeam Archive", - "cmd": ["docker-compose", "-f", "archive/docker-compose.archive.yml", "up", "-d"] - }, - "archive-down": { - "description": "Stop local Moonbeam Archive", - "cmd": ["docker-compose", "-f", "archive/docker-compose.archive.yml", "down"] - }, - // ... + "archive-up": { + "description": "Start local Moonbeam Archive", + "cmd": [ + "docker-compose", + "-f", + "archive/docker-compose.archive.yml", + "up", + "-d" + ] + }, + "archive-down": { + "description": "Stop local Moonbeam Archive", + "cmd": [ + "docker-compose", + "-f", + "archive/docker-compose.archive.yml", + "down" + ] + }, + // ... } - } +} ``` !!! 注意事项 @@ -457,7 +482,8 @@ import { EvmBatchProcessor } from "@subsquid/evm-processor"; import { Transfer } from "./model"; import { events } from "./abi/MyTok"; -const contractAddress = "0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3".toLowerCase(); +const contractAddress = + '0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3'.toLowerCase(); const processor = new EvmBatchProcessor() .setDataSource({ chain: "http://localhost:9944", // Local development node @@ -471,33 +497,37 @@ const processor = new EvmBatchProcessor() data: true, }, transaction: { - hash: true - } - } + hash: true, + }, + }, }); processor.run(new TypeormDatabase(), async (ctx) => { - const transfers: Transfer[] = [] + const transfers: Transfer[] = []; for (let c of ctx.blocks) { for (let i of c.items) { - - if (i.address === contractAddress && i.kind === "evmLog"){ - if (i.transaction){ - const { from, to, value } = events.Transfer.decode(i.evmLog) - transfers.push(new Transfer({ - id: `${String(c.header.height).padStart(10, '0')}-${i.transaction.hash.slice(3,8)}`, + if (i.address === contractAddress && i.kind === 'evmLog') { + if (i.transaction) { + const { from, to, value } = events.Transfer.decode(i.evmLog); + transfers.push( + new Transfer({ + id: `${String(c.header.height).padStart( + 10, + '0' + )}-${i.transaction.hash.slice(3, 8)}`, block: c.header.height, from: from, to: to, value: value.toBigInt(), timestamp: BigInt(c.header.timestamp), - txHash: i.transaction.hash - })) - } + txHash: i.transaction.hash, + }) + ); + } } } - } - await ctx.store.save(transfers) + } + await ctx.store.save(transfers); }); ``` diff --git a/tutorials/integrations/nft-subsquid.md b/tutorials/integrations/nft-subsquid.md index 415ba8aa..b9017e45 100644 --- a/tutorials/integrations/nft-subsquid.md +++ b/tutorials/integrations/nft-subsquid.md @@ -157,7 +157,7 @@ Subsquid SDK为用户提供[`SubstrateBatchProcessor`类](https://docs.subsquid. ```js processor.setDataSource({ chain: process.env.RPC_ENDPOINT, // TODO: Add the endpoint to your .env file - archive: lookupArchive("moonbeam", {type: "Substrate"}), + archive: lookupArchive('moonbeam', { type: 'Substrate' }), }); ``` @@ -166,7 +166,7 @@ Subsquid SDK为用户提供[`SubstrateBatchProcessor`类](https://docs.subsquid. ```js processor.setDataSource({ chain: process.env.RPC_ENDPOINT, // TODO: Add the endpoint to your .env file - archive: lookupArchive("moonriver", {type: "Substrate"}), + archive: lookupArchive('moonriver', { type: 'Substrate' }), }); ``` @@ -175,7 +175,7 @@ Subsquid SDK为用户提供[`SubstrateBatchProcessor`类](https://docs.subsquid. ```js processor.setDataSource({ chain: process.env.RPC_ENDPOINT, // TODO: Add the endpoint to your .env file - archive: lookupArchive("moonbase", {type: "Substrate"}), + archive: lookupArchive('moonbase', { type: 'Substrate' }), }); ```