部署和调用

智能合约的部署

部署合约其实是创建了一个CreateSmartContract类型的交易,可以通过fullnode api wallet/deploycontract来创建交易,创建完成后,再进行交易的签名和广播:

curl --request POST \
     --url https://api.shasta.trongrid.io/wallet/deploycontract \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --data '
{
     "owner_address": "41D1E7A6BC354106CB410E65FF8B181C600FF14292",
     "abi": "[{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"uint256\"},{\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"value\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]",
     "bytecode": "608060405234801561001057600080fd5b5060de8061001f6000396000f30060806040526004361060485763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631ab06ee58114604d5780639507d39a146067575b600080fd5b348015605857600080fd5b506065600435602435608e565b005b348015607257600080fd5b50607c60043560a0565b60408051918252519081900360200190f35b60009182526020829052604090912055565b600090815260208190526040902054905600a165627a7a72305820fdfe832221d60dd582b4526afa20518b98c2e1cb0054653053a844cf265b25040029",
     "fee_limit": 1000000,
     "origin_energy_limit": 100000,
     "name": "SomeContract",
     "call_value": 0,
     "consume_user_resource_percent": 100
}
'

返回的结果为:

{
  "visible": false,
  "txID": "e4eb4df3a64a33565059ee3cef29b93b79f58ece9e7e8153fda3bbfe40fb0524",
  "contract_address": "416c5d359d1836085cdad65788e1ce53d3d7a13dd6",
  "raw_data": {
    "contract": [
      {
        "parameter": {
          "value": {
            "owner_address": "41d1e7a6bc354106cb410e65ff8b181c600ff14292",
            "new_contract": {
              "bytecode": "608060405234801561001057600080fd5b5060de8061001f6000396000f30060806040526004361060485763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631ab06ee58114604d5780639507d39a146067575b600080fd5b348015605857600080fd5b506065600435602435608e565b005b348015607257600080fd5b50607c60043560a0565b60408051918252519081900360200190f35b60009182526020829052604090912055565b600090815260208190526040902054905600a165627a7a72305820fdfe832221d60dd582b4526afa20518b98c2e1cb0054653053a844cf265b25040029",
              "consume_user_resource_percent": 100,
              "name": "SomeContract",
              "origin_address": "41d1e7a6bc354106cb410e65ff8b181c600ff14292",
              "abi": {
                "entrys": [
                  {
                    "inputs": [
                      {
                        "name": "key",
                        "type": "uint256"
                      },
                      {
                        "name": "value",
                        "type": "uint256"
                      }
                    ],
                    "name": "set",
                    "stateMutability": "Nonpayable",
                    "type": "Function"
                  },
                  {
                    "outputs": [
                      {
                        "name": "value",
                        "type": "uint256"
                      }
                    ],
                    "constant": true,
                    "inputs": [
                      {
                        "name": "key",
                        "type": "uint256"
                      }
                    ],
                    "name": "get",
                    "stateMutability": "View",
                    "type": "Function"
                  }
                ]
              },
              "origin_energy_limit": 100000
            }
          },
          "type_url": "type.googleapis.com/protocol.CreateSmartContract"
        },
        "type": "CreateSmartContract"
      }
    ],
    "ref_block_bytes": "0a49",
    "ref_block_hash": "975853d6629c8702",
    "expiration": 1652153760000,
    "fee_limit": 1000000,
    "timestamp": 1652153701556
  },
  "raw_data_hex": "0a020a492208975853d6629c87024080f2a6e08a305add03081e12d8030a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e437265617465536d617274436f6e747261637412a3030a1541d1e7a6bc354106cb410e65ff8b181c600ff142921289030a1541d1e7a6bc354106cb410e65ff8b181c600ff142921a5c0a2b1a03736574220e12036b65791a0775696e743235362210120576616c75651a0775696e74323536300240030a2d10011a03676574220e12036b65791a0775696e743235362a10120576616c75651a0775696e743235363002400222fd01608060405234801561001057600080fd5b5060de8061001f6000396000f30060806040526004361060485763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631ab06ee58114604d5780639507d39a146067575b600080fd5b348015605857600080fd5b506065600435602435608e565b005b348015607257600080fd5b50607c60043560a0565b60408051918252519081900360200190f35b60009182526020829052604090912055565b600090815260208190526040902054905600a165627a7a72305820fdfe832221d60dd582b4526afa20518b98c2e1cb0054653053a844cf265b2504002930643a0c536f6d65436f6e747261637440a08d0670b4a9a3e08a309001c0843d"
}

不同类型的交易的交易的结构都是一样的,只是raw_data中包含的contract内容不同,主要体现在交易中的contract.parameter.value字段.

部署合约交易中的contract.parameter.value包含以下内容:

  • owner_address: 合约部署者地址
  • new_contract: 新部署的合约的详细信息
    • origin_address:合约部署者地址
    • contract_address:合约地址
    • ABI:合约的ABI
    • bytecode: 合约代码编译后字节码
    • call_value:部署合约时传入合约的TRX数量
    • consume_user_resource_percent:用户能量费用占比
    • name:合约名
    • origin_energy_limit:对于每笔交易消耗合约部署者的能量上限,以sun为单位
  • call_token_value: 发送到新部署合约的TRC10代币数量
  • token_id: TRC10 token id

智能合约的调用和查询

triggersmartcontract

合约调用是创建了一个TriggerSmartContract类型的交易,可以通过fullnode api wallet/triggersmartcontract来创建触发合约调用的交易,创建完成交易后,需要对其签名,然后广播到全网。


curl -X POST https://api.shasta.trongrid.io/wallet/triggersmartcontract -d '{
"contract_address":"419E62BE7F4F103C36507CB2A753418791B1CDC182",
"function_selector":"transfer(address,uint256)",
"parameter":"00000000000000000000004115208EF33A926919ED270E2FA61367B2DA3753DA0000000000000000000000000000000000000000000000000000000000000032",
"fee_limit":100000000,
"call_value":0,
"owner_address":"41977C20977F412C2A1AA4EF3D49FEE5EC4C31CDFB"
}'

参数说明:

  • contract_address:合约的地址
  • owner_address:调用者地址
  • function_selector:触发的合约方法
  • parameter:编码后的合约方法的参数值,本例中应该传入的参数有两个,分别是address和uint256类型,具体如何对参数进行编码和解码,请参考参数编码解码章节
  • fee_limit:调用者愿意承担的交易所消耗的能量的上限,请参考feelimit说明
  • call_value:传入合约的TRX数量

上述命令执行成功后,将返回如下结果,其中包括一个合约调用交易transaction:

{
    "result": {
        "result": true
    },
    "transaction": {
        "visible": false,
        "txID": "d2ce86097df40287ad45ebc67f0d546ee98c2d7cd7c101e4d4d5b0c8a752d900",
        "raw_data": {
            "contract": [{
                "parameter": {
                    "value": {
                        "data": "a9059cbb00000000000000000000004115208ef33a926919ed270e2fa61367b2da3753da0000000000000000000000000000000000000000000000000000000000000032",
                        "owner_address": "41977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb",
                        "contract_address": "419e62be7f4f103c36507cb2a753418791b1cdc182"
                    },
                    "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
                },
                "type": "TriggerSmartContract"
            }],
            "ref_block_bytes": "1c51",
            "ref_block_hash": "74912b480b7b887c",
            "expiration": 1652169501000,
            "fee_limit": 100000000,
            "timestamp": 1652169442098
        },
        "raw_data_hex": "0a021c51220874912b480b7b887c40c8d2e7e78a305aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a1541977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb1215419e62be7f4f103c36507cb2a753418791b1cdc1822244a9059cbb00000000000000000000004115208ef33a926919ed270e2fa61367b2da3753da000000000000000000000000000000000000000000000000000000000000003270b286e4e78a30900180c2d72f"
    }
}

合约调用交易中的contract.parameter.value包含以下内容:

  • owner_address:合约调用者地址
  • contract_address:合约地址
  • data:合约函数选择器及其参数, 前4个字节是合约函数选择器,它是对合约函数名称及参数做Keccak-256 运算得到的结果的前 4 字节,用于虚拟机对函数的寻址。data的其余字节是函数的参数,具体如何编解码,请参考参数编码解码章节。
  • call_value:发送到合约的TRX数量
  • token_id:发送到合约的TRC10代币的token id
  • call_token_value:发送到合约的TRC10代币的数量

triggerconstantcontract

通过fullnode api wallet/triggerconstantcontract来调用合约的常量函数,因为是查询操作,不需要上链,所以不需要签名和广播:

curl -X POST https://127.0.0.1:8090/wallet/triggerconstantcontract -d '{
"contract_address":"419E62BE7F4F103C36507CB2A753418791B1CDC182",
"function_selector":"balanceOf(address)",
"parameter":"000000000000000000000041977C20977F412C2A1AA4EF3D49FEE5EC4C31CDFB",
"owner_address":"41977C20977F412C2A1AA4EF3D49FEE5EC4C31CDFB"
}'

参数说明:

  • contract_address:合约的地址
  • owner_address:调用者地址
  • function_selector:触发的合约方法
  • parameter:合约方法要传入的参数,具体如何编解码,请参考参数编码解码章节。

返回结果如下:

{
    "result": {
        "result": true
    },
    "constant_result": ["0000000000000000000000000000000000000000000000000000000430e1b700"],
    "transaction": {
        "ret": [{}],
        "visible": false,
        "txID": "7f47212aed2fdab232195feece54fc302bde2ce379e92ffd0d0e95206ce7a3bb",
        "raw_data": {
            "contract": [{
                "parameter": {
                    "value": {
                        "data": "70a08231000000000000000000000041977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb",
                        "owner_address": "41977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb",
                        "contract_address": "419e62be7f4f103c36507cb2a753418791b1cdc182"
                    },
                    "type_url": "type.googleapis.com/protocol.TriggerSmartContract"
                },
                "type": "TriggerSmartContract"
            }],
            "ref_block_bytes": "5ab1",
            "ref_block_hash": "f24f075df912f43e",
            "expiration": 1590382815000,
            "timestamp": 1590382762536
        },
        "raw_data_hex": "0a025ab12208f24f075df912f43e4098cecfd1a42e5a8e01081f1289010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412540a1541977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb1215419e62be7f4f103c36507cb2a753418791b1cdc182222470a08231000000000000000000000041977c20977f412c2a1aa4ef3d49fee5ec4c31cdfb70a8b4ccd1a42e"
    }
}
  • constant_result:就是查询合约的结果,本例中返回值是uint256类型,具体如何对返回值进行编码和解码,请参考参数编码解码章节

consume_user_resource_percent

合约调用需要支付一定的资源费用,为了鼓励用户进行合约交易,降低其调用成本,TRON网络支持合约部署者分摊一部分的合约调用费用。在部署合约时,可通过参数consume_user_resource_percent来设置用户的能量支付比率。

用户能量支付比率是用户为智能合约执行支付的能量与开发者支付的能量的占比。 例如,如果用户能量支付比率设置为60,则用户支付60%的合约执行所需的能量,而开发者(合同部署者)支付剩余的40%的能量。 此参数只能为0到100之间(含0和100)的整数。 建议开发者适当调高用户能量支付比例,以防用户攻击合约并耗尽合约所有者的帐户资源。

合约成功部署后,也可以修改用户能量支付比率,比如合约拥有者可以通过fullnode HTTP API wallet/updatesetting 来修改合约的用户能量支付比率。

注意:虽然合约开发者可能需要承担一定比例的合约调用所需的能量费用,但是当开发者账户的能量不足以支付他所承担的部分时或本次调用消耗开发者账户的能量超过了origin_energy_limit时,剩余部分全部由调用者承担。

feelimit

feelimit是指调用者愿意承担的智能合约部署或调用所消耗的能量成本的上限,以sun为单位 (1TRX = 1e6 sun),目前可设置的能量费用上限为10000 TRX 即 1e10 sun,如果将feelimit设置为大于 1e10 的值,则会产生错误。

由于执行合约时,Energy的计算和扣除是逐条进行的,一旦feeLimit的超出最大值,则合约执行失败,已扣除的Energy无法退还;

在部署合约到主网之前,最好设置一个合理的费用限制。比如在部署大型合约或运行复杂功能时,需要设置更大的feelimit,但是,由于存在合约执行超时、合约中存在无限循环、非法操作和向不存在的帐户转账等情况,设置相对较低的费用限制将是更好的选择。