Single Nominator Pool
Single Nominator is a TON smart contract that enables secure validation for TON blockchain. The contract is designed for TON validators that have enough self stake to validate by themselves without relying on third-party nominators stakes. The contract provides an alternative simplified implementation for the Nominator Pool smart contract that supports a Single Nominator only.
Set up single-nominator
Before start make sure you have topped up and activated validator's wallet.
- Enable single nominator mode
MyTonCtrl> enable_mode single-nominator
- Check if single-nominator mode is enabled.
MyTonCtrl> status_modes
Name Status Description
single-nominator enabled Orbs's single nominator pools.
- Create pool
MyTonCtrl> new_single_pool <pool-name> <owner_address>
If you have already created pool it's possible to import it:
MyTonCtrl> import_pool <pool-name> <pool-addr>
- Type
pools_list
to display pool addresses
MyTonCtrl> pools_list
Name Status Balance Version Address
test-pool empty 0.0 spool_r2 kf_JcC5pn3etTAdwOnc16_tyMmKE8-ftNUnf0OnUjAIdDJpX
- Activate the pool
MyTonCtrl> activate_single_pool <pool-name>
After successfully activated pool:
MyTonCtrl> pools_list
Name Status Balance Version Address
test-pool active 0.99389 spool_r2 kf_JcC5pn3etTAdwOnc16_tyMmKE8-ftNUnf0OnUjAIdDJpX
Now you can work with this pool via mytonctrl like with a standard nominator pool.
If the pool's balance is enough to participate in both rounds (balance > min_stake_amount * 2
) then MyTonCtrl will automatically participate in both rounds using stake = balance / 2
, unless user sets stake manually using command set stake
. This behaviour is different from using a nominator pool but similar to staking using validator wallet.
Start without mytonctrl
Prepare launched Validator
If you have mytonctrl installed and validator running:
- Stop validation and withdraw all funds.
Prepare from the beginning
If you had no Validator before, do the following:
- Run a Validator and make sure it's synced.
- Stop validation and withdraw all funds.
Prepare Single Nominator
Install nodejs v.16 and later and npm (detailed instructions)
Install
ts-node
andarg
module
$ sudo apt install ts-node
$ sudo npm i arg -g
- Create symlinks for compilers:
$ sudo ln -s /usr/bin/ton/crypto/fift /usr/local/bin/fift
$ sudo ln -s /usr/bin/ton/crypto/func /usr/local/bin/func
- Run test to make sure everything is set up properly:
$ npm run test
- Replace mytonctrl nominator-pool scripts: https://raw.githubusercontent.com/orbs-network/single-nominator/main/mytonctrl-scripts/install-pool-scripts.sh
Create Single Nominator Pool
- Get Toncenter API key from a Telegram @tonapibot
- Set env variables:
export OWNER_ADDRESS=<owner_address>
export VALIDATOR_ADDRESS=<validator_wallet_address>
export TON_ENDPOINT=https://toncenter.com/api/v2/jsonRPC
export TON_API_KEY=<toncenter api key>
- Create deployer address:
$ npm run init-deploy-wallet
Insufficient Deployer [EQAo5U...yGgbvR] funds 0
- Topup deployer address with 2.1 TON
- Deploy pool contract, you will get pool address:
Ef-kC0..._WLqgs
:
$ npm run deploy
- Convert address to .addr:
$ fift -s ./scripts/fift/str-to-addr.fif Ef-kC0..._WLqgs
(Saving address to file single-nominator.addr)
- Backup deployer private key "./build/deploy.config.json" and "single-nominator.addr" files
- Copy "single-nominator.addr" to "mytoncore/pools/single-nominator-1.addr"
- Send stake from owner address to single nominator address
Withdrawals from Single Nominator
Using wallets to withdraw from Single Nominator Fift:
- Create "withdraw.boc" request with amount:
$ fift -s ./scripts/fift/withdraw.fif <withdraw_amount>
- Create and sign request from owner's wallet:
$ fift -s wallet-v3.fif <my-wallet> <single_nominator_address> <sub_wallet_id> <seqno> <amount=1> -B withdraw.boc
- Broadcast query:
$ lite-client -C global.config.json -c 'sendfile wallet-query.boc'
tons
- Create "withdraw.boc" request with amount:
$ fift -s ./scripts/fift/withdraw.fif <withdraw_amount>
- Send request to single nominator address:
a.
$ tons wallet transfer <my-wallet> <single_nominator_address> <amount=1> --body withdraw.boc
tonkeeper
b.
npm link typescript
c.
npx ts-node scripts/ts/withdraw-deeplink.ts <single-nominator-addr> <withdraw-amount>
d. Open deeplink on the owner's phone
Deposit pool
You can make a deposit using MyTonCtrl, using the following commands:
MyTonCtrl> mg <from-wallet-name> <pool-account-addr> <amount>
or
MyTonCtrl> deposit_to_pool <pool-addr> <amount>
which deposits pool from validator wallet.
Or use the following steps:
Go to the pool’s page https://tonscan.org/nominator/<pool_address>.
Make sure that the information about the pool is fully displayed, if the pool has the wrong smart contract, there will be no information.
Press the
ADD STAKE
button or scan the QR-code using Tonkeeper or any other TON Wallet.After you are transferred to the wallet, please, enter the amount of TON and then send the transaction. After that TON coins will be added to staking.
If the wallet does not open automatically, you can send the transaction manually by copying the pool address. Send it through any TON wallet. From the sent transaction, 1 TON will be debited as a commission for processing the deposit.
Withdraw funds
To get coins back after staking, send 1 TON to the pool’s address, add a comment w (small letter) to the transaction. This 1 TON minus commission will be returned, and a smart-contract will understand that you want to bring the coins back and it will send them back right after the end of the validator’s work cycle. It usually takes up to 18 hours on Mainnet and 2 hours on Testnet.
You can also withdraw funds using the following command:
MyTonCtrl> withdraw_from_pool <pool-addr> <amount>
Or you can create and send transaction manually:
- JS (@ton)
- Golang
import { Address, beginCell, internal, storeMessageRelaxed, toNano } from "@ton/core";
async function main() {
const single_nominator_address = Address.parse('single nominator address');
const WITHDRAW_OP = 0x1000
const amount = 50000
const messageBody = beginCell()
.storeUint(WITHDRAW_OP, 32) // op code for withdrawal
.storeUint(0, 64) // query_id
.storeCoins(amount) // amount to withdraw
.endCell();
const internalMessage = internal({
to: single_nominator_address,
value: toNano('1'),
bounce: true,
body: messageBody
});
}
func WithdrawSingleNominatorMessage(single_nominator_address string, query_id, amount uint64) (*tonconnect.Message, error) {
const WITHDRAW_OP = 0x1000
payload, _ := cell.BeginCell().
MustStoreUInt(WITHDRAW_OP, 32). // op code for withdrawal
MustStoreUInt(query_id, 64). // query_id
MustStoreCoins(amount). // amount to withdraw
EndCell().MarshalJSON()
msg, err := tonconnect.NewMessage(
single_nominator_address,
tlb.MustFromTON("1").Nano().String(), // nanocoins to transfer/compute message
tonconnect.WithPayload(payload))
if err != nil {
return nil, err
}
return msg, nil
}
Election process
Set up a Single Nominator Pool
Configure the Single Nominator Pool contract using the following instructions.
Join the elections
Deposit minimum stake amount to the Single Nominator Pool.
MyTonCtrl will automatically join the elections. You can set the stake amount that mytonctrl sends to the Elector contract ~ every 18 hours on Mainnet and 2 hours on Testnet.
MyTonCtrl> set stake 90000
Minimum stake amount could be found using status
command.
You can set stake
as null
and it will be calculated according to the stakePercent
value (could be checked with status_settings
command).
It's possible to check is election has already been started:
MyTonCtrl> status
and for Testnet:
MyTonCtrl> status fast
As example:
If the election has been started and Single Nominator Pool is activated, validator should automatically send ElectorNewStake message to the Elector contract at the beginning of the next round.
Check validator wallet:
MyTonCtrl> wl
Name Status Balance Ver Wch Address
validator_wallet_001 active 995.828585374 v1 -1 kf_dctjwS4tqWdeG4GcCLJ53rkgxZOGGrdDzHJ_mxPkm_Xct
Then check it transaction history:
MyTonCtrl> vas kf_dctjwS4tqWdeG4GcCLJ53rkgxZOGGrdDzHJ_mxPkm_Xct
Address Status Balance Version
kf_dctjwS4tqWdeG4GcCLJ53rkgxZOGGrdDzHJ_mxPkm_Xct active 995.828585374 v1r3
Code hash
c3b9bb03936742cfbb9dcdd3a5e1f3204837f613ef141f273952aa41235d289e
Time Coins From/To
39 minutes ago >>> 1.3 kf_hz3BIXrn5npis1cPX5gE9msp1nMTYKZ3l4obzc8phrBfF
This ElectorNewStake transaction in Single Nominator contract history in Tonviewer:
On the above example MyTonCtrl automatically stake 90000
Toncoins on the Elector contract.
Checking Validator Status
At the beginning of the next round check MyTonCtrl validator status with status
command (status fast
on Testnet).
You can confirm if your node has become a full validator by checking the following conditions:
- Validator Efficiency - An efficiency of the local validator should be green and not
n/a
. - Validator Index - The validator index should be greater than -1.
Checking profit
At the end of the round MyTonCtrl sends ElectorRecoverStakeRequest message to the Elector contract. It responses with stake + profit
amount of Toncoins to your Single Nominator Pool.
You can also check transactions history of your pool with vas
command:
Stop participating
If user doesn't want to take part in validating anymore:
- Disable validator mode:
MyTonCtrl> disable_mode validator
- Withdraw all funds from the Single Nominator contract to the owner wallet.
Transitioning a Regular Validator to Nominator Pool Mode
- Disable
validator
mode to discontinue election participation. - Await the return of both your stakes from the elector.
- Proceed with the following steps.