From 7751ea92793fb84796b966527185143cede4940a Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Thu, 14 Nov 2024 17:08:16 +0000 Subject: [PATCH 1/6] Add TON Pool and split stakers --- packages/staking-cli/src/cmd/ton.ts | 86 +++- .../ton/src/{staker.ts => TonBaseStaker.ts} | 444 ++---------------- packages/ton/src/TonNominatorPoolStaker.ts | 201 ++++++++ packages/ton/src/TonPoolStaker.ts | 126 +++++ .../ton/src/TonSingleNominatorPoolStaker.ts | 219 +++++++++ packages/ton/src/index.ts | 5 +- 6 files changed, 660 insertions(+), 421 deletions(-) rename packages/ton/src/{staker.ts => TonBaseStaker.ts} (52%) create mode 100644 packages/ton/src/TonNominatorPoolStaker.ts create mode 100644 packages/ton/src/TonPoolStaker.ts create mode 100644 packages/ton/src/TonSingleNominatorPoolStaker.ts diff --git a/packages/staking-cli/src/cmd/ton.ts b/packages/staking-cli/src/cmd/ton.ts index 5abe88a..cfd25be 100644 --- a/packages/staking-cli/src/cmd/ton.ts +++ b/packages/staking-cli/src/cmd/ton.ts @@ -7,7 +7,7 @@ import type { SignerType } from '../enums' import { prompt, readConfig, getNetworkConfig, log, defaultLogger } from '../util' import { SafeJSONStringify } from '@chorus-one/utils' import { newSigner } from '../signer' -import { TonStaker } from '@chorus-one/ton' +import { TonPoolStaker, TonNominatorPoolStaker, TonSingleNominatorPoolStaker } from '@chorus-one/ton' export interface CLINetworkConfig extends TonNetworkConfig { // block explorer URL to display Transaction ID via Web UI. Example: @@ -29,6 +29,16 @@ function makeTxCommand (): Command { .option('-b, --broadcast', 'broadcast generated transaction', false) .option('-j, --journal ', "write TX'es to the local journal log", 'true') + tx.command('delegate-pool') + .description('generate a delegate funds to TON pool contract transaction') + .argument('', 'amount of tokens to stake expressed in TON denom e.g 0.1') + .action(getDelegatePoolTx) + + tx.command('unstake-pool') + .description('generate a unstake funds to TON pool contract transaction') + .argument('', 'amount of tokens to unstake expressed in TON denom e.g 0.1') + .action(getUnstakePoolTx) + tx.command('delegate-nominator-pool') .description('generate a delegate funds to TON nominator pool contract transaction') .argument('', 'amount of tokens to stake expressed in TON denom e.g 0.1') @@ -70,11 +80,11 @@ async function init ( const networkConfig = getNetworkConfig(config) const signer = await newSigner(config, signerType as SignerType, { - addressDerivationFn: TonStaker.getAddressDerivationFn({ + addressDerivationFn: TonNominatorPoolStaker.getAddressDerivationFn({ addressDerivationConfig: networkConfig.addressDerivationConfig }), - mnemonicToSeedFn: TonStaker.getMnemonicToSeedFn(), - seedToKeypairFn: TonStaker.getSeedToKeypairFn(), + mnemonicToSeedFn: TonNominatorPoolStaker.getMnemonicToSeedFn(), + seedToKeypairFn: TonNominatorPoolStaker.getSeedToKeypairFn(), keyType: KeyType.ED25519, logger: defaultLogger }) @@ -95,9 +105,6 @@ async function runTx ( const [config, signer] = await init(cmd) const networkConfig = getNetworkConfig(config) - const tonStaker: TonStaker = new TonStaker({ ...networkConfig }) - await tonStaker.init() - const logger = defaultLogger logger.info(0, 3, 'inspect input data') @@ -117,11 +124,42 @@ async function runTx ( let unsignedTx: UnsignedTx | undefined + let tonStaker: TonPoolStaker | TonNominatorPoolStaker | TonSingleNominatorPoolStaker + try { switch (msgType) { + case 'delegate-pool': { + tonStaker = new TonPoolStaker({ ...networkConfig }) + await tonStaker.init() + + unsignedTx = ( + await tonStaker.buildStakeTx({ + delegatorAddress: config.delegatorAddress, + validatorAddress: config.validatorAddress, + amount: arg[0] // amount + }) + ).tx + break + } + case 'unstake-pool': { + tonStaker = new TonPoolStaker({ ...networkConfig }) + await tonStaker.init() + + unsignedTx = ( + await tonStaker.buildUnstakeTx({ + delegatorAddress: config.delegatorAddress, + validatorAddress: config.validatorAddress, + amount: arg[0] // amount + }) + ).tx + break + } case 'delegate-nominator-pool': { + tonStaker = new TonNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( - await tonStaker.buildStakeNominatorPoolTx({ + await tonStaker.buildStakeTx({ delegatorAddress: config.delegatorAddress, validatorAddress: config.validatorAddress, amount: arg[0] // amount @@ -130,8 +168,11 @@ async function runTx ( break } case 'unstake-nominator-pool': { + tonStaker = new TonNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( - await tonStaker.buildUnstakeNominatorPoolTx({ + await tonStaker.buildUnstakeTx({ delegatorAddress: config.delegatorAddress, validatorAddress: config.validatorAddress }) @@ -139,8 +180,11 @@ async function runTx ( break } case 'delegate-single-nominator-pool': { + tonStaker = new TonSingleNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( - await tonStaker.buildStakeSingleNominatorPoolTx({ + await tonStaker.buildStakeTx({ delegatorAddress: config.delegatorAddress, validatorAddress: config.validatorAddress, amount: arg[0] // amount @@ -149,8 +193,11 @@ async function runTx ( break } case 'unstake-single-nominator-pool': { + tonStaker = new TonSingleNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( - await tonStaker.buildUnstakeSingleNominatorPoolTx({ + await tonStaker.buildUnstakeTx({ delegatorAddress: config.delegatorAddress, validatorAddress: config.validatorAddress, amount: arg[0] // amount @@ -159,6 +206,9 @@ async function runTx ( break } case 'transfer': { + tonStaker = new TonNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( await tonStaker.buildTransferTx({ destinationAddress: config.validatorAddress, @@ -168,6 +218,9 @@ async function runTx ( break } case 'deploy-wallet': { + tonStaker = new TonNominatorPoolStaker({ ...networkConfig }) + await tonStaker.init() + unsignedTx = ( await tonStaker.buildDeployWalletTx({ address: config.delegatorAddress @@ -175,6 +228,9 @@ async function runTx ( ).tx break } + default: { + cmd.error('unsupported message type', { exitCode: 1, code: `${msgType}.tx.unsupported` }) + } } } catch (e: any) { cmd.error(e, { exitCode: 1, code: msgType + '.tx.sign' }) @@ -224,6 +280,14 @@ async function runTx ( } } +async function getDelegatePoolTx (amount: string, options: any, cmd: Command<[string]>): Promise { + await runTx('delegate-pool', options, cmd, [amount]) +} + +async function getUnstakePoolTx (amount: string, options: any, cmd: Command<[string]>): Promise { + await runTx('unstake-pool', options, cmd, [amount]) +} + async function getDelegateNominatorPoolTx (amount: string, options: any, cmd: Command<[string]>): Promise { await runTx('delegate-nominator-pool', options, cmd, [amount]) } diff --git a/packages/ton/src/staker.ts b/packages/ton/src/TonBaseStaker.ts similarity index 52% rename from packages/ton/src/staker.ts rename to packages/ton/src/TonBaseStaker.ts index 636e181..e52ce1e 100644 --- a/packages/ton/src/staker.ts +++ b/packages/ton/src/TonBaseStaker.ts @@ -2,12 +2,11 @@ import type { Signer } from '@chorus-one/signer' import type { TonNetworkConfig, TonSigningData, - NominatorInfo, - PoolData, AddressDerivationConfig, UnsignedTx, SignedTx, - TonTxStatus + TonTxStatus, + PoolData } from './types' import { toNano, @@ -16,13 +15,9 @@ import { WalletContractV4, internal, MessageRelaxed, - TupleReader, - TupleItem, SendMode, Address, - TransactionDescriptionGeneric, - beginCell, - Cell + TransactionDescriptionGeneric } from '@ton/ton' import { createWalletTransferV4, externalMessage, sign } from './tx' import * as tonMnemonic from 'tonweb-mnemonic' @@ -33,10 +28,10 @@ import { ed25519 } from '@noble/curves/ed25519' * * It also provides the ability to retrieve staking information and rewards for a delegator. */ -export class TonStaker { - private readonly networkConfig: Required - private readonly addressDerivationConfig: AddressDerivationConfig - private client?: TonClient +export class TonBaseStaker { + protected readonly networkConfig: Required + protected readonly addressDerivationConfig: AddressDerivationConfig + protected client?: TonClient /** * This **static** method is used to derive an address from a public key. @@ -136,265 +131,6 @@ export class TonStaker { }) } - /** - * Builds a staking (delegation) transaction for Nominator Pool contract. - * For more information see: https://github.com/ton-blockchain/nominator-pool - * - * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address to stake from - * @param params.validatorAddress - The validator address to stake to - * @param params.amount - The amount to stake, specified in `TON` - * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires - * - * @returns Returns a promise that resolves to a TON nominator pool staking transaction. - */ - async buildStakeNominatorPoolTx (params: { - delegatorAddress: string - validatorAddress: string - amount: string - validUntil?: number - }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, amount, validUntil } = params - - // ensure the address is for the right network - this.checkIfAddressTestnetFlagMatches(validatorAddress) - - // ensure the validator address is bounceable. - // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. - // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent - if (!Address.parseFriendly(validatorAddress).isBounceable) { - throw new Error( - 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' - ) - } - - // this is also a somewhat okay way to check the contract is indeed a staking pool contract - const data = await this.getContractPoolData(validatorAddress) - if (data.nominators_count >= data.max_nominators_count) { - throw new Error('validator has reached the maximum number of nominators') - } - - // ensure we stake at least the minimum required amount - const nominators = (await this.getPoolContractNominators({ validatorAddress })).nominators - const ourNominator = nominators.find((n) => Address.parseRaw(n.address).equals(Address.parse(delegatorAddress))) - const amountStaked = ourNominator ? toNano(ourNominator.amount) : BigInt(0) - const amountToStake = toNano(amount) - - if (amountToStake + amountStaked < data.min_nominator_stake) { - throw new Error( - `amount to stake (${fromNano(amountToStake)}) is less than the minimum stake required (${fromNano(data.min_nominator_stake)})` - ) - } - - const tx = { - validUntil: defaultValidUntil(validUntil), - message: { - address: validatorAddress, - // to stake tokens we need to send a large amount of tokens - // it is critical that the transaction is bounceable - // otherwise in the case of contract failure we may loose tokens! - bounceable: true, - amount: toNano(amount), - payload: 'd' // 'd' for deposit / delegation - } - } - - return { tx } - } - - /** - * Builds an unstaking (withdraw nominator) transaction for Nominator Pool contract. - * For more information see: https://github.com/ton-blockchain/nominator-pool - * - * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address - * @param params.validatorAddress - The validator address to unstake from - * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires - * - * @returns Returns a promise that resolves to a TON nominator pool unstaking transaction. - */ - async buildUnstakeNominatorPoolTx (params: { - delegatorAddress: string - validatorAddress: string - validUntil?: number - }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, validUntil } = params - - // "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." - // - // source: https://github.com/ton-blockchain/nominator-pool?tab=readme-ov-file#nominators-withdrawal - const amount = '1' // 1 TON - - // ensure the address is for the right network - this.checkIfAddressTestnetFlagMatches(validatorAddress) - - // ensure the validator address is bounceable. - // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. - // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent - if (!Address.parseFriendly(validatorAddress).isBounceable) { - throw new Error( - 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' - ) - } - - // this is also a somewhat okay way to check the contract is indeed a staking pool contract - const data = await this.getContractPoolData(validatorAddress) - if (data.nominators_count === 0) { - throw new Error('there is no nominators currently staking to the nominator pool contract') - } - - // ensure that the delegator has staked to the validator - const nominators = (await this.getPoolContractNominators({ validatorAddress })).nominators - const ourNominator = nominators.find((n) => Address.parseRaw(n.address).equals(Address.parse(delegatorAddress))) - if (!ourNominator) { - throw new Error('delegator is not staking to the nominator pool contract') - } - - const tx = { - validUntil: defaultValidUntil(validUntil), - message: { - address: validatorAddress, - // to unstake tokens we need to send a some tokens that should - // be returned to us in case of error - bounceable: true, - amount: toNano(amount), - payload: 'w' // 'w' for withdraw - } - } - - return { tx } - } - - /** - * Builds a staking (delegation) transaction for Single Nominator Pool contract. - * For more information see: https://github.com/orbs-network/single-nominator/tree/main - * - * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address to stake from - * @param params.validatorAddress - The validator address to stake to - * @param params.amount - The amount to stake, specified in `TON` - * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires - * - * @returns Returns a promise that resolves to a TON nominator pool staking transaction. - */ - async buildStakeSingleNominatorPoolTx (params: { - delegatorAddress: string - validatorAddress: string - amount: string - validUntil?: number - }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, amount, validUntil } = params - - // ensure the address is for the right network - this.checkIfAddressTestnetFlagMatches(validatorAddress) - - // ensure the validator address is bounceable. - // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. - // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent - if (!Address.parseFriendly(validatorAddress).isBounceable) { - throw new Error( - 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' - ) - } - - // be sure the delegator is the owner of the contract otherwise we can't withdraw the funds back - const roles = await this.getContractRoles(validatorAddress) - if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { - throw new Error('delegator is not the owner of the single nominator pool contract') - } - - // this serves purely as a sanity check - const data = await this.getContractPoolData(validatorAddress) - if (data.nominators_count !== 1) { - throw new Error('the single nominator pool contract is expected to have exactly one nominator') - } - - const tx = { - validUntil: defaultValidUntil(validUntil), - message: { - address: validatorAddress, - // to stake tokens we need to send a large amount of tokens - // it is critical that the transaction is bounceable - // otherwise in the case of contract failure we may loose tokens! - bounceable: true, - amount: toNano(amount), - payload: Cell.EMPTY - } - } - - return { tx } - } - - /** - * Builds a unstaking (withdraw nominator) transaction for Single Nominator Pool contract. - * For more information see: https://github.com/orbs-network/single-nominator/tree/main - * - * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address - * @param params.validatorAddress - The validator address to unstake from - * @param params.amount - The amount to unstake, specified in `TON` - * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires - * - * @returns Returns a promise that resolves to a TON nominator pool unstaking transaction. - */ - async buildUnstakeSingleNominatorPoolTx (params: { - delegatorAddress: string - validatorAddress: string - amount: string - validUntil?: number - }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, amount, validUntil } = params - - // ensure the address is for the right network - this.checkIfAddressTestnetFlagMatches(validatorAddress) - - // ensure the validator address is bounceable. - // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. - // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent - if (!Address.parseFriendly(validatorAddress).isBounceable) { - throw new Error( - 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' - ) - } - - // only onwer can withdraw the funds - const roles = await this.getContractRoles(validatorAddress) - if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { - throw new Error('delegator is not the owner of the single nominator pool contract') - } - - // this serves purely as a sanity check - const data = await this.getContractPoolData(validatorAddress) - if (data.nominators_count !== 1) { - throw new Error('the single nominator pool contract is expected to have exactly one nominator') - } - - // source: https://github.com/orbs-network/single-nominator/tree/main?tab=readme-ov-file#1-withdraw - // https://github.com/orbs-network/single-nominator/blob/main/scripts/ts/withdraw-deeplink.ts#L7C5-L7C137 - const payload = beginCell().storeUint(0x1000, 32).storeUint(1, 64).storeCoins(toNano(amount)).endCell() - - // 1 TON should be enough to cover the transaction fees (similar to nominator pool contract) - const amountToCoverTxFees = '1' - - // ensure we don't drain the validator wallet by accident - this.checkMinimumExistentialBalance(validatorAddress, amount) - - const tx = { - validUntil: defaultValidUntil(validUntil), - message: { - address: validatorAddress, - // to unstake tokens we need to send a some tokens that should - // be returned to us in case of error - bounceable: true, - amount: toNano(amountToCoverTxFees), - payload - } - } - - return { tx } - } - /** * Builds a token transfer transaction * @@ -489,47 +225,6 @@ export class TonStaker { return { tx } } - /** - * Retrieves the active nominators for a Nominator Pool contract. - * For more information see: https://github.com/ton-blockchain/nominator-pool - * - * @param params - Parameters for the request - * @param params.validatorAddress - The validator address to gather rewards data from - * - * @returns Returns a promise that resolves to the nominator data for the validator address. - */ - async getPoolContractNominators (params: { validatorAddress: string }): Promise<{ nominators: NominatorInfo[] }> { - const client = this.getClient() - const { validatorAddress } = params - - // ensure the address is for the right network - this.checkIfAddressTestnetFlagMatches(validatorAddress) - - const response = await client.runMethod(Address.parse(validatorAddress), 'list_nominators', []) - - // @ts-expect-error the library does not handle 'list' type well. This is a workaround to get the data out of the 'list' type - const reader = new TupleReader(response.stack.pop().items as TupleItem[]) - - // extract nominators from contract response - const nominators: NominatorInfo[] = [] - - if (reader.remaining > 0) { - do { - const x = reader.readTuple() - nominators.push({ - // The nominator pool contract allows only the basechain addresses (`0:`) - // https://github.com/ton-blockchain/nominator-pool/blob/main/func/pool.fc#L618 - address: `0:${BigInt(x.readBigNumber()).toString(16)}`, - amount: fromNano(x.readBigNumber()), - pending_deposit_amount: fromNano(x.readBigNumber()), - withdraw_requested: fromNano(x.readBigNumber()) - }) - } while (reader.remaining) - } - - return { nominators } - } - /** * Retrieves the account balance * @@ -549,48 +244,6 @@ export class TonStaker { return { amount: fromNano(amount) } } - /** - * Retrieves the staking information for a specified delegator. - * - * @param params - Parameters for the request - * @param params.delegatorAddress - The delegator (wallet) address - * @param params.validatorAddress - The validator address to gather rewards data from - * @param params.contractType - The validator contract type (single-nominator-pool or nominator-pool) - * - * @returns Returns a promise that resolves to the staking information for the specified delegator. - */ - async getStake (params: { - delegatorAddress: string - validatorAddress: string - contractType: 'single-nominator-pool' | 'nominator-pool' - }): Promise<{ balance: string }> { - const { delegatorAddress, validatorAddress, contractType } = params - - if (contractType === 'nominator-pool') { - const { nominators } = await this.getPoolContractNominators({ validatorAddress }) - if (nominators.length === 0) { - return { balance: '0' } - } - - const nominator = nominators.find((n) => Address.parse(n.address).equals(Address.parse(delegatorAddress))) - if (nominator === undefined) { - return { balance: '0' } - } - - return { balance: nominator.amount } - } - - // otherise it is a single nominator pool contract - const roles = await this.getContractRoles(validatorAddress) - if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { - throw new Error('delegator is not the owner of the single nominator pool contract') - } - - const balance = await this.getBalance({ address: validatorAddress }) - - return { balance: balance.amount } - } - /** * Signs a transaction using the provided signer. * @@ -776,7 +429,7 @@ export class TonStaker { return { status: 'success', receipt: transaction } } - private getClient (): TonClient { + protected getClient (): TonClient { if (!this.client) { throw new Error('TonStaker not initialized. Did you forget to call init()?') } @@ -784,27 +437,31 @@ export class TonStaker { return this.client } - private async getContractRoles ( - contractAddress: string - ): Promise<{ ownerAddress: Address; validatorAddress: Address }> { - const client = this.getClient() - const response = await client.runMethod(Address.parse(contractAddress), 'get_roles', []) + protected checkIfAddressTestnetFlagMatches (address: string): void { + const addr = Address.parseFriendly(address) - // reference: https://github.com/orbs-network/single-nominator/blob/main/contracts/single-nominator.fc#L186 - if (response.stack.remaining !== 2) { - throw new Error('invalid get_pool_data response, expected 17 fields got ' + response.stack.remaining) + if (addr.isTestOnly !== this.addressDerivationConfig.testOnly) { + if (addr.isTestOnly) { + throw new Error(`address ${address} is a testnet address but the configuration is for mainnet`) + } else { + throw new Error(`address ${address} is a mainnet address but the configuration is for testnet`) + } } + } - const ownerAddress = response.stack.readAddress() - const validatorAddress = response.stack.readAddress() + protected async checkMinimumExistentialBalance (address: string, amount: string): Promise { + const balance = await this.getBalance({ address }) + const minBalance = this.networkConfig.minimumExistentialBalance - return { - ownerAddress, - validatorAddress + if (toNano(balance.amount) - toNano(amount) < toNano(minBalance)) { + throw new Error( + `sending ${amount} would result in balance below the minimum existential balance of ${minBalance} for address ${address}` + ) } } - private async getContractPoolData (contractAddress: string): Promise { + // NOTE: this method is used only by Nominator and SingleNominator stakers, not by Pool + protected async getNominatorContractPoolData (contractAddress: string): Promise { const client = this.getClient() const response = await client.runMethod(Address.parse(contractAddress), 'get_pool_data', []) @@ -832,45 +489,6 @@ export class TonStaker { min_nominator_stake } } - - private async getSinglePoolContractRoles ( - contractAddress: string - ): Promise<{ ownerAddress: Address; validatorAddress: Address }> { - const client = this.getClient() - const response = await client.runMethod(Address.parse(contractAddress), 'get_roles', []) - - if (response.stack.remaining !== 2) { - throw new Error('invalid get_roles response, expected 2 fields got ' + response.stack.remaining) - } - - return { - ownerAddress: response.stack.readAddress(), - validatorAddress: response.stack.readAddress() - } - } - - private checkIfAddressTestnetFlagMatches (address: string): void { - const addr = Address.parseFriendly(address) - - if (addr.isTestOnly !== this.addressDerivationConfig.testOnly) { - if (addr.isTestOnly) { - throw new Error(`address ${address} is a testnet address but the configuration is for mainnet`) - } else { - throw new Error(`address ${address} is a mainnet address but the configuration is for testnet`) - } - } - } - - private async checkMinimumExistentialBalance (address: string, amount: string): Promise { - const balance = await this.getBalance({ address }) - const minBalance = this.networkConfig.minimumExistentialBalance - - if (toNano(balance.amount) - toNano(amount) < toNano(minBalance)) { - throw new Error( - `sending ${amount} would result in balance below the minimum existential balance of ${minBalance} for address ${address}` - ) - } - } } function defaultAddressDerivationConfig (): AddressDerivationConfig { @@ -893,6 +511,14 @@ function getWalletContract (version: number, workchain: number, publicKey: Buffe } } -function defaultValidUntil (validUntil?: number): number { +export function defaultValidUntil (validUntil?: number): number { return validUntil ?? Math.floor(Date.now() / 1000) + 180 // 3 minutes } + +export function getRandomQueryId () { + return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) +} + +export function getDefaultGas () { + return 100000 +} diff --git a/packages/ton/src/TonNominatorPoolStaker.ts b/packages/ton/src/TonNominatorPoolStaker.ts new file mode 100644 index 0000000..f5db1b2 --- /dev/null +++ b/packages/ton/src/TonNominatorPoolStaker.ts @@ -0,0 +1,201 @@ +import { Address, toNano, fromNano } from '@ton/ton' +import { defaultValidUntil, TonBaseStaker } from './TonBaseStaker' +import { NominatorInfo, UnsignedTx } from './types' + +export class TonNominatorPoolStaker extends TonBaseStaker { + /** + * Builds a staking (delegation) transaction for Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address to stake from + * @param params.validatorAddress - The validator address to stake to + * @param params.amount - The amount to stake, specified in `TON` + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool staking transaction. + */ + async buildStakeTx (params: { + delegatorAddress: string + validatorAddress: string + amount: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, amount, validUntil } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } + + // this is also a somewhat okay way to check the contract is indeed a staking pool contract + const data = await this.getNominatorContractPoolData(validatorAddress) + if (data.nominators_count >= data.max_nominators_count) { + throw new Error('validator has reached the maximum number of nominators') + } + + // ensure we stake at least the minimum required amount + const nominators = (await this.getPoolContractNominators({ validatorAddress })).nominators + const ourNominator = nominators.find((n) => Address.parseRaw(n.address).equals(Address.parse(delegatorAddress))) + const amountStaked = ourNominator ? toNano(ourNominator.amount) : BigInt(0) + const amountToStake = toNano(amount) + + if (amountToStake + amountStaked < data.min_nominator_stake) { + throw new Error( + `amount to stake (${fromNano(amountToStake)}) is less than the minimum stake required (${fromNano(data.min_nominator_stake)})` + ) + } + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + // to stake tokens we need to send a large amount of tokens + // it is critical that the transaction is bounceable + // otherwise in the case of contract failure we may loose tokens! + bounceable: true, + amount: toNano(amount), + payload: 'd' // 'd' for deposit / delegation + } + } + + return { tx } + } + + /** + * Builds an unstaking (withdraw nominator) transaction for Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address + * @param params.validatorAddress - The validator address to unstake from + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool unstaking transaction. + */ + async buildUnstakeTx (params: { + delegatorAddress: string + validatorAddress: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, validUntil } = params + + // "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." + // + // source: https://github.com/ton-blockchain/nominator-pool?tab=readme-ov-file#nominators-withdrawal + const amount = '1' // 1 TON + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } + + // this is also a somewhat okay way to check the contract is indeed a staking pool contract + const data = await this.getNominatorContractPoolData(validatorAddress) + if (data.nominators_count === 0) { + throw new Error('there is no nominators currently staking to the nominator pool contract') + } + + // ensure that the delegator has staked to the validator + const nominators = (await this.getPoolContractNominators({ validatorAddress })).nominators + const ourNominator = nominators.find((n) => Address.parseRaw(n.address).equals(Address.parse(delegatorAddress))) + if (!ourNominator) { + throw new Error('delegator is not staking to the nominator pool contract') + } + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + // to unstake tokens we need to send a some tokens that should + // be returned to us in case of error + bounceable: true, + amount: toNano(amount), + payload: 'w' // 'w' for withdraw + } + } + + return { tx } + } + + /** + * Retrieves the staking information for a specified delegator. + * + * @param params - Parameters for the request + * @param params.delegatorAddress - The delegator (wallet) address + * @param params.validatorAddress - The validator address to gather rewards data from + * @param params.contractType - The validator contract type (single-nominator-pool or nominator-pool) + * + * @returns Returns a promise that resolves to the staking information for the specified delegator. + */ + async getStake (params: { delegatorAddress: string; validatorAddress: string }): Promise<{ balance: string }> { + const { delegatorAddress, validatorAddress } = params + const { nominators } = await this.getPoolContractNominators({ validatorAddress }) + if (nominators.length === 0) { + return { balance: '0' } + } + + const nominator = nominators.find((n) => Address.parse(n.address).equals(Address.parse(delegatorAddress))) + if (nominator === undefined) { + return { balance: '0' } + } + + return { balance: nominator.amount } + } + + /** + * Retrieves the active nominators for a Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for the request + * @param params.validatorAddress - The validator address to gather rewards data from + * + * @returns Returns a promise that resolves to the nominator data for the validator address. + */ + async getPoolContractNominators (params: { validatorAddress: string }): Promise<{ nominators: NominatorInfo[] }> { + const client = this.getClient() + const { validatorAddress } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + const response = await client.runMethod(Address.parse(validatorAddress), 'list_nominators', []) + + // @ts-expect-error the library does not handle 'list' type well. This is a workaround to get the data out of the 'list' type + const reader = new TupleReader(response.stack.pop().items as TupleItem[]) + + // extract nominators from contract response + const nominators: NominatorInfo[] = [] + + if (reader.remaining > 0) { + do { + const x = reader.readTuple() + nominators.push({ + // The nominator pool contract allows only the basechain addresses (`0:`) + // https://github.com/ton-blockchain/nominator-pool/blob/main/func/pool.fc#L618 + address: `0:${BigInt(x.readBigNumber()).toString(16)}`, + amount: fromNano(x.readBigNumber()), + pending_deposit_amount: fromNano(x.readBigNumber()), + withdraw_requested: fromNano(x.readBigNumber()) + }) + } while (reader.remaining) + } + + return { nominators } + } +} diff --git a/packages/ton/src/TonPoolStaker.ts b/packages/ton/src/TonPoolStaker.ts new file mode 100644 index 0000000..920da50 --- /dev/null +++ b/packages/ton/src/TonPoolStaker.ts @@ -0,0 +1,126 @@ +import { Address, beginCell, toNano } from '@ton/ton' +import { defaultValidUntil, getDefaultGas, getRandomQueryId, TonBaseStaker } from './TonBaseStaker' +import { UnsignedTx } from './types' + +export class TonPoolStaker extends TonBaseStaker { + /** + * Builds a staking (delegation) transaction for Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address to stake from + * @param params.validatorAddress - The validator address to stake to + * @param params.amount - The amount to stake, specified in `TON` + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool staking transaction. + */ + async buildStakeTx (params: { + delegatorAddress: string + validatorAddress: string + amount: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, amount, validUntil } = params + + const payload = beginCell() + .storeUint(2077040623, 32) + .storeUint(getRandomQueryId(), 64) // Query ID + .storeCoins(getDefaultGas()) // Gas + .endCell() + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + bounceable: true, + amount: toNano(amount), + payload + } + } + + return { tx } + } + + /** + * Builds a staking (delegation) transaction for Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address to stake from + * @param params.validatorAddress - The validator address to stake to + * @param params.amount - The amount to stake, specified in `TON` + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool staking transaction. + */ + async buildUnstakeTx (params: { + delegatorAddress: string + validatorAddress: string + amount: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, amount, validUntil } = params + + const data = await this.getOnePoolParams({ validatorAddress }) + + const payload = beginCell() + .storeUint(3665837821, 32) + .storeUint(getRandomQueryId(), 64) // Query ID + .storeCoins(getDefaultGas()) // Gas + .storeCoins(toNano(amount)) // Amount + .endCell() + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + bounceable: true, + amount: data.withdrawFee + data.receiptPrice, + payload + } + } + + return { tx } + } + + private async getOnePoolStake (params: { delegatorAddress: string; validatorAddress: string }) { + const { delegatorAddress, validatorAddress } = params + const client = this.getClient() + + const response = await client.runMethod(Address.parse(validatorAddress), 'get_member', [ + { type: 'slice', cell: beginCell().storeAddress(Address.parse(delegatorAddress)).endCell() } + ]) + + return { + balance: response.stack.readBigNumber(), + pendingDeposit: response.stack.readBigNumber(), + pendingWithdraw: response.stack.readBigNumber(), + withdraw: response.stack.readBigNumber() + } + } + + private async getOnePoolParams (params: { validatorAddress: string }) { + const { validatorAddress } = params + const client = this.getClient() + const response = await client.runMethod(Address.parse(validatorAddress), 'get_params', []) + + const result = { + enabled: response.stack.readBoolean(), + updatesEnables: response.stack.readBoolean(), + minStake: response.stack.readBigNumber(), + depositFee: response.stack.readBigNumber(), + withdrawFee: response.stack.readBigNumber(), + poolFee: response.stack.readBigNumber(), + receiptPrice: response.stack.readBigNumber() + } + + return { + minStake: result.minStake, + depositFee: result.depositFee, + withdrawFee: result.withdrawFee, + poolFee: result.poolFee, + receiptPrice: result.receiptPrice + } + } +} diff --git a/packages/ton/src/TonSingleNominatorPoolStaker.ts b/packages/ton/src/TonSingleNominatorPoolStaker.ts new file mode 100644 index 0000000..0f1c51a --- /dev/null +++ b/packages/ton/src/TonSingleNominatorPoolStaker.ts @@ -0,0 +1,219 @@ +import { Address, toNano, Cell, beginCell, fromNano } from '@ton/ton' +import { defaultValidUntil, TonBaseStaker } from './TonBaseStaker' +import { NominatorInfo, UnsignedTx } from './types' + +export class TonSingleNominatorPoolStaker extends TonBaseStaker { + /** + * Builds a staking (delegation) transaction for Single Nominator Pool contract. + * For more information see: https://github.com/orbs-network/single-nominator/tree/main + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address to stake from + * @param params.validatorAddress - The validator address to stake to + * @param params.amount - The amount to stake, specified in `TON` + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool staking transaction. + */ + async buildStakeTx (params: { + delegatorAddress: string + validatorAddress: string + amount: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, amount, validUntil } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } + + // be sure the delegator is the owner of the contract otherwise we can't withdraw the funds back + const roles = await this.getContractRoles(validatorAddress) + if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { + throw new Error('delegator is not the owner of the single nominator pool contract') + } + + // this serves purely as a sanity check + const data = await this.getNominatorContractPoolData(validatorAddress) + if (data.nominators_count !== 1) { + throw new Error('the single nominator pool contract is expected to have exactly one nominator') + } + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + // to stake tokens we need to send a large amount of tokens + // it is critical that the transaction is bounceable + // otherwise in the case of contract failure we may loose tokens! + bounceable: true, + amount: toNano(amount), + payload: Cell.EMPTY + } + } + + return { tx } + } + + /** + * Builds a unstaking (withdraw nominator) transaction for Single Nominator Pool contract. + * For more information see: https://github.com/orbs-network/single-nominator/tree/main + * + * @param params - Parameters for building the transaction + * @param params.delegatorAddress - The delegator address + * @param params.validatorAddress - The validator address to unstake from + * @param params.amount - The amount to unstake, specified in `TON` + * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires + * + * @returns Returns a promise that resolves to a TON nominator pool unstaking transaction. + */ + async buildUnstakeTx (params: { + delegatorAddress: string + validatorAddress: string + amount: string + validUntil?: number + }): Promise<{ tx: UnsignedTx }> { + const { delegatorAddress, validatorAddress, amount, validUntil } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } + + // only onwer can withdraw the funds + const roles = await this.getContractRoles(validatorAddress) + if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { + throw new Error('delegator is not the owner of the single nominator pool contract') + } + + // this serves purely as a sanity check + const data = await this.getNominatorContractPoolData(validatorAddress) + if (data.nominators_count !== 1) { + throw new Error('the single nominator pool contract is expected to have exactly one nominator') + } + + // source: https://github.com/orbs-network/single-nominator/tree/main?tab=readme-ov-file#1-withdraw + // https://github.com/orbs-network/single-nominator/blob/main/scripts/ts/withdraw-deeplink.ts#L7C5-L7C137 + const payload = beginCell().storeUint(0x1000, 32).storeUint(1, 64).storeCoins(toNano(amount)).endCell() + + // 1 TON should be enough to cover the transaction fees (similar to nominator pool contract) + const amountToCoverTxFees = '1' + + // ensure we don't drain the validator wallet by accident + this.checkMinimumExistentialBalance(validatorAddress, amount) + + const tx = { + validUntil: defaultValidUntil(validUntil), + message: { + address: validatorAddress, + // to unstake tokens we need to send a some tokens that should + // be returned to us in case of error + bounceable: true, + amount: toNano(amountToCoverTxFees), + payload + } + } + + return { tx } + } + + /** + * Retrieves the staking information for a specified delegator. + * + * @param params - Parameters for the request + * @param params.delegatorAddress - The delegator (wallet) address + * @param params.validatorAddress - The validator address to gather rewards data from + * @param params.contractType - The validator contract type (single-nominator-pool or nominator-pool) + * + * @returns Returns a promise that resolves to the staking information for the specified delegator. + */ + async getStake (params: { delegatorAddress: string; validatorAddress: string }): Promise<{ balance: string }> { + const { delegatorAddress, validatorAddress } = params + + // otherise it is a single nominator pool contract + const roles = await this.getContractRoles(validatorAddress) + if (!roles.ownerAddress.equals(Address.parse(delegatorAddress))) { + throw new Error('delegator is not the owner of the single nominator pool contract') + } + + const balance = await this.getBalance({ address: validatorAddress }) + + return { balance: balance.amount } + } + + /** + * Retrieves the active nominators for a Nominator Pool contract. + * For more information see: https://github.com/ton-blockchain/nominator-pool + * + * @param params - Parameters for the request + * @param params.validatorAddress - The validator address to gather rewards data from + * + * @returns Returns a promise that resolves to the nominator data for the validator address. + */ + async getPoolContractNominators (params: { validatorAddress: string }): Promise<{ nominators: NominatorInfo[] }> { + const client = this.getClient() + const { validatorAddress } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + const response = await client.runMethod(Address.parse(validatorAddress), 'list_nominators', []) + + // @ts-expect-error the library does not handle 'list' type well. This is a workaround to get the data out of the 'list' type + const reader = new TupleReader(response.stack.pop().items as TupleItem[]) + + // extract nominators from contract response + const nominators: NominatorInfo[] = [] + + if (reader.remaining > 0) { + do { + const x = reader.readTuple() + nominators.push({ + // The nominator pool contract allows only the basechain addresses (`0:`) + // https://github.com/ton-blockchain/nominator-pool/blob/main/func/pool.fc#L618 + address: `0:${BigInt(x.readBigNumber()).toString(16)}`, + amount: fromNano(x.readBigNumber()), + pending_deposit_amount: fromNano(x.readBigNumber()), + withdraw_requested: fromNano(x.readBigNumber()) + }) + } while (reader.remaining) + } + + return { nominators } + } + + private async getContractRoles ( + contractAddress: string + ): Promise<{ ownerAddress: Address; validatorAddress: Address }> { + const client = this.getClient() + const response = await client.runMethod(Address.parse(contractAddress), 'get_roles', []) + + // reference: https://github.com/orbs-network/single-nominator/blob/main/contracts/single-nominator.fc#L186 + if (response.stack.remaining !== 2) { + throw new Error('invalid get_pool_data response, expected 17 fields got ' + response.stack.remaining) + } + + const ownerAddress = response.stack.readAddress() + const validatorAddress = response.stack.readAddress() + + return { + ownerAddress, + validatorAddress + } + } +} diff --git a/packages/ton/src/index.ts b/packages/ton/src/index.ts index 25152ce..62d6ee2 100644 --- a/packages/ton/src/index.ts +++ b/packages/ton/src/index.ts @@ -1,4 +1,7 @@ -export { TonStaker } from './staker' +export { TonSingleNominatorPoolStaker } from './TonSingleNominatorPoolStaker' +export { TonNominatorPoolStaker } from './TonNominatorPoolStaker' +export { TonPoolStaker } from './TonPoolStaker' + export { TonNetworkConfig, TonSigningData, From ac9b5abf2696a52e249025261d5433b25b439fcc Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Thu, 14 Nov 2024 18:12:09 +0000 Subject: [PATCH 2/6] Add support for 2 TON pools --- packages/staking-cli/src/cmd/ton.ts | 47 ++++++++++++++++++++++++++--- packages/staking-cli/src/types.d.ts | 3 ++ packages/ton/src/TonPoolStaker.ts | 13 ++++++-- packages/ton/src/constants.ts | 26 ++++++++++++++++ packages/ton/src/index.ts | 2 ++ 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 packages/ton/src/constants.ts diff --git a/packages/staking-cli/src/cmd/ton.ts b/packages/staking-cli/src/cmd/ton.ts index cfd25be..0aa8234 100644 --- a/packages/staking-cli/src/cmd/ton.ts +++ b/packages/staking-cli/src/cmd/ton.ts @@ -34,9 +34,17 @@ function makeTxCommand (): Command { .argument('', 'amount of tokens to stake expressed in TON denom e.g 0.1') .action(getDelegatePoolTx) + const validateIndex = (value: string): '1' | '2' => { + if (value !== '1' && value !== '2') { + throw new Error('validator index must be 1 or 2') + } + return value + } + tx.command('unstake-pool') .description('generate a unstake funds to TON pool contract transaction') .argument('', 'amount of tokens to unstake expressed in TON denom e.g 0.1') + .requiredOption('-I, --validator-index ', 'validator index to unstake from (1 or 2)', validateIndex) .action(getUnstakePoolTx) tx.command('delegate-nominator-pool') @@ -95,7 +103,7 @@ async function init ( async function runTx ( msgType: string, - _options: any, + options: { validatorIndex: '1' | '2' } | undefined, cmd: Command<[string]> | Command<[string, string]> | Command<[string, string, string]> | Command<[]>, arg: string[] ): Promise { @@ -132,10 +140,20 @@ async function runTx ( tonStaker = new TonPoolStaker({ ...networkConfig }) await tonStaker.init() + if (!config.validatorAddress2) { + cmd.error('second validator address is required for TON Pool', { exitCode: 1, code: `${msgType}.tx.abort` }) + } + const validatorAddressPair: [string, string] = [config.validatorAddress, config.validatorAddress2] + + const validatorToDelegate = await tonStaker.getPoolAddressForStake({ validatorAddressPair }) + const validatorIndex = validatorToDelegate === config.validatorAddress ? 1 : 2 + + console.log('Delegating to validator #' + validatorIndex + ': ' + validatorToDelegate) + unsignedTx = ( await tonStaker.buildStakeTx({ delegatorAddress: config.delegatorAddress, - validatorAddress: config.validatorAddress, + validatorAddressPair, amount: arg[0] // amount }) ).tx @@ -145,10 +163,25 @@ async function runTx ( tonStaker = new TonPoolStaker({ ...networkConfig }) await tonStaker.init() + if (!config.validatorAddress2) { + cmd.error('second validator address is required for TON Pool', { exitCode: 1, code: `${msgType}.tx.abort` }) + } + + if (!options?.validatorIndex) { + cmd.error('validator index is required for TON Pool', { exitCode: 1, code: `${msgType}.tx.abort` }) + } + const validatorAddressPair: [string, string] = [config.validatorAddress, config.validatorAddress2] + + const validatorIndex = parseInt(options.validatorIndex) + + const validatorAddress = validatorAddressPair[validatorIndex - 1] + + console.log('Unstaking from validator #' + validatorIndex + ': ' + validatorAddress) + unsignedTx = ( await tonStaker.buildUnstakeTx({ delegatorAddress: config.delegatorAddress, - validatorAddress: config.validatorAddress, + validatorAddress, amount: arg[0] // amount }) ).tx @@ -233,7 +266,7 @@ async function runTx ( } } } catch (e: any) { - cmd.error(e, { exitCode: 1, code: msgType + '.tx.sign' }) + cmd.error(e, { exitCode: 1, code: msgType + '.tx.abort' }) } if (unsignedTx === undefined) { @@ -284,7 +317,11 @@ async function getDelegatePoolTx (amount: string, options: any, cmd: Command<[st await runTx('delegate-pool', options, cmd, [amount]) } -async function getUnstakePoolTx (amount: string, options: any, cmd: Command<[string]>): Promise { +async function getUnstakePoolTx ( + amount: string, + options: { validatorIndex: '1' | '2' }, + cmd: Command<[string]> +): Promise { await runTx('unstake-pool', options, cmd, [amount]) } diff --git a/packages/staking-cli/src/types.d.ts b/packages/staking-cli/src/types.d.ts index 2d8aa9d..6751dce 100644 --- a/packages/staking-cli/src/types.d.ts +++ b/packages/staking-cli/src/types.d.ts @@ -22,6 +22,9 @@ export interface Config { // define validator address to interact with (delegate, undelegate etc) validatorAddress: string + // second validator address, used only for TON Pool + validatorAddress2?: string + // define the expected delegator account delegatorAddress: string diff --git a/packages/ton/src/TonPoolStaker.ts b/packages/ton/src/TonPoolStaker.ts index 920da50..bc97586 100644 --- a/packages/ton/src/TonPoolStaker.ts +++ b/packages/ton/src/TonPoolStaker.ts @@ -17,11 +17,12 @@ export class TonPoolStaker extends TonBaseStaker { */ async buildStakeTx (params: { delegatorAddress: string - validatorAddress: string + validatorAddressPair: [string, string] amount: string validUntil?: number }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, amount, validUntil } = params + const { delegatorAddress, validatorAddressPair, amount, validUntil } = params + const validatorAddress = await this.getPoolAddressForStake({ validatorAddressPair }) const payload = beginCell() .storeUint(2077040623, 32) @@ -123,4 +124,12 @@ export class TonPoolStaker extends TonBaseStaker { receiptPrice: result.receiptPrice } } + + /** @ignore */ + async getPoolAddressForStake (params: { validatorAddressPair: [string, string] }) { + const { validatorAddressPair } = params + // The logic to be implemented, we return the first address for now + + return validatorAddressPair[0] + } } diff --git a/packages/ton/src/constants.ts b/packages/ton/src/constants.ts new file mode 100644 index 0000000..b40eed4 --- /dev/null +++ b/packages/ton/src/constants.ts @@ -0,0 +1,26 @@ +/** + * Contains the TON validator addresses for Chorus One's validators. + */ +export const CHORUS_ONE_TON_VALIDATORS = { + /** + * TON mainnet validator addresses. + */ + mainnet: { + /** + * Chorus One's TON Pool Pair for the mainnet + */ + tonPoolPair: [] + }, + /** + * TON testnet validator addresses. + */ + testnet: { + /** + * Chorus One's TON Pool Pair for the testnet + */ + tonPoolPair: [ + 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' + ] + } +} as const diff --git a/packages/ton/src/index.ts b/packages/ton/src/index.ts index 62d6ee2..870411d 100644 --- a/packages/ton/src/index.ts +++ b/packages/ton/src/index.ts @@ -2,6 +2,8 @@ export { TonSingleNominatorPoolStaker } from './TonSingleNominatorPoolStaker' export { TonNominatorPoolStaker } from './TonNominatorPoolStaker' export { TonPoolStaker } from './TonPoolStaker' +export { CHORUS_ONE_TON_VALIDATORS } from './constants' + export { TonNetworkConfig, TonSigningData, From 8a2b4760231d6a32b9ffa6419aafd1b349ee2d38 Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Thu, 14 Nov 2024 18:32:47 +0000 Subject: [PATCH 3/6] Add getters and validation --- packages/staking-cli/src/cmd/ton.ts | 2 - packages/ton/src/TonPoolStaker.ts | 69 ++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/packages/staking-cli/src/cmd/ton.ts b/packages/staking-cli/src/cmd/ton.ts index 0aa8234..1b9cf0b 100644 --- a/packages/staking-cli/src/cmd/ton.ts +++ b/packages/staking-cli/src/cmd/ton.ts @@ -152,7 +152,6 @@ async function runTx ( unsignedTx = ( await tonStaker.buildStakeTx({ - delegatorAddress: config.delegatorAddress, validatorAddressPair, amount: arg[0] // amount }) @@ -180,7 +179,6 @@ async function runTx ( unsignedTx = ( await tonStaker.buildUnstakeTx({ - delegatorAddress: config.delegatorAddress, validatorAddress, amount: arg[0] // amount }) diff --git a/packages/ton/src/TonPoolStaker.ts b/packages/ton/src/TonPoolStaker.ts index bc97586..c054794 100644 --- a/packages/ton/src/TonPoolStaker.ts +++ b/packages/ton/src/TonPoolStaker.ts @@ -1,4 +1,4 @@ -import { Address, beginCell, toNano } from '@ton/ton' +import { Address, beginCell, fromNano, toNano } from '@ton/ton' import { defaultValidUntil, getDefaultGas, getRandomQueryId, TonBaseStaker } from './TonBaseStaker' import { UnsignedTx } from './types' @@ -8,7 +8,6 @@ export class TonPoolStaker extends TonBaseStaker { * For more information see: https://github.com/ton-blockchain/nominator-pool * * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address to stake from * @param params.validatorAddress - The validator address to stake to * @param params.amount - The amount to stake, specified in `TON` * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires @@ -16,14 +15,25 @@ export class TonPoolStaker extends TonBaseStaker { * @returns Returns a promise that resolves to a TON nominator pool staking transaction. */ async buildStakeTx (params: { - delegatorAddress: string validatorAddressPair: [string, string] amount: string validUntil?: number }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddressPair, amount, validUntil } = params + const { validatorAddressPair, amount, validUntil } = params const validatorAddress = await this.getPoolAddressForStake({ validatorAddressPair }) + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } + const payload = beginCell() .storeUint(2077040623, 32) .storeUint(getRandomQueryId(), 64) // Query ID @@ -56,14 +66,25 @@ export class TonPoolStaker extends TonBaseStaker { * @returns Returns a promise that resolves to a TON nominator pool staking transaction. */ async buildUnstakeTx (params: { - delegatorAddress: string validatorAddress: string amount: string validUntil?: number }): Promise<{ tx: UnsignedTx }> { - const { delegatorAddress, validatorAddress, amount, validUntil } = params + const { validatorAddress, amount, validUntil } = params + + // ensure the address is for the right network + this.checkIfAddressTestnetFlagMatches(validatorAddress) + + // ensure the validator address is bounceable. + // NOTE: TEP-002 specifies that the address bounceable flag should match both the internal message and the address. + // This has no effect as we force the bounce flag anyway. However it is a good practice to be consistent + if (!Address.parseFriendly(validatorAddress).isBounceable) { + throw new Error( + 'validator address is not bounceable! It is required for nominator pool contract operations to use bounceable addresses' + ) + } - const data = await this.getOnePoolParams({ validatorAddress }) + const data = await this.getPoolParamsUnformatted({ validatorAddress }) const payload = beginCell() .storeUint(3665837821, 32) @@ -85,7 +106,7 @@ export class TonPoolStaker extends TonBaseStaker { return { tx } } - private async getOnePoolStake (params: { delegatorAddress: string; validatorAddress: string }) { + async getStake (params: { delegatorAddress: string; validatorAddress: string }) { const { delegatorAddress, validatorAddress } = params const client = this.getClient() @@ -94,19 +115,31 @@ export class TonPoolStaker extends TonBaseStaker { ]) return { - balance: response.stack.readBigNumber(), - pendingDeposit: response.stack.readBigNumber(), - pendingWithdraw: response.stack.readBigNumber(), - withdraw: response.stack.readBigNumber() + balance: fromNano(response.stack.readBigNumber()), + pendingDeposit: fromNano(response.stack.readBigNumber()), + pendingWithdraw: fromNano(response.stack.readBigNumber()), + withdraw: fromNano(response.stack.readBigNumber()) + } + } + + async getPoolParams (params: { validatorAddress: string }) { + const result = await this.getPoolParamsUnformatted(params) + + return { + minStake: fromNano(result.minStake), + depositFee: fromNano(result.depositFee), + withdrawFee: fromNano(result.withdrawFee), + poolFee: fromNano(result.poolFee), + receiptPrice: fromNano(result.receiptPrice) } } - private async getOnePoolParams (params: { validatorAddress: string }) { + private async getPoolParamsUnformatted (params: { validatorAddress: string }) { const { validatorAddress } = params const client = this.getClient() const response = await client.runMethod(Address.parse(validatorAddress), 'get_params', []) - const result = { + return { enabled: response.stack.readBoolean(), updatesEnables: response.stack.readBoolean(), minStake: response.stack.readBigNumber(), @@ -115,14 +148,6 @@ export class TonPoolStaker extends TonBaseStaker { poolFee: response.stack.readBigNumber(), receiptPrice: response.stack.readBigNumber() } - - return { - minStake: result.minStake, - depositFee: result.depositFee, - withdrawFee: result.withdrawFee, - poolFee: result.poolFee, - receiptPrice: result.receiptPrice - } } /** @ignore */ From 76b764e3ffeace6e9e59fd85bded73f3ef1b8da5 Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Thu, 14 Nov 2024 19:59:51 +0000 Subject: [PATCH 4/6] Fix tests --- packages/ton/src/TonNominatorPoolStaker.ts | 2 +- packages/ton/src/TonSingleNominatorPoolStaker.ts | 2 +- packages/ton/test/staker.spec.ts | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ton/src/TonNominatorPoolStaker.ts b/packages/ton/src/TonNominatorPoolStaker.ts index f5db1b2..2ee8e4a 100644 --- a/packages/ton/src/TonNominatorPoolStaker.ts +++ b/packages/ton/src/TonNominatorPoolStaker.ts @@ -1,4 +1,4 @@ -import { Address, toNano, fromNano } from '@ton/ton' +import { Address, toNano, fromNano, TupleReader, TupleItem } from '@ton/ton' import { defaultValidUntil, TonBaseStaker } from './TonBaseStaker' import { NominatorInfo, UnsignedTx } from './types' diff --git a/packages/ton/src/TonSingleNominatorPoolStaker.ts b/packages/ton/src/TonSingleNominatorPoolStaker.ts index 0f1c51a..db2f645 100644 --- a/packages/ton/src/TonSingleNominatorPoolStaker.ts +++ b/packages/ton/src/TonSingleNominatorPoolStaker.ts @@ -1,4 +1,4 @@ -import { Address, toNano, Cell, beginCell, fromNano } from '@ton/ton' +import { Address, toNano, Cell, beginCell, fromNano, TupleReader } from '@ton/ton' import { defaultValidUntil, TonBaseStaker } from './TonBaseStaker' import { NominatorInfo, UnsignedTx } from './types' diff --git a/packages/ton/test/staker.spec.ts b/packages/ton/test/staker.spec.ts index e6add5c..c9305ce 100644 --- a/packages/ton/test/staker.spec.ts +++ b/packages/ton/test/staker.spec.ts @@ -1,4 +1,4 @@ -import { TonStaker } from '@chorus-one/ton' +import { TonNominatorPoolStaker } from '@chorus-one/ton' import { Address, TupleItem, TupleReader } from '@ton/core' import { describe, it } from 'mocha' import { use, assert, expect, spy } from 'chai' @@ -12,7 +12,7 @@ use(spies) describe('TonStaker', () => { const delegatorAddress = '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr' const validatorAddress = 'kf8SWCvzf6eJK4Q0ZOe14PqDdsT5wk0_Ni0wAThL0cVorNVU' - const staker = new TonStaker({ + const staker = new TonNominatorPoolStaker({ rpcUrl: 'https://ton.fake.website', addressDerivationConfig: { walletContractVersion: 4, @@ -75,7 +75,7 @@ describe('TonStaker', () => { }) it('should generate correct unsigned delegate tx', async () => { - const { tx } = await staker.buildStakeNominatorPoolTx({ + const { tx } = await staker.buildStakeTx({ delegatorAddress, validatorAddress, amount: '0.5' @@ -103,7 +103,7 @@ describe('TonStaker', () => { const [amount, expectedAmount, expectedError] = testData const runTest = async (amount: string): Promise => { - const { tx } = await staker.buildStakeNominatorPoolTx({ + const { tx } = await staker.buildStakeTx({ delegatorAddress, validatorAddress, amount From cecb9eaf898cfc30010f22817f8e639c715d7028 Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Mon, 18 Nov 2024 19:39:00 +0000 Subject: [PATCH 5/6] Methods docs for TON Pool --- book/build-your-staking-dapp/ton/methods.md | 277 ------------- .../ton/nominator/methods.md | 156 +++++++ .../ton/single-nominator/methods.md | 163 ++++++++ .../ton/ton-pool/methods.md | 127 ++++++ .../classes/ethereum_src.EthereumStaker.md | 2 +- .../classes/ton_src.TonNominatorPoolStaker.md | 381 ++++++++++++++++++ book/docs/classes/ton_src.TonPoolStaker.md | 378 +++++++++++++++++ ...> ton_src.TonSingleNominatorPoolStaker.md} | 219 ++++------ packages/ethereum/src/staker.ts | 10 +- packages/ton/src/TonBaseStaker.ts | 32 +- packages/ton/src/TonPoolStaker.ts | 29 +- 11 files changed, 1328 insertions(+), 446 deletions(-) delete mode 100644 book/build-your-staking-dapp/ton/methods.md create mode 100644 book/build-your-staking-dapp/ton/nominator/methods.md create mode 100644 book/build-your-staking-dapp/ton/single-nominator/methods.md create mode 100644 book/build-your-staking-dapp/ton/ton-pool/methods.md create mode 100644 book/docs/classes/ton_src.TonNominatorPoolStaker.md create mode 100644 book/docs/classes/ton_src.TonPoolStaker.md rename book/docs/classes/{ton_src.TonStaker.md => ton_src.TonSingleNominatorPoolStaker.md} (64%) diff --git a/book/build-your-staking-dapp/ton/methods.md b/book/build-your-staking-dapp/ton/methods.md deleted file mode 100644 index 74b96c0..0000000 --- a/book/build-your-staking-dapp/ton/methods.md +++ /dev/null @@ -1,277 +0,0 @@ -# Methods - -This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network. - -The Chorus One SDK supports various staking operations including staking, unstaking, withdrawing, and retrieving staking information. - -Below, we explore each method with practical examples to help you get started. - ---- - -## buildStakeNominatorPoolTx - -### Description - -The `buildStakeNominatorPoolTx` method helps you create a transaction for staking TON tokens with a validator using the Nominator Pool contract. - -Staking tokens involves locking them up to support the network's security and operations, and in return, you earn rewards. - -### How to Use - -To build a staking transaction, you will need to specify the amount to stake, the delegator's address (your wallet), and the validator's address where you want to stake your tokens. - -- Optionally, you can provide a Unix timestamp for when the transaction expires. - -### Example - -```javascript -const { tx } = await staker.buildStakeNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - amount: '1', // 1 TON - validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour -}) -``` - -In the above example, we're staking 1 TON with a specified validator with an optional expiration time. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#buildstakenominatorpooltx) - ---- - -## buildUnstakeNominatorPoolTx - -### Description - -The `buildUnstakeNominatorPoolTx` method allows you to create a transaction for unstaking tokens from a validator using the Nominator Pool contract. - -Unstaking involves withdrawing your staked tokens, which then enter a waiting period before they become available for withdrawal. - -### How to Use - -To build an unstaking transaction, you will need to provide the delegator's address (your wallet), and the validator's address from which you want to withdraw your tokens. - -- Optionally, you can provide a Unix timestamp for when the transaction expires. - -### Example - -```javascript -const { tx } = await staker.buildUnstakeNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour -}) -``` - -In the above example, we are unstaking all staked TON from a specified validator, with an optional expiration time of 1 hour. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#buildunstakenominatorpooltx) - ---- - -## buildStakeSingleNominatorPoolTx - -### Description - -The `buildStakeSingleNominatorPoolTx` method helps you create a transaction for staking TON tokens with a validator using the Single Nominator Pool contract. - -{% hint style="info" %} -The Single Nominator Pool contract accepts only one delegator. Usually the contract is deployed by a network operator like Chorus One on demand, because there is a significant amount of stake required to get into a validator set. - -The benefit of Single Pool contract is that a nominator can do partial stake withdraws. Which is not possible with Nominator Pool contract. -{% endhint %} - -Staking tokens involves locking them up to support the network's security and operations, and in return, you earn rewards. - -### How to Use - -To build a staking transaction, you will need to specify the amount to stake, the delegator's address (your wallet), and the validator's address where you want to stake your tokens. - -- Optionally, you can provide a Unix timestamp for when the transaction expires. - -### Example - -```javascript -const { tx } = await staker.buildSingleStakeNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - amount: '1', // 1 TON - validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour -}) -``` - -In the above example, we're staking 1 TON with a specified validator with an optional expiration time. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#buildstakenominatorpooltx) - ---- - -## buildUnstakeSingleNominatorPoolTx - -### Description - -The `buildUnstakeSingleNominatorPoolTx` method allows you to create a transaction for unstaking tokens from a validator using the Single Nominator Pool contract. - -Unstaking involves withdrawing your staked tokens, which then enter a waiting period before they become available for withdrawal. - -### How to Use - -To build an unstaking transaction, you will need to provide the delegator's address (your wallet), amount and the validator's address from which you want to withdraw your tokens. - -- Optionally, you can provide a Unix timestamp for when the transaction expires. - -### Example - -```javascript -const { tx } = await staker.buildUnstakeSingleNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - amount: '1', // 1 TON - validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour -}) -``` - -In the above example, we are unstaking 1 TON from a specified validator, with an optional expiration time of 1 hour. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#buildunstakenominatorpooltx) - ---- - -## buildTransferTx - -### Description - -The `buildTransferTx` method allows you to create a transaction for transferring tokens to another address. - -### How to Use - -To build a transfer transaction, you will need to specify the destination address, the amount of TON to transfer, and optionally, a Unix timestamp for when the transaction expires along with a memo to include with the transaction. - -### Example - -```javascript -const { tx } = await staker.buildTransferTx({ - destinationAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - amount: '1', // 1 TON - validUntil: Math.floor(Date.now() / 1000) + 3600, // Optional, expires in 1 hour - memo: 'Staking with Chorus One' // Optional -}) -``` - -In the above example, we are transferring 1 TON to a specified address, with an optional expiration time of 1 hour and memo that reads "Staking with Chorus One". - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#buildtransfertx) - ---- - -## buildDeployWalletTx - -### Description - -The `buildDeployWalletTx` method allows you to create a transaction for deploying a wallet contract to a specified address. - -### How to Use - -To build a wallet deployment transaction, you will need to specify the address you wish to deploy the wallet contract to, and optionally, a Unix timestamp for when the transaction expires. - -### Example - -```javascript -const { tx } = await staker.buildDeployWalletTx({ - address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour -}) -``` - -Here we can see we are deploying a wallet contract to a specified address, with an optional expiration time of 1 hour. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#builddeploywallettx) - ---- - -## getPoolContractNominators - -### Description - -The `getPoolContractNominators` method retrieves the active nominators for a specified Nominator Pool contract. - -- This includes information on the nominators who have staked tokens with a specific validator. - -### How to Use - -To get this information, you will need to provide the validator's address. - -### Example - -```javascript -const { nominators } = await staker.getPoolContractNominators({ - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP' -}) -console.log(`Active nominators: ${nominators}`) -``` - -In this example, we are retrieving the active nominators for the specified validator. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#getpoolcontractnominators) - ---- - -## getBalance - -### Description - -The `getBalance` method retrieves the account balance for a specified address. - -### How to Use - -To retrieve the balance data, you will need to provide the address for which you want to retrieve the balance. - -### Example - -```javascript -const { amount } = await staker.getBalance({ - address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr' -}) -console.log(`Account balance: ${amount}`) -``` - -In the above example, we are retrieving the account balance for a specified address. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#getbalance) - ---- - -## getStake - -## Description - -The `getStake` method retrieves the staking information from a delegator. - -- This includes the amount of tokens currently staked with a validator. - -## How to Use - -To get staking information, you need to provide the delegator's address (your wallet), the validator's address, and the contract type (Nominator Pool or Single Nominator Pool). - -## Example - -```javascript -const { balance } = await staker.getStake({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - contractType: 'nominator-pool' -}) -console.log(`Staked balance: ${balance}`) -``` - -In this example, we're retrieving the staked balance for a given delegator and validator. - -- [Read more in the API Reference](../../docs/classes/ton_src.TonStaker.md#getstake) - ---- - -## Further Reading - -For more detailed information and additional methods please refer to the official API reference: - -- [TON SDK API Reference](../../docs/classes/ton_src.TonStaker.md) diff --git a/book/build-your-staking-dapp/ton/nominator/methods.md b/book/build-your-staking-dapp/ton/nominator/methods.md new file mode 100644 index 0000000..a9927a4 --- /dev/null +++ b/book/build-your-staking-dapp/ton/nominator/methods.md @@ -0,0 +1,156 @@ +# Methods + +This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **Nominator Pool** contract. + +The Chorus One SDK supports various staking operations including staking, unstaking, withdrawing, and retrieving staking information. + +Below, we explore each method with practical examples to help you get started. + +--- + +## buildStakeTx + +### Description + +The `buildStakeTx` method helps you create a transaction for staking TON tokens with a validator using the Nominator Pool contract. + +Staking tokens involves locking them up to support the network's security and operations, and in return, you earn rewards. + +### How to Use + +To build a staking transaction, you will need to specify the amount to stake, the delegator's address (your wallet), and the validator's address where you want to stake your tokens. + +- Optionally, you can provide a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildStakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + amount: '1', // 1 TON + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In the above example, we're staking 1 TON with a specified validator with an optional expiration time. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md#buildstaketx) + +--- + +## buildUnstakeTx + +### Description + +The `buildUnstakeTx` method allows you to create a transaction for unstaking tokens from a validator using the Nominator Pool contract. + +Unstaking involves withdrawing your staked tokens, which then enter a waiting period before they become available for withdrawal. + +### How to Use + +To build an unstaking transaction, you will need to provide the delegator's address (your wallet), and the validator's address from which you want to withdraw your tokens. + +- Optionally, you can provide a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildUnstakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In the above example, we are unstaking all staked TON from a specified validator, with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md#buildunstaketx) + +--- + +## buildDeployWalletTx + +### Description + +The `buildDeployWalletTx` method allows you to create a transaction for deploying a wallet contract to a specified address. + +### How to Use + +To build a wallet deployment transaction, you will need to specify the address you wish to deploy the wallet contract to, and optionally, a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildDeployWalletTx({ + address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +Here we can see we are deploying a wallet contract to a specified address, with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md#builddeploywallettx) + +--- + +## getPoolContractNominators + +### Description + +The `getPoolContractNominators` method retrieves the active nominators for a specified Nominator Pool contract. + +- This includes information on the nominators who have staked tokens with a specific validator. + +### How to Use + +To get this information, you will need to provide the validator's address. + +### Example + +```javascript +const { nominators } = await staker.getPoolContractNominators({ + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP' +}) +console.log(`Active nominators: ${nominators}`) +``` + +In this example, we are retrieving the active nominators for the specified validator. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md#getpoolcontractnominators) + +--- + +## getStake + +## Description + +The `getStake` method retrieves the staking information from a delegator. + +- This includes the amount of tokens currently staked with a validator. + +## How to Use + +To get staking information, you need to provide the delegator's address (your wallet) and the validator's address. + +## Example + +```javascript +const { balance } = await staker.getStake({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', +}) +console.log(`Staked balance: ${balance}`) +``` + +In this example, we're retrieving the staked balance for a given delegator and validator. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md#getstake) + +--- + +## Further Reading + +For more detailed information and additional methods please refer to the official API reference: + +- [TON Nominator Pool SDK API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md) diff --git a/book/build-your-staking-dapp/ton/single-nominator/methods.md b/book/build-your-staking-dapp/ton/single-nominator/methods.md new file mode 100644 index 0000000..1f96bba --- /dev/null +++ b/book/build-your-staking-dapp/ton/single-nominator/methods.md @@ -0,0 +1,163 @@ +# Methods + +This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **Single Nominator Pool** contract. + +The Chorus One SDK supports various staking operations including staking, unstaking, withdrawing, and retrieving staking information. + +Below, we explore each method with practical examples to help you get started. + +--- + +## buildStakeTx + +### Description + +The `buildStakeTx` method helps you create a transaction for staking TON tokens with a validator using the Single Nominator Pool contract. + +{% hint style="info" %} +The Single Nominator Pool contract accepts only one delegator. Usually the contract is deployed by a network operator like Chorus One on demand, because there is a significant amount of stake required to get into a validator set. + +The benefit of Single Pool contract is that a nominator can do partial stake withdraws. Which is not possible with Nominator Pool contract. +{% endhint %} + +Staking tokens involves locking them up to support the network's security and operations, and in return, you earn rewards. + +### How to Use + +To build a staking transaction, you will need to specify the amount to stake, the delegator's address (your wallet), and the validator's address where you want to stake your tokens. + +- Optionally, you can provide a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildStakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + amount: '1', // 1 TON + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In the above example, we're staking 1 TON with a specified validator with an optional expiration time. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md#buildstaketx) + +--- + +## buildUnstakeTx + +### Description + +The `buildUnstakeTx` method allows you to create a transaction for unstaking tokens from a validator using the Single Nominator Pool contract. + +Unstaking involves withdrawing your staked tokens, which then enter a waiting period before they become available for withdrawal. + +### How to Use + +To build an unstaking transaction, you will need to provide the delegator's address (your wallet), amount and the validator's address from which you want to withdraw your tokens. + +- Optionally, you can provide a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildUnstakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + amount: '1', // 1 TON + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In the above example, we are unstaking 1 TON from a specified validator, with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md#buildunstaketx) + +--- + +## buildDeployWalletTx + +### Description + +The `buildDeployWalletTx` method allows you to create a transaction for deploying a wallet contract to a specified address. + +### How to Use + +To build a wallet deployment transaction, you will need to specify the address you wish to deploy the wallet contract to, and optionally, a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildDeployWalletTx({ + address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +Here we can see we are deploying a wallet contract to a specified address, with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md#builddeploywallettx) + +--- + +## getPoolContractNominators + +### Description + +The `getPoolContractNominators` method retrieves the active nominators for a specified Single Nominator Pool contract. + +- This includes information on the nominators who have staked tokens with a specific validator. + +### How to Use + +To get this information, you will need to provide the validator's address. + +### Example + +```javascript +const { nominators } = await staker.getPoolContractNominators({ + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP' +}) +console.log(`Active nominators: ${nominators}`) +``` + +In this example, we are retrieving the active nominators for the specified validator. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md#getpoolcontractnominators) + +--- + +## getStake + +## Description + +The `getStake` method retrieves the staking information from a delegator. + +- This includes the amount of tokens currently staked with a validator. + +## How to Use + +To get staking information, you need to provide the delegator's address (your wallet) and the validator's address. + +## Example + +```javascript +const { balance } = await staker.getStake({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', +}) +console.log(`Staked balance: ${balance}`) +``` + +In this example, we're retrieving the staked balance for a given delegator and validator. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md#getstake) + +--- + +## Further Reading + +For more detailed information and additional methods please refer to the official API reference: + +- [TON SDK API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md) diff --git a/book/build-your-staking-dapp/ton/ton-pool/methods.md b/book/build-your-staking-dapp/ton/ton-pool/methods.md new file mode 100644 index 0000000..7fa4177 --- /dev/null +++ b/book/build-your-staking-dapp/ton/ton-pool/methods.md @@ -0,0 +1,127 @@ +# Methods + +This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **TON Pool** contract. + +The Chorus One SDK supports various staking operations including staking, unstaking, withdrawing, and retrieving staking information. + +Below, we explore each method with practical examples to help you get started. + +--- + +## buildStakeTx + +### Description + +The `buildStakeTx` method creates a staking transaction for the TON Pool contract. This method uses a two-pool solution and automatically selects the best pool for staking. + +Staking tokens supports the network's operations and earns rewards for the delegator. + +### How to Use + +To build a staking transaction, you need to provide the validator address pair, the staking amount (in TON), and optionally, a Unix timestamp indicating when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildStakeTx({ + validatorAddressPair: [ + 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' + ], + amount: '2', // 2 TON + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In the example above, we stake 2 TON using a validator address pair with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonPoolStaker.md#buildstaketx) + +--- + +## buildUnstakeTx + +### Description + +The `buildUnstakeTx` method creates a transaction for unstaking tokens from the TON Pool contract. + +Unstaking involves removing your staked tokens from a validator, which may be subject to fees and a withdrawal waiting period. + +### How to Use + +To build an unstaking transaction, you need to provide the validator's address, the amount to unstake (in TON), and optionally, a Unix timestamp for when the transaction expires. + +### Example + +```javascript +const { tx } = await staker.buildUnstakeTx({ + validatorAddress: 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + amount: '1', // 1 TON + validUntil: Math.floor(Date.now() / 1000) + 3600 // Optional, expires in 1 hour +}) +``` + +In this example, we are unstaking 1 TON from the specified validator with an optional expiration time of 1 hour. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonPoolStaker.md#buildunstaketx) + +--- + +## getStake + +### Description + +The `getStake` method retrieves staking information for a specific delegator (your wallet) on the TON Pool contract. + +- This includes details such as the staked amount, pending deposits, pending withdrawals, and available withdrawal balance. + +### How to Use + +To retrieve staking information, you need to provide the delegator's address (your wallet) and the validator's address. + +### Example + +```javascript +const stakeInfo = await staker.getStake({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F' +}) +console.log('Staking Info:', stakeInfo) +``` + +In this example, we retrieve staking information, including balances and pending deposits, for the given delegator and validator. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonPoolStaker.md#getstake) + +--- + +## getPoolParams + +### Description + +The `getPoolParams` method retrieves staking parameters for a specified validator, including information such as minimum stake, deposit fees, withdrawal fees, pool fees, and receipt price. + +### How to Use + +To get the pool parameters, you need to provide the validator's address. + +### Example + +```javascript +const poolParams = await staker.getPoolParams({ + validatorAddress: 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F' +}) +console.log('Pool Parameters:', poolParams) +``` + +In this example, we retrieve the pool parameters for a given validator, such as fees and minimum stake requirements. + +- [Read more in the API Reference](../../../docs/classes/ton_src.TonPoolStaker.md#getpoolparams) + +--- + +## Further Reading + +For more detailed information and additional methods, please refer to the official API reference: + +- [TON SDK API Reference](../../../docs/classes/ton_src.TonPoolStaker.md) \ No newline at end of file diff --git a/book/docs/classes/ethereum_src.EthereumStaker.md b/book/docs/classes/ethereum_src.EthereumStaker.md index b971269..79334ed 100644 --- a/book/docs/classes/ethereum_src.EthereumStaker.md +++ b/book/docs/classes/ethereum_src.EthereumStaker.md @@ -187,7 +187,7 @@ Builds a mint transaction. | `params.delegatorAddress` | \`0x$\{string}\` | The delegator (wallet) address | | `params.validatorAddress` | \`0x$\{string}\` | The validator (vault) address to mint shares for | | `params.amount` | `string` | The amount to mint, specified in `osETH`. E.g. "1" - 1 osETH | -| `params.referrer?` | \`0x$\{string}\` | (Optional) The address of the referrer. This is used to track the origin of transactions, providing insights into which sources or campaigns are driving activity. This can be useful for analytics and optimizing user acquisition strategies. | +| `params.referrer?` | \`0x$\{string}\` | (Optional) The address of the referrer. This is used to track the origin of transactions, providing insights into which sources or campaigns are driving activity. This can be useful for analytics and optimizing user acquisition strategies | ### Returns diff --git a/book/docs/classes/ton_src.TonNominatorPoolStaker.md b/book/docs/classes/ton_src.TonNominatorPoolStaker.md new file mode 100644 index 0000000..09b3e59 --- /dev/null +++ b/book/docs/classes/ton_src.TonNominatorPoolStaker.md @@ -0,0 +1,381 @@ +# Hierarchy + +- `TonBaseStaker` + + ↳ **`TonNominatorPoolStaker`** + +# Table of contents + +## Constructors + +- [constructor](ton_src.TonNominatorPoolStaker.md#constructor) + +## Methods + +- [getAddressDerivationFn](ton_src.TonNominatorPoolStaker.md#getaddressderivationfn) +- [getMnemonicToSeedFn](ton_src.TonNominatorPoolStaker.md#getmnemonictoseedfn) +- [getSeedToKeypairFn](ton_src.TonNominatorPoolStaker.md#getseedtokeypairfn) +- [buildStakeTx](ton_src.TonNominatorPoolStaker.md#buildstaketx) +- [buildUnstakeTx](ton_src.TonNominatorPoolStaker.md#buildunstaketx) +- [getStake](ton_src.TonNominatorPoolStaker.md#getstake) +- [getPoolContractNominators](ton_src.TonNominatorPoolStaker.md#getpoolcontractnominators) +- [init](ton_src.TonNominatorPoolStaker.md#init) +- [buildDeployWalletTx](ton_src.TonNominatorPoolStaker.md#builddeploywallettx) +- [sign](ton_src.TonNominatorPoolStaker.md#sign) +- [broadcast](ton_src.TonNominatorPoolStaker.md#broadcast) +- [getTxStatus](ton_src.TonNominatorPoolStaker.md#gettxstatus) + +# Constructors + +## constructor + +• **new TonNominatorPoolStaker**(`params`): [`TonNominatorPoolStaker`](ton_src.TonNominatorPoolStaker.md) + +This creates a new TonStaker instance. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Initialization parameters | +| `params.rpcUrl` | `string` | RPC URL (e.g. https://toncenter.com/api/v2/jsonRPC) | +| `params.allowSeamlessWalletDeployment?` | `boolean` | (Optional) If enabled, the wallet contract is deployed automatically when needed | +| `params.allowTransferToInactiveAccount?` | `boolean` | (Optional) Allow token transfers to inactive accounts | +| `params.minimumExistentialBalance?` | `string` | (Optional) The amount of TON to keep in the wallet | +| `params.addressDerivationConfig?` | [`AddressDerivationConfig`](../interfaces/ton_src.AddressDerivationConfig.md) | (Optional) TON address derivation configuration | + +### Returns + +[`TonNominatorPoolStaker`](ton_src.TonNominatorPoolStaker.md) + +An instance of TonStaker. + +### Inherited from + +TonBaseStaker.constructor + +# Methods + +## getAddressDerivationFn + +▸ **getAddressDerivationFn**(`params?`): (`publicKey`: `Uint8Array`, `_derivationPath`: `string`) => `Promise`\<`string`[]\> + +This **static** method is used to derive an address from a public key. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params?` | `Object` | Parameters for the address derivation | +| `params.addressDerivationConfig` | [`AddressDerivationConfig`](../interfaces/ton_src.AddressDerivationConfig.md) | TON address derivation configuration | + +### Returns + +`fn` + +Returns a single address derived from the public key + +▸ (`publicKey`, `_derivationPath`): `Promise`\<`string`[]\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `publicKey` | `Uint8Array` | +| `_derivationPath` | `string` | + +#### Returns + +`Promise`\<`string`[]\> + +### Inherited from + +TonBaseStaker.getAddressDerivationFn + +___ + +## getMnemonicToSeedFn + +▸ **getMnemonicToSeedFn**(): (`mnemonic`: `string`, `password?`: `string`) => `Promise`\<`Uint8Array`\> + +This **static** method is used to convert BIP39 mnemonic to seed. In TON +network the seed is used as a private key. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Returns + +`fn` + +Returns a seed derived from the mnemonic + +▸ (`mnemonic`, `password?`): `Promise`\<`Uint8Array`\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `mnemonic` | `string` | +| `password?` | `string` | + +#### Returns + +`Promise`\<`Uint8Array`\> + +### Inherited from + +TonBaseStaker.getMnemonicToSeedFn + +___ + +## getSeedToKeypairFn + +▸ **getSeedToKeypairFn**(): (`seed`: `Uint8Array`, `hdPath?`: `string`) => `Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +This **static** method is used to convert a seed to a keypair. Note that +TON network doesn't use BIP44 HD Path for address derivation. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Returns + +`fn` + +Returns a public and private keypair derived from the seed + +▸ (`seed`, `hdPath?`): `Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `seed` | `Uint8Array` | +| `hdPath?` | `string` | + +#### Returns + +`Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +### Inherited from + +TonBaseStaker.getSeedToKeypairFn + +___ + +## buildStakeTx + +▸ **buildStakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds a staking (delegation) transaction for Nominator Pool contract. +For more information see: https://github.com/ton-blockchain/nominator-pool + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.delegatorAddress` | `string` | The delegator address to stake from | +| `params.validatorAddress` | `string` | The validator address to stake to | +| `params.amount` | `string` | The amount to stake, specified in `TON` | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON nominator pool staking transaction. + +___ + +## buildUnstakeTx + +▸ **buildUnstakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds an unstaking (withdraw nominator) transaction for Nominator Pool contract. +For more information see: https://github.com/ton-blockchain/nominator-pool + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.delegatorAddress` | `string` | The delegator address | +| `params.validatorAddress` | `string` | The validator address to unstake from | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON nominator pool unstaking transaction. + +___ + +## getStake + +▸ **getStake**(`params`): `Promise`\<\{ `balance`: `string` }\> + +Retrieves the staking information for a specified delegator. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the request | +| `params.delegatorAddress` | `string` | The delegator (wallet) address | +| `params.validatorAddress` | `string` | The validator address to gather rewards data from | + +### Returns + +`Promise`\<\{ `balance`: `string` }\> + +Returns a promise that resolves to the staking information for the specified delegator. + +___ + +## getPoolContractNominators + +▸ **getPoolContractNominators**(`params`): `Promise`\<\{ `nominators`: [`NominatorInfo`](../interfaces/ton_src.NominatorInfo.md)[] }\> + +Retrieves the active nominators for a Nominator Pool contract. +For more information see: https://github.com/ton-blockchain/nominator-pool + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the request | +| `params.validatorAddress` | `string` | The validator address to gather rewards data from | + +### Returns + +`Promise`\<\{ `nominators`: [`NominatorInfo`](../interfaces/ton_src.NominatorInfo.md)[] }\> + +Returns a promise that resolves to the nominator data for the validator address. + +___ + +## init + +▸ **init**(): `Promise`\<`void`\> + +Initializes the TonStaker instance and connects to the blockchain. + +### Returns + +`Promise`\<`void`\> + +A promise which resolves once the TonStaker instance has been initialized. + +### Inherited from + +TonBaseStaker.init + +___ + +## buildDeployWalletTx + +▸ **buildDeployWalletTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds a wallet deployment transaction + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.address` | `string` | The address to deploy the wallet contract to | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON wallet deployment transaction. + +### Inherited from + +TonBaseStaker.buildDeployWalletTx + +___ + +## sign + +▸ **sign**(`params`): `Promise`\<[`SignedTx`](../interfaces/ton_src.SignedTx.md)\> + +Signs a transaction using the provided signer. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the signing process | +| `params.signer` | `Signer` | Signer instance | +| `params.signerAddress` | `string` | The address of the signer | +| `params.tx` | [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) | The transaction to sign | + +### Returns + +`Promise`\<[`SignedTx`](../interfaces/ton_src.SignedTx.md)\> + +A promise that resolves to an object containing the signed transaction. + +### Inherited from + +TonBaseStaker.sign + +___ + +## broadcast + +▸ **broadcast**(`params`): `Promise`\<`string`\> + +This method is used to broadcast a signed transaction to the TON network. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the broadcast | +| `params.signedTx` | [`SignedTx`](../interfaces/ton_src.SignedTx.md) | The signed transaction to be broadcasted | + +### Returns + +`Promise`\<`string`\> + +Returns a promise that resolves to the response of the transaction that was broadcast to the network. + +### Inherited from + +TonBaseStaker.broadcast + +___ + +## getTxStatus + +▸ **getTxStatus**(`params`): `Promise`\<`TonTxStatus`\> + +Retrieves the status of a transaction using the transaction hash. + +This method is intended to check for transactions made recently (within limit) and not for historical transactions. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the transaction status request | +| `params.address` | `string` | The account address to query | +| `params.txHash` | `string` | The transaction hash to query | +| `params.limit?` | `number` | (Optional) The maximum number of transactions to fetch | + +### Returns + +`Promise`\<`TonTxStatus`\> + +A promise that resolves to an object containing the transaction status. + +### Inherited from + +TonBaseStaker.getTxStatus diff --git a/book/docs/classes/ton_src.TonPoolStaker.md b/book/docs/classes/ton_src.TonPoolStaker.md new file mode 100644 index 0000000..167c386 --- /dev/null +++ b/book/docs/classes/ton_src.TonPoolStaker.md @@ -0,0 +1,378 @@ +# Hierarchy + +- `TonBaseStaker` + + ↳ **`TonPoolStaker`** + +# Table of contents + +## Constructors + +- [constructor](ton_src.TonPoolStaker.md#constructor) + +## Methods + +- [getAddressDerivationFn](ton_src.TonPoolStaker.md#getaddressderivationfn) +- [getMnemonicToSeedFn](ton_src.TonPoolStaker.md#getmnemonictoseedfn) +- [getSeedToKeypairFn](ton_src.TonPoolStaker.md#getseedtokeypairfn) +- [buildStakeTx](ton_src.TonPoolStaker.md#buildstaketx) +- [buildUnstakeTx](ton_src.TonPoolStaker.md#buildunstaketx) +- [getStake](ton_src.TonPoolStaker.md#getstake) +- [getPoolParams](ton_src.TonPoolStaker.md#getpoolparams) +- [init](ton_src.TonPoolStaker.md#init) +- [buildDeployWalletTx](ton_src.TonPoolStaker.md#builddeploywallettx) +- [sign](ton_src.TonPoolStaker.md#sign) +- [broadcast](ton_src.TonPoolStaker.md#broadcast) +- [getTxStatus](ton_src.TonPoolStaker.md#gettxstatus) + +# Constructors + +## constructor + +• **new TonPoolStaker**(`params`): [`TonPoolStaker`](ton_src.TonPoolStaker.md) + +This creates a new TonStaker instance. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Initialization parameters | +| `params.rpcUrl` | `string` | RPC URL (e.g. https://toncenter.com/api/v2/jsonRPC) | +| `params.allowSeamlessWalletDeployment?` | `boolean` | (Optional) If enabled, the wallet contract is deployed automatically when needed | +| `params.allowTransferToInactiveAccount?` | `boolean` | (Optional) Allow token transfers to inactive accounts | +| `params.minimumExistentialBalance?` | `string` | (Optional) The amount of TON to keep in the wallet | +| `params.addressDerivationConfig?` | [`AddressDerivationConfig`](../interfaces/ton_src.AddressDerivationConfig.md) | (Optional) TON address derivation configuration | + +### Returns + +[`TonPoolStaker`](ton_src.TonPoolStaker.md) + +An instance of TonStaker. + +### Inherited from + +TonBaseStaker.constructor + +# Methods + +## getAddressDerivationFn + +▸ **getAddressDerivationFn**(`params?`): (`publicKey`: `Uint8Array`, `_derivationPath`: `string`) => `Promise`\<`string`[]\> + +This **static** method is used to derive an address from a public key. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params?` | `Object` | Parameters for the address derivation | +| `params.addressDerivationConfig` | [`AddressDerivationConfig`](../interfaces/ton_src.AddressDerivationConfig.md) | TON address derivation configuration | + +### Returns + +`fn` + +Returns a single address derived from the public key + +▸ (`publicKey`, `_derivationPath`): `Promise`\<`string`[]\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `publicKey` | `Uint8Array` | +| `_derivationPath` | `string` | + +#### Returns + +`Promise`\<`string`[]\> + +### Inherited from + +TonBaseStaker.getAddressDerivationFn + +___ + +## getMnemonicToSeedFn + +▸ **getMnemonicToSeedFn**(): (`mnemonic`: `string`, `password?`: `string`) => `Promise`\<`Uint8Array`\> + +This **static** method is used to convert BIP39 mnemonic to seed. In TON +network the seed is used as a private key. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Returns + +`fn` + +Returns a seed derived from the mnemonic + +▸ (`mnemonic`, `password?`): `Promise`\<`Uint8Array`\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `mnemonic` | `string` | +| `password?` | `string` | + +#### Returns + +`Promise`\<`Uint8Array`\> + +### Inherited from + +TonBaseStaker.getMnemonicToSeedFn + +___ + +## getSeedToKeypairFn + +▸ **getSeedToKeypairFn**(): (`seed`: `Uint8Array`, `hdPath?`: `string`) => `Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +This **static** method is used to convert a seed to a keypair. Note that +TON network doesn't use BIP44 HD Path for address derivation. + +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + +### Returns + +`fn` + +Returns a public and private keypair derived from the seed + +▸ (`seed`, `hdPath?`): `Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +#### Parameters + +| Name | Type | +| :------ | :------ | +| `seed` | `Uint8Array` | +| `hdPath?` | `string` | + +#### Returns + +`Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> + +### Inherited from + +TonBaseStaker.getSeedToKeypairFn + +___ + +## buildStakeTx + +▸ **buildStakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds a staking transaction for TON Pool contract. It uses 2 pool solution, and picks the best pool +to stake to automatically. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.validatorAddressPair` | [`string`, `string`] | The validator address pair to stake to | +| `params.amount` | `string` | The amount to stake, specified in `TON` | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON nominator pool staking transaction. + +___ + +## buildUnstakeTx + +▸ **buildUnstakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds an unstaking transaction for TON Pool contract. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.validatorAddress` | `string` | The validator address to unstake from | +| `params.amount` | `string` | The amount to stake, specified in `TON` | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON nominator pool staking transaction. + +___ + +## getStake + +▸ **getStake**(`params`): `Promise`\<\{ `balance`: `string` ; `pendingDeposit`: `string` ; `pendingWithdraw`: `string` ; `withdraw`: `string` }\> + +Retrieves the staking information for a specified delegator. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the request | +| `params.delegatorAddress` | `string` | The delegator (wallet) address | +| `params.validatorAddress` | `string` | (Optional) The validator address to gather staking information from | + +### Returns + +`Promise`\<\{ `balance`: `string` ; `pendingDeposit`: `string` ; `pendingWithdraw`: `string` ; `withdraw`: `string` }\> + +Returns a promise that resolves to the staking information for the specified delegator. + +___ + +## getPoolParams + +▸ **getPoolParams**(`params`): `Promise`\<\{ `minStake`: `string` ; `depositFee`: `string` ; `withdrawFee`: `string` ; `poolFee`: `string` ; `receiptPrice`: `string` }\> + +Retrieves the staking information for a specified pool, including minStake and fees information. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the request | +| `params.validatorAddress` | `string` | The validator (vault) address | + +### Returns + +`Promise`\<\{ `minStake`: `string` ; `depositFee`: `string` ; `withdrawFee`: `string` ; `poolFee`: `string` ; `receiptPrice`: `string` }\> + +Returns a promise that resolves to the staking information for the specified pool. + +___ + +## init + +▸ **init**(): `Promise`\<`void`\> + +Initializes the TonStaker instance and connects to the blockchain. + +### Returns + +`Promise`\<`void`\> + +A promise which resolves once the TonStaker instance has been initialized. + +### Inherited from + +TonBaseStaker.init + +___ + +## buildDeployWalletTx + +▸ **buildDeployWalletTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Builds a wallet deployment transaction + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for building the transaction | +| `params.address` | `string` | The address to deploy the wallet contract to | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | + +### Returns + +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> + +Returns a promise that resolves to a TON wallet deployment transaction. + +### Inherited from + +TonBaseStaker.buildDeployWalletTx + +___ + +## sign + +▸ **sign**(`params`): `Promise`\<[`SignedTx`](../interfaces/ton_src.SignedTx.md)\> + +Signs a transaction using the provided signer. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the signing process | +| `params.signer` | `Signer` | Signer instance | +| `params.signerAddress` | `string` | The address of the signer | +| `params.tx` | [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) | The transaction to sign | + +### Returns + +`Promise`\<[`SignedTx`](../interfaces/ton_src.SignedTx.md)\> + +A promise that resolves to an object containing the signed transaction. + +### Inherited from + +TonBaseStaker.sign + +___ + +## broadcast + +▸ **broadcast**(`params`): `Promise`\<`string`\> + +This method is used to broadcast a signed transaction to the TON network. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the broadcast | +| `params.signedTx` | [`SignedTx`](../interfaces/ton_src.SignedTx.md) | The signed transaction to be broadcasted | + +### Returns + +`Promise`\<`string`\> + +Returns a promise that resolves to the response of the transaction that was broadcast to the network. + +### Inherited from + +TonBaseStaker.broadcast + +___ + +## getTxStatus + +▸ **getTxStatus**(`params`): `Promise`\<`TonTxStatus`\> + +Retrieves the status of a transaction using the transaction hash. + +This method is intended to check for transactions made recently (within limit) and not for historical transactions. + +### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `params` | `Object` | Parameters for the transaction status request | +| `params.address` | `string` | The account address to query | +| `params.txHash` | `string` | The transaction hash to query | +| `params.limit?` | `number` | (Optional) The maximum number of transactions to fetch | + +### Returns + +`Promise`\<`TonTxStatus`\> + +A promise that resolves to an object containing the transaction status. + +### Inherited from + +TonBaseStaker.getTxStatus diff --git a/book/docs/classes/ton_src.TonStaker.md b/book/docs/classes/ton_src.TonSingleNominatorPoolStaker.md similarity index 64% rename from book/docs/classes/ton_src.TonStaker.md rename to book/docs/classes/ton_src.TonSingleNominatorPoolStaker.md index e4e5c6c..8705820 100644 --- a/book/docs/classes/ton_src.TonStaker.md +++ b/book/docs/classes/ton_src.TonSingleNominatorPoolStaker.md @@ -1,37 +1,35 @@ -This class provides the functionality to stake assets on the Ton network. +# Hierarchy -It also provides the ability to retrieve staking information and rewards for a delegator. +- `TonBaseStaker` + + ↳ **`TonSingleNominatorPoolStaker`** # Table of contents ## Constructors -- [constructor](ton_src.TonStaker.md#constructor) +- [constructor](ton_src.TonSingleNominatorPoolStaker.md#constructor) ## Methods -- [getAddressDerivationFn](ton_src.TonStaker.md#getaddressderivationfn) -- [getMnemonicToSeedFn](ton_src.TonStaker.md#getmnemonictoseedfn) -- [getSeedToKeypairFn](ton_src.TonStaker.md#getseedtokeypairfn) -- [init](ton_src.TonStaker.md#init) -- [buildStakeNominatorPoolTx](ton_src.TonStaker.md#buildstakenominatorpooltx) -- [buildUnstakeNominatorPoolTx](ton_src.TonStaker.md#buildunstakenominatorpooltx) -- [buildStakeSingleNominatorPoolTx](ton_src.TonStaker.md#buildstakesinglenominatorpooltx) -- [buildUnstakeSingleNominatorPoolTx](ton_src.TonStaker.md#buildunstakesinglenominatorpooltx) -- [buildTransferTx](ton_src.TonStaker.md#buildtransfertx) -- [buildDeployWalletTx](ton_src.TonStaker.md#builddeploywallettx) -- [getPoolContractNominators](ton_src.TonStaker.md#getpoolcontractnominators) -- [getBalance](ton_src.TonStaker.md#getbalance) -- [getStake](ton_src.TonStaker.md#getstake) -- [sign](ton_src.TonStaker.md#sign) -- [broadcast](ton_src.TonStaker.md#broadcast) -- [getTxStatus](ton_src.TonStaker.md#gettxstatus) +- [getAddressDerivationFn](ton_src.TonSingleNominatorPoolStaker.md#getaddressderivationfn) +- [getMnemonicToSeedFn](ton_src.TonSingleNominatorPoolStaker.md#getmnemonictoseedfn) +- [getSeedToKeypairFn](ton_src.TonSingleNominatorPoolStaker.md#getseedtokeypairfn) +- [buildStakeTx](ton_src.TonSingleNominatorPoolStaker.md#buildstaketx) +- [buildUnstakeTx](ton_src.TonSingleNominatorPoolStaker.md#buildunstaketx) +- [getStake](ton_src.TonSingleNominatorPoolStaker.md#getstake) +- [getPoolContractNominators](ton_src.TonSingleNominatorPoolStaker.md#getpoolcontractnominators) +- [init](ton_src.TonSingleNominatorPoolStaker.md#init) +- [buildDeployWalletTx](ton_src.TonSingleNominatorPoolStaker.md#builddeploywallettx) +- [sign](ton_src.TonSingleNominatorPoolStaker.md#sign) +- [broadcast](ton_src.TonSingleNominatorPoolStaker.md#broadcast) +- [getTxStatus](ton_src.TonSingleNominatorPoolStaker.md#gettxstatus) # Constructors ## constructor -• **new TonStaker**(`params`): [`TonStaker`](ton_src.TonStaker.md) +• **new TonSingleNominatorPoolStaker**(`params`): [`TonSingleNominatorPoolStaker`](ton_src.TonSingleNominatorPoolStaker.md) This creates a new TonStaker instance. @@ -48,10 +46,14 @@ This creates a new TonStaker instance. ### Returns -[`TonStaker`](ton_src.TonStaker.md) +[`TonSingleNominatorPoolStaker`](ton_src.TonSingleNominatorPoolStaker.md) An instance of TonStaker. +### Inherited from + +TonBaseStaker.constructor + # Methods ## getAddressDerivationFn @@ -88,6 +90,10 @@ Returns a single address derived from the public key `Promise`\<`string`[]\> +### Inherited from + +TonBaseStaker.getAddressDerivationFn + ___ ## getMnemonicToSeedFn @@ -97,6 +103,8 @@ ___ This **static** method is used to convert BIP39 mnemonic to seed. In TON network the seed is used as a private key. +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + ### Returns `fn` @@ -116,6 +124,10 @@ Returns a seed derived from the mnemonic `Promise`\<`Uint8Array`\> +### Inherited from + +TonBaseStaker.getMnemonicToSeedFn + ___ ## getSeedToKeypairFn @@ -125,6 +137,8 @@ ___ This **static** method is used to convert a seed to a keypair. Note that TON network doesn't use BIP44 HD Path for address derivation. +It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + ### Returns `fn` @@ -144,74 +158,15 @@ Returns a public and private keypair derived from the seed `Promise`\<\{ `publicKey`: `Uint8Array` ; `privateKey`: `Uint8Array` }\> -___ - -## init - -▸ **init**(): `Promise`\<`void`\> - -Initializes the TonStaker instance and connects to the blockchain. - -### Returns - -`Promise`\<`void`\> - -A promise which resolves once the TonStaker instance has been initialized. - -___ - -## buildStakeNominatorPoolTx - -▸ **buildStakeNominatorPoolTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Builds a staking (delegation) transaction for Nominator Pool contract. -For more information see: https://github.com/ton-blockchain/nominator-pool - -### Parameters - -| Name | Type | Description | -| :------ | :------ | :------ | -| `params` | `Object` | Parameters for building the transaction | -| `params.delegatorAddress` | `string` | The delegator address to stake from | -| `params.validatorAddress` | `string` | The validator address to stake to | -| `params.amount` | `string` | The amount to stake, specified in `TON` | -| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | - -### Returns - -`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Returns a promise that resolves to a TON nominator pool staking transaction. - -___ - -## buildUnstakeNominatorPoolTx - -▸ **buildUnstakeNominatorPoolTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Builds an unstaking (withdraw nominator) transaction for Nominator Pool contract. -For more information see: https://github.com/ton-blockchain/nominator-pool - -### Parameters +### Inherited from -| Name | Type | Description | -| :------ | :------ | :------ | -| `params` | `Object` | Parameters for building the transaction | -| `params.delegatorAddress` | `string` | The delegator address | -| `params.validatorAddress` | `string` | The validator address to unstake from | -| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | - -### Returns - -`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Returns a promise that resolves to a TON nominator pool unstaking transaction. +TonBaseStaker.getSeedToKeypairFn ___ -## buildStakeSingleNominatorPoolTx +## buildStakeTx -▸ **buildStakeSingleNominatorPoolTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> +▸ **buildStakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> Builds a staking (delegation) transaction for Single Nominator Pool contract. For more information see: https://github.com/orbs-network/single-nominator/tree/main @@ -234,9 +189,9 @@ Returns a promise that resolves to a TON nominator pool staking transaction. ___ -## buildUnstakeSingleNominatorPoolTx +## buildUnstakeTx -▸ **buildUnstakeSingleNominatorPoolTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> +▸ **buildUnstakeTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> Builds a unstaking (withdraw nominator) transaction for Single Nominator Pool contract. For more information see: https://github.com/orbs-network/single-nominator/tree/main @@ -259,49 +214,25 @@ Returns a promise that resolves to a TON nominator pool unstaking transaction. ___ -## buildTransferTx - -▸ **buildTransferTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Builds a token transfer transaction - -### Parameters - -| Name | Type | Description | -| :------ | :------ | :------ | -| `params` | `Object` | Parameters for building the transaction | -| `params.destinationAddress` | `string` | Where to send the tokens | -| `params.amount` | `string` | The amount to stake, specified in `TON` | -| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | -| `params.memo?` | `string` | (Optional) A short note to include with the transaction | - -### Returns - -`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> - -Returns a promise that resolves to a TON token transfer transaction. - -___ - -## buildDeployWalletTx +## getStake -▸ **buildDeployWalletTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> +▸ **getStake**(`params`): `Promise`\<\{ `balance`: `string` }\> -Builds a wallet deployment transaction +Retrieves the staking information for a specified delegator. ### Parameters | Name | Type | Description | | :------ | :------ | :------ | -| `params` | `Object` | Parameters for building the transaction | -| `params.address` | `string` | The address to deploy the wallet contract to | -| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | +| `params` | `Object` | Parameters for the request | +| `params.delegatorAddress` | `string` | The delegator (wallet) address | +| `params.validatorAddress` | `string` | The validator address to gather rewards data from | ### Returns -`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> +`Promise`\<\{ `balance`: `string` }\> -Returns a promise that resolves to a TON wallet deployment transaction. +Returns a promise that resolves to the staking information for the specified delegator. ___ @@ -327,47 +258,47 @@ Returns a promise that resolves to the nominator data for the validator address. ___ -## getBalance +## init -▸ **getBalance**(`params`): `Promise`\<\{ `amount`: `string` }\> +▸ **init**(): `Promise`\<`void`\> -Retrieves the account balance +Initializes the TonStaker instance and connects to the blockchain. -### Parameters +### Returns -| Name | Type | Description | -| :------ | :------ | :------ | -| `params` | `Object` | Parameters for the request | -| `params.address` | `string` | The account address to gather balance data from | +`Promise`\<`void`\> -### Returns +A promise which resolves once the TonStaker instance has been initialized. -`Promise`\<\{ `amount`: `string` }\> +### Inherited from -Returns a promise that resolves to the account balance +TonBaseStaker.init ___ -## getStake +## buildDeployWalletTx -▸ **getStake**(`params`): `Promise`\<\{ `balance`: `string` }\> +▸ **buildDeployWalletTx**(`params`): `Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> -Retrieves the staking information for a specified delegator. +Builds a wallet deployment transaction ### Parameters | Name | Type | Description | | :------ | :------ | :------ | -| `params` | `Object` | Parameters for the request | -| `params.delegatorAddress` | `string` | The delegator (wallet) address | -| `params.validatorAddress` | `string` | The validator address to gather rewards data from | -| `params.contractType` | ``"single-nominator-pool"`` \| ``"nominator-pool"`` | The validator contract type (single-nominator-pool or nominator-pool) | +| `params` | `Object` | Parameters for building the transaction | +| `params.address` | `string` | The address to deploy the wallet contract to | +| `params.validUntil?` | `number` | (Optional) The Unix timestamp when the transaction expires | ### Returns -`Promise`\<\{ `balance`: `string` }\> +`Promise`\<\{ `tx`: [`UnsignedTx`](../interfaces/ton_src.UnsignedTx.md) }\> -Returns a promise that resolves to the staking information for the specified delegator. +Returns a promise that resolves to a TON wallet deployment transaction. + +### Inherited from + +TonBaseStaker.buildDeployWalletTx ___ @@ -392,6 +323,10 @@ Signs a transaction using the provided signer. A promise that resolves to an object containing the signed transaction. +### Inherited from + +TonBaseStaker.sign + ___ ## broadcast @@ -413,6 +348,10 @@ This method is used to broadcast a signed transaction to the TON network. Returns a promise that resolves to the response of the transaction that was broadcast to the network. +### Inherited from + +TonBaseStaker.broadcast + ___ ## getTxStatus @@ -437,3 +376,7 @@ This method is intended to check for transactions made recently (within limit) a `Promise`\<`TonTxStatus`\> A promise that resolves to an object containing the transaction status. + +### Inherited from + +TonBaseStaker.getTxStatus diff --git a/packages/ethereum/src/staker.ts b/packages/ethereum/src/staker.ts index 41594e1..143d5dd 100644 --- a/packages/ethereum/src/staker.ts +++ b/packages/ethereum/src/staker.ts @@ -77,8 +77,9 @@ export class EthereumStaker { * @param params.delegatorAddress - The delegator (wallet) address to stake from * @param params.validatorAddress - The validator (vault) address to stake with * @param params.amount - The amount to stake, specified in `ETH`. E.g. "1" - 1 ETH - * @param params.referrer - (Optional) A unique Ethereum address representing the source of the delegation, such as a - * marketing campaign or integration partner. This allows precise tracking and management of transaction origins. + * @param params.referrer - (Optional) The address of the referrer. This is used to track the origin of transactions, + * providing insights into which sources or campaigns are driving activity. This can be useful for analytics and + * optimizing user acquisition strategies * * @returns Returns a promise that resolves to an Ethereum staking transaction. */ @@ -167,8 +168,9 @@ export class EthereumStaker { * @param params.delegatorAddress - The delegator (wallet) address * @param params.validatorAddress - The validator (vault) address to mint shares for * @param params.amount - The amount to mint, specified in `osETH`. E.g. "1" - 1 osETH - * @param params.referrer - (Optional) A unique Ethereum address representing the source of the delegation, such as a - * marketing campaign or integration partner. This allows precise tracking and management of transaction origins. + * @param params.referrer - (Optional) The address of the referrer. This is used to track the origin of transactions, + * providing insights into which sources or campaigns are driving activity. This can be useful for analytics and + * optimizing user acquisition strategies * * @returns Returns a promise that resolves to an Ethereum mint transaction. */ diff --git a/packages/ton/src/TonBaseStaker.ts b/packages/ton/src/TonBaseStaker.ts index e52ce1e..5dccc5e 100644 --- a/packages/ton/src/TonBaseStaker.ts +++ b/packages/ton/src/TonBaseStaker.ts @@ -29,8 +29,11 @@ import { ed25519 } from '@noble/curves/ed25519' * It also provides the ability to retrieve staking information and rewards for a delegator. */ export class TonBaseStaker { + /** @ignore */ protected readonly networkConfig: Required + /** @ignore */ protected readonly addressDerivationConfig: AddressDerivationConfig + /** @ignore */ protected client?: TonClient /** @@ -59,6 +62,8 @@ export class TonBaseStaker { * This **static** method is used to convert BIP39 mnemonic to seed. In TON * network the seed is used as a private key. * + * It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + * * @returns Returns a seed derived from the mnemonic */ static getMnemonicToSeedFn = @@ -71,6 +76,8 @@ export class TonBaseStaker { * This **static** method is used to convert a seed to a keypair. Note that * TON network doesn't use BIP44 HD Path for address derivation. * + * It can be used for signer initialization, e.g. `FireblocksSigner` or `LocalSigner`. + * * @returns Returns a public and private keypair derived from the seed */ static getSeedToKeypairFn = @@ -131,17 +138,7 @@ export class TonBaseStaker { }) } - /** - * Builds a token transfer transaction - * - * @param params - Parameters for building the transaction - * @param params.destinationAddress - Where to send the tokens - * @param params.amount - The amount to stake, specified in `TON` - * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires - * @param params.memo - (Optional) A short note to include with the transaction - * - * @returns Returns a promise that resolves to a TON token transfer transaction. - */ + /** @ignore */ async buildTransferTx (params: { destinationAddress: string amount: string @@ -225,14 +222,7 @@ export class TonBaseStaker { return { tx } } - /** - * Retrieves the account balance - * - * @param params - Parameters for the request - * @param params.address - The account address to gather balance data from - * - * @returns Returns a promise that resolves to the account balance - */ + /** @ignore */ async getBalance (params: { address: string }): Promise<{ amount: string }> { const client = this.getClient() const { address } = params @@ -429,6 +419,7 @@ export class TonBaseStaker { return { status: 'success', receipt: transaction } } + /** @ignore */ protected getClient (): TonClient { if (!this.client) { throw new Error('TonStaker not initialized. Did you forget to call init()?') @@ -437,6 +428,7 @@ export class TonBaseStaker { return this.client } + /** @ignore */ protected checkIfAddressTestnetFlagMatches (address: string): void { const addr = Address.parseFriendly(address) @@ -449,6 +441,7 @@ export class TonBaseStaker { } } + /** @ignore */ protected async checkMinimumExistentialBalance (address: string, amount: string): Promise { const balance = await this.getBalance({ address }) const minBalance = this.networkConfig.minimumExistentialBalance @@ -461,6 +454,7 @@ export class TonBaseStaker { } // NOTE: this method is used only by Nominator and SingleNominator stakers, not by Pool + /** @ignore */ protected async getNominatorContractPoolData (contractAddress: string): Promise { const client = this.getClient() const response = await client.runMethod(Address.parse(contractAddress), 'get_pool_data', []) diff --git a/packages/ton/src/TonPoolStaker.ts b/packages/ton/src/TonPoolStaker.ts index c054794..3c768a4 100644 --- a/packages/ton/src/TonPoolStaker.ts +++ b/packages/ton/src/TonPoolStaker.ts @@ -4,11 +4,11 @@ import { UnsignedTx } from './types' export class TonPoolStaker extends TonBaseStaker { /** - * Builds a staking (delegation) transaction for Nominator Pool contract. - * For more information see: https://github.com/ton-blockchain/nominator-pool + * Builds a staking transaction for TON Pool contract. It uses 2 pool solution, and picks the best pool + * to stake to automatically. * * @param params - Parameters for building the transaction - * @param params.validatorAddress - The validator address to stake to + * @param params.validatorAddressPair - The validator address pair to stake to * @param params.amount - The amount to stake, specified in `TON` * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires * @@ -54,12 +54,10 @@ export class TonPoolStaker extends TonBaseStaker { } /** - * Builds a staking (delegation) transaction for Nominator Pool contract. - * For more information see: https://github.com/ton-blockchain/nominator-pool + * Builds an unstaking transaction for TON Pool contract. * * @param params - Parameters for building the transaction - * @param params.delegatorAddress - The delegator address to stake from - * @param params.validatorAddress - The validator address to stake to + * @param params.validatorAddress - The validator address to unstake from * @param params.amount - The amount to stake, specified in `TON` * @param params.validUntil - (Optional) The Unix timestamp when the transaction expires * @@ -106,6 +104,15 @@ export class TonPoolStaker extends TonBaseStaker { return { tx } } + /** + * Retrieves the staking information for a specified delegator. + * + * @param params - Parameters for the request + * @param params.delegatorAddress - The delegator (wallet) address + * @param params.validatorAddress - (Optional) The validator address to gather staking information from + * + * @returns Returns a promise that resolves to the staking information for the specified delegator. + */ async getStake (params: { delegatorAddress: string; validatorAddress: string }) { const { delegatorAddress, validatorAddress } = params const client = this.getClient() @@ -122,6 +129,14 @@ export class TonPoolStaker extends TonBaseStaker { } } + /** + * Retrieves the staking information for a specified pool, including minStake and fees information. + * + * @param params - Parameters for the request + * @param params.validatorAddress - The validator (vault) address + * + * @returns Returns a promise that resolves to the staking information for the specified pool. + */ async getPoolParams (params: { validatorAddress: string }) { const result = await this.getPoolParamsUnformatted(params) From e96853e5457c19f8e1c576e07008f797f1aa5dc1 Mon Sep 17 00:00:00 2001 From: Dmitry Yakimov Date: Wed, 27 Nov 2024 01:15:22 +0000 Subject: [PATCH 6/6] Add guide --- book/README.md | 12 +- book/SUMMARY.md | 16 +- .../ton/nominator/README.md | 2 + .../ton/nominator/methods.md | 2 +- .../ton/nominator/overview.md | 154 ++++++++++++++ book/build-your-staking-dapp/ton/overview.md | 196 ++---------------- .../ton/single-nominator/README.md | 2 + .../ton/single-nominator/methods.md | 2 +- .../ton/single-nominator/overview.md | 153 ++++++++++++++ .../ton/ton-pool/README.md | 2 + .../ton/ton-pool/methods.md | 2 +- .../ton/ton-pool/overview.md | 179 ++++++++++++++++ packages/ton/README.md | 14 +- 13 files changed, 542 insertions(+), 194 deletions(-) create mode 100644 book/build-your-staking-dapp/ton/nominator/README.md create mode 100644 book/build-your-staking-dapp/ton/nominator/overview.md create mode 100644 book/build-your-staking-dapp/ton/single-nominator/README.md create mode 100644 book/build-your-staking-dapp/ton/single-nominator/overview.md create mode 100644 book/build-your-staking-dapp/ton/ton-pool/README.md create mode 100644 book/build-your-staking-dapp/ton/ton-pool/overview.md diff --git a/book/README.md b/book/README.md index 5a2c6a5..29f78e2 100644 --- a/book/README.md +++ b/book/README.md @@ -337,9 +337,9 @@ console.log(status) // 'success' // Configuration // ------------- -import { TonStaker } from '@chorus-one/ton' +import { TonPoolStaker } from '@chorus-one/ton' -const staker = new TonStaker({ +const staker = new TonPoolStaker({ rpcUrl: 'https://toncenter.com/api/v2/jsonRPC' }) @@ -351,11 +351,13 @@ await staker.init() const delegatorAddress = '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr' // You can use the Chorus One validator address or specify your own -const validatorAddress = '' +const validatorAddressPair = [ + 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' +] const { tx } = await staker.buildStakeTx({ - delegatorAddress, - validatorAddress, + validatorAddressPair, amount: '1' // 1 TON }) diff --git a/book/SUMMARY.md b/book/SUMMARY.md index d293a9a..c8362d2 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -25,7 +25,15 @@ - [Methods](build-your-staking-dapp/solana/methods.md) - [TON](build-your-staking-dapp/ton/README.md) - [Overview](build-your-staking-dapp/ton/overview.md) - - [Methods](build-your-staking-dapp/ton/methods.md) + - [TON Pool](build-your-staking-dapp/ton/ton-pool/README.md) + - [Overview](build-your-staking-dapp/ton/ton-pool/overview.md) + - [Methods](build-your-staking-dapp/ton/ton-pool/methods.md) + - [Nominator](build-your-staking-dapp/ton/nominator/README.md) + - [Overview](build-your-staking-dapp/ton/nominator/overview.md) + - [Methods](build-your-staking-dapp/ton/nominator/methods.md) + - [Single Nominator](build-your-staking-dapp/ton/single-nominator/README.md) + - [Overview](build-your-staking-dapp/ton/single-nominator/overview.md) + - [Methods](build-your-staking-dapp/ton/single-nominator/methods.md) ## Ethereum Tutorial @@ -57,7 +65,9 @@ - [NearStaker](docs/classes/near_src.NearStaker.md) - [SolanaStaker](docs/classes/solana_src.SolanaStaker.md) - [SubstrateStaker](docs/classes/substrate_src.SubstrateStaker.md) - - [TonStaker](docs/classes/ton_src.TonStaker.md) + - [TonPoolStaker](docs/classes/ton_src.TonPoolStaker.md) + - [TonNominatorPoolStaker](docs/classes/ton_src.TonNominatorPoolStaker.md) + - [TonSingleNominatorPoolStaker](docs/classes/ton_src.TonSingleNominatorPoolStaker.md) - [Signers](api-reference/signers/README.md) - [FireblocksSigner](docs/classes/signer_fireblocks_src.FireblocksSigner.md) - [LocalSigner](docs/classes/signer_local_src.LocalSigner.md) @@ -67,7 +77,7 @@ - [Transaction](docs/interfaces/ethereum_src.Transaction.md) - [Polkadot (Substrate)](api-reference/types/polkadot-substrate/README.md) - [RewardDestination](docs/enums/substrate_src.RewardDestination.md) - - [Ton](api-reference/types/ton/README.md) + - [TON](api-reference/types/ton/README.md) - [AddressDerivationConfig](docs/interfaces/ton_src.AddressDerivationConfig.md) - [NominatorInfo](docs/interfaces/ton_src.NominatorInfo.md) - [PoolData](docs/interfaces/ton_src.PoolData.md) diff --git a/book/build-your-staking-dapp/ton/nominator/README.md b/book/build-your-staking-dapp/ton/nominator/README.md new file mode 100644 index 0000000..0ad48bd --- /dev/null +++ b/book/build-your-staking-dapp/ton/nominator/README.md @@ -0,0 +1,2 @@ +# Nominator Pool + diff --git a/book/build-your-staking-dapp/ton/nominator/methods.md b/book/build-your-staking-dapp/ton/nominator/methods.md index a9927a4..6d7167f 100644 --- a/book/build-your-staking-dapp/ton/nominator/methods.md +++ b/book/build-your-staking-dapp/ton/nominator/methods.md @@ -1,4 +1,4 @@ -# Methods +# Nominator Pool: Methods This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **Nominator Pool** contract. diff --git a/book/build-your-staking-dapp/ton/nominator/overview.md b/book/build-your-staking-dapp/ton/nominator/overview.md new file mode 100644 index 0000000..7eceee7 --- /dev/null +++ b/book/build-your-staking-dapp/ton/nominator/overview.md @@ -0,0 +1,154 @@ +# Nominator Pool: Overview + +The **Nominator Pool** is ideal for groups looking to pool resources and stake collectively. It allows up to 40 users to combine their holdings, with a collective minimum of 400,000 TON (at least 10,000 TON per user). Rewards are automatically distributed proportionally, making it a convenient and efficient option for shared staking. + +The **Chorus One SDK** simplifies this process by providing developers with the tools needed to build, sign, and broadcast staking transactions. + +{% hint style="info" %} + +**Compatibility Notice** + +The methods provided in this documentation are compatible with popular TON libraries such as `@ton/ton`. This compatibility ensures that you can seamlessly integrate these methods into your existing TON projects. + +{% endhint %} + +## Setting Up the Staker + +To get started with staking on TON using the Chorus One SDK, you will first need to initialize the SDK. + +- **Note:** For testing purposes we will be using the TON testnet. + +First, create an instance of `TonNominatorPoolStaker` with the following configuration: + +```javascript +import { TonNominatorPoolStaker } from '@chorus-one/ton' + +const staker = new TonNominatorPoolStaker({ + rpcUrl: 'https://testnet.toncenter.com/api/v2/jsonRPC' +}) +``` + +**Configuration Parameters**: + +- **rpcUrl**: The URL of the TON RPC endpoint. This is where the SDK will connect to interact with the network. In this example, we are using a public endpoint for the testnet. + +--- + +## Initializing the Staker + +After configuring the `TonNominatorPoolStaker`, you can initialize it to prepare for staking operations. + +This can be done via the following input: + +```javascript +await staker.init() +``` + +The `init` method establishes a connection with the configured RPC endpoint and prepares the staker for operations such as building and broadcasting transactions. + +--- + +## Building Transactions + +Once the staker and signer are set up, you can start building transactions for staking operations. + +The `TonNominatorPoolStaker` class provides methods to build transactions for staking, unstaking, and wallet deployment. + +- You can learn more about these methods in the [Methods](methods.md) section. + +**Example of building a nominator pool staking transaction:** + +```javascript +const { tx } = await staker.buildStakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + amount: '1', // 1 TON +}) +``` + +--- + +## Getting the Validator Address provided by Chorus One + +To be eligible for the validator election process, validators need a minimum stake of 400,000 TON locked in the validator contract: + +Due to above requirements we deploy the TON Validator contract upon client request. If you'd like to stake TON with Chorus One, please contact us at [staking@chorus.one](mailto:staking@chorus.one) + +--- + +## Signing the Transaction + +Once the transaction is built, you can sign that transaction using your own signing solution e.g.: + +```js +const signedTx = await yourWallet.signTransaction(tx) +``` + +Additionally, you can use the Chorus One SDK to sign transactions using Fireblocks, mnemonic or other methods. + +- For detailed information on setting up and configuring these options, please refer to the [What is a Signer?](../../signers-explained/what-is-a-signer.md) section. + +{% tabs %} +{% tab title="Using Fireblocks for Signing" %} +By integrating Fireblocks you can leverage its robust security features to sign transactions on the TON network. To set up Fireblocks, you must provide the necessary API key, secret key, and vault ID. + +Example shown below: + +```javascript +import { TonNominatorPoolStaker } from '@chorus-one/TON' +import { FireblocksSigner } from '@chorus-one/signer-fireblocks' + +const signer = new FireblocksSigner({ + apiSecretKey: 'your-api-secret-key', + apiKey: 'your-api-key', + vaultName: 'your-vault-name', + assetId: 'TON_TEST', + addressDerivationFn: TonNominatorPoolStaker.getAddressDerivationFn() +}) + +await signer.init() + +const { signedTx } = await staker.sign({ + signer, + signerAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + tx +}) +``` + +For more information please refer to the [Signing with Fireblocks](../../signers-explained/fireblocks.md) +{% endtab %} +{% endtabs %} + +--- + +## Broadcasting the Transaction + +After signing the transaction, you will need to broadcast it to the network. You can do this using the `broadcast` method: + +```javascript +const txHash = await staker.broadcast({ signedTx }) +``` + +And now you can track the transaction status: + +```javascript +const { status, receipt } = await staker.getTxStatus({ + address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + txHash +}) + +console.log(status) // 'success' +``` + +--- + +## Next Steps + +In this section you learned how to set up the Chorus One SDK for the TON network using the TON testnet, which included how to build staking transactions, sign, broadcast, and track them. + +- To learn more about the available methods on `TonNominatorPoolStaker`, continue to the [Methods](methods.md) section. + +## Further Reading + +- [TonNominatorPoolStaker API Reference](../../../docs/classes/ton_src.TonNominatorPoolStaker.md) +- [What is a Signer?](../../signers-explained/what-is-a-signer.md) diff --git a/book/build-your-staking-dapp/ton/overview.md b/book/build-your-staking-dapp/ton/overview.md index 17997de..c2c4d22 100644 --- a/book/build-your-staking-dapp/ton/overview.md +++ b/book/build-your-staking-dapp/ton/overview.md @@ -8,190 +8,30 @@ Toncoin (TON) the native cryptocurrency of the TON blockchain, excels in scalabi The **Chorus One SDK** simplifies this process by providing developers with the tools needed to build, sign, and broadcast staking transactions. -It supports: +## Pick the Pool Technology -- The official Nominator Pool smart contracts available for review on the official [TON Docs](https://docs.ton.org/participate/network-maintenance/nominators) -- The official Single Nominator Pool smart contract available for review on the official [TON Docs](https://docs.ton.org/participate/network-maintenance/single-nominator) +Before you start developing your staking application, you need to decide which pool technology you want to use. We recommend the **TON Pool** for most use cases, as it is easy to start using, it supports an unlimited number of delegators, and it's minimal stake is only 10 TON. -This guide will walk you through the fundamentals of staking on TON using the Chorus One SDK. + However, if you have specific requirements, you can choose the **Nominator** or **Single Nominator** pool. -{% hint style="info" %} - -**Compatibility Notice** - -The methods provided in this documentation are compatible with popular TON libraries such as `@ton/ton`. This compatibility ensures that you can seamlessly integrate these methods into your existing TON projects. - -{% endhint %} - -## Setting Up the Staker - -To get started with staking on TON using the Chorus One SDK, you will first need to initialize the SDK. - -- **Note:** For testing purposes we will be using the TON testnet. - -First, create an instance of `TonStaker` with the following configuration: - -```javascript -import { TonStaker } from '@chorus-one/ton' - -const staker = new TonStaker({ - rpcUrl: 'https://testnet.toncenter.com/api/v2/jsonRPC' -}) -``` - -**Configuration Parameters**: - -- **rpcUrl**: The URL of the TON RPC endpoint. This is where the SDK will connect to interact with the network. In this example, we are using a public endpoint for the testnet. -- **allowSeamlessWalletDeployment**: (Optional) If enabled, the wallet contract is deployed automatically when needed. Default is `false`. -- **allowTransferToInactiveAccount**: (Optional) Allows token transfers to inactive accounts. Default is `false`. -- **minimumExistentialBalance**: (Optional) The amount of TON to keep in the wallet. Default is `'5'`. -- **addressDerivationConfig** (Optional): TON address derivation configuration, which includes: - - **walletContractVersion**: Version of the wallet contract. Default is `'4'`. - - **workchain**: The workchain ID. Default is `0`. - - **bounceable**: Indicates if the address is bounceable. Default is `false`. - - **testOnly**: Indicates if the configuration is for testing purposes only. Default is `false`. - - **urlSafe**: Indicates if the address should be URL-safe. Default is `false`. - -Learn more about the address derivation params at [TEP-0002](https://github.com/ton-blockchain/TEPs/blob/master/text/0002-address.md#smart-contract-addresses) - ---- - -## Initializing the Staker - -After configuring the `TonStaker`, you can initialize it to prepare for staking operations. - -This can be done via the following input: - -```javascript -await staker.init() -``` - -The `init` method establishes a connection with the configured RPC endpoint and prepares the staker for operations such as building and broadcasting transactions. - ---- - -## Building Transactions - -Once the staker and signer are set up, you can start building transactions for staking operations. - -The `TonStaker` class provides methods to build transactions for staking and transfers of tokens. - -- You can learn more about these methods in the [Methods](methods.md) section. - -On the TON blockchain, users stake their tokens through smart contracts. There are different options available depending on your staking preferences: - -[**Nominator Pool**](https://github.com/ton-blockchain/nominator-pool): This involves multiple nominators who collectively stake their tokens and participate in the decision-making process for selecting validators. It is a decentralized approach, ideal for community-driven projects. - -**Example of building a nominator pool staking transaction:** - -```javascript -const { tx } = await staker.buildStakeNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - amount: '1' // 1 TON -}) -``` - -[**Single Nominator Pool**](https://github.com/orbs-network/single-nominator/tree/main): This allows a single entity to act as the sole nominator, making all decisions regarding staking. It offers centralized control and simpler management, suitable for entities that prefer centralized decision-making. - -**Example of building a single nominator pool staking transaction:** +| | [TON Pool](./ton-pool/overview.md) | [Nominator](./nominator/overview.md) | [Single Nominator](./single-nominator/overview.md) | +| - | - | - |- | +| Recommended | ✅ | | | +| Best for | Most use cases | Large delegators | Single delegators | +| Delegators | ∞ | 40 Max | 1 | +| Minimal Stake | 10 TON | 10,000 TON | 400,000 TON | +| Partial Withdrawal | ✅ | ❌ Must withdraw all funds | ✅| +| Pool creation | ✅ Not needed | ❌ Per request | ❌ Per request | -```javascript -const { tx } = await staker.buildStakeSingleNominatorPoolTx({ - delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', - amount: '1' // 1 TON -}) -``` +Once you have chosen the pool technology, continue with the respective guide. ---- +- [TON Pool Guide](./ton-pool/overview.md) +- [Nominator Pool Guide](./nominator/overview.md) +- [Single Nominator Pool Guide](./single-nominator/overview.md) -## Getting the Validator Address provided by Chorus One - -To be eligible for the validator election process, validators need a minimum stake of 300,000 TON locked in the validator contract: - -1. single-nominator - only one delegator allowed -2. nominator-pool - up to 40 delegators allowed - -{% hint style="info" %} -Due to above requirements we deploy the TON Validator contract upon client request. If you'd like to stake TON with Chorus One, please contact us at [staking@chorus.one](mailto:staking@chorus.one) -{% endhint %} - ---- - -## Signing the Transaction - -Once the transaction is built, you can sign that transaction using your own signing solution e.g.: - -```js -const signedTx = await yourWallet.signTransaction(tx) -``` - -Additionally, you can use the Chorus One SDK to sign transactions using Fireblocks, mnemonic or other methods. - -- For detailed information on setting up and configuring these options, please refer to the [What is a Signer?](../../signers-explained/what-is-a-signer.md) section. - -{% tabs %} -{% tab title="Using Fireblocks for Signing" %} -By integrating Fireblocks you can leverage its robust security features to sign transactions on the TON network. To set up Fireblocks, you must provide the necessary API key, secret key, and vault ID. - -Example shown below: - -```javascript -import { TonStaker } from '@chorus-one/TON' -import { FireblocksSigner } from '@chorus-one/signer-fireblocks' - -const signer = new FireblocksSigner({ - apiSecretKey: 'your-api-secret-key', - apiKey: 'your-api-key', - vaultName: 'your-vault-name', - assetId: 'TON_TEST', - addressDerivationFn: TonStaker.getAddressDerivationFn() -}) - -await signer.init() - -const { signedTx } = await staker.sign({ - signer, - signerAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - tx -}) -``` - -For more information please refer to the [Signing with Fireblocks](../../signers-explained/fireblocks.md) -{% endtab %} -{% endtabs %} - ---- - -## Broadcasting the Transaction - -After signing the transaction, you will need to broadcast it to the network. You can do this using the `broadcast` method: - -```javascript -const txHash = await staker.broadcast({ signedTx }) -``` - -And now you can track the transaction status: - -```javascript -const { status, receipt } = await staker.getTxStatus({ - address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', - txHash -}) - -console.log(status) // 'success' -``` - ---- - -## Next Steps - -In this section you learned how to set up the Chorus One SDK for the TON network using the TON testnet, which included how to build staking transactions, sign, broadcast, and track them. - -- To learn more about the available methods on `TonStaker`, continue to the [Methods](methods.md) section. ## Further Reading -- [TonStaker API Reference](../../docs/classes/ton_src.TonStaker.md) -- [What is a Signer?](../../signers-explained/what-is-a-signer.md) +- [Why to Stake on TON](https://chorus.one/articles/first-look-exploring-standout-innovations-in-the-ton-ecosystem) +- [How Staking Works on TON](https://chorus.one/articles/ton-series-2-the-mechanisms-of-staking-ton) + diff --git a/book/build-your-staking-dapp/ton/single-nominator/README.md b/book/build-your-staking-dapp/ton/single-nominator/README.md new file mode 100644 index 0000000..2d7cf54 --- /dev/null +++ b/book/build-your-staking-dapp/ton/single-nominator/README.md @@ -0,0 +1,2 @@ +# Single Nominator Pool + diff --git a/book/build-your-staking-dapp/ton/single-nominator/methods.md b/book/build-your-staking-dapp/ton/single-nominator/methods.md index 1f96bba..887ef74 100644 --- a/book/build-your-staking-dapp/ton/single-nominator/methods.md +++ b/book/build-your-staking-dapp/ton/single-nominator/methods.md @@ -1,4 +1,4 @@ -# Methods +# Single Nominator Pool: Methods This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **Single Nominator Pool** contract. diff --git a/book/build-your-staking-dapp/ton/single-nominator/overview.md b/book/build-your-staking-dapp/ton/single-nominator/overview.md new file mode 100644 index 0000000..f74772d --- /dev/null +++ b/book/build-your-staking-dapp/ton/single-nominator/overview.md @@ -0,0 +1,153 @@ +# Single Nominator Pool: Overview + +The **Single Nominator Pool** is a secure staking solution designed for large holders (minimum 400,000 TON) who value full control over their assets. By removing the need for multiple nominators, it minimizes the attack surface and enhances security. This pool is tailored for solo stakers, offering partial withdrawals and a straightforward, independent staking experience. + +The **Chorus One SDK** simplifies staking process by providing developers with the tools needed to build, sign, and broadcast staking transactions. + +{% hint style="info" %} + +**Compatibility Notice** + +The methods provided in this documentation are compatible with popular TON libraries such as `@ton/ton`. This compatibility ensures that you can seamlessly integrate these methods into your existing TON projects. + +{% endhint %} + +## Setting Up the Staker + +To get started with staking on TON using the Chorus One SDK, you will first need to initialize the SDK. + +- **Note:** For testing purposes we will be using the TON testnet. + +First, create an instance of `TonSingleNominatorPoolStaker` with the following configuration: + +```javascript +import { TonSingleNominatorPoolStaker } from '@chorus-one/ton' + +const staker = new TonSingleNominatorPoolStaker({ + rpcUrl: 'https://testnet.toncenter.com/api/v2/jsonRPC' +}) +``` + +**Configuration Parameters**: + +- **rpcUrl**: The URL of the TON RPC endpoint. This is where the SDK will connect to interact with the network. In this example, we are using a public endpoint for the testnet. + +--- + +## Initializing the Staker + +After configuring the `TonSingleNominatorPoolStaker`, you can initialize it to prepare for staking operations. + +This can be done via the following input: + +```javascript +await staker.init() +``` + +The `init` method establishes a connection with the configured RPC endpoint and prepares the staker for operations such as building and broadcasting transactions. + +--- + +## Building Transactions + +Once the staker and signer are set up, you can start building transactions for staking operations. + +The `TonSingleNominatorPoolStaker` class provides methods to build transactions for staking, unstaking, and wallet deployment. + +- You can learn more about these methods in the [Methods](methods.md) section. + +**Example of building a nominator pool staking transaction:** + +```javascript +const { tx } = await staker.buildStakeTx({ + delegatorAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + validatorAddress: 'Ef9rkkVM0xr4rKZZMAfBkXU0U8qMnkTmqbUhYRNBvRt5knxP', + amount: '1', // 1 TON +}) +``` +--- + +## Getting the Validator Address provided by Chorus One + +To be eligible for the validator election process, validators need a minimum stake of 400,000 TON locked in the validator contract: + +Due to above requirements we deploy the TON Validator contract upon client request. If you'd like to stake TON with Chorus One, please contact us at [staking@chorus.one](mailto:staking@chorus.one) + +--- + +## Signing the Transaction + +Once the transaction is built, you can sign that transaction using your own signing solution e.g.: + +```js +const signedTx = await yourWallet.signTransaction(tx) +``` + +Additionally, you can use the Chorus One SDK to sign transactions using Fireblocks, mnemonic or other methods. + +- For detailed information on setting up and configuring these options, please refer to the [What is a Signer?](../../signers-explained/what-is-a-signer.md) section. + +{% tabs %} +{% tab title="Using Fireblocks for Signing" %} +By integrating Fireblocks you can leverage its robust security features to sign transactions on the TON network. To set up Fireblocks, you must provide the necessary API key, secret key, and vault ID. + +Example shown below: + +```javascript +import { TonSingleNominatorPoolStaker } from '@chorus-one/TON' +import { FireblocksSigner } from '@chorus-one/signer-fireblocks' + +const signer = new FireblocksSigner({ + apiSecretKey: 'your-api-secret-key', + apiKey: 'your-api-key', + vaultName: 'your-vault-name', + assetId: 'TON_TEST', + addressDerivationFn: TonSingleNominatorPoolStaker.getAddressDerivationFn() +}) + +await signer.init() + +const { signedTx } = await staker.sign({ + signer, + signerAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + tx +}) +``` + +For more information please refer to the [Signing with Fireblocks](../../signers-explained/fireblocks.md) +{% endtab %} +{% endtabs %} + +--- + +## Broadcasting the Transaction + +After signing the transaction, you will need to broadcast it to the network. You can do this using the `broadcast` method: + +```javascript +const txHash = await staker.broadcast({ signedTx }) +``` + +And now you can track the transaction status: + +```javascript +const { status, receipt } = await staker.getTxStatus({ + address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + txHash +}) + +console.log(status) // 'success' +``` + +--- + +## Next Steps + +In this section you learned how to set up the Chorus One SDK for the TON network using the TON testnet, which included how to build staking transactions, sign, broadcast, and track them. + +- To learn more about the available methods on `TonSingleNominatorPoolStaker`, continue to the [Methods](methods.md) section. + +## Further Reading + +- [TonSingleNominatorPoolStaker API Reference](../../../docs/classes/ton_src.TonSingleNominatorPoolStaker.md) +- [What is a Signer?](../../../signers-explained/what-is-a-signer.md) diff --git a/book/build-your-staking-dapp/ton/ton-pool/README.md b/book/build-your-staking-dapp/ton/ton-pool/README.md new file mode 100644 index 0000000..4dff18d --- /dev/null +++ b/book/build-your-staking-dapp/ton/ton-pool/README.md @@ -0,0 +1,2 @@ +# TON Pool + diff --git a/book/build-your-staking-dapp/ton/ton-pool/methods.md b/book/build-your-staking-dapp/ton/ton-pool/methods.md index 7fa4177..b56f847 100644 --- a/book/build-your-staking-dapp/ton/ton-pool/methods.md +++ b/book/build-your-staking-dapp/ton/ton-pool/methods.md @@ -1,4 +1,4 @@ -# Methods +# TON Pool: Methods This section provides an overview of the key methods available in the **Chorus One SDK** for staking on the TON Network via the **TON Pool** contract. diff --git a/book/build-your-staking-dapp/ton/ton-pool/overview.md b/book/build-your-staking-dapp/ton/ton-pool/overview.md new file mode 100644 index 0000000..dd3d29c --- /dev/null +++ b/book/build-your-staking-dapp/ton/ton-pool/overview.md @@ -0,0 +1,179 @@ +# TON Pool: Overview + +The **TON Pool** is the most accessible and flexible staking solution, designed for users of all sizes with a low minimum stake of just 10 TON. It supports unlimited delegators, automates staking management, and offers partial withdrawals for convenience. Easy to use and scalable, it's the go-to option for most staking needs. + +The **Chorus One SDK** simplifies this process by providing developers with the tools needed to build, sign, and broadcast staking transactions. + +{% hint style="info" %} + +**Compatibility Notice** + +The methods provided in this documentation are compatible with popular TON libraries such as `@ton/ton`. This compatibility ensures that you can seamlessly integrate these methods into your existing TON projects. + +{% endhint %} + +## Understanding Key Concepts + + +### Battle-Tested TON Whales Contracts + +The **TON Pool** is powered by [TON Whales contracts](https://tonwhales.com/), a robust and proven technology that has operated reliably in the TON ecosystem for several years. These contracts have been tested extensively in real-world conditions, providing a solid foundation for secure and efficient staking operations. + +## Two Validator Pool Addresses + +To ensure uninterrupted network participation, TON Pool utilizes two validator pool addresses: one for odd cycles and another for even cycles. These pools alternate between cycles to enable seamless staking and validation without downtime. This design ensures continuous operation and smooth participation in the TON blockchain’s validation process. + +When using the **Chorus One SDK**, you must provide a pair of validator addresses (odd and even) when configuring your staking transactions. This ensures your staked assets are properly integrated into the network’s alternating validation mechanism. + +## Setting Up the Staker + +To get started with staking on TON using the Chorus One SDK, you will first need to initialize the SDK. + +- **Note:** For testing purposes we will be using the TON testnet. + +First, create an instance of `TonPoolStaker` with the following configuration: + +```javascript +import { TonPoolStaker } from '@chorus-one/ton' + +const staker = new TonPoolStaker({ + rpcUrl: 'https://testnet.toncenter.com/api/v2/jsonRPC' +}) +``` + +**Configuration Parameters**: + +- **rpcUrl**: The URL of the TON RPC endpoint. This is where the SDK will connect to interact with the network. In this example, we are using a public endpoint for the testnet. + +--- + +## Initializing the Staker + +After configuring the `TonPoolStaker`, you can initialize it to prepare for staking operations. + +This can be done via the following input: + +```javascript +await staker.init() +``` + +The `init` method establishes a connection with the configured RPC endpoint and prepares the staker for operations such as building and broadcasting transactions. + +--- + +## Building Transactions + +Once the staker and signer are set up, you can start building transactions for staking operations. + +The `TonPoolStaker` class provides methods to build transactions for staking, unstaking, and wallet deployment. + +- You can learn more about these methods in the [Methods](methods.md) section. + +**Example of building a single nominator pool staking transaction:** + +```javascript +const { tx } = await staker.buildStakeTx({ + validatorAddressPair: [ + 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' + ], + amount: '2', // 2 TON +}) +``` + +--- + +## Getting the Validators Pair Address provided by Chorus One + +The `@chorus-one/ton` module includes Chorus One validator pairs for the chains, organized by network(mainnet or testnet). You can use these addresses when building transactions. + +```javascript +import { CHORUS_ONE_TON_VALIDATORS } from '@chorus-one/ton' + +const validatorAddressPair = CHORUS_ONE_TON_VALIDATORS.testnet.tonPoolPair +console.log(vaultAddressPair) +// [ +// 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', +// 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' +// ] +``` + + +--- + +## Signing the Transaction + +Once the transaction is built, you can sign that transaction using your own signing solution e.g.: + +```js +const signedTx = await yourWallet.signTransaction(tx) +``` + +Additionally, you can use the Chorus One SDK to sign transactions using Fireblocks, mnemonic or other methods. + +- For detailed information on setting up and configuring these options, please refer to the [What is a Signer?](../../signers-explained/what-is-a-signer.md) section. + +{% tabs %} +{% tab title="Using Fireblocks for Signing" %} +By integrating Fireblocks you can leverage its robust security features to sign transactions on the TON network. To set up Fireblocks, you must provide the necessary API key, secret key, and vault ID. + +Example shown below: + +```javascript +import { TonPoolStaker } from '@chorus-one/TON' +import { FireblocksSigner } from '@chorus-one/signer-fireblocks' + +const signer = new FireblocksSigner({ + apiSecretKey: 'your-api-secret-key', + apiKey: 'your-api-key', + vaultName: 'your-vault-name', + assetId: 'TON_TEST', + addressDerivationFn: TonPoolStaker.getAddressDerivationFn() +}) + +await signer.init() + +const { signedTx } = await staker.sign({ + signer, + signerAddress: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + tx +}) +``` + +For more information please refer to the [Signing with Fireblocks](../../signers-explained/fireblocks.md) +{% endtab %} +{% endtabs %} + +--- + +## Broadcasting the Transaction + +After signing the transaction, you will need to broadcast it to the network. You can do this using the `broadcast` method: + +```javascript +const txHash = await staker.broadcast({ signedTx }) +``` + +And now you can track the transaction status: + +```javascript +const { status, receipt } = await staker.getTxStatus({ + address: '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr', + txHash +}) + +console.log(status) // 'success' +``` + +--- + +## Next Steps + +In this section you learned how to set up the Chorus One SDK for the TON network using the TON testnet, which included how to build staking transactions, sign, broadcast, and track them. + +- To learn more about the available methods on `TonPoolStaker`, continue to the [Methods](methods.md) section. + +## Further Reading + +- [TonPoolStaker API Reference](../../../docs/classes/ton_src.TonPoolStaker.md) +- [What is a Signer?](../../../signers-explained/what-is-a-signer.md) diff --git a/packages/ton/README.md b/packages/ton/README.md index 1da9d93..7fdefc1 100644 --- a/packages/ton/README.md +++ b/packages/ton/README.md @@ -22,9 +22,9 @@ Here is a basic example of how to use the Chorus One SDK to build, sign, and bro // Configuration // ------------- -import { TonStaker } from '@chorus-one/ton' +import { TonPoolStaker } from '@chorus-one/ton' -const staker = new TonStaker({ +const staker = new TonPoolStaker({ rpcUrl: 'https://toncenter.com/api/v2/jsonRPC' }) @@ -34,11 +34,15 @@ await staker.init() // ------------------------ const delegatorAddress = '0QDsF87nkTYgkvu1z5xveCEGTRnZmEVaVT0gdxoeyaNvmoCr' -const validatorAddress = '' + +// You can use the Chorus One validator address or specify your own +const validatorAddressPair = [ + 'kQAHBakDk_E7qLlNQZxJDsqj_ruyAFpqarw85tO-c03fK26F', + 'kQCltujow9Sq3ZVPPU6CYGfqwDxYwjlmFGZ1Wt0bAYebio4o' +] const { tx } = await staker.buildStakeTx({ - delegatorAddress, - validatorAddress, + validatorAddressPair, amount: '1' // 1 TON })