使用web3進行合約部署呼叫以及監聽
阿新 • • 發佈:2019-02-19
token合約是官方提供的一個樣例,這裡給出我修改過的版本,方便演示.
contract MyToken { /* Public variables of the token */ string public name; string public symbol; uint8 public decimals; /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint)) public allowance; mapping (address => mapping (address => uint)) public spentAllowance; /* This generates a public event on the blockchain that will notify clients */ event Transfer(address indexed from, address indexed to, uint256 value); event ReceiveApproval(address _from, uint256 _value, address _token, bytes _extraData); /* Initializes contract with initial supply tokens to the creator of the contract */ function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol) { balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes decimals = decimalUnits; // Amount of decimals for display purposes } /* Send coins */ function transfer(address _to, uint256 _value) { if (balanceOf[msg.sender] < _value) throw; // Check if the sender has enough if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows balanceOf[msg.sender] -= _value; // Subtract from the sender balanceOf[_to] += _value; // Add the same to the recipient Transfer(msg.sender, _to, _value); // Notify anyone listening that this transfer took place } /* Allow another contract to spend some tokens in your behalf */ function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) { allowance[msg.sender][_spender] = _value; ReceiveApproval(msg.sender, _value, this, _extraData); } /* A contract attempts to get the coins */ function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (balanceOf[_from] < _value) throw; // Check if the sender has enough if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows if (spentAllowance[_from][msg.sender] + _value > allowance[_from][msg.sender]) throw; // Check allowance balanceOf[_from] -= _value; // Subtract from the sender balanceOf[_to] += _value; // Add the same to the recipient spentAllowance[_from][msg.sender] += _value; Transfer(msg.sender, _to, _value); } /* This unnamed function is called whenever someone tries to send ether to it */ function () { throw; // Prevents accidental sending of ether } }
編譯token
通過solc編譯得到的json abi以及hex編碼的code,由於太長,太佔地方就不放上來了.
這些會在部署以及呼叫的時候用到.
下面來通過web3進行合約的部署,讀取資料,發起事務以及監聽事件的發生.
部署合約
部署合約需要建立事務,話費gas,因此相關賬戶必須事先解鎖,web3目前沒有api可以解鎖賬戶,需要自己在控制檯事先解鎖才行.
首先建立合約,需要制定abi.
然後就可以部署合約了,這時候需要合約的code,
部署合約的結果可以通過非同步函式來獲取,例子已經給出.
var Web3 = require('web3'); var web3 = new Web3(new Web3.providers.IpcProvider("\\\\.\\pipe\\geth.ipc",net)); var eth=web3.eth; var tokenContract = new web3.eth.Contract(MyTokenABI, null, { from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa' // 目前web3沒有api來解鎖賬戶,只能自己事先解鎖 }); tokenContract.deploy({ data: MyTokenBin, arguments: [32222, 'token on web3',0,'web3'] }).send({ from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa', gas: 1500000, gasPrice: '30000000000000' }, function(error, transactionHash){ console.log("deploy tx hash:"+transactionHash) }) .on('error', function(error){ console.error(error) }) .on('transactionHash', function(transactionHash){ console.log("hash:",transactionHash)}) .on('receipt', function(receipt){ console.log(receipt.contractAddress) // contains the new contract address }) .on('confirmation', function(confirmationNumber, receipt){console.log("receipt,",receipt)}) .then(function(newContractInstance){ console.log(newContractInstance.options.address) // instance with the new contract address });
查詢合約
合約部署成功以後,有了地址就可以根據地址來查詢合約的狀態.
查詢合約狀態並不需要發起事務,也不需要花費gas,因此比較簡單.
var tokenContract = new web3.eth.Contract(MyTokenABI, '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9');
tokenContract.methods.name().call(null,function(error,result){
console.log("contract name "+result);
})
呼叫合約函式
合約的函式除了指明返回值是constant的以外,都需要發起事務,這時候就需要指定呼叫者,因為要花費該賬戶的gas.
這裡呼叫一下transfer函式.
tokenContract.methods.transfer("0x8c1b2e9e838e2bf510ec7ff49cc607b718ce8401",387).send({from: '0x1a9ec3b0b807464e6d3398a59d6b0a369bf422fa'})
.on('transactionHash', function(hash){
})
.on('confirmation', function(confirmationNumber, receipt){
})
.on('receipt', function(receipt){
// receipt example
console.log(receipt); //查詢這裡可以得到結果
})
.on('error', console.error); // If a out of gas error, the second parameter is the receipt.
監聽事件
剛剛呼叫transfer的時候還會觸發合約的事件Transfer,如果程式關注誰給誰進行了轉賬,那麼就可以通過監聽該事件.
通過指定fromBlock,toBlock可以限制事件發生的範圍,除了這個還有一個filter引數可以進行更詳細的限制,
如有興趣可以查詢文件web3文件
tokenContract.events.Transfer({
fromBlock: 0,
toBlock:'latest'
}, function(error, event){ /*console.log("result:\n"+JSON.stringify(event)); */})
.on('data', function(event){
console.log(event); // same results as the optional callback above
})
.on('changed', function(event){
// remove event from local database
})
.on('error', console.error);
需要說明的是,這個監聽不僅傳送歷史事件,未來所有事件也會傳送.
下面的結果是首先執行程式,會先打印出來剛剛進行的轉賬.
然後我在通過其他途徑進行轉賬操作,這時候終端會把新的轉賬也打印出來.
歷史轉賬:
{ address: '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9',
blockNumber: 10680,
transactionHash: '0x27d5ab9277df504a436b1068697a444d30228584094632f10ab7ba5213a4eccc',
transactionIndex: 0,
blockHash: '0xcde734882b0d8cb7a5bf1f7e6d1ccfac5365308de2d7391ce286b45c5546f40b',
logIndex: 0,
removed: false,
id: 'log_2588a961',
returnValues:
Result {
'0': '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
'1': '0x8c1b2E9e838e2Bf510eC7Ff49CC607b718Ce8401',
'2': '387',
from: '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
to: '0x8c1b2E9e838e2Bf510eC7Ff49CC607b718Ce8401',
value: '387' },
event: 'Transfer',
signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
raw:
{ data: '0x0000000000000000000000000000000000000000000000000000000000000183',
topics:
[ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x0000000000000000000000001a9ec3b0b807464e6d3398a59d6b0a369bf422fa',
'0x0000000000000000000000008c1b2e9e838e2bf510ec7ff49cc607b718ce8401' ] } }
實時監控到的轉賬
{ address: '0x6a0dF9E94a41fCd89d8236a8C03f9D678df5Acf9',
blockNumber: 10740,
transactionHash: '0xb42651720e8b8b64283cbd245aebaa7ad7e3dda58b9887f645ad6957bd7771b8',
transactionIndex: 0,
blockHash: '0xcdca97ba5a277e402a93188df03a758c916c37eea0f7498365d227ebd7cb2ee2',
logIndex: 0,
removed: false,
id: 'log_edc5dc68',
returnValues:
Result {
'0': '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
'1': '0x0000000000000000000000000000000000000001',
'2': '32',
from: '0x1a9eC3b0b807464e6D3398a59d6b0a369Bf422fA',
to: '0x0000000000000000000000000000000000000001',
value: '32' },
event: 'Transfer',
signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
raw:
{ data: '0x0000000000000000000000000000000000000000000000000000000000000020',
topics:
[ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x0000000000000000000000001a9ec3b0b807464e6d3398a59d6b0a369bf422fa',
'0x0000000000000000000000000000000000000000000000000000000000000001' ] } }