blockchain - !!! 重点内容. 在infura上使用编码coding的方式,创建和部署contract coding to deploy contract infura web3 ether
访问量: 829
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,看你的源代码)
