@ton/sandbox 0.11.0 → 0.12.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 +19 -0
- package/README.md +153 -29
- package/dist/blockchain/Blockchain.d.ts +5 -1
- package/dist/blockchain/Blockchain.js +86 -57
- package/dist/blockchain/BlockchainContractProvider.d.ts +1 -1
- package/dist/blockchain/BlockchainContractProvider.js +3 -3
- package/dist/blockchain/BlockchainSender.d.ts +1 -1
- package/dist/blockchain/BlockchainSender.js +2 -2
- package/dist/blockchain/BlockchainStorage.d.ts +1 -1
- package/dist/blockchain/BlockchainStorage.js +2 -2
- package/dist/blockchain/SmartContract.d.ts +2 -2
- package/dist/blockchain/SmartContract.js +15 -10
- package/dist/event/Event.d.ts +1 -1
- package/dist/executor/Executor.d.ts +1 -1
- package/dist/executor/Executor.js +2 -2
- package/dist/treasury/Treasury.d.ts +1 -1
- package/dist/treasury/Treasury.js +10 -10
- package/dist/utils/message.d.ts +1 -1
- package/dist/utils/message.js +2 -2
- package/dist/utils/prettyLogTransaction.d.ts +1 -1
- package/dist/utils/prettyLogTransaction.js +2 -2
- package/dist/utils/printTransactionFees.d.ts +1 -1
- package/dist/utils/testTreasurySubwalletId.js +2 -2
- package/package.json +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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.12.0] - 2023-10-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Step by step execution (`blockchain.sendMessageIter`)
|
|
13
|
+
- Better docs
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `now` from `Blockchain` is now honored in `SmartContract.receiveMessage`
|
|
18
|
+
- Exit code 1 is now counted as success in get methods
|
|
19
|
+
|
|
20
|
+
## [0.11.1] - 2023-07-26
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Migrated dependencies to @ton organization packages
|
|
25
|
+
- Bumped @ton/test-utils version to 0.3.1
|
|
26
|
+
|
|
8
27
|
## [0.11.0] - 2023-05-11
|
|
9
28
|
|
|
10
29
|
### Added
|
package/README.md
CHANGED
|
@@ -4,16 +4,32 @@ This package allows you to emulate arbitrary TON smart contracts, send messages
|
|
|
4
4
|
|
|
5
5
|
The key difference of this package from [ton-contract-executor](https://github.com/ton-community/ton-contract-executor) is the fact that the latter only emulates the compute phase of the contract - it does not know about any other phases and thus does not know anything about fees and balances (in a sense that it does not know whether a contract's balance will be enough to process all the out messages that it produces). On the other hand, this package emulates all the phases of a contract, and as a result, the emulation is much closer to what would happen in a real network.
|
|
6
6
|
|
|
7
|
+
## Content
|
|
8
|
+
|
|
9
|
+
* [Instalation](#installation)
|
|
10
|
+
* [Usage](#usage)
|
|
11
|
+
* [Writing Tests](#writing-tests)
|
|
12
|
+
* [Basic test template](#basic-test-template)
|
|
13
|
+
* [Test a transaction with matcher](#test-a-transaction-with-matcher)
|
|
14
|
+
* [Testing transaction fees](#testing-transaction-fees)
|
|
15
|
+
* [Cross contract tests](#cross-contract-tests)
|
|
16
|
+
* [Test examples](#test-examples)
|
|
17
|
+
* [Viewing logs](#viewing-logs)
|
|
18
|
+
* [Network/Block configuration](#networkblock-configuration)
|
|
19
|
+
* [Contributors](#contributors)
|
|
20
|
+
* [License](#license)
|
|
21
|
+
* [Donations](#donations)
|
|
22
|
+
|
|
7
23
|
## Installation
|
|
8
24
|
|
|
9
25
|
Requires node 16 or higher.
|
|
10
26
|
|
|
11
27
|
```
|
|
12
|
-
yarn add @ton/sandbox ton @ton/core ton
|
|
28
|
+
yarn add @ton/sandbox @ton/ton @ton/core @ton/crypto
|
|
13
29
|
```
|
|
14
30
|
or
|
|
15
31
|
```
|
|
16
|
-
npm i @ton/sandbox ton @ton/core ton
|
|
32
|
+
npm i @ton/sandbox @ton/ton @ton/core @ton/crypto
|
|
17
33
|
```
|
|
18
34
|
|
|
19
35
|
## Usage
|
|
@@ -25,14 +41,14 @@ import { Blockchain } from "@ton/sandbox";
|
|
|
25
41
|
const blockchain = await Blockchain.create()
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
After that, you can use the low level methods on Blockchain (such as sendMessage) to emulate any messages that you want, but the recommended way to use it is to write wrappers for your contract using the `Contract` interface from
|
|
44
|
+
After that, you can use the low level methods on Blockchain (such as sendMessage) to emulate any messages that you want, but the recommended way to use it is to write wrappers for your contract using the `Contract` interface from `@ton/core`. Then you can use `blockchain.openContract` on instances of such contracts, and they will be wrapped in a Proxy that will supply a `ContractProvider` as a first argument to all its methods starting with either `get` or `send`. Also all `send` methods will get Promisified and will return results of running the blockchain message queue along with the original method's result in the `result` field.
|
|
29
45
|
|
|
30
46
|
A good example of this is the [treasury contract](/src/treasury/Treasury.ts) that is basically a built-in highload wallet meant to help you write tests for your systems of smart contracts. When `blockchain.treasury` is called, an instance of `TreasuryContract` is created and `blockchain.openContract` is called to "open" it. After that, when you call `treasury.send`, `Blockchain` automatically supplies the first `provider` argument.
|
|
31
47
|
|
|
32
48
|
For your own contracts, you can draw inspiration from the contracts in the [examples](/examples/) - all of them use the `provider.internal` method to send internal messages using the treasuries passed in from the unit test file.
|
|
33
49
|
Here is an excerpt of that from [NftItem.ts](/examples/contracts/NftItem.ts):
|
|
34
50
|
```typescript
|
|
35
|
-
import { Address, beginCell, Cell, Contract, ContractProvider, Sender, toNano, Builder } from "ton
|
|
51
|
+
import { Address, beginCell, Cell, Contract, ContractProvider, Sender, toNano, Builder } from "@ton/core";
|
|
36
52
|
|
|
37
53
|
class NftItem implements Contract {
|
|
38
54
|
async sendTransfer(provider: ContractProvider, via: Sender, params: {
|
|
@@ -62,7 +78,7 @@ When you call `nftItem.sendTransfer(treasury.getSender(), { to: recipient })` (w
|
|
|
62
78
|
|
|
63
79
|
Here is another excerpt that shows the way to interact with get methods from wrappers:
|
|
64
80
|
```typescript
|
|
65
|
-
import { Contract, ContractProvider } from "ton
|
|
81
|
+
import { Contract, ContractProvider } from "@ton/core";
|
|
66
82
|
|
|
67
83
|
export type NftItemData = {
|
|
68
84
|
inited: boolean
|
|
@@ -94,10 +110,70 @@ Notes:
|
|
|
94
110
|
- Ideally, at most one call to **either** `provider.internal` or `provider.external` should be made within a `send` method. Otherwise, you may get hard to interpret (but generally speaking correct) results.
|
|
95
111
|
- No calls to `provider.external` or `provider.internal` should be made within `get` methods. Otherwise, you will get weird and wrong results in the following `send` methods of any contract.
|
|
96
112
|
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
|
|
97
116
|
## Writing tests
|
|
98
117
|
|
|
118
|
+
### Basic test template
|
|
119
|
+
|
|
99
120
|
You can install additional `@ton/test-utils` package by running `yarn add @ton/test-utils -D` or `npm i --save-dev @ton/test-utils` (with `.toHaveTransaction` for jest or `.transaction` or `.to.have.transaction` for chai matcher) to add additional helpers for ease of testing. Don't forget to import them in your unit test files though!
|
|
100
121
|
|
|
122
|
+
Writing tests in Sandbox works through defining arbitary actions with the contract and comparing their results with the expected result, for example:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
it('should execute with success', async () => { // description of the test case
|
|
126
|
+
const res = await main.sendMessage(sender.getSender(), toNano('0.05')); // performing an action with contract main and saving result in res
|
|
127
|
+
|
|
128
|
+
expect(res.transactions).toHaveTransaction({ // configure the expected result with expect() function
|
|
129
|
+
from: main.address, // set expected sender for transaction we want to test matcher properties from
|
|
130
|
+
success: true // set the desirable result using matcher property success
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
printTransactionFees(res.transactions); // print table with details on spent fees
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
### Test a transaction with matcher
|
|
139
|
+
|
|
140
|
+
The basic workflow of creating a test is:
|
|
141
|
+
1. Create a specific wrapped `Contract` entity using `blockchain.openContract()`.
|
|
142
|
+
2. Describe the actions your `Contract` should perform and save the execution result in `res` variable.
|
|
143
|
+
3. Verify the properties using the `expect()` function and the matcher `toHaveTransaction()`.
|
|
144
|
+
|
|
145
|
+
The `toHaveTransaction` matcher expects an object with any combination of fields from the `FlatTransaction` type defined with the following properties
|
|
146
|
+
|
|
147
|
+
| Name | Type | Description |
|
|
148
|
+
|----------------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
149
|
+
| from | Address? | Contract address of the message sender |
|
|
150
|
+
| to | Address | Contract address of the message destination |
|
|
151
|
+
| on | Address | Contract address of the message destination (Alternative name of the property `to`). |
|
|
152
|
+
| value | bigint? | Amount of Toncoins in the message in nanotons |
|
|
153
|
+
| body | Cell | Message body defined as a Cell |
|
|
154
|
+
| inMessageBounced | boolean? | Boolean flag Bounced. True - message is bounced, False - message is not bounced. |
|
|
155
|
+
| inMessageBounceable | boolean? | Boolean flag Bounceable. True - message can be bounced, False - message can not be bounced. |
|
|
156
|
+
| op | number? | Op code is the operation identifier number (crc32 from TL-B usually). Expected in the first 32 bits of a message body. |
|
|
157
|
+
| initData | Cell? | InitData Cell. Used for contract deployment processes. |
|
|
158
|
+
| initCode | Cell? | initCode Cell. Used for contract deployment processes. |
|
|
159
|
+
| deploy | boolean | Custom Sandbox flag that indicates whether the contract was deployed during this transaction. True if contract before this transaction was not initialized and after this transaction became initialized. Otherwise - False. |
|
|
160
|
+
| lt | bigint | Logical time (set by validators in a normal network, monotonically increases by a set interval in Sandbox). Used for defining order of transactions related to a certain contract |
|
|
161
|
+
| now | bigint | Unix timestamp of the transaction |
|
|
162
|
+
| outMessagesCount | number | Quantity of outbound messages in a certain transaction |
|
|
163
|
+
| oldStatus | AccountStatus | AccountStatus before transaction execution |
|
|
164
|
+
| endStatus | AccountStatus | AccountStatus after transaction execution |
|
|
165
|
+
| totalFees | bigint? | Number of spent fees in nanotons |
|
|
166
|
+
|aborted| boolean? | True - execution of certain transaction aborted and rollbacked because of errors or insufficient gas. Otherwise - False. |
|
|
167
|
+
|destroyed| boolean? | True - if the existing contract was destroyed due to executing a certain transaction. Otherwise - False. |
|
|
168
|
+
|exitCode| number? | TVM exit code (from compute phase) |
|
|
169
|
+
|actionResultCode| number? | Action phase result code |
|
|
170
|
+
|success| boolean? | Custom Sandbox flag that defines the resulting status of a certain transaction. True - if both the compute and the action phase succeeded. Otherwise - False. |
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
You can omit those that you're not interested in, and you can also pass in functions accepting those types returning booleans (`true` meaning good) to check for example number ranges, message opcodes, etc. Note however that if a field is optional (like `from?: Address`), then the function needs to accept the optional type, too.
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
101
177
|
Here is an excerpt of how it's used in the NFT collection example mentioned above:
|
|
102
178
|
```typescript
|
|
103
179
|
const buyResult = await buyer.send({
|
|
@@ -119,32 +195,80 @@ expect(buyResult.transactions).toHaveTransaction({
|
|
|
119
195
|
```
|
|
120
196
|
(in that example `jest` is used)
|
|
121
197
|
|
|
122
|
-
|
|
198
|
+
|
|
199
|
+
### Testing transaction fees
|
|
200
|
+
It is possible to configure and update the current time of the `Blockchain`, which allows one to inspect how much a contract would spend on storage fees.
|
|
201
|
+
|
|
202
|
+
Suppose we have a `main` instance defined as a wrapped `Contract` instance `main = blockchain.openContract(/* non-wrapped Main instance */)`, and we wish to determine the amount of storage fees that will be accrued between two actions within a specified period.
|
|
203
|
+
|
|
123
204
|
```typescript
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
205
|
+
it('should storage fees cost less than 1 TON', async () => {
|
|
206
|
+
const time1 = Math.floor(Date.now() / 1000); // current local unix time
|
|
207
|
+
const time2 = time1 + 365 * 24 * 60 * 60; // offset for a year
|
|
208
|
+
|
|
209
|
+
blockchain.now = time1; // set current time
|
|
210
|
+
const res1 = await main.sendMessage(sender.getSender(), toNano('0.05')); // preview of fees
|
|
211
|
+
printTransactionFees(res1.transactions);
|
|
212
|
+
|
|
213
|
+
blockchain.now = time2; // set current time
|
|
214
|
+
const res2 = await main.sendMessage(sender.getSender(), toNano('0.05')); // preview of fees
|
|
215
|
+
printTransactionFees(res2.transactions);
|
|
216
|
+
|
|
217
|
+
const tx2 = res2.transactions[1]; // extract the transaction that executed in a year
|
|
218
|
+
if (tx2.description.type !== 'generic') {
|
|
219
|
+
throw new Error('Generic transaction expected');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check that the storagePhase fees are less than 1 TON over the course of a year
|
|
223
|
+
expect(tx2.description.storagePhase?.storageFeesCollected).toBeLessThanOrEqual(toNano('1'));
|
|
224
|
+
});
|
|
143
225
|
```
|
|
144
226
|
|
|
145
|
-
|
|
227
|
+
### Cross contract tests
|
|
228
|
+
|
|
229
|
+
The Sandbox emulates the entire process of executing cross-contract interactions as if they occurred on a real blockchain.
|
|
230
|
+
The result of sending a message (transfer) contains basic information about all transactions and actions.
|
|
231
|
+
You can verify all of these by creating specific requirements via `expect()` for each action and transaction.
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
res = await main.sendMessage(...);
|
|
235
|
+
|
|
236
|
+
expect(res).toHaveTransaction(...) // test case
|
|
237
|
+
<...>
|
|
238
|
+
expect(res).toHaveTransaction(...) // test case
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
For instance, with [Modern Jetton](https://github.com/EmelyanenkoK/modern_jetton) it's possible to test whether a `mint` message results in minting to a new jetton wallet contract and returns the excess to the minter contract.
|
|
242
|
+
```typescript
|
|
243
|
+
it('minter admin should be able to mint jettons', async () => {
|
|
244
|
+
// can mint from deployer
|
|
245
|
+
let initialTotalSupply = await jettonMinter.getTotalSupply();
|
|
246
|
+
const deployerJettonWallet = await userWallet(deployer.address);
|
|
247
|
+
let initialJettonBalance = toNano('1000.23');
|
|
248
|
+
const mintResult = await jettonMinter.sendMint(deployer.getSender(), deployer.address, initialJettonBalance, toNano('0.05'), toNano('1'));
|
|
249
|
+
|
|
250
|
+
expect(mintResult.transactions).toHaveTransaction({ // test transaction of deployment of a jetton wallet
|
|
251
|
+
from: jettonMinter.address,
|
|
252
|
+
to: deployerJettonWallet.address,
|
|
253
|
+
deploy: true,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(mintResult.transactions).toHaveTransaction({ // test transaction of excesses returned to minter
|
|
257
|
+
from: deployerJettonWallet.address,
|
|
258
|
+
to: jettonMinter.address
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Test Examples
|
|
265
|
+
You can typically find various tests for Sandbox-based project contracts in the `./tests` directory.
|
|
266
|
+
Learn more from examples:
|
|
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)
|
|
146
270
|
|
|
147
|
-
|
|
271
|
+
## Viewing logs
|
|
148
272
|
|
|
149
273
|
`Blockchain` and `SmartContract` use `LogsVerbosity` to determine what kinds of logs to print. Here is the definition:
|
|
150
274
|
```typescript
|
|
@@ -185,7 +309,7 @@ blockchain.verbosity = {
|
|
|
185
309
|
```
|
|
186
310
|
Note that unlike with `setVerbosityForAddress`, with this setter you have to specify all the values from `LogsVerbosity`.
|
|
187
311
|
|
|
188
|
-
|
|
312
|
+
## Setting smart contract state directly
|
|
189
313
|
|
|
190
314
|
If you want to test some behavior on a contract if it had specific code, data, and other state fields, but do not want to execute all the required transactions for that, you can directly set the full state of the contract as it is stored in sandbox by using this method on the `Blockchain` instance:
|
|
191
315
|
```
|
|
@@ -195,7 +319,7 @@ There are 2 helpers exported from sandbox that can help you create the `ShardAcc
|
|
|
195
319
|
|
|
196
320
|
Note that this is a low-level function and does not check any invariants, such as that the address passed as the argument matches the one that is present in the `ShardAccount`, meaning it is possible to break stuff if you're not careful when using it.
|
|
197
321
|
|
|
198
|
-
|
|
322
|
+
## Network/Block configuration
|
|
199
323
|
|
|
200
324
|
By default, this package will use its [stored network configuration](src/config/defaultConfig.ts) to emulate messages. However, you can set any configuration you want when creating the `Blockchain` instance by passing the configuration cell in the optional `params` argument in the `config` field.
|
|
201
325
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, Cell, Message, Transaction, ContractProvider, Contract, Sender, ShardAccount, TupleItem, ExternalAddress, StateInit } from "ton
|
|
1
|
+
import { Address, Cell, Message, Transaction, ContractProvider, Contract, Sender, ShardAccount, TupleItem, ExternalAddress, StateInit } from "@ton/core";
|
|
2
2
|
import { Executor, TickOrTock } from "../executor/Executor";
|
|
3
3
|
import { BlockchainStorage } from "./BlockchainStorage";
|
|
4
4
|
import { Event } from "../event/Event";
|
|
@@ -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;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Blockchain = void 0;
|
|
4
4
|
const defaultConfig_1 = require("../config/defaultConfig");
|
|
5
|
-
const
|
|
5
|
+
const core_1 = require("@ton/core");
|
|
6
6
|
const Executor_1 = require("../executor/Executor");
|
|
7
7
|
const BlockchainStorage_1 = require("./BlockchainStorage");
|
|
8
8
|
const Event_1 = require("../event/Event");
|
|
@@ -80,7 +80,7 @@ class Blockchain {
|
|
|
80
80
|
this.storage = opts.storage;
|
|
81
81
|
}
|
|
82
82
|
get config() {
|
|
83
|
-
return
|
|
83
|
+
return core_1.Cell.fromBase64(this.networkConfig);
|
|
84
84
|
}
|
|
85
85
|
get configBase64() {
|
|
86
86
|
return this.networkConfig;
|
|
@@ -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);
|
|
@@ -102,7 +111,7 @@ class Blockchain {
|
|
|
102
111
|
});
|
|
103
112
|
}
|
|
104
113
|
async pushMessage(message) {
|
|
105
|
-
const msg = message instanceof
|
|
114
|
+
const msg = message instanceof core_1.Cell ? (0, core_1.loadMessage)(message.beginParse()) : message;
|
|
106
115
|
if (msg.info.type === 'external-out') {
|
|
107
116
|
throw new Error('Cannot send external out message');
|
|
108
117
|
}
|
|
@@ -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
|
});
|
|
@@ -210,15 +239,15 @@ class Blockchain {
|
|
|
210
239
|
const contract = await this.getContract(wallet.address);
|
|
211
240
|
if ((params?.predeploy ?? true) && (contract.accountState === undefined || contract.accountState.type === 'uninit')) {
|
|
212
241
|
await this.sendMessage((0, message_1.internal)({
|
|
213
|
-
from: new
|
|
242
|
+
from: new core_1.Address(0, Buffer.alloc(32)),
|
|
214
243
|
to: wallet.address,
|
|
215
|
-
value: (0,
|
|
244
|
+
value: (0, core_1.toNano)(1),
|
|
216
245
|
stateInit: wallet.init,
|
|
217
246
|
}));
|
|
218
|
-
contract.balance = params?.balance ?? (0,
|
|
247
|
+
contract.balance = params?.balance ?? (0, core_1.toNano)(TREASURY_INIT_BALANCE_TONS);
|
|
219
248
|
}
|
|
220
249
|
else if ((params?.resetBalanceIfZero ?? true) && contract.balance === 0n) {
|
|
221
|
-
contract.balance = params?.balance ?? (0,
|
|
250
|
+
contract.balance = params?.balance ?? (0, core_1.toNano)(TREASURY_INIT_BALANCE_TONS);
|
|
222
251
|
}
|
|
223
252
|
return wallet;
|
|
224
253
|
}
|
|
@@ -233,15 +262,15 @@ class Blockchain {
|
|
|
233
262
|
openContract(contract) {
|
|
234
263
|
let address;
|
|
235
264
|
let init = undefined;
|
|
236
|
-
if (!
|
|
265
|
+
if (!core_1.Address.isAddress(contract.address)) {
|
|
237
266
|
throw Error('Invalid address');
|
|
238
267
|
}
|
|
239
268
|
address = contract.address;
|
|
240
269
|
if (contract.init) {
|
|
241
|
-
if (!(contract.init.code instanceof
|
|
270
|
+
if (!(contract.init.code instanceof core_1.Cell)) {
|
|
242
271
|
throw Error('Invalid init.code');
|
|
243
272
|
}
|
|
244
|
-
if (!(contract.init.data instanceof
|
|
273
|
+
if (!(contract.init.data instanceof core_1.Cell)) {
|
|
245
274
|
throw Error('Invalid init.data');
|
|
246
275
|
}
|
|
247
276
|
init = contract.init;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, Cell, ContractGetMethodResult, ContractProvider, ContractState, Message, Sender, SendMode, TupleItem } from "ton
|
|
1
|
+
import { Address, Cell, ContractGetMethodResult, ContractProvider, ContractState, Message, Sender, SendMode, TupleItem } from "@ton/core";
|
|
2
2
|
import { TickOrTock } from "../executor/Executor";
|
|
3
3
|
import { GetMethodResult, SmartContract } from "./SmartContract";
|
|
4
4
|
export interface SandboxContractProvider extends ContractProvider {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BlockchainContractProvider = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
function bigintToBuffer(x, n = 32) {
|
|
6
6
|
const b = Buffer.alloc(n);
|
|
7
7
|
for (let i = 0; i < n; i++) {
|
|
@@ -72,8 +72,8 @@ class BlockchainContractProvider {
|
|
|
72
72
|
async internal(via, args) {
|
|
73
73
|
const init = ((await this.getState()).state.type !== 'active' && this.init) ? this.init : undefined;
|
|
74
74
|
const bounce = (args.bounce !== null && args.bounce !== undefined) ? args.bounce : true;
|
|
75
|
-
const value = typeof args.value === 'string' ? (0,
|
|
76
|
-
const body = typeof args.body === 'string' ? (0,
|
|
75
|
+
const value = typeof args.value === 'string' ? (0, core_1.toNano)(args.value) : args.value;
|
|
76
|
+
const body = typeof args.body === 'string' ? (0, core_1.comment)(args.body) : args.body;
|
|
77
77
|
await via.send({
|
|
78
78
|
to: this.address,
|
|
79
79
|
value,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BlockchainSender = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
class BlockchainSender {
|
|
6
6
|
constructor(blockchain, address) {
|
|
7
7
|
this.blockchain = blockchain;
|
|
@@ -22,7 +22,7 @@ class BlockchainSender {
|
|
|
22
22
|
createdAt: 0,
|
|
23
23
|
createdLt: 0n,
|
|
24
24
|
},
|
|
25
|
-
body: args.body ?? new
|
|
25
|
+
body: args.body ?? new core_1.Cell()
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { AccountState, Address } from "ton
|
|
2
|
+
import { AccountState, Address } from "@ton/core";
|
|
3
3
|
import { SmartContract } from "./SmartContract";
|
|
4
4
|
import { Blockchain } from "./Blockchain";
|
|
5
5
|
export interface BlockchainStorage {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RemoteBlockchainStorage = exports.wrapTonClient4ForRemote = exports.LocalBlockchainStorage = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
const SmartContract_1 = require("./SmartContract");
|
|
6
6
|
class LocalBlockchainStorage {
|
|
7
7
|
constructor() {
|
|
@@ -28,7 +28,7 @@ function convertTonClient4State(state) {
|
|
|
28
28
|
case 'uninit':
|
|
29
29
|
return { type: 'uninit' };
|
|
30
30
|
case 'active':
|
|
31
|
-
return { type: 'active', state: { code: state.code === null ? undefined :
|
|
31
|
+
return { type: 'active', state: { code: state.code === null ? undefined : core_1.Cell.fromBase64(state.code), data: state.data === null ? undefined : core_1.Cell.fromBase64(state.data) } };
|
|
32
32
|
case 'frozen':
|
|
33
33
|
return { type: 'frozen', stateHash: BigInt('0x' + Buffer.from(state.stateHash, 'base64').toString('hex')) };
|
|
34
34
|
default:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Blockchain } from "./Blockchain";
|
|
3
|
-
import { Address, Cell, Message, ShardAccount, Transaction, TupleItem, TupleReader } from "ton
|
|
3
|
+
import { Address, Cell, Message, ShardAccount, Transaction, TupleItem, TupleReader } from "@ton/core";
|
|
4
4
|
import { EmulationResult, RunCommonArgs, TickOrTock } from "../executor/Executor";
|
|
5
5
|
export declare function createShardAccount(args: {
|
|
6
6
|
address?: Address;
|
|
@@ -72,7 +72,7 @@ export declare class SmartContract {
|
|
|
72
72
|
set balance(v: bigint);
|
|
73
73
|
get lastTransactionHash(): bigint;
|
|
74
74
|
get lastTransactionLt(): bigint;
|
|
75
|
-
get accountState(): import("ton
|
|
75
|
+
get accountState(): import("@ton/core").AccountState | undefined;
|
|
76
76
|
get account(): ShardAccount;
|
|
77
77
|
set account(account: ShardAccount);
|
|
78
78
|
static create(blockchain: Blockchain, args: {
|
|
@@ -13,11 +13,11 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
13
13
|
var _SmartContract_account, _SmartContract_parsedAccount, _SmartContract_lastTxTime, _SmartContract_verbosity;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.SmartContract = exports.TimeError = exports.GetMethodError = exports.createEmptyShardAccount = exports.createShardAccount = void 0;
|
|
16
|
-
const
|
|
16
|
+
const core_1 = require("@ton/core");
|
|
17
17
|
const selector_1 = require("../utils/selector");
|
|
18
18
|
function createShardAccount(args) {
|
|
19
19
|
let wc = args.workchain ?? 0;
|
|
20
|
-
let address = args.address ?? (0,
|
|
20
|
+
let address = args.address ?? (0, core_1.contractAddress)(wc, { code: args.code, data: args.data });
|
|
21
21
|
let balance = args.balance ?? 0n;
|
|
22
22
|
return {
|
|
23
23
|
account: {
|
|
@@ -105,7 +105,7 @@ class SmartContract {
|
|
|
105
105
|
_SmartContract_lastTxTime.set(this, void 0);
|
|
106
106
|
_SmartContract_verbosity.set(this, void 0);
|
|
107
107
|
this.address = shardAccount.account.addr;
|
|
108
|
-
__classPrivateFieldSet(this, _SmartContract_account, (0,
|
|
108
|
+
__classPrivateFieldSet(this, _SmartContract_account, (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(shardAccount)).endCell().toBoc().toString('base64'), "f");
|
|
109
109
|
__classPrivateFieldSet(this, _SmartContract_parsedAccount, shardAccount, "f");
|
|
110
110
|
__classPrivateFieldSet(this, _SmartContract_lastTxTime, shardAccount.account?.storageStats.lastPaid ?? 0, "f");
|
|
111
111
|
this.blockchain = blockchain;
|
|
@@ -148,12 +148,12 @@ class SmartContract {
|
|
|
148
148
|
}
|
|
149
149
|
get account() {
|
|
150
150
|
if (__classPrivateFieldGet(this, _SmartContract_parsedAccount, "f") === undefined) {
|
|
151
|
-
__classPrivateFieldSet(this, _SmartContract_parsedAccount, (0,
|
|
151
|
+
__classPrivateFieldSet(this, _SmartContract_parsedAccount, (0, core_1.loadShardAccount)(core_1.Cell.fromBase64(__classPrivateFieldGet(this, _SmartContract_account, "f")).beginParse()), "f");
|
|
152
152
|
}
|
|
153
153
|
return __classPrivateFieldGet(this, _SmartContract_parsedAccount, "f");
|
|
154
154
|
}
|
|
155
155
|
set account(account) {
|
|
156
|
-
__classPrivateFieldSet(this, _SmartContract_account, (0,
|
|
156
|
+
__classPrivateFieldSet(this, _SmartContract_account, (0, core_1.beginCell)().store((0, core_1.storeShardAccount)(account)).endCell().toBoc().toString('base64'), "f");
|
|
157
157
|
__classPrivateFieldSet(this, _SmartContract_parsedAccount, account, "f");
|
|
158
158
|
__classPrivateFieldSet(this, _SmartContract_lastTxTime, account.account?.storageStats.lastPaid ?? 0, "f");
|
|
159
159
|
}
|
|
@@ -181,9 +181,14 @@ class SmartContract {
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
receiveMessage(message, params) {
|
|
184
|
+
// Sync now with blockchain instance if not specified in parameters
|
|
185
|
+
params = {
|
|
186
|
+
now: this.blockchain.now,
|
|
187
|
+
...params,
|
|
188
|
+
};
|
|
184
189
|
return this.runCommon(() => this.blockchain.executor.runTransaction({
|
|
185
190
|
...this.createCommonArgs(params),
|
|
186
|
-
message: (0,
|
|
191
|
+
message: (0, core_1.beginCell)().store((0, core_1.storeMessage)(message)).endCell(),
|
|
187
192
|
}));
|
|
188
193
|
}
|
|
189
194
|
runTickTock(which, params) {
|
|
@@ -207,7 +212,7 @@ class SmartContract {
|
|
|
207
212
|
if (this.verbosity.print && this.verbosity.debugLogs && res.debugLogs.length > 0) {
|
|
208
213
|
console.log(res.debugLogs);
|
|
209
214
|
}
|
|
210
|
-
const tx = (0,
|
|
215
|
+
const tx = (0, core_1.loadTransaction)(core_1.Cell.fromBase64(res.result.transaction).beginParse());
|
|
211
216
|
__classPrivateFieldSet(this, _SmartContract_account, res.result.shardAccount, "f");
|
|
212
217
|
__classPrivateFieldSet(this, _SmartContract_parsedAccount, undefined, "f");
|
|
213
218
|
__classPrivateFieldSet(this, _SmartContract_lastTxTime, tx.now, "f");
|
|
@@ -249,13 +254,13 @@ class SmartContract {
|
|
|
249
254
|
if (this.verbosity.print && this.verbosity.debugLogs && res.debugLogs.length > 0) {
|
|
250
255
|
console.log(res.debugLogs);
|
|
251
256
|
}
|
|
252
|
-
if (res.output.vm_exit_code !== 0) {
|
|
257
|
+
if (res.output.vm_exit_code !== 0 && res.output.vm_exit_code !== 1) {
|
|
253
258
|
throw new GetMethodError(res.output.vm_exit_code, BigInt(res.output.gas_used), res.logs, res.output.vm_log, res.debugLogs);
|
|
254
259
|
}
|
|
255
|
-
const resStack = (0,
|
|
260
|
+
const resStack = (0, core_1.parseTuple)(core_1.Cell.fromBase64(res.output.stack));
|
|
256
261
|
return {
|
|
257
262
|
stack: resStack,
|
|
258
|
-
stackReader: new
|
|
263
|
+
stackReader: new core_1.TupleReader(resStack),
|
|
259
264
|
exitCode: res.output.vm_exit_code,
|
|
260
265
|
gasUsed: BigInt(res.output.gas_used),
|
|
261
266
|
blockchainLogs: res.logs,
|
package/dist/event/Event.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Executor = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
const base64_1 = require("../utils/base64");
|
|
6
6
|
const EmulatorModule = require('./emulator-emscripten.js');
|
|
7
7
|
const verbosityToNum = {
|
|
@@ -93,7 +93,7 @@ class Executor {
|
|
|
93
93
|
method_id: args.methodId,
|
|
94
94
|
debug_enabled: args.debugEnabled,
|
|
95
95
|
};
|
|
96
|
-
let stack = (0,
|
|
96
|
+
let stack = (0, core_1.serializeTuple)(args.stack);
|
|
97
97
|
this.debugLogs = [];
|
|
98
98
|
const resp = JSON.parse(this.extractString(this.invoke('_run_get_method', [
|
|
99
99
|
JSON.stringify(params),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Address, Cell, Contract, ContractProvider, MessageRelaxed, Sender, SenderArguments, SendMode } from "ton
|
|
1
|
+
import { Address, Cell, Contract, ContractProvider, MessageRelaxed, Sender, SenderArguments, SendMode } from "@ton/core";
|
|
2
2
|
export type Treasury = Sender & {
|
|
3
3
|
address: Address;
|
|
4
4
|
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TreasuryContract = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
const DictionaryMessageValue = {
|
|
6
6
|
serialize(src, builder) {
|
|
7
7
|
builder.storeUint(src.sendMode, 8);
|
|
8
|
-
builder.storeRef((0,
|
|
8
|
+
builder.storeRef((0, core_1.beginCell)().store((0, core_1.storeMessageRelaxed)(src.message)));
|
|
9
9
|
},
|
|
10
10
|
parse(src) {
|
|
11
11
|
let sendMode = src.loadUint(8);
|
|
12
|
-
let message = (0,
|
|
12
|
+
let message = (0, core_1.loadMessageRelaxed)(src.loadRef().beginParse());
|
|
13
13
|
return { sendMode, message };
|
|
14
14
|
},
|
|
15
15
|
};
|
|
16
16
|
function senderArgsToMessageRelaxed(args) {
|
|
17
|
-
return (0,
|
|
17
|
+
return (0, core_1.internal)({
|
|
18
18
|
to: args.to,
|
|
19
19
|
value: args.value,
|
|
20
20
|
init: args.init,
|
|
@@ -27,11 +27,11 @@ class TreasuryContract {
|
|
|
27
27
|
return new TreasuryContract(workchain, subwalletId);
|
|
28
28
|
}
|
|
29
29
|
constructor(workchain, subwalletId) {
|
|
30
|
-
const data = (0,
|
|
30
|
+
const data = (0, core_1.beginCell)()
|
|
31
31
|
.storeUint(subwalletId, 256)
|
|
32
32
|
.endCell();
|
|
33
33
|
this.init = { code: TreasuryContract.code, data };
|
|
34
|
-
this.address = (0,
|
|
34
|
+
this.address = (0, core_1.contractAddress)(workchain, this.init);
|
|
35
35
|
this.subwalletId = subwalletId;
|
|
36
36
|
}
|
|
37
37
|
async sendMessages(provider, messages, sendMode) {
|
|
@@ -60,23 +60,23 @@ class TreasuryContract {
|
|
|
60
60
|
return (await provider.getState()).balance;
|
|
61
61
|
}
|
|
62
62
|
createTransfer(args) {
|
|
63
|
-
let sendMode =
|
|
63
|
+
let sendMode = core_1.SendMode.PAY_GAS_SEPARATELY;
|
|
64
64
|
if (args.sendMode !== null && args.sendMode !== undefined) {
|
|
65
65
|
sendMode = args.sendMode;
|
|
66
66
|
}
|
|
67
67
|
if (args.messages.length > 255) {
|
|
68
68
|
throw new Error('Maximum number of messages is 255');
|
|
69
69
|
}
|
|
70
|
-
let messages =
|
|
70
|
+
let messages = core_1.Dictionary.empty(core_1.Dictionary.Keys.Int(16), DictionaryMessageValue);
|
|
71
71
|
let index = 0;
|
|
72
72
|
for (let m of args.messages) {
|
|
73
73
|
messages.set(index++, { sendMode, message: m });
|
|
74
74
|
}
|
|
75
|
-
return (0,
|
|
75
|
+
return (0, core_1.beginCell)()
|
|
76
76
|
.storeUint(this.subwalletId, 256)
|
|
77
77
|
.storeDict(messages)
|
|
78
78
|
.endCell();
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
exports.TreasuryContract = TreasuryContract;
|
|
82
|
-
TreasuryContract.code =
|
|
82
|
+
TreasuryContract.code = core_1.Cell.fromBase64('te6cckEBBAEARQABFP8A9KQT9LzyyAsBAgEgAwIAWvLT/+1E0NP/0RK68qL0BNH4AH+OFiGAEPR4b6UgmALTB9QwAfsAkTLiAbPmWwAE0jD+omUe');
|
package/dist/utils/message.d.ts
CHANGED
package/dist/utils/message.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.internal = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
function internal(params) {
|
|
6
6
|
return {
|
|
7
7
|
info: {
|
|
@@ -17,7 +17,7 @@ function internal(params) {
|
|
|
17
17
|
createdAt: params.createdAt ?? 0,
|
|
18
18
|
createdLt: params.createdLt ?? 0n,
|
|
19
19
|
},
|
|
20
|
-
body: params.body ?? new
|
|
20
|
+
body: params.body ?? new core_1.Cell(),
|
|
21
21
|
init: params.stateInit,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.prettyLogTransactions = exports.prettyLogTransaction = void 0;
|
|
4
|
-
const
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
5
|
function prettyLogTransaction(tx) {
|
|
6
6
|
let res = `${tx.inMessage?.info.src} ➡️ ${tx.inMessage?.info.dest}\n`;
|
|
7
7
|
for (let message of tx.outMessages.values()) {
|
|
8
8
|
if (message.info.type === 'internal') {
|
|
9
|
-
res += ` ➡️ ${(0,
|
|
9
|
+
res += ` ➡️ ${(0, core_1.fromNano)(message.info.value.coins)} 💎 ${message.info.dest}\n`;
|
|
10
10
|
}
|
|
11
11
|
else {
|
|
12
12
|
res += ` ➡️ ${message.info.dest}\n`;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.testSubwalletId = void 0;
|
|
4
|
-
const
|
|
4
|
+
const crypto_1 = require("@ton/crypto");
|
|
5
5
|
const prefix = 'TESTSEED';
|
|
6
6
|
function testSubwalletId(seed) {
|
|
7
|
-
return BigInt('0x' + (0,
|
|
7
|
+
return BigInt('0x' + (0, crypto_1.sha256_sync)(prefix + seed).toString('hex'));
|
|
8
8
|
}
|
|
9
9
|
exports.testSubwalletId = testSubwalletId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ton/sandbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "TON transaction emulator",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,20 +13,20 @@
|
|
|
13
13
|
"url": "git+https://github.com/ton-org/sandbox"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@ton
|
|
16
|
+
"@ton/core": "^0.49.2",
|
|
17
|
+
"@ton/crypto": "3.2.0",
|
|
18
|
+
"@ton/test-utils": "^0.3.1",
|
|
19
|
+
"@ton/ton": "^13.4.2",
|
|
17
20
|
"@types/jest": "^29.5.0",
|
|
18
21
|
"@types/node": "^18.15.11",
|
|
19
22
|
"jest": "^29.5.0",
|
|
20
|
-
"ton": "^13.4.1",
|
|
21
|
-
"ton-core": "^0.49.0",
|
|
22
|
-
"ton-crypto": "3.2.0",
|
|
23
23
|
"ts-jest": "^29.0.5",
|
|
24
24
|
"ts-node": "^10.9.1",
|
|
25
25
|
"typescript": "^4.9.5"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"ton
|
|
29
|
-
"ton
|
|
28
|
+
"@ton/core": ">=0.49.2",
|
|
29
|
+
"@ton/crypto": ">=3.2.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"wasm:pack": "ts-node ./scripts/pack-wasm.ts",
|
|
@@ -34,5 +34,6 @@
|
|
|
34
34
|
"test": "yarn wasm:pack && yarn jest src",
|
|
35
35
|
"build": "rm -rf dist && yarn wasm:pack && yarn test && tsc && yarn wasm:copy",
|
|
36
36
|
"config:pack": "ts-node ./scripts/pack-config.ts"
|
|
37
|
-
}
|
|
38
|
-
|
|
37
|
+
},
|
|
38
|
+
"packageManager": "yarn@3.6.1"
|
|
39
|
+
}
|