第12篇 web3.js - Ethereum JavaScript API(contract,部署与调用智能合约)

本文环境:

      区块链:以太坊POA联盟链;

      出块节点数:3;

      操作系统:windows 64;

      节点版本:Geth1.9.14;

      node版本:v10.14.0

参考文档:https://web3js.readthedocs.io/en/v1.2.8/

目录

一、new contract

二、属性

2.1 defaultAccount

2.2 defaultBlock

2.3 defaultHardfork

2.4 defaultChain

2.5 defaultCommon

2.6 transactionBlockTimeout

2.7 transactionConfirmationBlocks

2.8 transactionPollingTimeout

2.9 handleRevert

2.10 选项属性

2.11 options.address

2.12 options.jsonInterface

三、方法

3.1 clone

3.2 deploy

本文实例1:使用代码部署智能合约

3.3 methods

3.4 methods.myMethod.call

本文实例2:调用智能合约“常量”方法,不改变状态

3.5 methods.myMethod.send

本文实例3:调用智能合约方法,改变状态

3.6 methods.myMethod.estimateGas

本文实例4:估算智能合约方法gas用量

3.7 methods.myMethod.encodeABI

本文实例5:对智能合约方法进行 ABI 编码

四、事件

4.1 once

4.2 events

4.3 events.allEvents

4.4 getPastEvents

四、本文智能合约源码


web3.eth.Contract对象让你可以轻松地与以太坊区块链上的智能合约进行交互。 当你创建一个新的合约对象时,只需要指定相应的智能合约 json 接口, web3 就会自动将所有的调用转换为基于 RPC 的底层 ABI 调用。

这使得你可以像 JavaScript 对象一样与智能合约进行交互。


一、new contract

new web3.eth.Contract(jsonInterface[, address][, options])

创建新的合约实例,并在其json interface对象中定义所有的方法和事件。

参数

  • jsonInterface - Object: 所要实例化合约的 json 接口
  • address - String (可选): 要调用的智能合约地址
  • options - Object (可选): 合约配置选项。 其中某些选项被用作合约调用和交易的回调:
  1. from - String: 交易发送方地址
  2. gasPrice - String: 为交易指定的 gas 价格,以 wei 为单位
  3. gas - Number: 交易可用的最大 gas 量(gas limit)。
  4. data - String: 合约字节码。当合约被 :ref:`部署 <contract-deploy>`时需要使用。

返回值

Object: 带有所有方法和事件的合约实例

//官方示例
var myContract = new web3.eth.Contract([...], '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', {
    from: '0x1234567890123456789012345678901234567891', // 默认交易发送地址
    gasPrice: '20000000000' // 以 wei 为单位的默认 gas 价格,当前价格为 20 gwei
});

二、属性

2.1 defaultAccount

web3.eth.Contract.defaultAccount
contract.defaultAccount // 合约实例上的默认账户

如果下面这些方法没有指定 "from" 属性,默认账户地址就会被用作默认的 "from" 属性:

  • web3.eth.sendTransaction()
  • web3.eth.call()
  • new web3.eth.Contract() -> myContract.methods.myMethod().call()
  • new web3.eth.Contract() -> myContract.methods.myMethod().send()

属性

String - 20 字节: 任意以太坊地址。 你应该在你的节点或 keystore 中拥有该地址的私钥。 (默认值为 undefined)

例子

web3.eth.defaultAccount;
> undefined

// 设置默认账户
web3.eth.defaultAccount = '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe';

2.2 defaultBlock

web3.eth.Contract.defaultBlock
contract.defaultBlock // 在合约实例上

默认块在一些特定方法上使用。你可以通过传入 defaultBlock 作为最后一个参数来覆盖它。 默认值为 “latest”。

属性

默认块参数的可能取值如下:

  • Number|BN|BigNumber: 区块号
  • "genesis" - String: 创世块
  • "latest" - String: 最新块(也就是当前链头块)
  • "pending" - String: 正在挖的块(包括 pending 状态交易)
  • "earliest" - String: 创世块

默认值为 "latest"

例子

contract.defaultBlock;
> "latest"

// 设置默认块
contract.defaultBlock = 231;

2.3 defaultHardfork

contract.defaultHardfork

本地签名交易时用的默认硬分叉属性

属性

默认硬分叉属性的可能取值如下:

  • "chainstart" - String
  • "homestead" - String
  • "dao" - String
  • "tangerineWhistle" - String
  • "spuriousDragon" - String
  • "byzantium" - String
  • "constantinople" - String
  • "petersburg" - String
  • "istanbul" - String

默认值为 "petersburg"

例子

contract.defaultHardfork;
> "petersburg"

// 设置默认硬分叉
contract.defaultHardfork = 'istanbul';

2.4 defaultChain

contract.defaultChain

默认链属性是本地签名交易的时候用的

属性

默认链属性可以是一下列表中之一:

  • "mainnet" - String
  • "goerli" - String
  • "kovan" - String
  • "rinkeby" - String
  • "ropsten" - String

默认值为 "mainnet"

例子

contract.defaultChain;
> "mainnet"

// 设置默认链
contract.defaultChain = 'goerli';

2.5 defaultCommon

contract.defaultCommon

默认通用属性是本地签名交易的时候用的

属性

默认通用属性包含如下所示的 Common 对象:

  • customChain - Object: 自定义链属性
  1. name - string: (可选) 链名字
  2. networkId - number: 自定义链的网络 Id
  3. chainId - number: 自定义链的链 Id
  • baseChain - string: (可选) mainnetgoerlikovanrinkeby, or ropsten
  • hardfork - string: (可选) chainstarthomesteaddaotangerineWhistlespuriousDragonbyzantiumconstantinoplepetersburg, or istanbul

默认值为 undefined

例子

contract.defaultCommon;
> {customChain: {name: 'custom-network', chainId: 1, networkId: 1}, baseChain: 'mainnet', hardfork: 'petersburg'}

// 设置默认通用值
contract.defaultCommon = {customChain: {name: 'custom-network', chainId: 1, networkId: 1}, baseChain: 'mainnet', hardfork: 'petersburg'};

2.6 transactionBlockTimeout

web3.eth.Contract.transcationBlockTimeout
contract.transactionBlockTimeout // 在合约实例上

transactionBlockTimeout 会被用在基于套接字的连接上。该属性定义了直到第一次确认发生它应该等待的区块数。 这意味着当超时发生时,PromiEvent 会拒绝并显示超时错误。

返回值

  • number: transactionBlockTimeout 当前设定的值 (默认值: 50)

2.7 transactionConfirmationBlocks

web3.eth.Contract.transactionConfirmationBlocks
contract.transactionConfirmationBlocks // 在合约实例上

定义了确认交易所需要的区块确认数。

返回值

  • number: transactionConfirmationBlocks 当前设定的值 (默认值: 24)

2.8 transactionPollingTimeout

web3.eth.Contract.transactionPollingTimeout
contract.transactionPollingTimeout // 在合约实例上

transactionPollingTimeout 将通过 HTTP 连接使用。 这个选项定义了 Web3 等待确认交易被网络挖出的收据的秒数。注意:当此种超时发生时,交易可能仍未完成。

返回值

  • number: transactionPollingTimeout 当前设定的值 (默认值: 750)

2.9 handleRevert

web3.eth.Contract.handleRevert
contract.handleRevert // 在合约实例上

handleRevert`选项属性默认值为`false,如果在 :ref:`send <contract-send>`或者 :ref:`call <contract-call>`合约方法时启用,将返回回退原因字符串。

注解

回退原因字符串和签名是存在于返回错误的属性中的。

返回值

  • booleanhandleRevert 的当前值 (默认值: false)

2.10 选项属性

myContract.options

合约实例的选项属性 对象from、 gas 和 ``gasPrice``作为发送交易时的备用值使用。

属性

Object - 选项属性:

  • address - String: 合约的部署地址。 
  • jsonInterface - Array: 合同的 json 接口。
  • data - String: 合约字节码。 部署合约时使用。
  • from - String: 交易发起方地址。
  • gasPrice - String: 用于交易的 gas 价格。以 wei 为单位。
  • gas - Number: 可用于该交易的 gas 用量上限 (gas limit)。
  • handleRevert - Boolean: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • transactionBlockTimeout - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • transactionConfirmationBlocks - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • transactionPollingTimeout - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • chain - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • hardfork - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。 
  • common - Number: 如果这里不设置,将使用 Eth 模块提供的默认值。

例子

myContract.options;
> {
    address: '0x1234567890123456789012345678901234567891',
    jsonInterface: [...],
    from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
    gasPrice: '10000000000000',
    gas: 1000000
}

myContract.options.from = '0x1234567890123456789012345678901234567891'; // 默认交易发送方地址
myContract.options.gasPrice = '20000000000000'; // 默认 gas 价格,以 wei 为单位
myContract.options.gas = 5000000; // 5M gas 作为备用值

2.11 options.address

myContract.options.address

用于本合约实例的地址。 所有通过 web3.js 从这个合约生成的交易都将包含这个地址作为 “to” 地址(也就是交易接收方地址)。

地址将以小写的方式保存。

属性

  • address - String|null: 本合约的地址, 如果未设置其值为 null

例子

myContract.options.address;
> '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae'

// 设置新地址
myContract.options.address = '0x1234FFDD...';

2.12 options.jsonInterface

myContract.options.jsonInterface

从合约的ABI派生出来的json接口对象。

属性

  • jsonInterface - Array: 当前合约的json接口。重设该接口会导致合约实例方法和事件的重新生成。

例子

myContract.options.jsonInterface;
> [{
    "type":"function",
    "name":"foo",
    "inputs": [{"name":"a","type":"uint256"}],
    "outputs": [{"name":"b","type":"address"}]
},{
    "type":"event",
    "name":"Event",
    "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}],
}]

// 设置新的接口
myContract.options.jsonInterface = [...];

三、方法

3.1 clone

myContract.clone()

克隆当前合约实例。

例子

var contract1 = new eth.Contract(abi, address, {gasPrice: '12345678', from: fromAddress});

var contract2 = contract1.clone();
contract2.options.address = address2;

(contract1.options.address !== contract2.options.address);
> true

3.2 deploy

myContract.deploy(options)

调用此函数将合约部署到区块链上。 成功部署后 promise 对象会被解析为新的合约实例。

参数

  • options - Object: 用于合约部署的选项。

  1. data - String: 合约字节码
  2. arguments - Array (可选): 在部署合约时传递给构造函数的参数。

返回值

Object: 交易对象:

  • Array - 参数: 之前传递给方法的参数。它们是可以被改变的。
  • Function - send: 用来部署合约。promise 会被解析为合约实例而不是交易收据。
  • Function - estimateGas: 估算部署合约所需要的 gas 用量。
  • Function - encodeABI: 编码由合约数据和构造函数参数构成的合约部署 ABI。

关于这些方法的更多详情,参见下面的文档。

例子

myContract.deploy({
    data: '0x12345...',
    arguments: [123, 'My String']
})
.send({
    from: '0x1234567890123456789012345678901234567891',
    gas: 1500000,
    gasPrice: '30000000000000'
}, function(error, transactionHash){ ... })
.on('error', function(error){ ... })
.on('transactionHash', function(transactionHash){ ... })
.on('receipt', function(receipt){
   console.log(receipt.contractAddress) // 包含新合约地址
})
.on('confirmation', function(confirmationNumber, receipt){ ... })
.then(function(newContractInstance){
    console.log(newContractInstance.options.address) // 带有新合约地址的合约实例
});


//数据已经设置为合约本身的选项
myContract.options.data = '0x12345...';

myContract.deploy({
    arguments: [123, 'My String']
})
.send({
    from: '0x1234567890123456789012345678901234567891',
    gas: 1500000,
    gasPrice: '30000000000000'
})
.then(function(newContractInstance){
    console.log(newContractInstance.options.address) // 具有新合同地址的合约实例
});


// 只是编码
myContract.deploy({
    data: '0x12345...',
    arguments: [123, 'My String']
})
.encodeABI();
> '0x12345...0000012345678765432'


// gas 估算
myContract.deploy({
    data: '0x12345...',
    arguments: [123, 'My String']
})
.estimateGas(function(err, gas){
    console.log(gas);
});

本文实例1:使用代码部署智能合约

//本文示例,实际部署了一个erc20合约,用于本文测试
var Web3= require('web3');   
var web3= new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

var initialAmount = 1000000;               /* var of type uint256 here */ 
var tokenName =  "kongfuziToken";          /* var of type string here */
var decimalUnits =  18;                    /* var of type uint8 here */
var tokenSymbol =  "KFZT";                 /* var of type string here */

var tokentestContract =  new web3.eth.Contract([{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialAmount","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]);

var tokentest = tokentestContract.deploy({
     data: '0x60806040523480156200001157600080fd5b506040516200137338038062001373833981018060405281019080805190602001909291908051820192919060200180519060200190929190805182019291905050506200007a848360ff16600a0a620001c66401000000000262001042176401000000009004565b600081905550600054600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6000546040518082815260200191505060405180910390a382600190805190602001906200014692919062000208565b5081600260006101000a81548160ff021916908360ff16021790555080600390805190602001906200017a92919062000208565b5033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050620002b7565b6000806000841415620001dd576000915062000201565b8284029050828482811515620001ef57fe5b04141515620001fd57600080fd5b8091505b5092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200024b57805160ff19168380011785556200027c565b828001600101855582156200027c579182015b828111156200027b5782518255916020019190600101906200025e565b5b5090506200028b91906200028f565b5090565b620002b491905b80821115620002b057600081600090555060010162000296565b5090565b90565b6110ac80620002c76000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100b4578063095ea7b31461014457806318160ddd146101a957806323b872dd146101d4578063313ce5671461025957806341c0e1b51461028a57806370a08231146102a15780638da5cb5b146102f857806395d89b411461034f578063a9059cbb146103df578063dd62ed3e14610444575b600080fd5b3480156100c057600080fd5b506100c96104bb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101095780820151818401526020810190506100ee565b50505050905090810190601f1680156101365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015057600080fd5b5061018f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610559565b604051808215151515815260200191505060405180910390f35b3480156101b557600080fd5b506101be61064b565b6040518082815260200191505060405180910390f35b3480156101e057600080fd5b5061023f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610651565b604051808215151515815260200191505060405180910390f35b34801561026557600080fd5b5061026e610acf565b604051808260ff1660ff16815260200191505060405180910390f35b34801561029657600080fd5b5061029f610ae2565b005b3480156102ad57600080fd5b506102e2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610b79565b6040518082815260200191505060405180910390f35b34801561030457600080fd5b5061030d610bc2565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561035b57600080fd5b50610364610be8565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103a4578082015181840152602081019050610389565b50505050905090810190601f1680156103d15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103eb57600080fd5b5061042a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c86565b604051808215151515815260200191505060405180910390f35b34801561045057600080fd5b506104a5600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f72565b6040518082815260200191505060405180910390f35b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105515780601f1061052657610100808354040283529160200191610551565b820191906000526020600020905b81548152906001019060200180831161053457829003601f168201915b505050505081565b600081600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561068e57600080fd5b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156106c957600080fd5b600082101515156106d957600080fd5b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561072757600080fd5b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156107b257600080fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054011015151561084157600080fd5b61088a600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483610ff9565b600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610916600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483611015565b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506109df600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483610ff9565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b600260009054906101000a900460ff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610b3e57600080fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60038054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610c7e5780601f10610c5357610100808354040283529160200191610c7e565b820191906000526020600020905b815481529060010190602001808311610c6157829003601f168201915b505050505081565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610cc357600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610cfe57600080fd5b60008210151515610d0e57600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610d5c57600080fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540110151515610deb57600080fd5b610e34600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483610ff9565b600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ec0600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483611015565b600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600082821115151561100a57600080fd5b818303905092915050565b600080828401905083811015801561102d5750828110155b151561103857600080fd5b8091505092915050565b60008060008414156110575760009150611079565b828402905082848281151561106857fe5b0414151561107557600080fd5b8091505b50929150505600a165627a7a72305820360d57956695d80a16337257760d883f19b65df7ef14137b17cbc8d21f722ef20029', 
     arguments: [initialAmount, tokenName, decimalUnits, tokenSymbol]
})
   .send({
     from: "0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568", 
     gas: '5700000'
   }, function(error, transactionHash){
	 console.log(error, transactionHash)
   })
   .on('receipt', function(receipt){
     console.log("receipt.contractAddress :" + receipt.contractAddress); // 包含新合约地址
     console.log(receipt)
   })
   .then(function(newContractInstance){
     console.log("newContractInstance.options.address :" + newContractInstance.options.address) // 带有新合约地址的合约实例
   });

/*
null '0xa63dd8dc8b3b1de2f7e1276a92dc71665684660b3f97d2d6a299659de2f88b6f'
receipt.contractAddress :0xb43938511C10A242dce4f5C110c54fBB51f5bd28
{ blockHash:
   '0x7f8d2898026aa7a0665f6460becc930c1a2afc55e5b323b5013c114eb3a6c14d',
  blockNumber: 278509,
  contractAddress: '0xb43938511C10A242dce4f5C110c54fBB51f5bd28',
  cumulativeGasUsed: 1114009,
  from: '0x38d8b866a1abebca20afc004622f5355eefeb568',
  gasUsed: 1114009,
  logsBloom:
   '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000200000042000000000000000000000000000000000000000000000000000420000010000000000000000000000000000000000000000000000000000000000000',
  status: true,
  to: null,
  transactionHash:
   '0xa63dd8dc8b3b1de2f7e1276a92dc71665684660b3f97d2d6a299659de2f88b6f',
  transactionIndex: 0,
  events:
   { Transfer:
      { address: '0xb43938511C10A242dce4f5C110c54fBB51f5bd28',
        blockNumber: 278509,
        transactionHash:
         '0xa63dd8dc8b3b1de2f7e1276a92dc71665684660b3f97d2d6a299659de2f88b6f',
        transactionIndex: 0,
        blockHash:
         '0x7f8d2898026aa7a0665f6460becc930c1a2afc55e5b323b5013c114eb3a6c14d',
        logIndex: 0,
        removed: false,
        id: 'log_d01b6181',
        returnValues: [Result],
        event: 'Transfer',
        signature:
         '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        raw: [Object] } } }
newContractInstance.options.address :0xb43938511C10A242dce4f5C110c54fBB51f5bd28
*/

注意:

不同版本web3.js带来的API变化问题。请检查你的web3.js版本:

如果version<1.0.0,使用:

new web3.eth.contract(studentFactoryArtifact,address);     // 注意区分contract大小写

如果version>1.0.0,使用:

new web3.eth.Contract(studentFactoryArtifact,address);     // 注意区分Contract大小写

3.3 methods

myContract.methods.myMethod([param1[, param2[, ...]]])

为指定方法创建一个交易对象, 可以被用来 calledsend, estimated.

该智能合约的方法可以通过下面几种方式得到:

  • 方法名: myContract.methods.myMethod(123)
  • 带参数的方法名: myContract.methods['myMethod(uint256)'](123)
  • 方法签名: myContract.methods['0x58cf5f10'](123)

这样可以调用与 JavaScript 合约对象名称相同但参数不同的函数。

返回值

Object: 交易对象:

  • Array - 参数: 之前传递给方法的参数。它们是可以被改变的。
  • Function - call: 将在不发送交易的情况下调用该“常量”方法并在 EVM 中执行其智能合约方法(无法更改智能合约状态)。
  • Function - send: 用来向合约发送交易并执行其方法(可以更改智能合约状态)。
  • Function - estimateGas: 将估算在链上执行该方法时所要消耗的 gas。
  • Function - encodeABI: 对合于方法进行 ABI 编码。得到的编码可以通过交易去 send,可以直接 call,也可以作为参数传给另外一个智能合约方法。

关于这些方法的更多详情,参见下面的文档。

例子

// 对一个方法发起 call 调用

myContract.methods.myMethod(123).call({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}, function(error, result){
    ...
});

// 或者发生交易并使用 promise
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(receipt){
    // receipt can also be a new contract instance, when coming from a "contract.deploy({...}).send()"
});

// 或者发送交易并使用事件
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.on('transactionHash', function(hash){
    ...
})
.on('receipt', function(receipt){
    ...
})
.on('confirmation', function(confirmationNumber, receipt){
    ...
})
.on('error', function(error, receipt) {
    ...
});

3.4 methods.myMethod.call

myContract.methods.myMethod([param1[, param2[, ...]]]).call(options[, callback])

将在不发送交易的情况下调用该“常量”方法并在 EVM 中执行其智能合约方法。注意此种调用方式无法改变智能合约状态。

参数

  • options - Object (可选): 用于发起调用的选项。
  1. from - String (可选): 调用“交易”的发起方地址。
  2. gasPrice - String (可选): 用于该调用“交易”的 gas 价格。以 wei 为计量单位。
  3. gas - Number (可选): 用于该调用“交易”的 gas 用量上限 (gas limit)。
  • callback - Function (可选): 回调函数,回调时将以智能合约方法执行结果作为第二个参数,以错误对象作为第一个参数。

返回值

  • Promise 返回 Mixed: 智能合约方法返回值。 如果只返回一个值,则按原样返回。如果有多个返回值,则作为一个带有属性和索引的对象返回。

例子

// 使用回调
myContract.methods.myMethod(123).call({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}, function(error, result){
    ...
});

// 使用 promise
myContract.methods.myMethod(123).call({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(result){
    ...
});


// 多返回值:

// Solidity
contract MyContract {
    function myFunction() returns(uint256 myNumber, string myString) {
        return (23456, "Hello!%");
    }
}

// web3.js
var MyContract = new web3.eth.Contract(abi, address);
MyContract.methods.myFunction().call()
.then(console.log);
> Result {
    myNumber: '23456',
    myString: 'Hello!%',
    0: '23456', // 这里这些是作为属性名称时的备用值
    1: 'Hello!%'
}


// 单参数返回:

// Solidity
contract MyContract {
    function myFunction() returns(string myString) {
        return "Hello!%";
    }
}

// web3.js
var MyContract = new web3.eth.Contract(abi, address);
MyContract.methods.myFunction().call()
.then(console.log);
> "Hello!%"

本文实例2:调用智能合约“常量”方法,不改变状态

var Web3= require('web3');   
var web3= new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

var contractAddress = "0xb43938511C10A242dce4f5C110c54fBB51f5bd28";   //智能合约地址
var accountsAddress = "0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568";
var contractAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialAmount","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
var myContract =  new web3.eth.Contract(contractAbi,contractAddress);

	
    myContract.methods.totalSupply().call().then(function(result){
        console.log("totalSupply:",result);
    });
	
    myContract.methods.name().call().then(function(result){
        console.log("name:",result);
    });
	
    myContract.methods.decimals().call().then(function(result){
        console.log("decimals:",result);
    });
	
    myContract.methods.symbol().call().then(function(result){
        console.log("symbol:",result);
    });
	
    myContract.methods.owner().call().then(function(result){
        console.log("owner:",result);
    });
	
    myContract.methods.balanceOf(accountsAddress).call().then(function(result){
        console.log("result1:",result);
        console.log("result2:",JSON.stringify(result));
    });

/*
totalSupply: 1000000000000000000000000
decimals: 18
name: kongfuziToken
symbol: KFZT
owner: 0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568
result1: 1000000000000000000000000
result2: "1000000000000000000000000"
*/

3.5 methods.myMethod.send

myContract.methods.myMethod([param1[, param2[, ...]]]).send(options[, callback])

向合约发送交易来执行其方法。注意这会改变合约状态。

参数

  • options - Object: 用来发送交易的选项。
  1. from - String: 交易发送方地址。
  2. gasPrice - String (可选): 用于该交易的 gas 价格,以 wei 为单位。
  3. gas - Number (可选): 该交易 gas 用量上限 (gas limit)。
  4. value - ``Number|String|BN|BigNumber``(可选): 交易转账金额,以 wei 为单位。
  • callback - Function (可选): 回调函数,触发时其第二个参数为交易哈希,第一个参数为错误对象。

返回值

回调 将返回 32 字节的交易哈希值。

PromiEvent: 一个 整合了事件发生器 <promiEvent> promise. 当收到交易*收据*时会被解析, 当该``send()``调用是从``someContract.deploy()``发出时,promise 会解析为*新合约地址*。重设该接口会导致合约实例方法和事件的重新生成。 此外也存在下面这些事件:

  • "transactionHash" 返回 String: 发送交易且得到交易哈希值后立即触发。
  • "receipt" 返回 Object: 当收到交易*收据*时触发。合约收据带有的不是``logs``,而是以事件名称为健,以事件本身为属性值的``events``。 关于返回事件对象的详情,参见 getPastEvents 返回值 。
  • "confirmation" 返回 NumberObject: 从区块被挖到的第一个区块确认开始,每次确认都会触发,直到第 24 次确认。触发时第一个参数为收到的确认数,第二个参数为收到交易收据。
  • "error" 返回 Error 和 Object|undefined: 交易发送过程中出错时触发。如果交易被网络拒绝且带有交易收据,第二个参数就是该交易收据。

例子

// 使用回调
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}, function(error, transactionHash){
    ...
});

// 使用 promise
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(receipt){
    // 当这个 receipt 对象来自于 "contract.deploy({...}).send()" 这么个调用时,它也可以是一个新合约实例
});


// 使用事件触发器
myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.on('transactionHash', function(hash){
    ...
})
.on('confirmation', function(confirmationNumber, receipt){
    ...
})
.on('receipt', function(receipt){
    // receipt 相关例子
    console.log(receipt);
    > {
        "transactionHash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
        "transactionIndex": 0,
        "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
        "blockNumber": 3,
        "contractAddress": "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
        "cumulativeGasUsed": 314159,
        "gasUsed": 30234,
        "events": {
            "MyEvent": {
                returnValues: {
                    myIndexedParam: 20,
                    myOtherIndexedParam: '0x123456789...',
                    myNonIndexParam: 'My String'
                },
                raw: {
                    data: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
                    topics: ['0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7', '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385']
                },
                event: 'MyEvent',
                signature: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
                logIndex: 0,
                transactionIndex: 0,
                transactionHash: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
                blockHash: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
                blockNumber: 1234,
                address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
            },
            "MyOtherEvent": {
                ...
            },
            "MyMultipleEvent":[{...}, {...}] // 如果同一事件有多个,则它们将被组装到数组中
        }
    }
})
.on('error', function(error, receipt) { // 如果交易被网络拒绝并带有交易收据,则第二个参数将是交易收据。
    ...
});

本文实例3:调用智能合约方法,改变状态

var Web3= require('web3');   
var web3= new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

var contractAddress = "0xb43938511C10A242dce4f5C110c54fBB51f5bd28";   //智能合约地址
var accountsAddress = "0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568";
var contractAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialAmount","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
var myContract =  new web3.eth.Contract(contractAbi,contractAddress);
	
    // 使用promise
    // personal.unlockAccount(eth.accounts[1],password,0)
    var toAddress = "0xDa25997b15a6BeA86116942B8Ab69a5620D82284";
    myContract.methods.transfer(toAddress,1230000000000).send({from: accountsAddress})
    .then(function(receipt){
		console.log("receipt:",receipt);
    });

/*
receipt: { blockHash:
   '0xbec129bb90df90619a19a064826d7baab7d84fd2f4c58a7a767d2e858c5b0c15',
  blockNumber: 301107,
  contractAddress: null,
  cumulativeGasUsed: 54019,
  from: '0x38d8b866a1abebca20afc004622f5355eefeb568',
  gasUsed: 54019,
  logsBloom:
   '0x00000000000000000010000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000200000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000200000042000000000000000000000000000000000000000000000000000400000010000000000000000000000000000000000000000000000000000000000000',
  status: true,
  to: '0xb43938511c10a242dce4f5c110c54fbb51f5bd28',
  transactionHash:
   '0x5f8850cbc8c21b7b10917777a4c9ebd5cbb0a2e5370d108edb767d0ca44576f1',
  transactionIndex: 0,
  events:
   { Transfer:
      { address: '0xb43938511C10A242dce4f5C110c54fBB51f5bd28',
        blockNumber: 301107,
        transactionHash:
         '0x5f8850cbc8c21b7b10917777a4c9ebd5cbb0a2e5370d108edb767d0ca44576f1',
        transactionIndex: 0,
        blockHash:
         '0xbec129bb90df90619a19a064826d7baab7d84fd2f4c58a7a767d2e858c5b0c15',
        logIndex: 0,
        removed: false,
        id: 'log_d82a25b4',
        returnValues: [Result],
        event: 'Transfer',
        signature:
         '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        raw: [Object] } } }
*/

3.6 methods.myMethod.estimateGas

myContract.methods.myMethod([param1[, param2[, ...]]]).estimateGas(options[, callback])

通过在 EVM 中执行方法来估算链上执行是需要的 gas 用量。 由于彼时合约状态的不同,当前估算的 gas 用量和随后通过真实交易所得到的实际 gas 用量可能会有所出入。

参数

  • options - Object (可选): 用于调用的选项。

  1. from - String (可选): 交易发起方地址。
  2. gas - Number (可选): 交易 gas 用量上限 (gas limit)。设置特定的值有助于检测 gas 耗尽相关错误,gas 耗尽时会返回相同的值。
  3. value - ``Number|String|BN|BigNumber``(可选): 交易转账金额,以 wei 为单位。
  • callback - Function (可选): 回调函数,触发时其第二个参数为 gas 估算量,第一个参数为错误对象。

返回值

  • Promise 返回 Number: 估算的 gas 用量

例子

// 使用回调
myContract.methods.myMethod(123).estimateGas({gas: 5000000}, function(error, gasAmount){
    if(gasAmount == 5000000)
        console.log('Method ran out of gas');
});

// 使用 promise
myContract.methods.myMethod(123).estimateGas({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(gasAmount){
    ...
})
.catch(function(error){
    ...
});

本文实例4:估算智能合约方法gas用量

var Web3= require('web3');   
var web3= new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

var contractAddress = "0xb43938511C10A242dce4f5C110c54fBB51f5bd28";   //智能合约地址
var accountsAddress = "0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568";
var contractAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialAmount","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
var myContract =  new web3.eth.Contract(contractAbi,contractAddress);
var toAddress = "0xDa25997b15a6BeA86116942B8Ab69a5620D82284";

    // 使用 promise
    // personal.unlockAccount(eth.accounts[1],password,0)
    myContract.methods.transfer(toAddress,1230000000000).estimateGas({from: accountsAddress})
    .then(function(gasAmount){
	console.log("gasAmount:",gasAmount);
    })
    .catch(function(error){
	console.log("error:",error);
    });

/*
gasAmount: 39019
*/

3.7 methods.myMethod.encodeABI

myContract.methods.myMethod([param1[, param2[, ...]]]).encodeABI()

为指定的合约方法进行 ABI 编码,可用于发送交易、调用方法或向另一个合约方法传递参数。

返回值

  • String: 编码后的 ABI 字节码,可用于交易发送或方法调用。

例子

myContract.methods.myMethod(123).encodeABI();
> '0x58cf5f1000000000000000000000000000000000000000000000000000000000000007B'

本文实例5:对智能合约方法进行 ABI 编码

var Web3= require('web3');   
var web3= new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

var contractAddress = "0xb43938511C10A242dce4f5C110c54fBB51f5bd28";   //智能合约地址
var accountsAddress = "0x38D8B866a1ABeBcA20AFC004622F5355EeFEB568";
var contractAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialAmount","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
var myContract =  new web3.eth.Contract(contractAbi,contractAddress);
var toAddress = "0xDa25997b15a6BeA86116942B8Ab69a5620D82284";

    console.log(myContract.methods.transfer(toAddress,1230000000000).encodeABI());

/*
0xa9059cbb000000000000000000000000da25997b15a6bea86116942b8ab69a5620d822840000000000000000000000000000000000000000000000000000011e61b68c00
*/

四、事件

4.1 once

myContract.once(event[, options], callback)

订阅一个事件并在第一次事件触发或错误发生后立即取消订阅。一个事件仅触发一次。

参数

  • event - String: 要订阅的合约事件名, 或者用 "allEvents" 来订阅所有事件。
  • options - Object (可选): 用于部署的选项。
  1. filter - Object (可选): 按索引参数过滤事件, 例如 {filter: {myNumber: [12,13]}} 表示 “myNumber” 为 12 或 13 的所有事件。
  2. topics - Array (可选): 手动设置事件过滤器的主题。如果提供了过滤器属性和事件签名,则不会自动设置(topic [0])
  • callback - Function: 回调函数,触发时把*事件*对象作为第二个参数,错误作为第一个参数。 关于详细事件结构,参见 getPastEvents 返回值 。

例子

myContract.once('MyEvent', {
    filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // 使用数组表示 或:比如 20 或 23。
    fromBlock: 0
}, function(error, event){ console.log(event); });

// 事件输入的例子
> {
    returnValues: {
        myIndexedParam: 20,
        myOtherIndexedParam: '0x123456789...',
        myNonIndexParam: 'My String'
    },
    raw: {
        data: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
        topics: ['0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7', '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385']
    },
    event: 'MyEvent',
    signature: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    logIndex: 0,
    transactionIndex: 0,
    transactionHash: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
    blockHash: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    blockNumber: 1234,
    address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
}

4.2 events

myContract.events.MyEvent([options][, callback])

订阅指定的合约事件

参数

  • options - Object (可选): 用于部署的选项。
  1. filter - Object (可选): 按索引参数过滤事件, 例如 {filter: {myNumber: [12,13]}} 表示 “myNumber” 为 12 或 13 的所有事件。
  2. fromBlock - Number|String|BN|BigNumber (可选): 读取从该编号开始的区块中的事件(大于或等于该区块号)。 也可以使用预先定义的区块号,比如 "latest""earlist""pending""genesis" 等。
  3. topics - Array (可选): 手动设置事件过滤器的主题。如果提供了过滤器属性和事件签名,则不会自动设置(topic [0])。
  • callback - Function (可选): 回调函数,触发时把*事件*对象作为第二个参数,错误作为第一个参数。

返回值

EventEmitter: 该事件发生器有以下事件:

  • "data" 返回 Object: 接收到新传入的事件时触发,参数为事件对象。
  • "changed" 返回 Object: 当事件从区块链上移除时触发。 该事件带有额外属性 "removed: true"
  • "error" 返回 Object: 当订阅中出现错误时触发。
  • "connected" 返回 String: 当订阅成功连接时触发一次。返回订阅 id。

返回的事件 “对象” 结构如下:

  • event - String: 事件名称。
  • signature - String|Null: 事件签名,如果是匿名事件,其值为 null
  • address - String: 该事件的发源地地址。
  • returnValues - Object: 事件返回值, 比如 {myVar: 1, myVar2: '0x234...'}.
  • logIndex - Number: 事件在区块中的索引位置。
  • transactionIndex - Number: 事件所在交易在区块中的索引位置。
  • transactionHash 32 Bytes - String: 事件所在交易的哈希值。
  • blockHash 32 Bytes - String: 事件所在区块链的哈希值。区块处于 pending 状态时其值为 null 。
  • blockNumber - Number: 事件所在区块的区块号。 区块处于 pending 状态时其值为 null 。
  • raw.data - String: 包含未索引的日志参数。
  • raw.topics - Array: 最大可保存 4 个 32 字节长的主题数组,主题 1-3 包含事件的索引参数。

例子

myContract.events.MyEvent({
    filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // 使用数组表示 或:如 20 或 23。
    fromBlock: 0
}, function(error, event){ console.log(event); })
.on("connected", function(subscriptionId){
    console.log(subscriptionId);
})
.on('data', function(event){
    console.log(event); // 与上述可选的回调结果相同
})
.on('changed', function(event){
    // 从本地数据库中删除事件
})
.on('error', function(error, receipt) { // 如果交易被网络拒绝并带有交易收据,第二个参数将是交易收据。
    ...
});

// 事件输出例子
> {
    returnValues: {
        myIndexedParam: 20,
        myOtherIndexedParam: '0x123456789...',
        myNonIndexParam: 'My String'
    },
    raw: {
        data: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
        topics: ['0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7', '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385']
    },
    event: 'MyEvent',
    signature: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    logIndex: 0,
    transactionIndex: 0,
    transactionHash: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
    blockHash: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    blockNumber: 1234,
    address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
}

4.3 events.allEvents

myContract.events.allEvents([options][, callback])

和 事件 相同,只是会接收合约的所有事件。 过滤属性可以选择性地过滤这些事件。


4.4 getPastEvents

myContract.getPastEvents(event[, options][, callback])

读取合约历史事件。

参数

  • event - String: 合约事件名,或者用 "allEvents" 读取所有事件。
  • options - Object (可选): 用于部署的选项。
  1. filter - Object (可选): 按索引参数过滤事件, 例如 {filter: {myNumber: [12,13]}} 表示 “myNumber” 为 12 或 13 的所有事件。
  2. fromBlock - Number|String|BN|BigNumber (可选): 读取从该编号开始的区块中的历史事件(大于或等于该区块号)。 也可以使用预先定义的区块编号,比如 "latest""earlist""pending""genesis" 。
  3. toBlock - Number|String|BN|BigNumber (可选): 读取截止到该编号的区块中的历史事件(小于或等于该区块号)(默认值为 “latest”)。 也可以使用预先定义的区块编号,比如 "latest""earlist""pending""genesis" 。
  4. topics - Array (可选): 用来手动设置事件过滤器的主题。如果设置了 filter 属性和事件签名,则不会自动设置(topic [0])。
  • callback - Function (可选): 回调函数,触发时其第一个参数为错误对象,第二个参数为历史事件日志数组。

返回值

  • Promise 返回 Array: 满足给定事件或过滤条件的历史事件对象数组。
  • 对于返回的事件对象结构,参见 getPastEvents 返回值

例子

myContract.getPastEvents('MyEvent', {
    filter: {myIndexedParam: [20,23], myOtherIndexedParam: '0x123456789...'}, // 使用数组表示 或:如 20 或 23。
    fromBlock: 0,
    toBlock: 'latest'
}, function(error, events){ console.log(events); })
.then(function(events){
    console.log(events) // 与上述可选回调结果相同
});

> [{
    returnValues: {
        myIndexedParam: 20,
        myOtherIndexedParam: '0x123456789...',
        myNonIndexParam: 'My String'
    },
    raw: {
        data: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
        topics: ['0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7', '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385']
    },
    event: 'MyEvent',
    signature: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    logIndex: 0,
    transactionIndex: 0,
    transactionHash: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
    blockHash: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
    blockNumber: 1234,
    address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
},{
    ...
}]

四、本文智能合约源码

请注意:本合约仅用于测试。

pragma solidity ^0.4.18;

/**
 * Math operations with safety checks
 */
contract SafeMath {
    function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    require(c / a == b);
    return c;
    }
 
    function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b > 0);
    uint256 c = a / b;
    require(a == b * c + a % b);
    return c;
    }
 
    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a);
    return a - b;
    }
 
    function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c>=a && c>=b);
    return c;
    } 
}

contract Token is SafeMath{

    function balanceOf(address _owner) public constant returns (uint256 balance);
	
    function transfer(address _to, uint256 _value) public returns (bool success);
	
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

    function approve(address _spender, uint256 _value) public returns (bool success);

    function allowance(address _owner, address _spender) public constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
	
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract TokenTEST is Token {
    uint256 public totalSupply;				
    string  public name;                   	
    uint8   public decimals;               
    string  public symbol;               	
    address public owner;                   
	
    /* This creates an array with all balances */
    mapping (address => uint256) balances;
    mapping (address => mapping (address => uint256)) allowed;

    function TokenTEST(uint256 initialAmount, string tokenName, uint8 decimalUnits, string tokenSymbol) public {
        totalSupply = SafeMath.safeMul(initialAmount , 10 ** uint256(decimalUnits));  
        balances[msg.sender] = totalSupply; 						
        Transfer(address(0), msg.sender, totalSupply);                         
		 
        name = tokenName;                   
        decimals = decimalUnits;          
        symbol = tokenSymbol;
        owner = msg.sender;
    }

    /* Send tokens */
    function transfer(address _to, uint256 _value) public returns (bool success) {
    	require(_to != address(0));
    	require(_to != msg.sender);
    	require(_value >= 0);
    	require(balances[msg.sender] >= _value);
    	require(balances[_to] + _value >= balances[_to]);
        
        balances[msg.sender] = SafeMath.safeSub(balances[msg.sender], _value);   // Subtract from the sender
        balances[_to] = SafeMath.safeAdd(balances[_to], _value);                 
        Transfer(msg.sender, _to, _value);		                                 
        return true;
    }

    /* A contract attempts to get the tokens */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_to != address(0));
        require(_to != _from);
        require(_value >= 0);
        require(_value <= balances[_from]);                  // Check if the sender has enough
        require(_value <= allowed[_from][msg.sender]);       // Check allowance
        require(balances[_to] + _value >= balances[_to]);    // Check for overflows
		
        balances[_from] = SafeMath.safeSub(balances[_from], _value);                           // Subtract from the sender
        balances[_to] = SafeMath.safeAdd(balances[_to], _value);    // Add the same to the recipient
        allowed[_from][msg.sender] = SafeMath.safeSub(allowed[_from][msg.sender], _value);
        Transfer(_from, _to, _value);			             
        return true;
    }
	
    function balanceOf(address _owner) public constant returns (uint256 balance) {
        return balances[_owner];
    }

    /* Allow another contract to spend some tokens in your behalf */	
    function approve(address _spender, uint256 _value) public returns (bool success) { 
        //require((_value == 0) || (allowed[msg.sender][_spender] == 0)); 
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
        return allowed[_owner][_spender];		
    }
	
    // only owner can kill
    function kill() { 
        require(msg.sender == owner);
        selfdestruct(owner);             
    }

}

猜你喜欢

转载自blog.csdn.net/wonderBlock/article/details/106842029