Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run cleanup on ton package #20

Merged
merged 2 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions packages/staking-cli/src/cmd/ton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async function init (

async function runTx (
msgType: string,
options: { validatorIndex?: '1' | '2' | undefined, disableStatefulCalculation?: boolean } | undefined,
options: { validatorIndex?: '1' | '2' | undefined; disableStatefulCalculation?: boolean } | undefined,
cmd: Command<[string]> | Command<[string, string]> | Command<[string, string, string]> | Command<[]>,
arg: string[]
): Promise<void> {
Expand Down Expand Up @@ -152,7 +152,7 @@ async function runTx (
cmd.error('validator address not found in the pool', { exitCode: 1, code: `${msgType}.tx.abort` })
}

console.log('Delegating to pool #' + (poolIndex+1) + ': ' + stakingPoolAddressPair[poolIndex])
console.log('Delegating to pool #' + (poolIndex + 1) + ': ' + stakingPoolAddressPair[poolIndex])

unsignedTx = (
await tonStaker.buildStakeTx({
Expand All @@ -172,8 +172,8 @@ async function runTx (

let validatorAddressPair: [string, string] = [config.validatorAddress, config.validatorAddress2]
if (options?.validatorIndex !== undefined) {
const validatorIndex = parseInt(options.validatorIndex)
validatorAddressPair = [validatorAddressPair[validatorIndex - 1], ""]
const validatorIndex = parseInt(options.validatorIndex)
validatorAddressPair = [validatorAddressPair[validatorIndex - 1], '']
}

unsignedTx = (
Expand All @@ -185,7 +185,12 @@ async function runTx (
})
).tx

console.log('Unstaking from ' + unsignedTx.messages?.length + ' contracts: ' + unsignedTx.messages?.map((msg) => msg.address).join(', '))
console.log(
'Unstaking from ' +
unsignedTx.messages?.length +
' contracts: ' +
unsignedTx.messages?.map((msg) => msg.address).join(', ')
)
break
}
case 'delegate-nominator-pool': {
Expand Down Expand Up @@ -320,7 +325,7 @@ async function getDelegatePoolTx (amount: string, options: any, cmd: Command<[st

async function getUnstakePoolTx (
amount: string,
options: { validatorIndex?: '1' | '2' | undefined, disableStatefulCalculation?: boolean },
options: { validatorIndex?: '1' | '2' | undefined; disableStatefulCalculation?: boolean },
cmd: Command<[string]>
): Promise<void> {
await runTx('unstake-pool', options, cmd, [amount])
Expand Down
68 changes: 35 additions & 33 deletions packages/ton/src/TonBaseStaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,14 @@ export class TonBaseStaker {

const tx = {
validUntil: defaultValidUntil(validUntil),
messages: [{
address: destinationAddress,
bounceable: bounceable,
amount: toNano(amount),
payload: memo ?? ''
}]
messages: [
{
address: destinationAddress,
bounceable: bounceable,
amount: toNano(amount),
payload: memo ?? ''
}
]
}

return { tx }
Expand Down Expand Up @@ -302,33 +304,33 @@ export class TonBaseStaker {
const msgs = tx.messages

if (msgs !== undefined && msgs.length > 0) {
msgs.map((msg) => {
if (msg.payload === undefined) {
throw new Error('missing payload')
}

// ensure the address is for the right network
this.checkIfAddressTestnetFlagMatches(msg.address)

// ensure the balance is above the minimum existential balance
this.checkMinimumExistentialBalance(signerAddress, fromNano(msg.amount))

// TON TEP-0002 defines how the flags within the address should be handled
// reference: https://github.com/ton-blockchain/TEPs/blob/master/text/0002-address.md#wallets-applications
//
// The Chorus TON SDK is not strictly a wallet application, so we follow most (but not all) of the rules.
// Specifically, we force the bounce flag wherever possible (for safety), but don't enforce user to specify
// the bounceable source address. This is because a user may use fireblocks signer where the address is in non-bounceable format.
internalMsgs.push(
internal({
value: msg.amount,
bounce: msg.bounceable,
to: msg.address,
body: msg.payload,
init: msg.stateInit
})
)
})
msgs.map((msg) => {
if (msg.payload === undefined) {
throw new Error('missing payload')
}

// ensure the address is for the right network
this.checkIfAddressTestnetFlagMatches(msg.address)

// ensure the balance is above the minimum existential balance
this.checkMinimumExistentialBalance(signerAddress, fromNano(msg.amount))

// TON TEP-0002 defines how the flags within the address should be handled
// reference: https://github.com/ton-blockchain/TEPs/blob/master/text/0002-address.md#wallets-applications
//
// The Chorus TON SDK is not strictly a wallet application, so we follow most (but not all) of the rules.
// Specifically, we force the bounce flag wherever possible (for safety), but don't enforce user to specify
// the bounceable source address. This is because a user may use fireblocks signer where the address is in non-bounceable format.
internalMsgs.push(
internal({
value: msg.amount,
bounce: msg.bounceable,
to: msg.address,
body: msg.payload,
init: msg.stateInit
})
)
})
} else {
internalMsgs = []
}
Expand Down
71 changes: 33 additions & 38 deletions packages/ton/src/TonClient.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,41 @@
import {
TonClient as NativeTonClient,
Cell,
} from '@ton/ton'
import axios from "axios";
import { z } from 'zod';
import { TonClient as NativeTonClient, Cell } from '@ton/ton'
import axios from 'axios'
import { z } from 'zod'

const configParamCodec = z.object({
ok: z.boolean(),
result: z.object({
'@type': z.string(),
config: z.object({
'@type': z.string(),
bytes: z.string(),
}),
'@extra': z.string(),
})
});
ok: z.boolean(),
result: z.object({
'@type': z.string(),
config: z.object({
'@type': z.string(),
bytes: z.string()
}),
'@extra': z.string()
})
})

export class TonClient extends NativeTonClient {
async getConfigParam (config_id: number): Promise<Cell> {
const url = new URL(this.parameters.endpoint)
const base = url.pathname.split('/').slice(0, -1).join('/')
url.pathname = base + '/getConfigParam'
url.searchParams.set('config_id', config_id.toString())

const r = await axios.get(url.toString())
if (r.status !== 200) {
throw Error('Unable to fetch config param, error: ' + r.status + ' ' + r.statusText)
}

async getConfigParam (config_id: number): Promise<Cell> {
const url = new URL(this.parameters.endpoint)
const base = url.pathname.split('/').slice(0, -1).join('/')
url.pathname = base + '/getConfigParam'
url.searchParams.set('config_id', config_id.toString())

const r = await axios.get(url.toString())
if (r.status !== 200) {
throw Error('Unable to fetch config param, error: ' + r.status + ' ' + r.statusText)
}

const configParam = configParamCodec.safeParse(r.data)
if (!configParam.success) {
throw Error('Unable to parse config param, error: ' + JSON.stringify(configParam.error))
}

const paramBytes = configParam.data?.result.config.bytes
if (paramBytes === undefined) {
throw Error('Failed to get config param bytes')
}
const configParam = configParamCodec.safeParse(r.data)
if (!configParam.success) {
throw Error('Unable to parse config param, error: ' + JSON.stringify(configParam.error))
}

return Cell.fromBoc(Buffer.from(paramBytes, 'base64'))[0];
const paramBytes = configParam.data?.result.config.bytes
if (paramBytes === undefined) {
throw Error('Failed to get config param bytes')
}
}

return Cell.fromBoc(Buffer.from(paramBytes, 'base64'))[0]
}
}
38 changes: 21 additions & 17 deletions packages/ton/src/TonNominatorPoolStaker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@ export class TonNominatorPoolStaker extends TonBaseStaker {

const tx = {
validUntil: defaultValidUntil(validUntil),
messages: [{
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
}]
messages: [
{
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 }
Expand Down Expand Up @@ -120,14 +122,16 @@ export class TonNominatorPoolStaker extends TonBaseStaker {

const tx = {
validUntil: defaultValidUntil(validUntil),
messages: [{
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
}]
messages: [
{
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 }
Expand Down
Loading