From 66a1feb790816fddb5b7d12197b493476f5f7572 Mon Sep 17 00:00:00 2001 From: thekiba Date: Mon, 12 Feb 2024 19:55:26 +0400 Subject: [PATCH 1/5] chore: update @ton/core@^0.55.0 --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 7f3acf8..11534a9 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@release-it/keep-a-changelog": "^3.1.0", - "@ton/core": "^0.53.0", + "@ton/core": "^0.55.0", "@ton/crypto": "3.2.0", "@ton/emulator": "^2.1.1", "@types/jest": "^27.0.1", diff --git a/yarn.lock b/yarn.lock index 2941bd0..6eacba3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -950,14 +950,14 @@ __metadata: languageName: node linkType: hard -"@ton/core@npm:^0.53.0": - version: 0.53.0 - resolution: "@ton/core@npm:0.53.0" +"@ton/core@npm:^0.55.0": + version: 0.55.0 + resolution: "@ton/core@npm:0.55.0" dependencies: symbol.inspect: 1.0.1 peerDependencies: "@ton/crypto": ">=3.2.0" - checksum: 6d84040bce46b8167d106ca07183c60a935b3be1934a8049f8296c7a957a7d9ae8f1f1d885df2c388c801813cfa5ac742190dfabd2b34529c338754160040d44 + checksum: 62201f0358cb9f5b1014f85681589008c9db193dd97294d48d22b590d468c33574371f4d8b203406fe8b1721d437930eb1b896c357a997fed29fd222e7da2681 languageName: node linkType: hard @@ -1000,7 +1000,7 @@ __metadata: resolution: "@ton/ton@workspace:." dependencies: "@release-it/keep-a-changelog": ^3.1.0 - "@ton/core": ^0.53.0 + "@ton/core": ^0.55.0 "@ton/crypto": 3.2.0 "@ton/emulator": ^2.1.1 "@types/jest": ^27.0.1 From 637af3abecc6ba0b5e153154809d2de2429de503 Mon Sep 17 00:00:00 2001 From: thekiba Date: Mon, 12 Feb 2024 20:08:46 +0400 Subject: [PATCH 2/5] feat: extend TonClient and TonClient4 providers with open and getTransactions methods --- src/client/TonClient.ts | 39 ++++++++++++++++++++++++++++++++------- src/client/TonClient4.ts | 27 +++++++++++++++++---------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/client/TonClient.ts b/src/client/TonClient.ts index 4cd0b59..b38d1f7 100644 --- a/src/client/TonClient.ts +++ b/src/client/TonClient.ts @@ -8,7 +8,26 @@ import { HttpApi } from "./api/HttpApi"; import { AxiosAdapter } from 'axios'; -import { Address, beginCell, Cell, comment, Contract, ContractProvider, ContractState, external, loadTransaction, Message, openContract, storeMessage, toNano, Transaction, TupleItem, TupleReader } from '@ton/core'; +import { + Address, + beginCell, + Cell, + comment, + Contract, + ContractProvider, + ContractState, + external, + loadTransaction, + Message, + openContract, + storeMessage, + toNano, + Transaction, + TupleItem, + TupleReader, + StateInit, + OpenedContract +} from '@ton/core'; import { Maybe } from "../utils/maybe"; export type TonClientParameters = { @@ -257,7 +276,7 @@ export class TonClient { } else { const message = external({ to: contract.address, - init: { code: contract.init.code, data: contract.init.data }, + init: contract.init, body: src }); await this.sendMessage(message); @@ -314,7 +333,7 @@ export class TonClient { * @param init optional init * @returns provider */ - provider(address: Address, init: { code: Cell | null, data: Cell | null } | null) { + provider(address: Address, init: StateInit | null) { return createProvider(this, address, init); } } @@ -372,7 +391,7 @@ function parseStack(src: any[]) { return new TupleReader(stack); } -function createProvider(client: TonClient, address: Address, init: { code: Cell | null, data: Cell | null } | null): ContractProvider { +function createProvider(client: TonClient, address: Address, init: StateInit | null): ContractProvider { return { async getState(): Promise { let state = await client.getContractState(address); @@ -422,7 +441,7 @@ function createProvider(client: TonClient, address: Address, init: { code: Cell // Resolve init // - let neededInit: { code: Cell | null, data: Cell | null } | null = null; + let neededInit: StateInit | null = null; if (init && !await client.isContractDeployed(address)) { neededInit = init; } @@ -433,7 +452,7 @@ function createProvider(client: TonClient, address: Address, init: { code: Cell const ext = external({ to: address, - init: neededInit ? { code: neededInit.code, data: neededInit.data } : null, + init: neededInit, body: message }) let boc = beginCell() @@ -445,7 +464,7 @@ function createProvider(client: TonClient, address: Address, init: { code: Cell async internal(via, message) { // Resolve init - let neededInit: { code: Cell | null, data: Cell | null } | null = null; + let neededInit: StateInit | null = null; if (init && (!await client.isContractDeployed(address))) { neededInit = init; } @@ -481,6 +500,12 @@ function createProvider(client: TonClient, address: Address, init: { code: Cell init: neededInit, body }); + }, + open(contract: T): OpenedContract { + return openContract(contract, (args) => createProvider(client, args.address, args.init ?? null)); + }, + getTransactions(address: Address, lt: bigint, hash: Buffer, limit?: number): Promise { + return client.getTransactions(address, { limit: limit ?? 100, lt: lt.toString(), hash: hash.toString('base64'), inclusive: true }); } } } diff --git a/src/client/TonClient4.ts b/src/client/TonClient4.ts index c498508..b503796 100644 --- a/src/client/TonClient4.ts +++ b/src/client/TonClient4.ts @@ -7,7 +7,7 @@ */ import axios, { AxiosAdapter } from "axios"; -import { Address, beginCell, Cell, comment, Contract, ContractProvider, ContractState, external, loadTransaction, openContract, parseTuple, serializeTuple, StateInit, storeMessage, toNano, Transaction, TupleItem, TupleReader } from "@ton/core"; +import { Address, beginCell, Cell, comment, Contract, ContractProvider, ContractState, external, loadTransaction, openContract, OpenedContract, parseTuple, serializeTuple, StateInit, storeMessage, toNano, Transaction, TupleItem, TupleReader } from "@ton/core"; import { Maybe } from "../utils/maybe"; import { toUrlSafe } from "../utils/toUrlSafe"; import { z } from 'zod'; @@ -293,8 +293,8 @@ export class TonClient4 { * @param init optional init data * @returns provider */ - provider(address: Address, init?: { code: Cell, data: Cell } | null) { - return createProvider(this, null, address, init ? init : null); + provider(address: Address, init?: StateInit | null) { + return createProvider(this, null, address, init ?? null); } /** @@ -304,12 +304,12 @@ export class TonClient4 { * @param init optional init data * @returns provider */ - providerAt(block: number, address: Address, init?: { code: Cell, data: Cell } | null) { - return createProvider(this, block, address, init ? init : null); + providerAt(block: number, address: Address, init?: StateInit | null) { + return createProvider(this, block, address, init ?? null); } } -function createProvider(client: TonClient4, block: number | null, address: Address, init: { code: Cell, data: Cell } | null): ContractProvider { +function createProvider(client: TonClient4, block: number | null, address: Address, init: StateInit | null): ContractProvider { return { async getState(): Promise { @@ -380,7 +380,7 @@ function createProvider(client: TonClient4, block: number | null, address: Addre let last = await client.getLastBlock(); // Resolve init - let neededInit: { code: Cell | null, data: Cell | null } | null = null; + let neededInit: StateInit | null = null; if (init && (await client.getAccountLite(last.last.seqno, address)).account.state.type !== 'active') { neededInit = init; } @@ -388,7 +388,7 @@ function createProvider(client: TonClient4, block: number | null, address: Addre // Send with state init const ext = external({ to: address, - init: neededInit ? { code: neededInit.code, data: neededInit.data } : null, + init: neededInit, body: message }); let pkg = beginCell() @@ -403,7 +403,7 @@ function createProvider(client: TonClient4, block: number | null, address: Addre let last = await client.getLastBlock(); // Resolve init - let neededInit: { code: Cell | null, data: Cell | null } | null = null; + let neededInit: StateInit | null = null; if (init && (await client.getAccountLite(last.last.seqno, address)).account.state.type !== 'active') { neededInit = init; } @@ -439,6 +439,13 @@ function createProvider(client: TonClient4, block: number | null, address: Addre init: neededInit, body }); + }, + open(contract: T): OpenedContract { + return openContract(contract, (args) => createProvider(client, block, args.address, args.init ?? null)); + }, + async getTransactions(address: Address, lt: bigint, hash: Buffer): Promise { + const result = await client.getAccountTransactions(address, lt, hash); + return result.flatMap(x => x.tx); } } } @@ -724,4 +731,4 @@ export type ParsedTransaction = z.infer; export type ParsedTransactions = { blocks: z.infer, transactions: ParsedTransaction[] -}; \ No newline at end of file +}; From a53b2b5392abe0cee30778da50838dd4dab823d4 Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 23 Feb 2024 15:47:32 +0400 Subject: [PATCH 3/5] refactor: make init parameter optional in provider method of TonClient --- src/client/TonClient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/TonClient.ts b/src/client/TonClient.ts index b38d1f7..fd13b8e 100644 --- a/src/client/TonClient.ts +++ b/src/client/TonClient.ts @@ -333,8 +333,8 @@ export class TonClient { * @param init optional init * @returns provider */ - provider(address: Address, init: StateInit | null) { - return createProvider(this, address, init); + provider(address: Address, init?: StateInit | null) { + return createProvider(this, address, init ?? null); } } From 51103254e2cb1eb7449724eb1e4be52ba420053b Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 23 Feb 2024 15:48:13 +0400 Subject: [PATCH 4/5] feat: enhance getTransactions of TonClient4 priovider with limit handling --- src/client/TonClient4.ts | 43 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/client/TonClient4.ts b/src/client/TonClient4.ts index b503796..50080fc 100644 --- a/src/client/TonClient4.ts +++ b/src/client/TonClient4.ts @@ -443,9 +443,46 @@ function createProvider(client: TonClient4, block: number | null, address: Addre open(contract: T): OpenedContract { return openContract(contract, (args) => createProvider(client, block, args.address, args.init ?? null)); }, - async getTransactions(address: Address, lt: bigint, hash: Buffer): Promise { - const result = await client.getAccountTransactions(address, lt, hash); - return result.flatMap(x => x.tx); + async getTransactions(address: Address, lt: bigint, hash: Buffer, limit?: number): Promise { + // Resolve last + const useLimit = typeof limit === 'number'; + if (useLimit && limit <= 0) { + return []; + } + + // Load transactions + let transactions: Transaction[] = []; + do { + const txs = await client.getAccountTransactions(address, lt, hash); + + const firstTx = txs[0].tx; + const [firstLt, firstHash] = [firstTx.lt, firstTx.hash()]; + const needSkipFirst = firstLt === lt && firstHash.equals(hash); + if (needSkipFirst) { + txs.shift(); + } + + if (txs.length === 0) { + break; + } + const lastTx = txs[txs.length - 1].tx; + const [lastLt, lastHash] = [lastTx.lt, lastTx.hash()]; + if (lastLt === lt && lastHash.equals(hash)) { + break; + } + + transactions.push(...txs.map(tx => tx.tx)); + lt = lastLt; + hash = lastHash; + } while (useLimit && transactions.length < limit); + + // Apply limit + if (useLimit) { + transactions = transactions.slice(0, limit); + } + + // Return transactions + return transactions; } } } From a847874730fb7ffaa706c88e0c214a180afb0be7 Mon Sep 17 00:00:00 2001 From: thekiba Date: Fri, 23 Feb 2024 16:28:40 +0400 Subject: [PATCH 5/5] fix: refine condition to skip first transaction in getTransactions --- src/client/TonClient4.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/TonClient4.ts b/src/client/TonClient4.ts index 50080fc..78fc249 100644 --- a/src/client/TonClient4.ts +++ b/src/client/TonClient4.ts @@ -457,7 +457,7 @@ function createProvider(client: TonClient4, block: number | null, address: Addre const firstTx = txs[0].tx; const [firstLt, firstHash] = [firstTx.lt, firstTx.hash()]; - const needSkipFirst = firstLt === lt && firstHash.equals(hash); + const needSkipFirst = transactions.length > 0 && firstLt === lt && firstHash.equals(hash); if (needSkipFirst) { txs.shift(); }