Skip to content

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 address
  • contract_address: smart contract address
  • abi: the api information of all the function of the smart contract
  • bytecode: smart contract byte code
  • call_value: TRX transferred into smart contract while call the contract
  • consume_user_resource_percent: resource consumption percentage set by the developer
  • name: smart contract name
  • origin_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 the updateEnergyLimit api to update this parameter (the new value must be greater than 0)
  • code_hash: hash of the contract runtime bytecode
  • trx_hash: root transaction id of the deployment. Populated only for contracts deployed via the CREATE2 opcode; left empty for contracts deployed via the CREATE opcode or via gRPC deployContract
  • version: smart contract version. When the network has activated the ALLOW_TVM_COMPATIBLE_EVM proposal, 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

  1. 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/delegatecall to 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.

  2. Voting for Super Representatives and withdrawing voting rewards from inside a contract. Enabled by the ALLOW_TVM_VOTE chain parameter, activated on mainnet by committee proposal #84. Provides VOTEWITNESS / WITHDRAWREWARD opcodes and related read-only precompiles.

  3. TRC10 token operations: sending TRC10 to a target address and querying the TRC10 balance of an address. Enabled by the ALLOW_TVM_TRANSFER_TRC10 chain parameter, activated on mainnet by committee proposal #15.

  4. 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.

  5. 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). The ALLOW_TVM_COMPATIBLE_EVM chain parameter has never been proposed, so the Ethereum-standard RIPEMD160 and BLAKE2F precompiles 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);
}
This is similar with the grammar of the conversion from other types converted to address type in Ethereum.

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;
        }
}
But if you are using wallet-cli, pass the 21-byte TRON address as a 32-byte ABI-encoded value (11 leading zero bytes followed by the 21-byte TRON address that starts with 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
}
If you want to use a base58 TRON address string (e.g. 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.

  • blockhash(uint blockNumber) returns (bytes32): specified block hash, can only apply to the latest 256 blocks and current block excluded. Note: the form block.blockhash(uint) was deprecated in upstream Solidity 0.4.22 and removed in 0.5.0; TRON's Solidity fork inherits the deprecation from tv_0.4.24 and the removal from tv_0.5.4 onwards — use the top-level blockhash(...) instead
  • block.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 #72
  • block.coinbase (address): Super Representative address that produced the current block
  • block.difficulty (uint): current block difficulty, not recommended, set 0
  • block.gaslimit (uint): current block gas limit, not supported, set 0
  • block.number (uint): current block number
  • block.timestamp (uint): current block timestamp
  • gasleft() returns (uint256): remaining gas
  • msg.data (bytes): complete call data
  • msg.gas (uint): remaining gas - since 0.4.21, not recommended, replaced by gasleft()
  • 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 message
  • now (uint): alias for block.timestamp. Removed in Solidity 0.7.0; use block.timestamp instead
  • tx.gasprice (uint): the gas price of transaction, not recommended, set 0
  • tx.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.