@ton/sandbox 0.11.1 → 0.13.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 +18 -0
- package/README.md +5 -2
- package/dist/blockchain/Blockchain.d.ts +4 -0
- package/dist/blockchain/Blockchain.js +76 -47
- package/dist/blockchain/SmartContract.d.ts +6 -0
- package/dist/blockchain/SmartContract.js +17 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.13.0] - 2023-10-05
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- On transaction emulation error, an `EmulationError` is now thrown that has an `error` string, `vmLogs`, and `exitCode` (the latter two being optional). The error is no longer being dumped into console
|
|
13
|
+
|
|
14
|
+
## [0.12.0] - 2023-10-03
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Step by step execution (`blockchain.sendMessageIter`)
|
|
19
|
+
- Better docs
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `now` from `Blockchain` is now honored in `SmartContract.receiveMessage`
|
|
24
|
+
- Exit code 1 is now counted as success in get methods
|
|
25
|
+
|
|
8
26
|
## [0.11.1] - 2023-07-26
|
|
9
27
|
|
|
10
28
|
### Changed
|
package/README.md
CHANGED
|
@@ -261,9 +261,12 @@ it('minter admin should be able to mint jettons', async () => {
|
|
|
261
261
|
});
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
### Test
|
|
265
|
-
You can typically find various tests for Sandbox-based project contracts in the `./tests` directory.
|
|
264
|
+
### Test Examples
|
|
265
|
+
You can typically find various tests for Sandbox-based project contracts in the `./tests` directory.
|
|
266
|
+
Learn more from examples:
|
|
266
267
|
|
|
268
|
+
* [FunC Test Examples](https://docs.ton.org/develop/smart-contracts/examples#examples-of-tests-for-smart-contracts)
|
|
269
|
+
* [Tact Test Examples](docs/tact-testing-examples.md)
|
|
267
270
|
|
|
268
271
|
## Viewing logs
|
|
269
272
|
|
|
@@ -88,11 +88,15 @@ export declare class Blockchain {
|
|
|
88
88
|
get config(): Cell;
|
|
89
89
|
get configBase64(): string;
|
|
90
90
|
sendMessage(message: Message | Cell, params?: MessageParams): Promise<SendMessageResult>;
|
|
91
|
+
sendMessageIter(message: Message | Cell, params?: MessageParams): Promise<AsyncIterator<BlockchainTransaction> & AsyncIterable<BlockchainTransaction>>;
|
|
91
92
|
runTickTock(on: Address | Address[], which: TickOrTock, params?: MessageParams): Promise<SendMessageResult>;
|
|
92
93
|
runGetMethod(address: Address, method: number | string, stack?: TupleItem[], params?: GetMethodParams): Promise<import("./SmartContract").GetMethodResult>;
|
|
93
94
|
protected pushMessage(message: Message | Cell): Promise<void>;
|
|
94
95
|
protected pushTickTock(on: Address, which: TickOrTock): Promise<void>;
|
|
95
96
|
protected runQueue(params?: MessageParams): Promise<SendMessageResult>;
|
|
97
|
+
protected txIter(needsLocking: boolean, params?: MessageParams): AsyncIterator<BlockchainTransaction> & AsyncIterable<BlockchainTransaction>;
|
|
98
|
+
protected processInternal(params?: MessageParams): Promise<IteratorResult<BlockchainTransaction>>;
|
|
99
|
+
protected processTx(needsLocking: boolean, params?: MessageParams): Promise<IteratorResult<BlockchainTransaction>>;
|
|
96
100
|
protected processQueue(params?: MessageParams): Promise<BlockchainTransaction[]>;
|
|
97
101
|
provider(address: Address, init?: {
|
|
98
102
|
code: Cell;
|
|
@@ -89,6 +89,15 @@ class Blockchain {
|
|
|
89
89
|
await this.pushMessage(message);
|
|
90
90
|
return await this.runQueue(params);
|
|
91
91
|
}
|
|
92
|
+
async sendMessageIter(message, params) {
|
|
93
|
+
params = {
|
|
94
|
+
now: this.now,
|
|
95
|
+
...params,
|
|
96
|
+
};
|
|
97
|
+
await this.pushMessage(message);
|
|
98
|
+
// Iterable will lock on per tx basis
|
|
99
|
+
return await this.txIter(true, params);
|
|
100
|
+
}
|
|
92
101
|
async runTickTock(on, which, params) {
|
|
93
102
|
for (const addr of (Array.isArray(on) ? on : [on])) {
|
|
94
103
|
await this.pushTickTock(addr, which);
|
|
@@ -130,60 +139,80 @@ class Blockchain {
|
|
|
130
139
|
externals: txes.map(tx => tx.externals).flat(),
|
|
131
140
|
};
|
|
132
141
|
}
|
|
142
|
+
txIter(needsLocking, params) {
|
|
143
|
+
const it = { next: () => this.processTx(needsLocking, params), [Symbol.asyncIterator]() { return it; } };
|
|
144
|
+
return it;
|
|
145
|
+
}
|
|
146
|
+
async processInternal(params) {
|
|
147
|
+
let result = undefined;
|
|
148
|
+
let done = this.messageQueue.length == 0;
|
|
149
|
+
while (!done) {
|
|
150
|
+
const message = this.messageQueue.shift();
|
|
151
|
+
let tx;
|
|
152
|
+
if (message.type === 'message') {
|
|
153
|
+
if (message.info.type === 'external-out') {
|
|
154
|
+
done = this.messageQueue.length == 0;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
this.currentLt += LT_ALIGN;
|
|
158
|
+
tx = (await this.getContract(message.info.dest)).receiveMessage(message, params);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.currentLt += LT_ALIGN;
|
|
162
|
+
tx = (await this.getContract(message.on)).runTickTock(message.which, params);
|
|
163
|
+
}
|
|
164
|
+
const transaction = {
|
|
165
|
+
...tx,
|
|
166
|
+
events: (0, Event_1.extractEvents)(tx),
|
|
167
|
+
parent: message.parentTransaction,
|
|
168
|
+
children: [],
|
|
169
|
+
externals: [],
|
|
170
|
+
};
|
|
171
|
+
transaction.parent?.children.push(transaction);
|
|
172
|
+
result = transaction;
|
|
173
|
+
done = true;
|
|
174
|
+
for (const message of transaction.outMessages.values()) {
|
|
175
|
+
if (message.info.type === 'external-out') {
|
|
176
|
+
transaction.externals.push({
|
|
177
|
+
info: {
|
|
178
|
+
type: 'external-out',
|
|
179
|
+
src: message.info.src,
|
|
180
|
+
dest: message.info.dest ?? undefined,
|
|
181
|
+
createdAt: message.info.createdAt,
|
|
182
|
+
createdLt: message.info.createdLt,
|
|
183
|
+
},
|
|
184
|
+
init: message.init ?? undefined,
|
|
185
|
+
body: message.body,
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
this.messageQueue.push({
|
|
190
|
+
type: 'message',
|
|
191
|
+
parentTransaction: transaction,
|
|
192
|
+
...message,
|
|
193
|
+
});
|
|
194
|
+
if (message.info.type === 'internal') {
|
|
195
|
+
this.startFetchingContract(message.info.dest);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return result === undefined ? { value: result, done: true } : { value: result, done: false };
|
|
200
|
+
}
|
|
201
|
+
async processTx(needsLocking, params) {
|
|
202
|
+
// Lock only if not locked already
|
|
203
|
+
return needsLocking ? await this.lock.with(async () => this.processInternal(params)) : await this.processInternal(params);
|
|
204
|
+
}
|
|
133
205
|
async processQueue(params) {
|
|
134
206
|
params = {
|
|
135
207
|
now: this.now,
|
|
136
208
|
...params,
|
|
137
209
|
};
|
|
138
210
|
return await this.lock.with(async () => {
|
|
211
|
+
// Locked already
|
|
212
|
+
const txs = this.txIter(false, params);
|
|
139
213
|
const result = [];
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
}
|
|
214
|
+
for await (const tx of txs) {
|
|
215
|
+
result.push(tx);
|
|
187
216
|
}
|
|
188
217
|
return result;
|
|
189
218
|
});
|
|
@@ -55,6 +55,12 @@ export declare class TimeError extends Error {
|
|
|
55
55
|
currentTime: number;
|
|
56
56
|
constructor(address: Address, previousTxTime: number, currentTime: number);
|
|
57
57
|
}
|
|
58
|
+
export declare class EmulationError extends Error {
|
|
59
|
+
error: string;
|
|
60
|
+
vmLogs?: string | undefined;
|
|
61
|
+
exitCode?: number | undefined;
|
|
62
|
+
constructor(error: string, vmLogs?: string | undefined, exitCode?: number | undefined);
|
|
63
|
+
}
|
|
58
64
|
export type SmartContractSnapshot = {
|
|
59
65
|
address: Address;
|
|
60
66
|
account: ShardAccount;
|
|
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
12
12
|
};
|
|
13
13
|
var _SmartContract_account, _SmartContract_parsedAccount, _SmartContract_lastTxTime, _SmartContract_verbosity;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.SmartContract = exports.TimeError = exports.GetMethodError = exports.createEmptyShardAccount = exports.createShardAccount = void 0;
|
|
15
|
+
exports.SmartContract = exports.EmulationError = exports.TimeError = exports.GetMethodError = exports.createEmptyShardAccount = exports.createShardAccount = void 0;
|
|
16
16
|
const core_1 = require("@ton/core");
|
|
17
17
|
const selector_1 = require("../utils/selector");
|
|
18
18
|
function createShardAccount(args) {
|
|
@@ -98,6 +98,15 @@ class TimeError extends Error {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
exports.TimeError = TimeError;
|
|
101
|
+
class EmulationError extends Error {
|
|
102
|
+
constructor(error, vmLogs, exitCode) {
|
|
103
|
+
super(`Error while executing transaction: ${error}`);
|
|
104
|
+
this.error = error;
|
|
105
|
+
this.vmLogs = vmLogs;
|
|
106
|
+
this.exitCode = exitCode;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.EmulationError = EmulationError;
|
|
101
110
|
class SmartContract {
|
|
102
111
|
constructor(shardAccount, blockchain) {
|
|
103
112
|
_SmartContract_account.set(this, void 0);
|
|
@@ -181,6 +190,11 @@ class SmartContract {
|
|
|
181
190
|
};
|
|
182
191
|
}
|
|
183
192
|
receiveMessage(message, params) {
|
|
193
|
+
// Sync now with blockchain instance if not specified in parameters
|
|
194
|
+
params = {
|
|
195
|
+
now: this.blockchain.now,
|
|
196
|
+
...params,
|
|
197
|
+
};
|
|
184
198
|
return this.runCommon(() => this.blockchain.executor.runTransaction({
|
|
185
199
|
...this.createCommonArgs(params),
|
|
186
200
|
message: (0, core_1.beginCell)().store((0, core_1.storeMessage)(message)).endCell(),
|
|
@@ -198,8 +212,7 @@ class SmartContract {
|
|
|
198
212
|
console.log(res.logs);
|
|
199
213
|
}
|
|
200
214
|
if (!res.result.success) {
|
|
201
|
-
|
|
202
|
-
throw new Error('Error executing transaction');
|
|
215
|
+
throw new EmulationError(res.result.error, res.result.vmResults?.vmLog, res.result.vmResults?.vmExitCode);
|
|
203
216
|
}
|
|
204
217
|
if (this.verbosity.print && this.verbosity.vmLogs !== 'none' && res.result.vmLog.length > 0) {
|
|
205
218
|
console.log(res.result.vmLog);
|
|
@@ -249,7 +262,7 @@ class SmartContract {
|
|
|
249
262
|
if (this.verbosity.print && this.verbosity.debugLogs && res.debugLogs.length > 0) {
|
|
250
263
|
console.log(res.debugLogs);
|
|
251
264
|
}
|
|
252
|
-
if (res.output.vm_exit_code !== 0) {
|
|
265
|
+
if (res.output.vm_exit_code !== 0 && res.output.vm_exit_code !== 1) {
|
|
253
266
|
throw new GetMethodError(res.output.vm_exit_code, BigInt(res.output.gas_used), res.logs, res.output.vm_log, res.debugLogs);
|
|
254
267
|
}
|
|
255
268
|
const resStack = (0, core_1.parseTuple)(core_1.Cell.fromBase64(res.output.stack));
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { Blockchain, SendMessageResult, BlockchainTransaction, PendingMessage, S
|
|
|
3
3
|
export { BlockchainContractProvider, SandboxContractProvider, } from './blockchain/BlockchainContractProvider';
|
|
4
4
|
export { BlockchainSender, } from './blockchain/BlockchainSender';
|
|
5
5
|
export { BlockchainStorage, LocalBlockchainStorage, RemoteBlockchainStorage, RemoteBlockchainStorageClient, wrapTonClient4ForRemote, } from './blockchain/BlockchainStorage';
|
|
6
|
-
export { Verbosity, LogsVerbosity, SmartContract, SmartContractTransaction, MessageParams, GetMethodParams, GetMethodResult, createEmptyShardAccount, createShardAccount, GetMethodError, TimeError, SmartContractSnapshot, } from './blockchain/SmartContract';
|
|
6
|
+
export { Verbosity, LogsVerbosity, SmartContract, SmartContractTransaction, MessageParams, GetMethodParams, GetMethodResult, createEmptyShardAccount, createShardAccount, GetMethodError, TimeError, SmartContractSnapshot, EmulationError, } from './blockchain/SmartContract';
|
|
7
7
|
export { TickOrTock, } from './executor/Executor';
|
|
8
8
|
export { Event, EventAccountCreated, EventAccountDestroyed, EventMessageSent, } from './event/Event';
|
|
9
9
|
export { Treasury, TreasuryContract, } from './treasury/Treasury';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.internal = exports.printTransactionFees = exports.prettyLogTransactions = exports.prettyLogTransaction = exports.TreasuryContract = exports.TimeError = exports.GetMethodError = exports.createShardAccount = exports.createEmptyShardAccount = exports.SmartContract = exports.wrapTonClient4ForRemote = exports.RemoteBlockchainStorage = exports.LocalBlockchainStorage = exports.BlockchainSender = exports.BlockchainContractProvider = exports.Blockchain = exports.defaultConfigSeqno = exports.defaultConfig = void 0;
|
|
3
|
+
exports.internal = exports.printTransactionFees = exports.prettyLogTransactions = exports.prettyLogTransaction = exports.TreasuryContract = exports.EmulationError = exports.TimeError = exports.GetMethodError = exports.createShardAccount = exports.createEmptyShardAccount = exports.SmartContract = exports.wrapTonClient4ForRemote = exports.RemoteBlockchainStorage = exports.LocalBlockchainStorage = exports.BlockchainSender = exports.BlockchainContractProvider = exports.Blockchain = exports.defaultConfigSeqno = exports.defaultConfig = void 0;
|
|
4
4
|
var defaultConfig_1 = require("./config/defaultConfig");
|
|
5
5
|
Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return defaultConfig_1.defaultConfig; } });
|
|
6
6
|
Object.defineProperty(exports, "defaultConfigSeqno", { enumerable: true, get: function () { return defaultConfig_1.defaultConfigSeqno; } });
|
|
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "createEmptyShardAccount", { enumerable: true, ge
|
|
|
20
20
|
Object.defineProperty(exports, "createShardAccount", { enumerable: true, get: function () { return SmartContract_1.createShardAccount; } });
|
|
21
21
|
Object.defineProperty(exports, "GetMethodError", { enumerable: true, get: function () { return SmartContract_1.GetMethodError; } });
|
|
22
22
|
Object.defineProperty(exports, "TimeError", { enumerable: true, get: function () { return SmartContract_1.TimeError; } });
|
|
23
|
+
Object.defineProperty(exports, "EmulationError", { enumerable: true, get: function () { return SmartContract_1.EmulationError; } });
|
|
23
24
|
var Treasury_1 = require("./treasury/Treasury");
|
|
24
25
|
Object.defineProperty(exports, "TreasuryContract", { enumerable: true, get: function () { return Treasury_1.TreasuryContract; } });
|
|
25
26
|
var prettyLogTransaction_1 = require("./utils/prettyLogTransaction");
|