blockchain - !!! 重点内容. 在infura上使用编码coding的方式,创建和部署contract coding to deploy contract infura web3 ether

访问量: 774

refer to: https://docs.infura.io/infura/tutorials/ethereum/deploy-a-contract-using-web3.js#2.-create-a-project-directory

1. 创建一个项目文件夹,例如

/workspace/blockchain/contract_on_goerli_using_infura

2. npm install web3 solc dotenv

这样当前目录下会出现  package.json 文件,内容如下

{
  "dependencies": {
    "dotenv": "^16.0.1",
    "solc": "^0.8.14-fixed",
    "web3": "^1.7.3"
  }
}

3. 创建一个 contract, 内容如下:   Demo.sol

pragma solidity >= 0.5.8;

contract Demo {
  event Echo (string message);

  function echo(string calldata message) external {
    emit Echo(message);
  }
}

4. 准备编译, 编译的话,手动操作很复杂很麻烦, 所以我们直接写一个脚本: compile.js

注意:这里使用该文件的原因,是solc会生成太多麻烦的内容(json的节点很复杂)所以我们用编程的方式,只截取其中有用的部分,然后放到一个新的json文件中即可。

const fs = require('fs').promises;

const solc = require('solc');

// 这个方法需要修改, 入口文件名称 Demo.sol   和 生成的文件名称 Demo.json 
async function main(){
  const sourceCode = await fs.readFile('Demo.sol', 'utf8');
  const {abi, bytecode} = compile(sourceCode, 'Demo');
  const artifact = JSON.stringify({ abi, bytecode}, null, 2);
  await fs.writeFile('Demo.json', artifact);
}

// 这个方法不用改。拿过来用就好了
function compile(sourceCode, contractName){
  const input = {
    language: 'Solidity',
    sources: { main: { content: sourceCode} },
    settings: {
      outputSelection: {
        '*': {
          '*': ['abi', 'evm.bytecode']
        }
      },
    },
  }

  const output = solc.compile(JSON.stringify(input));
  const artifact = JSON.parse(output).contracts.main[contractName];
  return {
    abi: artifact.abi,
    bytecode: artifact.evm.bytecode.object
  };
}

main().then( () => process.exit(0) )

5. 运行 node compile.js  就可以编译了。得到 Demo.json ,内容如下:

(可以看到,获得的是 abi 和 bytecode ,真正deploy的时候,用这个bytecode就足够了)

$ cat Demo.json
{
  "abi": [
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "string",
          "name": "message",
          "type": "string"
        }
      ],
      "name": "Echo",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "string",
          "name": "message",
          "type": "string"
        }
      ],
      "name": "echo",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ],
  "bytecode": "608060405234801561001057600080fd5b506101fd806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f15da72914610030575b600080fd5b61004a600480360381019061004591906100f8565b61004c565b005b7fdb84d7c006c4de68f9c0bd50b8b81ed31f29ebeec325c872d36445c6565d757c828260405161007d9291906101a3565b60405180910390a15050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126100b8576100b7610093565b5b8235905067ffffffffffffffff8111156100d5576100d4610098565b5b6020830191508360018202830111156100f1576100f061009d565b5b9250929050565b6000806020838503121561010f5761010e610089565b5b600083013567ffffffffffffffff81111561012d5761012c61008e565b5b610139858286016100a2565b92509250509250929050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b60006101828385610145565b935061018f838584610156565b61019883610165565b840190509392505050565b600060208201905081810360008301526101be818486610176565b9050939250505056fea2646970667358221220cd4858d1e016af1a21fc10e1a72faf5c472597f772f4397aa6ece1263538448c64736f6c634300080e0033"
}

6. 发布. 这里写一个发布脚本 deploy.js  内容如下:

const Web3 = require('web3');

const fs = require('fs')
const {abi, bytecode} = JSON.parse(fs.readFileSync('Demo.json'))

async function main(){
  // step1. 初始化web3 , 根据某个rpc server endpoint
  const network = process.env.ETHEREUM_NETWORK
  const web3 = new Web3(
    new Web3.providers.HttpProvider(
      `https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
    )
  )

  // step2. 创建签名用的东东
  const signer = web3.eth.accounts.privateKeyToAccount(
    process.env.SIGNER_PRIVATE_KEY
  )
  web3.eth.accounts.wallet.add(signer)

  // step3. 初始化contract
  const contract = new web3.eth.Contract(abi)
  contract.options.data = bytecode

  // step4. 发布该 contract
  const deployTx = contract.deploy()
  const deployedContract = await deployTx
    .send({
      from: signer.address, // 这里用到了signer的address
      gas: await deployTx.estimateGas()
    })
    .once('transactionHash', (txhash) => {
      console.log("Mining deployment transaction ... ", txhash)
      console.log(`https://${network}.etherscan.io/tx/${txhash}`)
    })

}

require('dotenv').config()
main()

7. 运行该脚本,内容如下:

$ node deploy.js
Mining deployment transaction ...  0x2afbc8b3dc020a3bd562a4a7eb8ced66bb08e9a5489baad902516de39b0a2aaa
https://goerli.etherscan.io/tx/0x2afbc8b3dc020a3bd562a4a7eb8ced66bb08e9a5489baad902516de39b0a2aaa

8. 调用contract的方法 ,  参考: https://docs.infura.io/infura/tutorials/ethereum/call-a-contract

创建文件 call.js  内容如下:

const Web3 = require('web3')

const fs = require('fs')

const { abi } = JSON.parse(fs.readFileSync('Demo.json'))

async function main(){
  const network = process.env.ETHEREUM_NETWORK

  // step1. 初始化web3 实例,增加json rpc server
  const web3 = new Web3(
    new Web3.providers.HttpProvider(
      `https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
    )
  )

  // step2. 创建signer
  const signer = web3.eth.accounts.privateKeyToAccount(  process.env.SIGNER_PRIVATE_KEY)
  web3.eth.accounts.wallet.add(signer)

  // step3. 创建contract, abi是关键
  const contract = new web3.eth.Contract( abi, process.env.DEMO_CONTRACT)

  // step4. 发起tx , 这里用到了签名
  const tx = contract.methods.echo(" Hi hihihi ")
  const receipt = await tx
    .send({ from: signer.address, gas: await tx.estimateGas() })
    .once("transactionHash" , (txHash) => {
      console.info("mining transaction...", txHash)
    })

  console.info("mined in block: ", receipt.blockNumber)
}

require('dotenv').config()
main()

9. 运行, 结果如下

node call.js
mining transaction... 0x50b234ecd061fe5014129aa5ad3f823dc46addcb2f9450bea967e07c719b8ca9
mined in block:  7061077

我们打开对应的网址,就可以查看到内容了:
https://goerli.etherscan.io/tx/0x50b234ecd061fe5014129aa5ad3f823dc46addcb2f9450bea967e07c719b8ca9

如何调用contract的 getter(view) 方法?

const tx = await contract.methods.getNumber().call() 

就可以了。

例如:

const Web3 = require('web3')

const fs = require('fs')

async function main(file_name_without_suffix, contract_address){
  const { abi } = JSON.parse(fs.readFileSync(file_name_without_suffix+'.json'))
  const network = process.env.ETHEREUM_NETWORK

  // step1. 初始化web3 实例,增加json rpc server
  const web3 = new Web3(
    new Web3.providers.HttpProvider(
      `https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
    )
  )

  // step2. 创建signer
  const signer = web3.eth.accounts.privateKeyToAccount(  process.env.SIGNER_PRIVATE_KEY)
  web3.eth.accounts.wallet.add(signer)

  // step3. 创建contract, abi是关键
  const contract = new web3.eth.Contract( abi, contract_address)

  const result = await contract.methods.getNumber().call()
  console.info("== result: ", result)
}

require('dotenv').config()

console.info("== 使用方式: $ node call.js TestContract 0xa1b2..z9   (该TestContract.json 和  必须存在)")
main(process.argv[2], process.argv[3]).then( () => process.exit(0) )

运行方式: node call_getter_setter.js TestGetterSetter 0x8c76df0d7d98f93afc88ba871314582e25d58b42

TestGetterSetter.sol

// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.7.0 < 0.9.0;

contract TestGetterSetter {

  uint256 number;

  function setNumber(uint256 num) public {
    number = num;
  }

  function getNumber() public view returns (uint256) {
    return number;
  }

}

调用 contract 的pure方法 (跟 view方法一模一样,都是 .method().call() )

先弄一个 pure function ,例如:

cat TestPure.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.7.0 < 0.9.0;

contract TestPure {
  function doSum(uint a, uint b) public pure returns(uint){
    return a + b ;
  }
}

然后部署,调用:

$ cat call_pure_function.js
const Web3 = require('web3')

const fs = require('fs')

async function main(file_name_without_suffix, contract_address){
  const { abi } = JSON.parse(fs.readFileSync(file_name_without_suffix+'.json'))
  const network = process.env.ETHEREUM_NETWORK

  // step1. 初始化web3 实例,增加json rpc server
  const web3 = new Web3(
    new Web3.providers.HttpProvider(
      `https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
    )
  )

  // step2. 创建signer
  const signer = web3.eth.accounts.privateKeyToAccount(  process.env.SIGNER_PRIVATE_KEY)
  web3.eth.accounts.wallet.add(signer)

  // step3. 创建contract, abi是关键
  const contract = new web3.eth.Contract( abi, contract_address)

  const tx = await contract.methods.doSum(300,4234234).call()
  console.info("== tx: ", tx)
}

require('dotenv').config()

console.info("== 使用方式: $ node call.js TestContract 0xa1b2..z9   (该TestContract.json 和  必须存在)")
main(process.argv[2], process.argv[3]).then( () => process.exit(0) )

event log 是啥?

如何验证Contract?

跟传统的etherscan.io上的验证一样, 点击contract url ,然后点击 contract  标签,verify的页面,

根据提示来就好了

需要注意的是:

1. solcjs --version 就可以知道自己的编译器的版本 一般都是不优化

2. 输入对应的源代码(或者json )

3. 选择对应的协议(一般是GPL 3,看你的源代码)

订阅/RSS Feed

Subscribe