Contract¶
Introduction¶
Smart contract is a computerized transaction protocol that automatically implements its terms. Smart contract is the same as common contract, they all define the terms and rules related to the participants. Once the contract is started, it can executes as designed.
TRON smart contract support Solidity language in (Ethereum). You can find the latest solidity version in the TRON solidity repository. Write a smart contract, then build the smart contract and deploy it to TRON network. When the smart contract is triggered, the corresponding function will be executed automatically.
Features¶
TRON virtual machine is based on Ethereum solidity language, it also has TRON's own features.
Definition of Smart Contract¶
TRON VM is compatible with Ethereum's smart contract, using protobuf to define the content of the contract:
message SmartContract {
message ABI {
message Entry {
enum EntryType {
UnknownEntryType = 0;
Constructor = 1;
Function = 2;
Event = 3;
Fallback = 4;
Receive = 5;
Error = 6;
}
message Param {
bool indexed = 1;
string name = 2;
string type = 3;
}
enum StateMutabilityType {
UnknownMutabilityType = 0;
Pure = 1;
View = 2;
Nonpayable = 3;
Payable = 4;
}
bool anonymous = 1;
bool constant = 2;
string name = 3;
repeated Param inputs = 4;
repeated Param outputs = 5;
EntryType type = 6;
bool payable = 7;
StateMutabilityType stateMutability = 8;
}
repeated Entry entrys = 1;
}
bytes origin_address = 1;
bytes contract_address = 2;
ABI abi = 3;
bytes bytecode = 4;
int64 call_value = 5;
int64 consume_user_resource_percent = 6;
string name = 7;
int64 origin_energy_limit = 8;
bytes code_hash = 9;
bytes trx_hash = 10;
int32 version = 11;
}
origin_address: smart contract creator addresscontract_address: smart contract addressabi: the api information of all the function of the smart contractbytecode: smart contract byte codecall_value: TRX transferred into smart contract while call the contractconsume_user_resource_percent: resource consumption percentage set by the developername: smart contract nameorigin_energy_limit: energy consumption of the developer limit in one call, must be greater than 0. For old contracts that were deployed without this parameter, the stored value is 0 but the runtime substitutes a default of 10,000,000 energy (CREATOR_DEFAULT_ENERGY_LIMIT); developers can use theupdateEnergyLimitapi to update this parameter (the new value must be greater than 0)code_hash: hash of the contract runtime bytecodetrx_hash: root transaction id of the deployment. Populated only for contracts deployed via theCREATE2opcode; left empty for contracts deployed via theCREATEopcode or via gRPCdeployContractversion: smart contract version. When the network has activated theALLOW_TVM_COMPATIBLE_EVMproposal, newly deployed contracts are stamped with version 1 so the runtime can gate EVM-compatible behavior to them, while older contracts (deployed before activation) keep version 0 and retain the original TVM semantics. As of writing this proposal is not active on mainnet, so all contracts on mainnet have version 0
Through other two grpc message types CreateSmartContract and TriggerSmartContract to create and use smart contract.
Usage of the Function of Smart Contract¶
constant function and non-constant function¶
There are two types of function according to whether any change will be made to the properties on the chain: constant function and non-constant function
Constant function uses view/pure to decorate, will return the result on the node it is called and not be broadcasted in the form of a transaction
Non-constant function will be broadcasted in the form of a transaction while being called, the function will change the data on the chain, such as transfer, changing the value of the internal variables of contracts, etc.
Note: legacy contracts may use the deprecated constant function modifier. It is a compile-time annotation only and is not encoded into bytecode, so already-deployed contracts continue to run normally; however, recompiling such sources with the current TRON Solidity compiler will fail with a parser error — use view/pure for new contracts.
message calls¶
Message calls can call the functions of other contracts, also can transfer TRX to the accounts of contract and none-contract. Like the common TRON triggercontract, Message calls have initiator, recipient, data, transfer amount, fees and return attributes. Every message call can generate a new one recursively. Contract can define the distribution of the remaining energy in the internal message call. If it comes with OutOfEnergyException in the internal message call, it will return false, but not error. In the meantime, only the energy sent with the internal message call will be consumed; if an energy limit is not specified via call.gas(x) (chained syntax, removed in Solidity 0.7.0) or {gas: x, value: ...} (options syntax, since Solidity 0.6.2), all the remaining energy will be forwarded to the inner call.
delegate call/call code/library¶
There is a special type of message call, delegate call. The difference with common message call is the code of the target address will be run in the context of the contract that initiates the call, msg.sender and msg.value remain unchanged. This means a contract can dynamically loadcode from another address while running. Storage, current address and balance all point to the contract that initiates the call, only the code is get from the address being called. This gives Solidity the ability to achieve the 'lib' function: the reusable code lib can be put in the storage of a contract to implement complex data structure library.
CREATE command¶
This command will create a new contract with a new address. The primary difference from Ethereum is that the new TRON address is derived as sha3omit12(rootTransactionId || nonce) — the root transaction id concatenated with the 8-byte nonce, then hashed (the nonce itself is not pre-hashed); the final 21-byte address has a leading 0x41 TRON address prefix. Different from Ethereum (where nonce is the sender account's transaction nonce), here nonce is a per-root-transaction counter that increments on every internal action (internal call, transfer, CREATE, suicide, etc.), not only on CREATE. Refer to TransactionUtil.generateContractAddress(byte[], long) for the exact implementation.
Note: Different from creating a contract by grpc's deployContract, contract created by CREATE command does not store contract abi.
built-in function and built-in function attribute¶
-
TVM is compatible with solidity language's transfer format, including:
- accompany with constructor to call transfer
- accompany with internal function to call transfer
- use
transfer/send/call/callcode/delegatecallto call transfer
Note: TRON's smart contract differs from TRON's system contract. Before the SOLIDITY_059 upgrade (chain parameter
ALLOW_TVM_SOLIDITY_059, activated by committee proposal #29), a smart-contract transfer to a non-existent address would fail. Since then, the TVM auto-creates the target account on transfer, matching the system-contract behavior. -
Voting for Super Representatives and withdrawing voting rewards from inside a contract. Enabled by the
ALLOW_TVM_VOTEchain parameter, activated on mainnet by committee proposal #84. ProvidesVOTEWITNESS/WITHDRAWREWARDopcodes and related read-only precompiles. -
TRC10 token operations: sending TRC10 to a target address and querying the TRC10 balance of an address. Enabled by the
ALLOW_TVM_TRANSFER_TRC10chain parameter, activated on mainnet by committee proposal #15. -
Staking TRX for resources (Stake 2.0), delegating / undelegating resources, and querying delegated balances from inside a contract. Enabled when the network supports the unfreeze-delay model (Stake 2.0), which is active on mainnet.
-
Compatible with most Ethereum built-in functions and precompiles (through the Constantinople, Istanbul, London, Shanghai and Cancun upgrades, each gated by its own
ALLOW_TVM_*chain parameter — all active on mainnet via committee proposals #18, #44, #72, #89 and #103 respectively). TheALLOW_TVM_COMPATIBLE_EVMchain parameter has never been proposed, so the Ethereum-standardRIPEMD160andBLAKE2Fprecompiles are not yet enabled.
Contract Address Used in Solidity Language¶
Ethereum VM address is 20 bytes, but TRON's VM address is 21 bytes.
address conversion¶
Need to convert TRON's address while using in solidity (recommended):
/**
* @dev convert uint256 (HexString add 0x at beginning) TRON address to solidity address type
* @param tronAddress uint256 tronAddress, begin with 0x, followed by HexString
* @return Solidity address type
*/
function convertFromTronInt(uint256 tronAddress) public view returns(address){
return address(tronAddress);
}
address judgement¶
Solidity has address constant judgement, if using 21 bytes address the compiler will throw out an error, so you should use 20 bytes address, like:
function compareAddress(address tronAddress) public view returns (uint256){
// if (tronAddress == 0x41ca35b7d915458ef540ade6068dfe2f44e8fa733c) { // compile error
if (tronAddress == 0xca35b7d915458ef540ade6068dfe2f44e8fa733c) { // right
return 1;
} else {
return 0;
}
}
41), e.g. 000000000000000000000041ca35b7d915458ef540ade6068dfe2f44e8fa733c.
variable assignment¶
Solidity has address constant assignment, if using 21 bytes address the compiler will throw out an error, so you should use 20 bytes address, like:
function assignAddress() public view {
// address newAddress = 0x41ca35b7d915458ef540ade6068dfe2f44e8fa733c; // compile error
address newAddress = 0xca35b7d915458ef540ade6068dfe2f44e8fa733c;
// do something
}
TLLM21wteSPs4hKjbxgmH1L6poyMjeTbHm), convert it to the 20-byte hex form first via wallet-cli or a TRON SDK before assigning it to a Solidity address.
Special Constants Differ from Ethereum¶
Currency¶
Like solidity supports ETH, TRON VM supports trx and sun, 1 trx = 1000000 sun, case sensitive, only support lower case. tron-studio supports trx and sun, remix does not support trx and sun. We recommend to use tron-studio instead of remix to build TRON smart contract.
Block Related¶
blockhash(uint blockNumber) returns (bytes32): specified block hash, can only apply to the latest 256 blocks and current block excluded. Note: the formblock.blockhash(uint)was deprecated in upstream Solidity 0.4.22 and removed in 0.5.0; TRON's Solidity fork inherits the deprecation fromtv_0.4.24and the removal fromtv_0.5.4onwards — use the top-levelblockhash(...)insteadblock.basefee(uint): returns the network energy fee from chain parameter (getEnergyFee); unlike Ethereum's per-block EIP-1559 base fee, this value only changes when a committee proposal modifies it. Available since the London upgrade (ALLOW_TVM_LONDON), activated on mainnet by committee proposal #72block.coinbase(address): Super Representative address that produced the current blockblock.difficulty(uint): current block difficulty, not recommended, set 0block.gaslimit(uint): current block gas limit, not supported, set 0block.number(uint): current block numberblock.timestamp(uint): current block timestampgasleft() returns (uint256): remaining gasmsg.data(bytes): complete call datamsg.gas(uint): remaining gas - since 0.4.21, not recommended, replaced bygasleft()msg.sender(address): message sender (current call)msg.sig(bytes4): first 4 bytes of call data (function identifier)msg.value(uint): the amount of SUN send with messagenow(uint): alias forblock.timestamp. Removed in Solidity 0.7.0; useblock.timestampinsteadtx.gasprice(uint): the gas price of transaction, not recommended, set 0tx.origin(address): transaction initiator
Energy¶
Each command of smart contract consume system resource while running, we use Energy as the unit of the consumption of the resource.