@ton/sandbox 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +221 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/dist/blockchain/Blockchain.d.ts +120 -0
- package/dist/blockchain/Blockchain.js +327 -0
- package/dist/blockchain/BlockchainContractProvider.d.ts +30 -0
- package/dist/blockchain/BlockchainContractProvider.js +90 -0
- package/dist/blockchain/BlockchainSender.d.ts +9 -0
- package/dist/blockchain/BlockchainSender.js +29 -0
- package/dist/blockchain/BlockchainStorage.d.ts +64 -0
- package/dist/blockchain/BlockchainStorage.js +105 -0
- package/dist/blockchain/SmartContract.d.ts +93 -0
- package/dist/blockchain/SmartContract.js +289 -0
- package/dist/config/defaultConfig.d.ts +2 -0
- package/dist/config/defaultConfig.js +5 -0
- package/dist/config/slimConfig.d.ts +2 -0
- package/dist/config/slimConfig.js +5 -0
- package/dist/event/Event.d.ts +19 -0
- package/dist/event/Event.js +46 -0
- package/dist/executor/Executor.d.ts +90 -0
- package/dist/executor/Executor.js +208 -0
- package/dist/executor/emulator-emscripten.js +21 -0
- package/dist/executor/emulator-emscripten.wasm.js +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +31 -0
- package/dist/treasury/Treasury.d.ts +23 -0
- package/dist/treasury/Treasury.js +82 -0
- package/dist/utils/AsyncLock.d.ts +6 -0
- package/dist/utils/AsyncLock.js +48 -0
- package/dist/utils/base64.d.ts +1 -0
- package/dist/utils/base64.js +42 -0
- package/dist/utils/crc16.d.ts +2 -0
- package/dist/utils/crc16.js +49 -0
- package/dist/utils/message.d.ts +15 -0
- package/dist/utils/message.js +24 -0
- package/dist/utils/prettyLogTransaction.d.ts +3 -0
- package/dist/utils/prettyLogTransaction.js +25 -0
- package/dist/utils/printTransactionFees.d.ts +3 -0
- package/dist/utils/printTransactionFees.js +63 -0
- package/dist/utils/selector.d.ts +1 -0
- package/dist/utils/selector.js +19 -0
- package/dist/utils/testTreasurySubwalletId.d.ts +1 -0
- package/dist/utils/testTreasurySubwalletId.js +9 -0
- package/package.json +38 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Blockchain = void 0;
|
|
4
|
+
const defaultConfig_1 = require("../config/defaultConfig");
|
|
5
|
+
const ton_core_1 = require("ton-core");
|
|
6
|
+
const Executor_1 = require("../executor/Executor");
|
|
7
|
+
const BlockchainStorage_1 = require("./BlockchainStorage");
|
|
8
|
+
const Event_1 = require("../event/Event");
|
|
9
|
+
const BlockchainContractProvider_1 = require("./BlockchainContractProvider");
|
|
10
|
+
const BlockchainSender_1 = require("./BlockchainSender");
|
|
11
|
+
const Treasury_1 = require("../treasury/Treasury");
|
|
12
|
+
const AsyncLock_1 = require("../utils/AsyncLock");
|
|
13
|
+
const message_1 = require("../utils/message");
|
|
14
|
+
const slimConfig_1 = require("../config/slimConfig");
|
|
15
|
+
const testTreasurySubwalletId_1 = require("../utils/testTreasurySubwalletId");
|
|
16
|
+
const CREATE_WALLETS_PREFIX = 'CREATE_WALLETS';
|
|
17
|
+
function createWalletsSeed(idx) {
|
|
18
|
+
return `${CREATE_WALLETS_PREFIX}${idx}`;
|
|
19
|
+
}
|
|
20
|
+
const LT_ALIGN = 1000000n;
|
|
21
|
+
const TREASURY_INIT_BALANCE_TONS = 1000000;
|
|
22
|
+
function blockchainConfigToBase64(config) {
|
|
23
|
+
switch (config) {
|
|
24
|
+
case 'default':
|
|
25
|
+
return defaultConfig_1.defaultConfig;
|
|
26
|
+
case 'slim':
|
|
27
|
+
return slimConfig_1.slimConfig;
|
|
28
|
+
default:
|
|
29
|
+
return config?.toBoc({ idx: false }).toString('base64') ?? defaultConfig_1.defaultConfig;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
class Blockchain {
|
|
33
|
+
snapshot() {
|
|
34
|
+
return {
|
|
35
|
+
contracts: this.storage.knownContracts().map(s => s.snapshot()),
|
|
36
|
+
networkConfig: this.networkConfig,
|
|
37
|
+
lt: this.currentLt,
|
|
38
|
+
time: this.currentTime,
|
|
39
|
+
verbosity: { ...this.logsVerbosity },
|
|
40
|
+
libs: this.globalLibs,
|
|
41
|
+
nextCreateWalletIndex: this.nextCreateWalletIndex,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async loadFrom(snapshot) {
|
|
45
|
+
this.storage.clearKnownContracts();
|
|
46
|
+
for (const contract of snapshot.contracts) {
|
|
47
|
+
const storageContract = await this.getContract(contract.address);
|
|
48
|
+
storageContract.loadFrom(contract);
|
|
49
|
+
}
|
|
50
|
+
this.networkConfig = snapshot.networkConfig;
|
|
51
|
+
this.currentLt = snapshot.lt;
|
|
52
|
+
this.currentTime = snapshot.time;
|
|
53
|
+
this.logsVerbosity = { ...snapshot.verbosity };
|
|
54
|
+
this.globalLibs = snapshot.libs;
|
|
55
|
+
this.nextCreateWalletIndex = snapshot.nextCreateWalletIndex;
|
|
56
|
+
}
|
|
57
|
+
get now() {
|
|
58
|
+
return this.currentTime;
|
|
59
|
+
}
|
|
60
|
+
set now(now) {
|
|
61
|
+
this.currentTime = now;
|
|
62
|
+
}
|
|
63
|
+
get lt() {
|
|
64
|
+
return this.currentLt;
|
|
65
|
+
}
|
|
66
|
+
constructor(opts) {
|
|
67
|
+
this.currentLt = 0n;
|
|
68
|
+
this.messageQueue = [];
|
|
69
|
+
this.logsVerbosity = {
|
|
70
|
+
print: true,
|
|
71
|
+
blockchainLogs: false,
|
|
72
|
+
vmLogs: 'none',
|
|
73
|
+
debugLogs: true,
|
|
74
|
+
};
|
|
75
|
+
this.lock = new AsyncLock_1.AsyncLock();
|
|
76
|
+
this.contractFetches = new Map();
|
|
77
|
+
this.nextCreateWalletIndex = 0;
|
|
78
|
+
this.networkConfig = blockchainConfigToBase64(opts.config);
|
|
79
|
+
this.executor = opts.executor;
|
|
80
|
+
this.storage = opts.storage;
|
|
81
|
+
}
|
|
82
|
+
get config() {
|
|
83
|
+
return ton_core_1.Cell.fromBase64(this.networkConfig);
|
|
84
|
+
}
|
|
85
|
+
get configBase64() {
|
|
86
|
+
return this.networkConfig;
|
|
87
|
+
}
|
|
88
|
+
async sendMessage(message, params) {
|
|
89
|
+
await this.pushMessage(message);
|
|
90
|
+
return await this.runQueue(params);
|
|
91
|
+
}
|
|
92
|
+
async runTickTock(on, which, params) {
|
|
93
|
+
for (const addr of (Array.isArray(on) ? on : [on])) {
|
|
94
|
+
await this.pushTickTock(addr, which);
|
|
95
|
+
}
|
|
96
|
+
return await this.runQueue(params);
|
|
97
|
+
}
|
|
98
|
+
async runGetMethod(address, method, stack = [], params) {
|
|
99
|
+
return (await this.getContract(address)).get(method, stack, {
|
|
100
|
+
now: this.now,
|
|
101
|
+
...params,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async pushMessage(message) {
|
|
105
|
+
const msg = message instanceof ton_core_1.Cell ? (0, ton_core_1.loadMessage)(message.beginParse()) : message;
|
|
106
|
+
if (msg.info.type === 'external-out') {
|
|
107
|
+
throw new Error('Cannot send external out message');
|
|
108
|
+
}
|
|
109
|
+
await this.lock.with(async () => {
|
|
110
|
+
this.messageQueue.push({
|
|
111
|
+
type: 'message',
|
|
112
|
+
...msg,
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async pushTickTock(on, which) {
|
|
117
|
+
await this.lock.with(async () => {
|
|
118
|
+
this.messageQueue.push({
|
|
119
|
+
type: 'ticktock',
|
|
120
|
+
on,
|
|
121
|
+
which,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
async runQueue(params) {
|
|
126
|
+
const txes = await this.processQueue(params);
|
|
127
|
+
return {
|
|
128
|
+
transactions: txes,
|
|
129
|
+
events: txes.map(tx => tx.events).flat(),
|
|
130
|
+
externals: txes.map(tx => tx.externals).flat(),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async processQueue(params) {
|
|
134
|
+
params = {
|
|
135
|
+
now: this.now,
|
|
136
|
+
...params,
|
|
137
|
+
};
|
|
138
|
+
return await this.lock.with(async () => {
|
|
139
|
+
const result = [];
|
|
140
|
+
while (this.messageQueue.length > 0) {
|
|
141
|
+
const message = this.messageQueue.shift();
|
|
142
|
+
let tx;
|
|
143
|
+
if (message.type === 'message') {
|
|
144
|
+
if (message.info.type === 'external-out') {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
this.currentLt += LT_ALIGN;
|
|
148
|
+
tx = (await this.getContract(message.info.dest)).receiveMessage(message, params);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this.currentLt += LT_ALIGN;
|
|
152
|
+
tx = (await this.getContract(message.on)).runTickTock(message.which, params);
|
|
153
|
+
}
|
|
154
|
+
const transaction = {
|
|
155
|
+
...tx,
|
|
156
|
+
events: (0, Event_1.extractEvents)(tx),
|
|
157
|
+
parent: message.parentTransaction,
|
|
158
|
+
children: [],
|
|
159
|
+
externals: [],
|
|
160
|
+
};
|
|
161
|
+
transaction.parent?.children.push(transaction);
|
|
162
|
+
result.push(transaction);
|
|
163
|
+
for (const message of transaction.outMessages.values()) {
|
|
164
|
+
if (message.info.type === 'external-out') {
|
|
165
|
+
transaction.externals.push({
|
|
166
|
+
info: {
|
|
167
|
+
type: 'external-out',
|
|
168
|
+
src: message.info.src,
|
|
169
|
+
dest: message.info.dest ?? undefined,
|
|
170
|
+
createdAt: message.info.createdAt,
|
|
171
|
+
createdLt: message.info.createdLt,
|
|
172
|
+
},
|
|
173
|
+
init: message.init ?? undefined,
|
|
174
|
+
body: message.body,
|
|
175
|
+
});
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
this.messageQueue.push({
|
|
179
|
+
type: 'message',
|
|
180
|
+
parentTransaction: transaction,
|
|
181
|
+
...message,
|
|
182
|
+
});
|
|
183
|
+
if (message.info.type === 'internal') {
|
|
184
|
+
this.startFetchingContract(message.info.dest);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
provider(address, init) {
|
|
192
|
+
return new BlockchainContractProvider_1.BlockchainContractProvider({
|
|
193
|
+
getContract: (addr) => this.getContract(addr),
|
|
194
|
+
pushMessage: (msg) => this.pushMessage(msg),
|
|
195
|
+
runGetMethod: (addr, method, args) => this.runGetMethod(addr, method, args),
|
|
196
|
+
pushTickTock: (on, which) => this.pushTickTock(on, which),
|
|
197
|
+
}, address, init);
|
|
198
|
+
}
|
|
199
|
+
sender(address) {
|
|
200
|
+
return new BlockchainSender_1.BlockchainSender({
|
|
201
|
+
pushMessage: (msg) => this.pushMessage(msg),
|
|
202
|
+
}, address);
|
|
203
|
+
}
|
|
204
|
+
treasuryParamsToMapKey(workchain, seed) {
|
|
205
|
+
return `${workchain}:${seed}`;
|
|
206
|
+
}
|
|
207
|
+
async treasury(seed, params) {
|
|
208
|
+
const subwalletId = (0, testTreasurySubwalletId_1.testSubwalletId)(seed);
|
|
209
|
+
const wallet = this.openContract(Treasury_1.TreasuryContract.create(params?.workchain ?? 0, subwalletId));
|
|
210
|
+
const contract = await this.getContract(wallet.address);
|
|
211
|
+
if ((params?.predeploy ?? true) && (contract.accountState === undefined || contract.accountState.type === 'uninit')) {
|
|
212
|
+
await this.sendMessage((0, message_1.internal)({
|
|
213
|
+
from: new ton_core_1.Address(0, Buffer.alloc(32)),
|
|
214
|
+
to: wallet.address,
|
|
215
|
+
value: (0, ton_core_1.toNano)(1),
|
|
216
|
+
stateInit: wallet.init,
|
|
217
|
+
}));
|
|
218
|
+
contract.balance = params?.balance ?? (0, ton_core_1.toNano)(TREASURY_INIT_BALANCE_TONS);
|
|
219
|
+
}
|
|
220
|
+
else if ((params?.resetBalanceIfZero ?? true) && contract.balance === 0n) {
|
|
221
|
+
contract.balance = params?.balance ?? (0, ton_core_1.toNano)(TREASURY_INIT_BALANCE_TONS);
|
|
222
|
+
}
|
|
223
|
+
return wallet;
|
|
224
|
+
}
|
|
225
|
+
async createWallets(n, params) {
|
|
226
|
+
const wallets = [];
|
|
227
|
+
for (let i = 0; i < n; i++) {
|
|
228
|
+
const seed = createWalletsSeed(this.nextCreateWalletIndex++);
|
|
229
|
+
wallets.push(await this.treasury(seed, params));
|
|
230
|
+
}
|
|
231
|
+
return wallets;
|
|
232
|
+
}
|
|
233
|
+
openContract(contract) {
|
|
234
|
+
let address;
|
|
235
|
+
let init = undefined;
|
|
236
|
+
if (!ton_core_1.Address.isAddress(contract.address)) {
|
|
237
|
+
throw Error('Invalid address');
|
|
238
|
+
}
|
|
239
|
+
address = contract.address;
|
|
240
|
+
if (contract.init) {
|
|
241
|
+
if (!(contract.init.code instanceof ton_core_1.Cell)) {
|
|
242
|
+
throw Error('Invalid init.code');
|
|
243
|
+
}
|
|
244
|
+
if (!(contract.init.data instanceof ton_core_1.Cell)) {
|
|
245
|
+
throw Error('Invalid init.data');
|
|
246
|
+
}
|
|
247
|
+
init = contract.init;
|
|
248
|
+
}
|
|
249
|
+
const provider = this.provider(address, init);
|
|
250
|
+
const blkch = this;
|
|
251
|
+
return new Proxy(contract, {
|
|
252
|
+
get(target, prop) {
|
|
253
|
+
const value = target[prop];
|
|
254
|
+
if (typeof prop === 'string' && typeof value === 'function') {
|
|
255
|
+
if (prop.startsWith('get')) {
|
|
256
|
+
return (...args) => value.apply(target, [provider, ...args]);
|
|
257
|
+
}
|
|
258
|
+
else if (prop.startsWith('send')) {
|
|
259
|
+
return async (...args) => {
|
|
260
|
+
const ret = value.apply(target, [provider, ...args]);
|
|
261
|
+
if (ret instanceof Promise) {
|
|
262
|
+
const r = await ret;
|
|
263
|
+
return {
|
|
264
|
+
...await blkch.runQueue(),
|
|
265
|
+
result: r,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
return {
|
|
270
|
+
...await blkch.runQueue(),
|
|
271
|
+
result: ret,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
startFetchingContract(address) {
|
|
282
|
+
const addrString = address.toRawString();
|
|
283
|
+
let promise = this.contractFetches.get(addrString);
|
|
284
|
+
if (promise !== undefined) {
|
|
285
|
+
return promise;
|
|
286
|
+
}
|
|
287
|
+
promise = this.storage.getContract(this, address);
|
|
288
|
+
this.contractFetches.set(addrString, promise);
|
|
289
|
+
return promise;
|
|
290
|
+
}
|
|
291
|
+
async getContract(address) {
|
|
292
|
+
const contract = await this.startFetchingContract(address);
|
|
293
|
+
this.contractFetches.delete(address.toRawString());
|
|
294
|
+
return contract;
|
|
295
|
+
}
|
|
296
|
+
get verbosity() {
|
|
297
|
+
return this.logsVerbosity;
|
|
298
|
+
}
|
|
299
|
+
set verbosity(value) {
|
|
300
|
+
this.logsVerbosity = value;
|
|
301
|
+
}
|
|
302
|
+
async setVerbosityForAddress(address, verbosity) {
|
|
303
|
+
const contract = await this.getContract(address);
|
|
304
|
+
contract.setVerbosity(verbosity);
|
|
305
|
+
}
|
|
306
|
+
setConfig(config) {
|
|
307
|
+
this.networkConfig = blockchainConfigToBase64(config);
|
|
308
|
+
}
|
|
309
|
+
async setShardAccount(address, account) {
|
|
310
|
+
const contract = await this.getContract(address);
|
|
311
|
+
contract.account = account;
|
|
312
|
+
}
|
|
313
|
+
get libs() {
|
|
314
|
+
return this.globalLibs;
|
|
315
|
+
}
|
|
316
|
+
set libs(value) {
|
|
317
|
+
this.globalLibs = value;
|
|
318
|
+
}
|
|
319
|
+
static async create(opts) {
|
|
320
|
+
return new Blockchain({
|
|
321
|
+
executor: await Executor_1.Executor.create(),
|
|
322
|
+
storage: opts?.storage ?? new BlockchainStorage_1.LocalBlockchainStorage(),
|
|
323
|
+
...opts
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
exports.Blockchain = Blockchain;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Address, Cell, ContractGetMethodResult, ContractProvider, ContractState, Message, Sender, SendMode, TupleItem } from "ton-core";
|
|
2
|
+
import { TickOrTock } from "../executor/Executor";
|
|
3
|
+
import { GetMethodResult, SmartContract } from "./SmartContract";
|
|
4
|
+
export interface SandboxContractProvider extends ContractProvider {
|
|
5
|
+
tickTock(which: TickOrTock): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare class BlockchainContractProvider implements SandboxContractProvider {
|
|
8
|
+
private readonly blockchain;
|
|
9
|
+
private readonly address;
|
|
10
|
+
private readonly init?;
|
|
11
|
+
constructor(blockchain: {
|
|
12
|
+
getContract(address: Address): Promise<SmartContract>;
|
|
13
|
+
pushMessage(message: Message): Promise<void>;
|
|
14
|
+
runGetMethod(address: Address, method: string, args: TupleItem[]): Promise<GetMethodResult>;
|
|
15
|
+
pushTickTock(on: Address, which: TickOrTock): Promise<void>;
|
|
16
|
+
}, address: Address, init?: {
|
|
17
|
+
code: Cell;
|
|
18
|
+
data: Cell;
|
|
19
|
+
} | undefined);
|
|
20
|
+
getState(): Promise<ContractState>;
|
|
21
|
+
get(name: string, args: TupleItem[]): Promise<ContractGetMethodResult>;
|
|
22
|
+
external(message: Cell): Promise<void>;
|
|
23
|
+
internal(via: Sender, args: {
|
|
24
|
+
value: string | bigint;
|
|
25
|
+
bounce?: boolean | null;
|
|
26
|
+
sendMode?: SendMode;
|
|
27
|
+
body?: string | Cell | null;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
tickTock(which: TickOrTock): Promise<void>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BlockchainContractProvider = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
function bigintToBuffer(x, n = 32) {
|
|
6
|
+
const b = Buffer.alloc(n);
|
|
7
|
+
for (let i = 0; i < n; i++) {
|
|
8
|
+
b[n - i - 1] = Number((x >> BigInt(i * 8)) & 0xffn);
|
|
9
|
+
}
|
|
10
|
+
return b;
|
|
11
|
+
}
|
|
12
|
+
function convertState(state) {
|
|
13
|
+
if (state === undefined)
|
|
14
|
+
return {
|
|
15
|
+
type: 'uninit'
|
|
16
|
+
};
|
|
17
|
+
switch (state.type) {
|
|
18
|
+
case 'uninit':
|
|
19
|
+
return {
|
|
20
|
+
type: 'uninit'
|
|
21
|
+
};
|
|
22
|
+
case 'active':
|
|
23
|
+
return {
|
|
24
|
+
type: 'active',
|
|
25
|
+
code: state.state.code?.toBoc(),
|
|
26
|
+
data: state.state.data?.toBoc(),
|
|
27
|
+
};
|
|
28
|
+
case 'frozen':
|
|
29
|
+
return {
|
|
30
|
+
type: 'frozen',
|
|
31
|
+
stateHash: bigintToBuffer(state.stateHash)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
class BlockchainContractProvider {
|
|
36
|
+
constructor(blockchain, address, init) {
|
|
37
|
+
this.blockchain = blockchain;
|
|
38
|
+
this.address = address;
|
|
39
|
+
this.init = init;
|
|
40
|
+
}
|
|
41
|
+
async getState() {
|
|
42
|
+
const contract = await this.blockchain.getContract(this.address);
|
|
43
|
+
return {
|
|
44
|
+
balance: contract.balance,
|
|
45
|
+
last: {
|
|
46
|
+
lt: contract.lastTransactionLt,
|
|
47
|
+
hash: bigintToBuffer(contract.lastTransactionHash),
|
|
48
|
+
},
|
|
49
|
+
state: convertState(contract.accountState),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async get(name, args) {
|
|
53
|
+
const result = await this.blockchain.runGetMethod(this.address, name, args);
|
|
54
|
+
return {
|
|
55
|
+
stack: result.stackReader,
|
|
56
|
+
gasUsed: result.gasUsed,
|
|
57
|
+
logs: result.vmLogs,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async external(message) {
|
|
61
|
+
const init = ((await this.getState()).state.type !== 'active' && this.init) ? this.init : undefined;
|
|
62
|
+
await this.blockchain.pushMessage({
|
|
63
|
+
info: {
|
|
64
|
+
type: 'external-in',
|
|
65
|
+
dest: this.address,
|
|
66
|
+
importFee: 0n,
|
|
67
|
+
},
|
|
68
|
+
init,
|
|
69
|
+
body: message,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async internal(via, args) {
|
|
73
|
+
const init = ((await this.getState()).state.type !== 'active' && this.init) ? this.init : undefined;
|
|
74
|
+
const bounce = (args.bounce !== null && args.bounce !== undefined) ? args.bounce : true;
|
|
75
|
+
const value = typeof args.value === 'string' ? (0, ton_core_1.toNano)(args.value) : args.value;
|
|
76
|
+
const body = typeof args.body === 'string' ? (0, ton_core_1.comment)(args.body) : args.body;
|
|
77
|
+
await via.send({
|
|
78
|
+
to: this.address,
|
|
79
|
+
value,
|
|
80
|
+
bounce,
|
|
81
|
+
sendMode: args.sendMode,
|
|
82
|
+
init,
|
|
83
|
+
body,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async tickTock(which) {
|
|
87
|
+
await this.blockchain.pushTickTock(this.address, which);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.BlockchainContractProvider = BlockchainContractProvider;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Address, Message, Sender, SenderArguments } from "ton-core";
|
|
2
|
+
export declare class BlockchainSender implements Sender {
|
|
3
|
+
private readonly blockchain;
|
|
4
|
+
readonly address: Address;
|
|
5
|
+
constructor(blockchain: {
|
|
6
|
+
pushMessage(message: Message): Promise<void>;
|
|
7
|
+
}, address: Address);
|
|
8
|
+
send(args: SenderArguments): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BlockchainSender = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
class BlockchainSender {
|
|
6
|
+
constructor(blockchain, address) {
|
|
7
|
+
this.blockchain = blockchain;
|
|
8
|
+
this.address = address;
|
|
9
|
+
}
|
|
10
|
+
async send(args) {
|
|
11
|
+
await this.blockchain.pushMessage({
|
|
12
|
+
info: {
|
|
13
|
+
type: 'internal',
|
|
14
|
+
ihrDisabled: true,
|
|
15
|
+
ihrFee: 0n,
|
|
16
|
+
bounce: args.bounce ?? true,
|
|
17
|
+
bounced: false,
|
|
18
|
+
src: this.address,
|
|
19
|
+
dest: args.to,
|
|
20
|
+
value: { coins: args.value },
|
|
21
|
+
forwardFee: 0n,
|
|
22
|
+
createdAt: 0,
|
|
23
|
+
createdLt: 0n,
|
|
24
|
+
},
|
|
25
|
+
body: args.body ?? new ton_core_1.Cell()
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.BlockchainSender = BlockchainSender;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { AccountState, Address } from "ton-core";
|
|
3
|
+
import { SmartContract } from "./SmartContract";
|
|
4
|
+
import { Blockchain } from "./Blockchain";
|
|
5
|
+
export interface BlockchainStorage {
|
|
6
|
+
getContract(blockchain: Blockchain, address: Address): Promise<SmartContract>;
|
|
7
|
+
knownContracts(): SmartContract[];
|
|
8
|
+
clearKnownContracts(): void;
|
|
9
|
+
}
|
|
10
|
+
export declare class LocalBlockchainStorage implements BlockchainStorage {
|
|
11
|
+
private contracts;
|
|
12
|
+
getContract(blockchain: Blockchain, address: Address): Promise<SmartContract>;
|
|
13
|
+
knownContracts(): SmartContract[];
|
|
14
|
+
clearKnownContracts(): void;
|
|
15
|
+
}
|
|
16
|
+
export interface RemoteBlockchainStorageClient {
|
|
17
|
+
getLastBlockSeqno(): Promise<number>;
|
|
18
|
+
getAccount(seqno: number, address: Address): Promise<{
|
|
19
|
+
state: AccountState;
|
|
20
|
+
balance: bigint;
|
|
21
|
+
lastTransaction?: {
|
|
22
|
+
lt: bigint;
|
|
23
|
+
hash: Buffer;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export declare function wrapTonClient4ForRemote(client: {
|
|
28
|
+
getLastBlock(): Promise<{
|
|
29
|
+
last: {
|
|
30
|
+
seqno: number;
|
|
31
|
+
};
|
|
32
|
+
}>;
|
|
33
|
+
getAccount(seqno: number, address: Address): Promise<{
|
|
34
|
+
account: {
|
|
35
|
+
state: {
|
|
36
|
+
type: "uninit";
|
|
37
|
+
} | {
|
|
38
|
+
type: "active";
|
|
39
|
+
code: string | null;
|
|
40
|
+
data: string | null;
|
|
41
|
+
} | {
|
|
42
|
+
type: "frozen";
|
|
43
|
+
stateHash: string;
|
|
44
|
+
};
|
|
45
|
+
balance: {
|
|
46
|
+
coins: string;
|
|
47
|
+
};
|
|
48
|
+
last: {
|
|
49
|
+
lt: string;
|
|
50
|
+
hash: string;
|
|
51
|
+
} | null;
|
|
52
|
+
};
|
|
53
|
+
}>;
|
|
54
|
+
}): RemoteBlockchainStorageClient;
|
|
55
|
+
export declare class RemoteBlockchainStorage implements BlockchainStorage {
|
|
56
|
+
private contracts;
|
|
57
|
+
private client;
|
|
58
|
+
private blockSeqno?;
|
|
59
|
+
constructor(client: RemoteBlockchainStorageClient, blockSeqno?: number);
|
|
60
|
+
private getLastBlockSeqno;
|
|
61
|
+
getContract(blockchain: Blockchain, address: Address): Promise<SmartContract>;
|
|
62
|
+
knownContracts(): SmartContract[];
|
|
63
|
+
clearKnownContracts(): void;
|
|
64
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RemoteBlockchainStorage = exports.wrapTonClient4ForRemote = exports.LocalBlockchainStorage = void 0;
|
|
4
|
+
const ton_core_1 = require("ton-core");
|
|
5
|
+
const SmartContract_1 = require("./SmartContract");
|
|
6
|
+
class LocalBlockchainStorage {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.contracts = new Map();
|
|
9
|
+
}
|
|
10
|
+
async getContract(blockchain, address) {
|
|
11
|
+
let existing = this.contracts.get(address.toString());
|
|
12
|
+
if (!existing) {
|
|
13
|
+
existing = SmartContract_1.SmartContract.empty(blockchain, address);
|
|
14
|
+
this.contracts.set(address.toString(), existing);
|
|
15
|
+
}
|
|
16
|
+
return existing;
|
|
17
|
+
}
|
|
18
|
+
knownContracts() {
|
|
19
|
+
return Array.from(this.contracts.values());
|
|
20
|
+
}
|
|
21
|
+
clearKnownContracts() {
|
|
22
|
+
this.contracts.clear();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.LocalBlockchainStorage = LocalBlockchainStorage;
|
|
26
|
+
function convertTonClient4State(state) {
|
|
27
|
+
switch (state.type) {
|
|
28
|
+
case 'uninit':
|
|
29
|
+
return { type: 'uninit' };
|
|
30
|
+
case 'active':
|
|
31
|
+
return { type: 'active', state: { code: state.code === null ? undefined : ton_core_1.Cell.fromBase64(state.code), data: state.data === null ? undefined : ton_core_1.Cell.fromBase64(state.data) } };
|
|
32
|
+
case 'frozen':
|
|
33
|
+
return { type: 'frozen', stateHash: BigInt('0x' + Buffer.from(state.stateHash, 'base64').toString('hex')) };
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(`Unknown type ${state}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function wrapTonClient4ForRemote(client) {
|
|
39
|
+
return {
|
|
40
|
+
getLastBlockSeqno: async () => {
|
|
41
|
+
const last = await client.getLastBlock();
|
|
42
|
+
return last.last.seqno;
|
|
43
|
+
},
|
|
44
|
+
getAccount: async (seqno, address) => {
|
|
45
|
+
const { account } = await client.getAccount(seqno, address);
|
|
46
|
+
return {
|
|
47
|
+
state: convertTonClient4State(account.state),
|
|
48
|
+
balance: BigInt(account.balance.coins),
|
|
49
|
+
lastTransaction: account.last === null ? undefined : {
|
|
50
|
+
lt: BigInt(account.last.lt),
|
|
51
|
+
hash: Buffer.from(account.last.hash, 'base64'),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
exports.wrapTonClient4ForRemote = wrapTonClient4ForRemote;
|
|
58
|
+
class RemoteBlockchainStorage {
|
|
59
|
+
constructor(client, blockSeqno) {
|
|
60
|
+
this.contracts = new Map();
|
|
61
|
+
this.client = client;
|
|
62
|
+
this.blockSeqno = blockSeqno;
|
|
63
|
+
}
|
|
64
|
+
async getLastBlockSeqno() {
|
|
65
|
+
return this.blockSeqno ?? await this.client.getLastBlockSeqno();
|
|
66
|
+
}
|
|
67
|
+
async getContract(blockchain, address) {
|
|
68
|
+
let existing = this.contracts.get(address.toString());
|
|
69
|
+
if (!existing) {
|
|
70
|
+
let blockSeqno = await this.getLastBlockSeqno();
|
|
71
|
+
let account = await this.client.getAccount(blockSeqno, address);
|
|
72
|
+
const lt = account.lastTransaction?.lt ?? 0n;
|
|
73
|
+
existing = new SmartContract_1.SmartContract({
|
|
74
|
+
lastTransactionHash: BigInt('0x' + (account.lastTransaction?.hash?.toString('hex') ?? '0')),
|
|
75
|
+
lastTransactionLt: lt,
|
|
76
|
+
account: {
|
|
77
|
+
addr: address,
|
|
78
|
+
storageStats: {
|
|
79
|
+
used: {
|
|
80
|
+
cells: 0n,
|
|
81
|
+
bits: 0n,
|
|
82
|
+
publicCells: 0n,
|
|
83
|
+
},
|
|
84
|
+
lastPaid: 0,
|
|
85
|
+
duePayment: null,
|
|
86
|
+
},
|
|
87
|
+
storage: {
|
|
88
|
+
lastTransLt: lt === 0n ? 0n : (lt + 1n),
|
|
89
|
+
balance: { coins: account.balance },
|
|
90
|
+
state: account.state,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
}, blockchain);
|
|
94
|
+
this.contracts.set(address.toString(), existing);
|
|
95
|
+
}
|
|
96
|
+
return existing;
|
|
97
|
+
}
|
|
98
|
+
knownContracts() {
|
|
99
|
+
return Array.from(this.contracts.values());
|
|
100
|
+
}
|
|
101
|
+
clearKnownContracts() {
|
|
102
|
+
this.contracts.clear();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.RemoteBlockchainStorage = RemoteBlockchainStorage;
|