Smart Contract¶
Smart contracts are the key feature of TRON network. Creating and interacting with smart contracts are made easy by TronPy.
Calling smart contract¶
There are two types of smart contract calls, const call and trigger call. For a const call, the contract method must be marked pure or view. And the calling result will be returned immediately.
While the trigger call is just a type of system contract call, you sign the calling transaction, and broadcast it. The calling result can be fetched and parsed through the API.
Const call¶
Const call is wrapped as a function object. The result is parsed according to ABI.
Take TRC20 as an example, the balance query is a very common task:
from tronpy import Tron
client = Tron(network='nile')
cntr = client.get_contract("THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia")
print(dir(cntr.functions)) # prints list of contract functions
for f in cntr.functions:
print(f) # prints function signature(i.e. type info)
# function allowance(address _owner, address _spender) view returns (uint256 remaining)
# function approve(address _spender, uint256 _amount) returns (bool success)
# function balanceOf(address _owner) view returns (uint256 balance)
# function decimals() view returns (uint8 )
# function name() view returns (string )
# function owner() view returns (address )
# function symbol() view returns (string )
# function totalSupply() view returns (uint256 theTotalSupply)
# function transfer(address _to, uint256 _amount) returns (bool success)
# function transferFrom(address _from, address _to, uint256 _amount) returns (bool success)
print('Symbol:', cntr.functions.symbol()) # The symbol string of the contract
# Symbol: RMB
precision = cntr.functions.decimals()
print('Balance:', cntr.functions.balanceOf('TJRabPrwbZy45sbavfcjinPJC18kjpRTv8') / 10 ** precision)
# Balance: 100000.0
Trigger call¶
Trigger call requires sign and broadcast.
>>> from tronpy import Tron from tronpy.keys import PrivateKey
>>> from tronpy.keys import PrivateKey
>>> client = Tron(network='nile')
>>> contract = client.get_contract('THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia')
>>> print(contract.functions.transfer)
function transfer(address _to, uint256 _amount) returns (bool success)
>>> txn = (
... contract.functions.transfer('TVjsyZ7fYF3qLF6BQgPmTEZy1xrNNyVAAA', 1_000)
... .with_owner('TGQgfK497YXmjdgvun9Bg5Zu3xE15v17cu') # address of the private key
... .fee_limit(5_000_000)
... .build()
... .sign(priv_key)
... )
>>> txn.broadcast() # or txn.broadcast()
{'result': True, 'txid': '63609d84524b754a97c111eec152700f273979bb00dad993d8dcce5848b4dd9a'}
>>> _.wait()
{'id': '63609d84524b754a97c111eec152700f273979bb00dad993d8dcce5848b4dd9a',
'blockNumber': 6609475, 'blockTimeStamp': 1592539509000,
'contractResult': ['0000000000000000000000000000000000000000000000000000000000000001'],
'contract_address': 'THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia',
'receipt': {'energy_usage': 13062, 'energy_usage_total': 13062, 'net_usage': 344, 'result': 'SUCCESS'},
'log': [{'address': 'THi2qJf6XmvTJSpZHc17HgQsmJop6kb3ia',
'topics': ['ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'00000000000000000000000046a23e25df9a0f6c18729dda9ad1af3b6a131160',
'000000000000000000000000d8dd39e2dea27a40001884901735e3940829bb44'],
'data': '00000000000000000000000000000000000000000000000000000000000003e8'}]}
# trigger output can be parsed manually
>>> contract.functions.transfer.parse_output(_['contractResult'][0])
True
# or use `.result()` to parse it automatically
>>> txn.broadcast().result()
True
Trigger call with transfer¶
Use with_transfer()
or with_asset_transfer()
.
>>> txn = (
... contract.functions.transfer.with_transfer(100_000_000)
... .call('TVjsyZ7fYF3qLF6BQgPmTEZy1xrNNyVAAA', 1_000)
... .with_owner('TGQgfK497YXmjdgvun9Bg5Zu3xE15v17cu') # address of the private key
... .fee_limit(5_000_000)
... .build()
... .sign(priv_key)
... )
Creating smart contract¶
When you’ve compiled your contract code, you can deploy it on chain.
from tronpy import Tron, Contract
from tronpy.keys import PrivateKey
client = Tron(network='nile')
priv_key = PrivateKey(bytes.fromhex("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"))
bytecode = "608060405234801561001057600080fd5b5060c78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146062575b600080fd5b606060048036036020811015604b57600080fd5b8101908080359060200190929190505050607e565b005b60686088565b6040518082815260200191505060405180910390f35b8060008190555050565b6000805490509056fea2646970667358221220c8daade51f673e96205b4a991ab6b94af82edea0f4b57be087ab123f03fc40f264736f6c63430006000033"
abi = [
{
"inputs": [],
"name": "get",
"outputs": [{"internalType": "uint256", "name": "retVal", "type": "uint256"}],
"stateMutability": "view",
"type": "function",
}
]
cntr = Contract(name="SimpleStore", bytecode=bytecode, abi=abi)
txn = (
client.trx.deploy_contract('TGQgfK497YXmjdgvun9Bg5Zu3xE15v17cu', cntr)
.fee_limit(5_000_000)
.build()
.sign(priv_key)
)
print(txn)
result = txn.broadcast().wait()
print(result)
print('Created:', result['contract_address'])
created_cntr = client.get_contract(result['contract_address'])
Note
The constructor’s parameters are provided via bytecode.
cntr = Contract(name="SimpleStore", bytecode=bytecode, abi=abi)
parameter = cntr.constructor.encode_parameter("TRh5N2iAmjyeJbbCXsDuo7PNZvyjVWtL2e", 18)
cntr.bytecode = bytecode + parameter
Default Fee Limit¶
The default fee limit is 5_000_000
for contract deploy or trigger, 0
otherwise.
Fee limit is set by .fee_limit()
method of transaction.
It also can be set via conf object:
client = Tron(network='nile', conf={'fee_limit': 10_000_000})
Contract with Un-published ABI¶
You can set JSON ABI via cntr.abi = [...]
.
import json
from tronpy import Tron
from tronpy import keys
dzi_trade = 'TS..........(omitted).............j'
from_addr = 'TV..........(omitted).............a'
priv_key = keys.PrivateKey(bytes.fromhex("975a...............(omitted)..............8d97b"))
abi = '''
[{"constant":false,
"inputs":[{"name":"min_tokens","type":"uint256"},{"name":"deadline","type":"uint256"}],
"name":"trxToTokenSwapInput",
"outputs":[{"name":"","type":"uint256"}],
"payable":true,
"stateMutability":"payable",
"type":"Function"}]
'''
client = Tron(network='nile')
cntr = client.get_contract(dzi_trade)
cntr.abi = json.loads(abi) # load ABI, while contract on chain has no ABI set.
# call contract functions with TRX transfer
txn = (
cntr.functions.trxToTokenSwapInput.with_transfer(1_000_000_000)(1_000_000_000_000, 5)
.with_owner(from_addr)
.fee_limit(1_000_000_000)
.build()
.sign(priv_key)
)
print("txn =>", txn)
print("broadcast and result =>", txn.broadcast().wait())
API reference¶
-
class
tronpy.contract.
Contract
(addr=None, *, bytecode: Union[str, bytes] = '', name: str = None, abi: Union[dict, List[dict], None] = None, user_resource_percent: int = 100, origin_energy_limit: int = 1, origin_address: str = None, owner_address: str = '410000000000000000000000000000000000000000', code_hash: str = None, client=None)¶ A smart contract object.
-
abi
= None¶ ABI list of the contract
-
address
= None¶ Address of the contract
-
bytecode
¶ Bytecode of the contract, in
hex
format
-
clear_abi
() → tronpy.tron.TransactionBuilder¶ Clear contract ABI.
-
code_hash
= None¶ Hash of smart contract bytecode.
-
constructor
¶ The constructor of the contract.
-
events
¶ The
ContractEvents
object, wraps all contract events.
-
functions
¶ The
ContractFunctions
object, wraps all contract methods.
-
name
= None¶ Name of the contract
-
origin_address
= None¶ Origin address of the contract, i.e. contract creator
-
origin_energy_limit
= None¶ Origin energy limit, default 1
-
owner_address
= None¶ Current transaction owner’s address, to call or trigger contract
-
update_origin_energy_limit
(limit: int) → tronpy.tron.TransactionBuilder¶ Create a Transaction to update origin energy limit.
-
update_user_resource_percent
(percent: int) → tronpy.tron.TransactionBuilder¶ Create a Transaction to update user resource percent.
-
user_resource_percent
= None¶ User resource percent, default 100
-
-
class
tronpy.contract.
ContractFunctions
¶ -
__getattr__
(method: str) → tronpy.contract.ContractMethod¶ Get the actual contract method object.
-
-
class
tronpy.contract.
ContractMethod
¶ -
__call__
(*args, **kwargs)¶ Call the contract method.
-
call
(*args, **kwargs) → tronpy.tron.TransactionBuilder¶ Call the contract method.
-
parse_output
(raw: str) → Any¶ Parse contract result as result.
-
with_asset_transfer
(amount: int, token_id: int) → tronpy.contract.ContractMethod¶ Call a contract function with TRC10 token transfer.
-
with_owner
(addr: str) → tronpy.contract.ContractMethod¶ Set the calling owner address.
Can also be changed through
TransactionBuilder.with_owner()
.
-
with_transfer
(amount: int) → tronpy.contract.ContractMethod¶ Call a contract function with TRX transfer.
amount
in SUN.
-