合约抽象封装

TronBox 提供了一个合约抽象层,用来与合约进行交互。跳到 API 部分以获取合约方法列表。

使用方法

要获取合约抽象实例,可以使用 artifacts 对象的 require() 方法来载入指定的合约构件。在控制台环境外,artifacts 在迁移文件和测试文件中也是有效的。可用如下方式创建指定合约的抽象对象:

const MyContract = artifacts.require('MyContract');

在开发控制台中也可以获取到合约抽象实例。在开发控制台可以使用 at, deployednew 方法获取到合约抽象实例:

tronbox(development) > MyContract.deployed().then(myContract => console.log(myContract));

你现在可以访问 MyContract 的以下函数以及许多其他函数:

  • at():创建一个部署在指定地址的 MyContract 合约抽象实例。
  • deployed():创建一个由 MyContract 管理的默认地址的 MyContract 合约抽象实例。
  • new():向链上部署一个新版本合约,并获取新合约对应的 MyContract 合约抽象实例。

每个合约抽象实例都绑定到 Tron 网络上的特定地址,并且 Javascript 实例的函数与合约函数是一一对应的。例如,如果你的 Solidity 合约有一个函数 someFunction(uint value) {} (solidity),那么你可以像这样在网络上执行该函数:

let deployed;
MyContract.deployed()
  .then(instance => {
    deployed = instance;
    return deployed.someFunction(5);
  })
  .then(result => {
    // Do something with the result or continue with more transactions.
  });

你也可以使用 async/await 语法。我们将在本文档的其余部分使用 async/await,但你也可以使用 Promise 来与合约方法交互。

const deployed = await MyContract.deployed();
const result = await deployed.someFunction(5);
// Do something with the result or continue with more transactions.

API

你需要注意两种 API。一种是静态合约抽象 API,另一种是合约实例 API。抽象 API 是所有合约抽象实例都存在的一组函数,这些函数存在于抽象本身(例如:MyContract.at())上。相比之下,实例 API 是可用于合约实例的 API ——即代表区块链上特定合约的抽象——并且该 API 是根据 Solidity 源文件中可用的函数动态创建的。

合约抽象 API

每个合约抽象—— MyContract 在上面的例子中——都有以下有用的功能:

MyContract.new([arg1, arg2, ...], [tx params])

此函数采用你的合约所需的任何构造函数参数,并将合约的新实例部署到网络。有一个可选的最后一个参数,你可以使用它来传递交易参数,包括 feeLimit,userFeePercentage 和 callValue。该函数返回一个 Promise 对象,它是新部署的合约抽象的新实例。

MyContract.at(address)

此函数通过传入地址创建一个新的合约抽象实例。在确保合约代码存在于指定地址后解析为合约抽象实例。

   警告:该方法将在未来支持。

MyContract.deployed()

返回由项目内部保存的合约部署地址创建的合约抽象实例。

MyContract.link(instance)

将一个由合约抽象实例的库链接到 MyContract。该库必须首先被部署并设置其部署地址。名称和部署地址将从合约抽象实例中推断出来。

库可以被多次链接,并将覆盖其先前的链接。

注意:这种方法还有两种形式,但推荐使用这种形式。

MyContract.link(name, address)

将特定名称和地址的库链接到 MyContract

MyContract.link(object)

通过一个对象将多个库链接到 MyContract。键必须是代表库名的字符串,值必须是代表地址的字符串。

MyContract.setNetwork(network_id)

设置 MyContract 当前使用的网络 ID。

MyContract.hasNetwork(network_id)

返回一个布尔值,表示该合约是否被部署在一个特定的网络中。

MyContract.defaults([new_defaults])

获取并选择性地设置从该合约抽象对象创建的所有实例的交易默认值。如果调用时没有任何参数,它将简单地返回一个代表当前默认值的对象。如果传递一个对象,这将设置新的默认值。可以设置的默认交易值的例子是:

MyContract.defaults({
  feeLimit: ...,
  callValue: ...,
  tokenValue: ...,
  tokenId: ...,
  userFeePercentage: ...,
  originEnergyLimit: ...
})

MyContract.clone(network_id)

克隆一个相同合约抽象的对象,但使用不同的 network_id。如果你想管理相同的合约,但在不同的网络上,这很有用。当使用这个函数时,不要忘记使用正确的网络。

const MyOtherContract = MyContract.clone(3);

合约实例 API

每个合约实例都是基于源 Solidity 合约的不同而动态创建 API。为了本文档的目的,让我们使用下面的 Solidity 源代码。

contract MyContract {
  uint public value;
  event ValueSet(uint val);
  function setValue(uint val) {
    value = val;
    emit ValueSet(value);
  }
  function getValue() constant returns (uint) {
    return value;
  }
}

从 Javascript 的角度来看,该合约具有三个功能 setValuegetValuevalue。 因为 value 是公开的所以会自动创建一个函数。

通过合约函数进行交易

当我们调用 setValue() 会创建一个交易。来自 Javascript:

const tx = await instance.setValue(5);

调用合约

然而,我们可以调用 getValue(),并用 .call() 来获取数值。调用总是免费的,不需要花费任何 TRX,所以它们适合于调用从区块链上读取数据的函数。

const value = await instance.getValue.call();
// value reprsents the `value` storage object in the solidity contract
// since the contract returns that value.

更有帮助的是,当函数被标记为 constant 时,我们甚至不需要使用 .call,因为 tronbox-contract 会自动知道该函数只能通过调用进行交互。

const value = await instance.getValue();
// val reprsents the `value` storage object in the solidity contract
// since the contract returns that value.