Nominator Pool
A smart contract, called a Nominator Pool, provides the ability for one or more nominators to lend Toncoin in a validator stake, and ensures that the validator can use that Toncoin only for validation. Also, the smart contract guarantees the distribution of the reward.
Architecture
Limits
This pool is designed for large amounts of coins.
During development, the main criterion was the safety and simplicity of the code.
The pool does not support small deposits or a large number of nominators in one pool.
Target tested configuration is 10k TONs minimum nominator stake and 40 nominators maximum in the pool.
The number of nominators above 40 has not been tested and we strongly advise against setting the number above 40 until such tests have been carried out.
Fees
Since the pool is located in the masterchain where the fees are high, it will take about 5 TON per validation round to operate the pool.
Operational fees are paid by the validator.
Note that there should always be 10 TON on the pool balance - this is the minimum balance for the network storage fee. 10 TON can not be withdrawn.
Reward distribution
For each round of validation, the pool sends a stake to the elector smart contract.
After the completion of the validation round, the pool recover its funds from the elector.
Usually the amount received is greater than the amount sent, the difference is the validation reward.
The validator receives a share of the reward, according to the immutable pool parameter validator_reward_share
.
validator_reward = (reward * validator_reward_share) / 10000;
nominators_reward = reward - validator_reward;
Nominators share the remaining reward according to the size of their stakes.
For example, if there are two nominators in the pool with stakes of 100k and 300k TON, then the first one will take 25% and the second 75% of the nominators_reward
.
Nominator Pool Slashing
In case of a large validation fine, when the amount received is less than the amount sent, the loss is debited from the validator's funds.
If the validator's funds are not enough, then the remaining loss will be deducted from the nominators in proportion to their stakes.
Note that the pool is designed in such a way that validator funds should always be enough to cover the maximum fine.
Validator's responsibility
A pool can participate in validation only if the validator funds exceeds the immutable pool parameter min_validator_stake
.
Also, the validator's funds must exceed the maximum possible fine for bad validation. The recommended fine is calculated based on the network config.
Otherwise, the pool will not send requests to participate in the validation round.
Nominator`s messages
To interact with the nominator pool, nominators send simple messages with a text comment (can be sent from any wallet application) to the pool smart contract.
Messages must be sent in bounceable mode!
In case of a typo or invalid message, the message will bounce back to the sender.
If you send a misspelled message or an invalid message in non-bounceable mode, you will lose coins.
Nominator's deposit
In order for the nominator to make a deposit, he needs to send message to nominator-pool smart contract with Toncoins and text comment "d".
The nominator can only send message from a wallet located in the basechain (with raw address 0:...
).
The amount of Toncoins must be greater than or equal to min_nominator_stake + 1 TON
.
1 TON upon deposit is deducted as a commission for deposit processing.
If the pool is not currently participating in validation (state == 0
), then the deposit will be credited immediately.
If the pool is currently participating in the validation (state != 0
), then the amount will be added to the pending_deposit_amount
of the nominator, and will be credited after the completion of the current round of validation.
The nominator can subsequently send more Toncoins to increase his deposit.
Note that if the nominator-pool has already reached the number of nominators equal to the max_nominators_count
, then deposits from new nominators will be rejected (they will bounce back to the sender).
Nominator's withdrawal
In order for the nominator to make a withdrawal, he needs to send message to nominator-pool smart contract with text comment "w" and some Toncoins for network fee (1 TON is enough). Unspent TONs attached to message will be returned except in very rare cases.
If there are enough Toncoins on the balance of the nominator-pool, the withdrawal will be made immediately. All funds will be on the balance of the nominator-pool when it has completed participation in the validation round, but has not yet submitted a request for participation in a new round.
If there are not enough Toncoins on the nominator-pool balance, then a withdraw_request
will be made for the nominator, and the Toncoins will be withdrawn after the end of the current validation round.
The nominator can only withdraw all of his funds at once. Partial withdrawal not supported.
Validator withdraw
The validator can withdraw from the pool all the Toncoins that does not belong to the nominators.
Participants must keep their private keys
If the nominator loses access to his wallet from which he made the deposit, he will not be able to withdraw his funds from the pool.
If the validator loses access to his wallet, then he will not be able to withdraw his (validator's) funds from the pool.
Loss of the wallet's private key of one pool participant does not affect other participants.
Emergency withdrawal
When operating normally, the validator must periodically send operational messages to the nominator pool, such as process withdraw requests
, update current validator set
, new_stake
, recover_stake
.
The validator software mytonctrl does this automatically.
In an emergency, for example if a validator goes missing and ceases to perform his duties, these operational messages can be sent by anyone and thus the nominators can withdraw their funds.
Voting for network config proposals
In TON, network configuration changes occur by voting of validators.
In the case of a nominator pool, it is make sense to all participants can vote, and the final result would be sent on behalf of the pool.
Thus, the nominator pool smart contract has a built-in functionality where the validator and nominators can indicate their vote for/against a specific proposal.
Based on such a vote, the validator sends the final vote to the network configuration smart contract through the validator software.
If the validator sent the final vote to the network configuration smart contract, and the vote does not match the opinion of the majority in the pool, in this case, the nominators can leave (and will leave) this pool and move to another one.
Since everything happens through transactions on-chain, such a mismatch will be stored on the blockchain and visible to everyone.
Nominator`s vote
Each new network configuration change proposal is initially posted to the TON Foundation channels @tonblockchain or @tonstatus.
In this post, in addition to the description of the proposal, the proposal's hash will be indicated in HEX form, e.g D855FFBCF813E50E10BEAB902D1177529CE79785CAE913EB96A72AE8EFBCBF47
.
In order for the nominator to vote for the proposal, he needs to send a message to the nominator pool smart contract with a text comment y<HASH>
.
In order for the nominator to vote against the proposal, he needs to send a message to the nominator pool smart contract with a text comment n<HASH>
.
Some amount of tokens must be attached to this message in order to pay the network fee (1 TON is enough). Unspent TONs attached to message will be returned.
Votes are stored in the pool contract for 30 days.
Only the validator and current nominators who have an active stake in the pool can vote.
Get-method get_pool_data
Returns:
- state - uint - current state of nominator pool. 0 - does not participate in validation, 1 - sent a
new_stake
request to participate in the validation round, 2 - received a successful confirmation about participation in the validation round. - nominators_count - uint - current number of nominators in the pool.
- stake_amount_sent - nanotons - with such a stake amount, the pool participates in the current round of validation.
- validator_amount - nanotons - amount of coins owned by the validator.
- validator_address - immutable - uint - validator wallet address. To get the address do
"-1:" + dec_to_hex(validator_address)
. - validator_reward_share - immutable - uint - what share of the reward from validation goes to the validator.
validator_reward = (reward * validator_reward_share) / 10000
. For example set 4000 to get 40%. - max_nominators_count - immutable - uint - the maximum number of nominators in this pool.
- min_validator_stake - immutable - nanotons - minimum stake for a validator in this pool.
- min_nominator_stake - immutable - nanotons - minimum stake for a nominator in this pool.
- nominators - Cell - raw dictionary with nominators.
- withdraw_requests - Cell - raw dictionary with withdrawal requests from nominators.
- stake_at - uint - ID of the validation round in which we are/are going to participate. Supposed start of next validation round (
utime_since
). - saved_validator_set_hash - uint - technical information.
- validator_set_changes_count - uint - technical information.
- validator_set_change_time - uint - technical information.
- stake_held_for - uint - technical information.
- config_proposal_votings - Cell - raw dictionary with config proposals votings.
Get-method list_nominators
Returns list of current pool's nominators.
Each entry contains:
- address - uint - nominator wallet address. To get the address do
"0:" + dec_to_hex(address)
. - amount - nanotons - current active stake of the nominator.
- pending_deposit_amount - nanotons - deposit amount that will be added to the nominator's active stake at the next round of validation.
- withdraw_request - int - if
-1
then this nominator sent a request to withdraw all of his funds.
Get-method get_nominator_data
It takes as an argument the address of the nominator and returns:
- amount - nanotons - current active stake of the nominator.
- pending_deposit_amount - nanotons - deposit amount that will be added to the nominator's active stake at the next round of validation.
- withdraw_request - int - if
-1
then this nominator sent a request to withdraw all of his funds.
Throws an 86
error if there is no such nominator in the pool.
To get a nominator for example with an address EQA0i8-CdGnF_DhUHHf92R1ONH6sIA9vLZ_WLcCIhfBBXwtG
you need to convert address to raw form 0:348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f
, drop 0:
and invoke get_nominator_data 0x348bcf827469c5fc38541c77fdd91d4e347eac200f6f2d9fd62dc08885f0415f
.
Get-method list_votes
Returns list of votes.
Each entry contains:
- proposal_hash - uint - hash of proposal. Use
dec_to_hex(proposal_hash)
to convert hash to HEX form. - votes_create_time - uint - the unixtime this vote was created.
Get-method list_voters
It takes as an argument the hash of the proposal and returns list of voters:
Each entry contains:
- address - voter's address. To get the nominator address do
"0:" + dec_to_hex(address)
, ifaddress = validator_address
do"-1:" + dec_to_hex(address)
. - support - int - if
-1
then it is a "vote for", otherwise it is a "vote against". - vote_time - uint - unixtime when he voted.
Voting results are calculated off-chain.
Integration into wallet applications
For deposits, withdrawals and votes, send simple messages to the pool with the desired text comments as described above.
When sending a deposit, you can store the amount that was sent in the local storage.
When sending a re-deposit, add it to this amount too.
To find out the current profit, call the get method get_nominator_data(your_address)
. Profit will be (amount + pending_deposit_amount - sent_amount_stored_in_local_storage
).
To get information about a pool, call get_pool_data
and list_nominators
get-methods.