- AdminControl contract
- SponsorWhitelistControl contract
- Staking Contract
(IMPORTANT: the interfaces are changed in Tethys mainnet. This document is synced with the newest version.)
Conflux introduces several built-in internal contracts for better system maintenance and on-chain governance. Now Conflux has six internal contracts:
SponsorWhitelistControl contract and
Staking contract are introduced from the beginning,
ConfluxContext are introduced at v2 hard-fork,
ParamsControl is introduced at v2.1 hard-fork. These contracts provide solidity function apis defined
here. These function can only be called via
STATICCALL operation. Using operation
DELEGATECALL to interact with internal contracts will trigger an error.
The addresses of these six internal contracts are list as follows:
All the example code in this document will use js-conflux-sdk. The solidity function apis are list here.
AdminControl contract is a debug tool for contract development. When a contract is created during a transaction, the sender for the current transaction will become the contract admin automatically.
admin address can transfer the administrator rights to another normal address or zero address by calling interface
setAdmin(address contractAddr, address newAdmin). A contract can never be an admin.
The admin of a contract has several administrator rights. It can call interface
destroy(address contractAddr) to destroy contract, just like a contract calling
suicide() function. The SponsorWhitelist internal contract provides some functions can only be called by admin address. These functions can update the whitelist in sponsor mechanism. They will be introduced later.
Note: For all the interfaces requiring administrator rights, no matter the execution success or not, no error or exception will be triggered during internal contract execution. For example, if a non-admin address tries to transfer the admin address to itself, this transaction will success but nothing will be changed.
ConfluxScan may mark a contract as debug mode if the contract has non-zero admin address. So remember, if you think the contract is ready for production environment, you should set admin address to zero.
AdminControl contract also provides a query interface
getAdmin(address contractAddr) which can be called by anyone.
- The admin is set at the start of contract creation. So if sender
Band set admin to
Cduring contract construction, the admin will be
Cwhen the contract is deployed.
- However, if sender
B, then contract
Cand then set admin to
Dduring contract contraction, then the set will fail because the admin of
Aand the sender for creating
- But, Conflux introduces a special policy. In case 2, if
Dis zero address, the set admin will success. This means that a contract can declare "I don't need admin" during contract creation.
Consider you have deployed a contract whose address is
contract_addr. The administrator can call
AdminControl.setAdmin(contract_addr, new_admin) to change the administrator and call
AdminControl.destroy(contract_addr) to kill the contract.
Conflux implements a sponsorship mechanism to subsidize the usage of smart contracts. Thus, a new account with zero balance is able to call smart contracts as long as the execution is sponsored (usually by the operator of Dapps). The built-in SponsorControl contract is introduced to record the sponsorship information of smart contracts.
When a message call happens, Conflux does not check sponsorship again. For example, if normal address
A calls contract
B and contract
B calls contract
C, Conflux only checks whether address
A is sponsored by contract
A is sponsored,
B will afford all the gas and/or collateral during the transaction execution, including the message call from
C. In other words, only a transaction sender could be sponsored.
The SponsorControl contract keeps the following information for each user-established contract:
sponsor_for_gas: this is the account that provides the subsidy for gas consumption;
sponsor_for_collateral: this is the account that provides the subsidy for collateral for storage;
sponsor_balance_for_gas: this is the balance of subsidy available for gas consumption;
sponsor_balance_for_collateral: this is the balance of subsidy available for collateral for storage;
sponsor_limit_for_gas_fee: this is the upper bound for the gas fee subsidy paid for every sponsored transaction;
whitelist: this is the list of normal accounts that are eligible for the subsidy, where a special all-zero address refers to all normal accounts. Only the contract itself and the admin have the authority to change this list.
There are two resources that can be sponsored: gas consumption and storage collateral.
- For gas consumption: If a transaction calls a contract with non-empty
sponsor_for_gasand the sender is in the
whitelistof the contract and the gas fee specified by the transaction is within the
sponsor_limit_for_gas_fee, the gas consumption of the transaction is paid from the
sponsor_balance_for_gasof the contract (if it is sufficient) rather than from the sender’s balance, and the execution of the transaction would fail if the
sponsor_balance_for_gascannot afford the gas consumption. Otherwise, the sender should pay for the gas consumption.
- For storage collateral: If a transaction calls a contract with non-empty
sponsor_for_collateraland the sender is in the
whitelistof the contract, the collateral for storage incurred in the execution of the transaction is deducted from
sponsor_balance_for_collateralof the contract, and the owner of those modified storage entries is set to the contract address accordingly. Otherwise, the sender should pay for the collateral for storage incurred in the execution.
When a contract is created, its
sponsor_for_collateral will be initialized by zero address, and the sponsor balance will be initialized by 0. Both sponsorship for gas and for collateral can be updated by calling the SponsorControl contract. The current sponsor can call this contract to transfer funds to increase the sponsor balances directly, and the current sponsor for gas is also allowed to increase the
sponsor_limit_for_gas_fee without transferring new funds. Other normal accounts can replace the current sponsor by calling this contract and providing more funds for sponsorship.
To replace the
sponsor_for_gas of a contract, the new sponsor should call function
setSponsorForGas(address contractAddr, uint upperBound) and transfer to the internal contract a fund. The following conditions are required to replace sponsor for gas:
- The transferred fund should more than the current
sponsor_balance_for_gasof the contract.
- The new value for
upperBoundparameter) should be no less than the old sponsor’s limit unless the old
sponsor_balance_for_gascannot afford the old
- The transferred fund should be >= 1000 times of the new limit, so that it is sufficient to subsidize at least
1000transactions calling the contract.
If the above conditions are satisfied, the remaining
sponsor_balance_for_gas will be refunded to the old
sponsor_for_gas, and the fund transferred to the internal contract will be added to the
sponsor_balance_for_gas of the contract. Then the
sponsor_limit_for_gas_fee will be updated according to the new sponsor’s specification. Otherwise, an exception will be triggered.
The replacement of
sponsor_for_collateral is similar except that there is no analog of the limit for gas fee. The function is
setSponsorForCollateral(address contractAddr). The new sponsor should transfer a fund more than the fund provided by the current sponsor for collateral of the contract. Then the current
sponsor_for_collateral will be fully refunded, i.e. the sum of
sponsor_balance_for_collateral and the total collateral for storage used by the contract, and both collateral sponsorship fields are changed as the new sponsor’s request accordingly.
Conflux also allows a contract account to be a sponsor.
#Add Sponsor Balance
The sponsor can provide additional sponsor balance without sponsorship replacement. In this case, the sponsor should also interact with function
setSponsorForGas(address contractAddr, uint upperBound) or
setSponsorForCollateral(address contractAddr), and meet all the requirements except condition 1. If requirements are satisfied, the transferred fund will be added to sponsor balance and the
sponsor_limit_for_gas_fee will be updated accordingly.
Only the contract itself or contract admin can update the contract whitelist. The sponsors have no rights for changing whitelist.
A contract can call function
addPrivilege(address memory) to any addresses to the whitelist. It means that if the
sponsor_for_gas is set, the contract will pay the gas fee for the accounts in the whitelist, and if the
sponsor_for_collateral is set, the contract will pay the CFS (collateral for storage) for the accounts in the whitelist. The zero address is a special address
0x0000000000000000000000000000000000000000. If this address is added to whitelist, all the transactions calling this contract will be sponsored. A contract can call this function
removePrivilege(address memory) to remove some normal account address from the whitelist. Remove a non-existent address will not cause an error or exception.
- A contract address can also be added to the whitelist, but it is meaningless because only the transaction sender could be sponsored.
The admin of a contract can use the interfaces
addPrivilegeByAdmin(address contractAddr, address memory addresses) and
removePrivilegeByAdmin(address contractAddr, address memory addresses) to maintain the whitelist.
Suppose you have a simple contract like this.
After deploying the contract and the address is
contract_addr, if someone wants to sponsor the gas consumption, he/she can send a transaction like below:
As for sponsor the storage collateral, you can simply replace the function
setSponsorForGas(contract_addr, your_upper_bound) to
After that you can maintain the
whitelist for your contract using
removePrivilege. The special address
0x0000000000000000000000000000000000000000 with all zeros means everyone is in the
whitelist. You need to use it carefully.
After that the accounts in
whiltelist will pay nothing while calling
Conflux introduces the staking mechanism for two reasons: first, staking mechanism provides a better way to charge the occupation of storage space (comparing to “pay once, occupy forever”); and second, this mechanism also helps in defining the voting power in decentralized governance.
At a high level, Conflux implements a built-in Staking contract to record the staking information of all accounts, for both normal addresses and smart contracts. By sending a transaction to this contract, users (both external users and smart contracts) can deposit/withdraw funds, which is also called stakes in the contract.
A user (or a contract) can deposit balance for staking by calling
deposit(uint amount) and then
amount Drip will be moved from its
stakingBalance. Notice that this function is non-payable, the user only needs to specify the amount to be staked without transferring any funds to internal contract and the minimum deposit amount is
The user can also withdraw balance by
withdraw(uint amount). The caller can call this function to withdraw some tokens from the Conflux Internal Staking Contract. The staking capital will be transferred to the user's balance in time. All the withdrawal applications will be processed on a first-come-first-served basis according to the sequence of staking orders.
#Locking and Voting Power
By locking the staking balance, the user can obtain vote power for further on-chain governance. With function
voteLock(uint amount, uint unlock_block_number), the account makes a promise that This process resembles making promise that "My
stakingBalance will always have at least
amount Drip before the block with block number
unlock_block_number". The account can make multiple promises, like "I will always at least 10 CFX in this year, and then always stake at least 5 CFX in the next year." Once the promise has been made, there is no way to cancel it! But the account can overwrite old promise by locking more balance. Whenever the account tries to withdraw
stakingBalance, the internal contract will check whether the rest balance matches the locking promise.
Here we introduce the detailed logic for locking balance by illustrating several examples. Suppose the current block number is
base, Conflux will generate about
x blocks in the rest of this year and
y blocks in the next year. Since Conflux generates two block per second,
y approximately equals to
2 * 60 * 60 * 24 * 365. And the value of
x depends on when you read this article.
- If an account has 10 CFX in
stakingBalance, and it calls
voteLock(100 * 10^18, base + x), then the transaction will fail because this account tries to lock 100 CFX with insufficient
- However, if this account calls
voteLock(8 * 10^18, base + x), the transaction will success.
- After that, if this account calls
voteLock(6 * 10^18, base + x + y), the transaction will also success. It means that 8 - 6 = 2 CFX will be unlocked until the end of this year, and another 6 CFX will be locked until the end of next year.
- Then, if this account calls
voteLock(0, base + x), nothing will happen. The transaction will not trigger an error during execution. The internal contract will regard this call as a meaningless promise: the account will stake at least 0 CFX. The old promises made in step 2 and step 3 will still hold.
- If this account calls
voteLock(9 * 10^18, base + x + y), the old two promises will be overwritten because "locking 9 CFX until the end of the next year" is a stronger promise.
Locking does not have any influence on the stake interest. When the account withdraw staking balance successfully, the staking interest will be computed as usual.
At any time, each locked Drip will be assigned a vote power from 0 to 1 according to its unlock time. The Drips to be unlocked in more than one year will have a full vote power. See section 8.3.2 in the Conflux Protocol Specification for more details.
Conflux v2 hard-fork has introduced three new internal contracts:
This contract can be used to query Conflux network info in contract including:
epochNumber- Current epoch number
posHeight- Current block height of PoS chain
finalizedEpochNumber- The latest finalized (by PoS chain) PoW epoch number
ConfluxContext's hex40 contract address is
This contract is used let user participate in PoS chain. If anyone want to become a PoS node, he need to interact with this contract. This contract provide serveral methods to increase or decrease PoS votes:
register- Regist in PoS chain to become a PoS node
increaseStake- Increase PoS stake
retire- Decrease PoS stake
Also several methods to query one account's PoS info:
getVotes- Query one account's votes info, will return
identifierToAddress- Query one PoS account's binded PoW address
addressToIdentifier- Query one PoW account's binded PoS address
PoSRegister's hex40 contract address is
CrossSpaceCall contract will be deployed at the address
0x0888000000000000000000000000000000000006 with the following interfaces. The Core space user/contract can interact with the accounts in the eSpace and process the return value in the same transaction. So the cross-space operations can be atomic.
For detail introduction check here
ParamsControl at address
0x0888000000000000000000000000000000000007 with the following interfaces. Which can be used to participate chain parameter DAO vote.