部署与调用
智能合约的部署
部署智能合约是创建一个 CreateSmartContract
类型的交易,可以通过全节点 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.parameter.value
字段。
合约部署交易中的 contract.parameter.value
包含以下内容:
owner_address
:合约所有者的地址,即合约部署者地址new_contract
:新的智能合约的详细信息origin_address
:智能合约所有者的地址contract_address
:智能合约的地址ABI
:智能合约的 ABIbytecode
:智能合约的字节码call_value
:发送给智能合约的 TRX 数量consume_user_resource_percent
:用户能量支付的百分比name
:智能合约的名称origin_energy_limit
:每笔交易所有者能量消耗的限制,以sun
为单位
call_token_value
:发送给新创建智能合约的 TRC10 通证数量token_id
:TRC10 通证 ID
智能合约调用与查询
triggersmartcontract
合约调用是创建一个 TriggerSmartContract
类型的交易。你可以通过全节点 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
:调用者愿意承担的交易能量消耗上限,请参考fee_limit
的描述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字节,用于虚拟机查找函数。数据的剩余字节是函数的参数。关于编码和解码的详细信息,请参考“参数编码与解码”章节call_value
:发送给智能合约的 TRX 数量token_id
:发送给合约的 TRC10 通证的 IDcall_token_value
:发送给智能合约的 TRC10 通证数量
triggerconstantcontract
通过全节点 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
设置用户的能量支付比例。
用户能量支付比例是用户为智能合约执行支付的能量占比。例如,如果用户能量支付比例设置为 60,用户支付合约执行所需能量的 60%,开发者(合约部署者)支付剩余 40% 的能量。此参数只能是 0 到 100 之间的整数(包括 0 和 100)。建议开发者适当提高用户的能量支付比例,以防止用户攻击合约并耗尽合约拥有者的账户资源。
合约成功部署后,用户能量支付比例也可以修改。例如,合约拥有者可以通过全节点 HTTP API wallet/updatesetting
进行修改。
注意:虽然合约开发者可能需要分担一定比例的合约调用能量费用,但当开发者账户的能量不足以支付其需要承担的部分,或此调用消耗的开发者账户能量超过 origin_energy_limit
的值时,剩余部分由调用者承担。
费用限制
feelimit
指的是调用者愿意为智能合约的部署或调用承担的能量费用上限,以 sun
为单位(1TRX = 1e6 sun
)。目前,能量费用上限可以设置为 15000TRX
。如果 feelimit
设置大于 15000 TRX,将会产生错误。
在执行合约时,能量按照每条指令逐一计算和扣除。如果使用的能量超出上限,合约执行将失败且扣除的能量不会被返还。
在将合约部署到主网之前,最好设置合理的 feelimit
。例如,在部署大型合约或运行复杂功能时,需要更大的 feelimit
。然而,由于合约执行超时、合约中的无限循环、非法操作和向不存在的账户转账等情况的存在,较低的 feelimit
会是更好的选择。