Smart Contract

Smart contract is the key feature of TRON network. Creating and interacting with smart contract are made easy by TronPy.

Calling smart contract

There are two types of smart contract call, 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: Optional[dict] = None, user_resource_percent: int = 100, origin_energy_limit: int = 1, origin_address: str = None, owner_address: str = '410000000000000000000000000000000000000000', client=None)

A smart contract object.

abi = None

ABI list of the contract

bytecode

Bytecode of the contract, in hex format

clear_abi() → tronpy.tron.TransactionBuilder

Clear contract ABI.

constructor

The constructor of the contract.

contract_address = None

Address of the contract

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.