Skip to content

Commit 13ea16e

Browse files
TomerHFBa0ngo
authored andcommitted
feat: add TON support
1 parent 7f3e56f commit 13ea16e

File tree

1 file changed

+55
-22
lines changed
  • apps/recovery-relay/lib/wallets/TON

1 file changed

+55
-22
lines changed
Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,58 @@
11
import { Ton as BaseTon } from '@fireblocks/wallet-derivation';
2-
import { ConnectedWallet } from '../ConnectedWallet';
32
import { TonClient, WalletContractV4 } from '@ton/ton';
43
import { beginCell, Cell, fromNano } from '@ton/core';
54
import { AccountData } from '../types';
65
import { defaultTonWalletV4R2code } from './tonParams';
76
import axios from 'axios';
7+
import { LateInitConnectedWallet } from '../LateInitConnectedWallet';
8+
9+
export class Ton extends BaseTon implements LateInitConnectedWallet {
10+
public memo: string | undefined;
11+
12+
public updateDataEndpoint(memo?: string): void {
13+
this.memo = memo;
14+
}
15+
16+
public getLateInitLabel(): string {
17+
throw new Error('Method not implemented.');
18+
}
819

9-
export class Ton extends BaseTon implements ConnectedWallet {
1020
public rpcURL: string | undefined;
21+
1122
public setRPCUrl(url: string): void {
1223
this.rpcURL = url;
1324
}
14-
private client = new TonClient({
15-
endpoint: this.isTestnet ? 'https://testnet.toncenter.com/api/v2/jsonRPC' : 'https://toncenter.com/api/v2/jsonRPC',
16-
});
25+
26+
private client: TonClient | undefined;
27+
28+
private init() {
29+
this.client = new TonClient({
30+
endpoint: this.rpcURL!,
31+
});
32+
}
33+
1734
private tonWallet = WalletContractV4.create({ publicKey: Buffer.from(this.publicKey.replace('0x', ''), 'hex'), workchain: 0 });
1835

1936
public async getBalance(): Promise<number> {
20-
await new Promise((resolve) => setTimeout(resolve, 2000));
21-
const contract = this.client.open(this.tonWallet);
22-
return Number(fromNano(await contract.getBalance()));
37+
if (this.client) {
38+
await new Promise((resolve) => setTimeout(resolve, 2000));
39+
const contract = this.client.open(this.tonWallet);
40+
return Number(fromNano(await contract.getBalance()));
41+
} else {
42+
this.relayLogger.error('TON: Client failed to initialize');
43+
throw new Error('TON: Client failed to initialize');
44+
}
2345
}
46+
2447
public async broadcastTx(tx: string): Promise<string> {
2548
try {
49+
// init the TonClient
50+
this.init();
51+
52+
// parse the tx back to Ton Cell
2653
const body = Cell.fromBoc(Buffer.from(tx, 'base64'))[0];
2754
const pubKey = Buffer.from(this.publicKey.replace('0x', ''), 'hex');
28-
2955
const externalMessage = beginCell().storeUint(0b10, 2).storeUint(0, 2).storeAddress(this.tonWallet.address).storeCoins(0);
30-
3156
const seqno = await this.getSeqno();
3257
if (seqno === 0) {
3358
// for the fist transaction we initialize a state init struct which consists of init struct and code
@@ -40,11 +65,16 @@ export class Ton extends BaseTon implements ConnectedWallet {
4065
}
4166
const finalExternalMessage = externalMessage.storeBit(1).storeRef(body).endCell();
4267

43-
await new Promise((resolve) => setTimeout(resolve, 2000));
44-
await this.client.sendFile(finalExternalMessage.toBoc());
45-
const txHash = finalExternalMessage.hash().toString('hex');
46-
this.relayLogger.debug(`TON: Tx broadcasted: ${txHash}`);
47-
return txHash;
68+
if (this.client) {
69+
// broadcast Tx and calc TxHash
70+
await new Promise((resolve) => setTimeout(resolve, 2000));
71+
await this.client.sendFile(finalExternalMessage.toBoc());
72+
const txHash = finalExternalMessage.hash().toString('hex');
73+
this.relayLogger.debug(`TON: Tx broadcasted: ${txHash}`);
74+
return txHash;
75+
} else {
76+
throw new Error('TON: Client failed to initialize');
77+
}
4878
} catch (e) {
4979
this.relayLogger.error(`TON: Error broadcasting tx: ${e}`);
5080
if (axios.isAxiosError(e)) {
@@ -53,20 +83,25 @@ export class Ton extends BaseTon implements ConnectedWallet {
5383
throw e;
5484
}
5585
}
86+
5687
public async prepare(): Promise<AccountData> {
57-
// get the balance
58-
const balance = await this.getBalance(); // returned in nanoTon
88+
// init the TonClient
89+
this.init();
90+
// get the balance, returned in nanoTon
91+
const balance = await this.getBalance();
5992

6093
// fee for regular tx is hardcoded to 0.02 TON
6194
const feeRate = 0.02;
62-
await new Promise((resolve) => setTimeout(resolve, 1000));
95+
await new Promise((resolve) => setTimeout(resolve, 2000));
96+
6397
// get seqno of the wallet, set it as exrtaParams
6498
const seqno = await this.getSeqno();
6599
const extraParams = new Map<string, any>();
66100
extraParams.set('seqno', seqno);
67101

68102
const preperedData = {
69103
balance,
104+
memo: this.memo,
70105
feeRate,
71106
extraParams,
72107
insufficientBalance: balance < 0.005,
@@ -76,21 +111,20 @@ export class Ton extends BaseTon implements ConnectedWallet {
76111
}
77112
private async getSeqno() {
78113
await new Promise((resolve) => setTimeout(resolve, 2000));
79-
return await this.client.open(this.tonWallet).getSeqno();
114+
return await this.client!.open(this.tonWallet).getSeqno();
80115
}
81116

82117
private createStateInit(pubKey: Buffer) {
83118
// the initial data cell our contract will hold. Wallet V4 has an extra value for plugins in the end
84119
const dataCell = beginCell()
85120
.storeUint(0, 32) // Seqno 0 for the first tx
86-
.storeUint(698983191, 32) // Subwallet ID
121+
.storeUint(698983191, 32) // Subwallet ID -> https://docs.ton.org/v3/guidelines/smart-contracts/howto/wallet#subwallet-ids
87122
.storeBuffer(pubKey) // Public Key
88123
.storeBit(0) // only for Wallet V4
89124
.endCell();
90125

91126
// we take a boiler place already made WalletV4R2 code
92127
const codeCell = Cell.fromBoc(Buffer.from(defaultTonWalletV4R2code, 'base64'))[0];
93-
94128
const stateInit = beginCell()
95129
.storeBit(0) // No split_depth
96130
.storeBit(0) // No special
@@ -100,7 +134,6 @@ export class Ton extends BaseTon implements ConnectedWallet {
100134
.storeRef(dataCell)
101135
.storeBit(0) // No library
102136
.endCell();
103-
104137
return stateInit;
105138
}
106139
}

0 commit comments

Comments
 (0)