@ton/blueprint 0.33.1 → 0.34.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 +22 -0
- package/README.md +98 -12
- package/dist/cli/Runner.d.ts +2 -0
- package/dist/cli/Runner.js +9 -1
- package/dist/cli/build.d.ts +1 -2
- package/dist/cli/build.js +3 -6
- package/dist/cli/cli.js +8 -1
- package/dist/cli/constants.d.ts +4 -0
- package/dist/cli/constants.js +44 -6
- package/dist/cli/create.js +2 -13
- package/dist/cli/help.js +2 -1
- package/dist/cli/pack.d.ts +2 -0
- package/dist/cli/pack.js +98 -0
- package/dist/cli/rename.d.ts +6 -0
- package/dist/cli/rename.js +101 -0
- package/dist/cli/rename.spec.d.ts +1 -0
- package/dist/cli/rename.spec.js +59 -0
- package/dist/cli/run.js +2 -1
- package/dist/cli/snapshot.d.ts +6 -0
- package/dist/cli/snapshot.js +36 -0
- package/dist/cli/test.d.ts +4 -0
- package/dist/cli/test.js +20 -4
- package/dist/compile/compile.d.ts +16 -0
- package/dist/compile/compile.js +23 -7
- package/dist/compile/tact/compile.tact.d.ts +2 -1
- package/dist/compile/tact/compile.tact.js +9 -5
- package/dist/config/Config.d.ts +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/network/Network.d.ts +1 -0
- package/dist/network/Network.js +2 -0
- package/dist/network/createNetworkProvider.js +20 -6
- package/dist/network/send/DeeplinkProvider.d.ts +2 -1
- package/dist/network/send/DeeplinkProvider.js +6 -4
- package/dist/network/send/MnemonicProvider.d.ts +14 -7
- package/dist/network/send/MnemonicProvider.js +28 -8
- package/dist/network/send/TonConnectProvider.d.ts +2 -1
- package/dist/network/send/TonConnectProvider.js +10 -4
- package/dist/paths.d.ts +3 -0
- package/dist/paths.js +4 -1
- package/dist/templates/func/common/contracts/imports/stdlib.fc.template +8 -7
- package/dist/templates/func/not-separated-common/contracts/imports/stdlib.fc.template +8 -7
- package/dist/templates/tact/counter/scripts/deploy.ts.template +1 -1
- package/dist/templates/tact/counter/scripts/increment.ts.template +1 -1
- package/dist/templates/tact/empty/scripts/deploy.ts.template +1 -1
- package/dist/utils/selection.utils.js +5 -4
- package/dist/utils/string.utils.d.ts +3 -0
- package/dist/utils/string.utils.js +20 -0
- package/dist/utils/ton.utils.d.ts +2 -1
- package/dist/utils/ton.utils.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ 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.34.0] - 2025-05-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added config option to look for wrappers recursively
|
|
13
|
+
- Exported `getCompilerConfigForContract` function for plugin support
|
|
14
|
+
- Added request timout configuration
|
|
15
|
+
- Added docs for script args
|
|
16
|
+
- Added the `rename` command which renames contracts
|
|
17
|
+
- Added the `pack` command which builds and prepares a publish-ready package of contracts' wrappers
|
|
18
|
+
- Added support for wallet IDs in mnemonic provider. Environment variables `WALLET_ID` or `SUBWALLET_NUMBER` should be set, or a .env file with them must be present in order for it to be usable
|
|
19
|
+
- Added command `blueprint snapshot` to run tests with metric collection and write new benchmark report
|
|
20
|
+
- Added option `blueprint test --gas-report` to run tests and compare with the last snapshot metrics
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fix address format in testnet
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Updated FunC stdlib
|
|
29
|
+
|
|
8
30
|
## [0.33.1] - 2025-05-16
|
|
9
31
|
|
|
10
32
|
### Fixed
|
package/README.md
CHANGED
|
@@ -16,12 +16,14 @@ A development environment for TON blockchain for writing, testing, and deploying
|
|
|
16
16
|
* [Directory structure](#directory-structure)
|
|
17
17
|
* [Building contracts](#building-contracts)
|
|
18
18
|
* [Running the test suites](#running-the-test-suites)
|
|
19
|
-
* [
|
|
20
|
-
|
|
19
|
+
* [Running scripts](#running-scripts)
|
|
20
|
+
* [Deploying contracts](#deploying-contracts)
|
|
21
|
+
* [Using Mnemonic Provider](#using-mnemonic-provider)
|
|
21
22
|
* [Contract development](#contract-development)
|
|
22
23
|
* [Creating contracts](#creating-contracts)
|
|
23
24
|
* [Writing contract code](#writing-contract-code)
|
|
24
25
|
* [Testing contracts](#testing-contracts)
|
|
26
|
+
* [Benchmark contracts](#benchmark-contracts)
|
|
25
27
|
* [Configuration](#configuration)
|
|
26
28
|
* [Plugins](#plugins)
|
|
27
29
|
* [Custom network](#custom-network)
|
|
@@ -100,23 +102,58 @@ Blueprint is an all-in-one development environment designed to enhance the proce
|
|
|
100
102
|
|
|
101
103
|
> Learn more about writing tests from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#writing-tests).
|
|
102
104
|
|
|
103
|
-
###
|
|
104
|
-
|
|
105
|
-
1. You need a deployment script in `scripts/deploy<CONTRACT>.ts` - [example](/example/scripts/deployCounter.ts)
|
|
106
|
-
2. Run interactive: `npx blueprint run` or `yarn blueprint run`
|
|
107
|
-
3. Non-interactive: `npx/yarn blueprint run deploy<CONTRACT> --<NETWORK> --<DEPLOY_METHOD>`
|
|
108
|
-
* Example: `yarn blueprint run deployCounter --mainnet --tonconnect`
|
|
109
|
-
|
|
110
|
-
### Custom scripts
|
|
105
|
+
### Running scripts
|
|
111
106
|
|
|
112
107
|
1. Custom scripts should be located in `scripts` folder
|
|
113
108
|
2. Script file must have exported function `run`
|
|
114
109
|
```ts
|
|
115
|
-
export async function run(provider: NetworkProvider) {
|
|
110
|
+
export async function run(provider: NetworkProvider, args: string[]) {
|
|
116
111
|
//
|
|
117
112
|
}
|
|
118
113
|
```
|
|
119
|
-
3. Script can be run using `npx/yarn blueprint run <SCRIPT
|
|
114
|
+
3. Script can be run using `npx/yarn blueprint run <SCRIPT> [arg1, arg2, ...]` command
|
|
115
|
+
|
|
116
|
+
#### Deploying contracts
|
|
117
|
+
|
|
118
|
+
1. You need a deployment script in `scripts/deploy<CONTRACT>.ts` - [example](/example/scripts/deployCounter.ts)
|
|
119
|
+
2. Run interactive: `npx blueprint run` or `yarn blueprint run`
|
|
120
|
+
3. Non-interactive: `npx/yarn blueprint run deploy<CONTRACT> --<NETWORK> --<DEPLOY_METHOD>`
|
|
121
|
+
* Example: `yarn blueprint run deployCounter --mainnet --tonconnect`
|
|
122
|
+
|
|
123
|
+
#### Using Mnemonic Provider
|
|
124
|
+
|
|
125
|
+
To run scripts using a wallet by mnemonic authentication, you need to configure your environment and use the `Mnemonic` option when running scripts.
|
|
126
|
+
|
|
127
|
+
Start by adding the following environment variables to your `.env` file:
|
|
128
|
+
* **`WALLET_MNEMONIC`**: Your wallet's mnemonic phrase (space-separated words).
|
|
129
|
+
* **`WALLET_VERSION`**: The wallet contract version to use. Supported versions: `v1r1`, `v1r2`, `v1r3`, `v2r1`, `v2r2`, `v3r1`, `v3r2`, `v4`, `v5r1`.
|
|
130
|
+
|
|
131
|
+
**Optional variables:**
|
|
132
|
+
* **`WALLET_ID`**: The wallet ID (can be used with versions below `v5r1`).
|
|
133
|
+
* **`SUBWALLET_NUMBER`**: The subwallet number used to build the wallet ID (can be used with `v5r1` wallets).
|
|
134
|
+
|
|
135
|
+
Once your environment is set up, you can use the mnemonic wallet for deployment with the appropriate configuration.
|
|
136
|
+
|
|
137
|
+
#### Deploying contracts
|
|
138
|
+
|
|
139
|
+
1. You need a deployment script in `scripts/deploy<CONTRACT>.ts` - [example](/example/scripts/deployCounter.ts)
|
|
140
|
+
2. Run interactive: `npx blueprint run` or `yarn blueprint run`
|
|
141
|
+
3. Non-interactive: `npx/yarn blueprint run deploy<CONTRACT> --<NETWORK> --<DEPLOY_METHOD>`
|
|
142
|
+
* Example: `yarn blueprint run deployCounter --mainnet --tonconnect`
|
|
143
|
+
|
|
144
|
+
#### Using Mnemonic Provider
|
|
145
|
+
|
|
146
|
+
To run scripts using a wallet by mnemonic authentication, you need to configure your environment and use the `Mnemonic` option when running scripts.
|
|
147
|
+
|
|
148
|
+
Start by adding the following environment variables to your `.env` file:
|
|
149
|
+
* **`WALLET_MNEMONIC`**: Your wallet's mnemonic phrase (space-separated words).
|
|
150
|
+
* **`WALLET_VERSION`**: The wallet contract version to use. Supported versions: `v1r1`, `v1r2`, `v1r3`, `v2r1`, `v2r2`, `v3r1`, `v3r2`, `v4`, `v5r1`.
|
|
151
|
+
|
|
152
|
+
**Optional variables:**
|
|
153
|
+
* **`WALLET_ID`**: The wallet ID (required for versions below `v5r1`).
|
|
154
|
+
* **`SUBWALLET_NUMBER`**: The subwallet number used to build the wallet ID (required for `v5r1` wallets).
|
|
155
|
+
|
|
156
|
+
Once your environment is set up, you can use the mnemonic wallet for deployment with the appropriate configuration.
|
|
120
157
|
|
|
121
158
|
### Updating FunC version
|
|
122
159
|
|
|
@@ -140,6 +177,12 @@ Before developing, make sure that your current working directory is located in t
|
|
|
140
177
|
2. Non-interactive: `npx/yarn blueprint create <CONTRACT> --type <TYPE>` (type can be `func-empty`, `tolk-empty`, `tact-empty`, `func-counter`, `tolk-counter`, `tact-counter`)
|
|
141
178
|
* Example: `yarn blueprint create MyNewContract --type func-empty`
|
|
142
179
|
|
|
180
|
+
### Renaming contracts
|
|
181
|
+
|
|
182
|
+
1. Run interactive: `npx blueprint rename` or `yarn blueprint rename`
|
|
183
|
+
2. Non-interactive: `npx/yarn blueprint rename <OLD_NAME> <NEW_NAME>`
|
|
184
|
+
* Example: `yarn blueprint rename OldContract NewContract `
|
|
185
|
+
|
|
143
186
|
### Writing contract code
|
|
144
187
|
|
|
145
188
|
#### FunC
|
|
@@ -162,6 +205,37 @@ Before developing, make sure that your current working directory is located in t
|
|
|
162
205
|
|
|
163
206
|
> Learn more about writing tests from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#writing-tests).
|
|
164
207
|
|
|
208
|
+
### Publishing Wrapper Code
|
|
209
|
+
|
|
210
|
+
1. **Authenticate with npm**
|
|
211
|
+
Run `npm adduser` to log in to your npm account.
|
|
212
|
+
> 📝 **Note:** You can learn more about advanced authentication in the official npm docs:
|
|
213
|
+
> [npmrc – Auth-Related Configuration](https://docs.npmjs.com/cli/v9/configuring-npm/npmrc#auth-related-configuration)
|
|
214
|
+
|
|
215
|
+
2. **Update the package version**
|
|
216
|
+
Edit the `version` field in your `package.json` to reflect the new release (e.g., `1.0.1` → `1.0.2`).
|
|
217
|
+
|
|
218
|
+
3. **Build the package**
|
|
219
|
+
Run the following command to generate and bundle your contract wrappers:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
blueprint pack
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
4. **Publish to npm**
|
|
226
|
+
Push the package to the public npm registry:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm publish --access public
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Benchmark contracts
|
|
233
|
+
|
|
234
|
+
1. Run `npx blueprint snapshot [--label=<comment>|-l <comment>]` to collect metrics of contracts and save snapshot
|
|
235
|
+
2. Run `npx blueprint test --gas-report|-g` to compare current metrics and saved snapshot
|
|
236
|
+
|
|
237
|
+
> Learn more about collect metric from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#benchmark-contracts).
|
|
238
|
+
|
|
165
239
|
## Configuration
|
|
166
240
|
|
|
167
241
|
A config may be created in order to control some of blueprint's features. If a config is needed, create a `blueprint.config.ts` file in the root of your project with something like this:
|
|
@@ -224,6 +298,18 @@ npx blueprint verify --custom https://toncenter.com/api/v2/jsonRPC --custom-vers
|
|
|
224
298
|
```
|
|
225
299
|
(or similarly using the config), however custom type MUST be specified as either `mainnet` or `testnet` when verifying.
|
|
226
300
|
|
|
301
|
+
### Request timeout
|
|
302
|
+
|
|
303
|
+
You can optionally configure how long HTTP requests should wait before timing out using the `requestTimout` field. This can be especially useful when working with unstable or slow networks.
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { Config } from '@ton/blueprint';
|
|
307
|
+
|
|
308
|
+
export const config: Config = {
|
|
309
|
+
requestTimeout: 10000, // 10 seconds
|
|
310
|
+
};
|
|
311
|
+
```
|
|
312
|
+
|
|
227
313
|
## Contributors
|
|
228
314
|
|
|
229
315
|
Special thanks to [@qdevstudio](https://t.me/qdevstudio) for their logo for blueprint.
|
package/dist/cli/Runner.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { UIProvider } from '../ui/UIProvider';
|
|
|
3
3
|
import { Config } from '../config/Config';
|
|
4
4
|
export declare const argSpec: {};
|
|
5
5
|
export type Args = arg.Result<typeof argSpec>;
|
|
6
|
+
export declare function extractPosArg(args: Args, position: number): string | undefined;
|
|
7
|
+
export declare function extractSecondArg(args: Args): string | undefined;
|
|
6
8
|
export declare function extractFirstArg(args: Args): string | undefined;
|
|
7
9
|
export type RunnerContext = {
|
|
8
10
|
config?: Config;
|
package/dist/cli/Runner.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.argSpec = void 0;
|
|
4
|
+
exports.extractPosArg = extractPosArg;
|
|
5
|
+
exports.extractSecondArg = extractSecondArg;
|
|
4
6
|
exports.extractFirstArg = extractFirstArg;
|
|
5
7
|
exports.argSpec = {};
|
|
8
|
+
function extractPosArg(args, position) {
|
|
9
|
+
return args._.length > position && args._[position].trim().length > 0 ? args._[position].trim() : undefined;
|
|
10
|
+
}
|
|
11
|
+
function extractSecondArg(args) {
|
|
12
|
+
return extractPosArg(args, 2);
|
|
13
|
+
}
|
|
6
14
|
function extractFirstArg(args) {
|
|
7
|
-
return args
|
|
15
|
+
return extractPosArg(args, 1);
|
|
8
16
|
}
|
package/dist/cli/build.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Args, Runner } from './Runner';
|
|
2
1
|
import { UIProvider } from '../ui/UIProvider';
|
|
3
|
-
|
|
2
|
+
import { Runner } from './Runner';
|
|
4
3
|
export declare function selectContract(ui: UIProvider, hint?: string): Promise<string>;
|
|
5
4
|
export declare function selectContract(ui: UIProvider, hint?: string, withAllOption?: boolean): Promise<string | string[]>;
|
|
6
5
|
export declare const build: Runner;
|
package/dist/cli/build.js
CHANGED
|
@@ -4,15 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.build = void 0;
|
|
7
|
-
exports.extractBuildFile = extractBuildFile;
|
|
8
7
|
exports.selectContract = selectContract;
|
|
9
|
-
const utils_1 = require("../utils");
|
|
10
8
|
const arg_1 = __importDefault(require("arg"));
|
|
9
|
+
const utils_1 = require("../utils");
|
|
11
10
|
const build_1 = require("../build");
|
|
12
11
|
const constants_1 = require("./constants");
|
|
13
|
-
|
|
14
|
-
return args._.length > 1 && args._[1].length > 0 ? args._[1] : undefined;
|
|
15
|
-
}
|
|
12
|
+
const Runner_1 = require("./Runner");
|
|
16
13
|
async function selectContract(ui, hint, withAllOption = false) {
|
|
17
14
|
const contracts = await (0, utils_1.findContracts)();
|
|
18
15
|
const options = contracts.map((contract) => ({ name: contract, value: contract }));
|
|
@@ -47,7 +44,7 @@ const build = async (args, ui) => {
|
|
|
47
44
|
await (0, build_1.buildAll)(ui);
|
|
48
45
|
}
|
|
49
46
|
else {
|
|
50
|
-
const selected = await selectContract(ui,
|
|
47
|
+
const selected = await selectContract(ui, (0, Runner_1.extractFirstArg)(args), true);
|
|
51
48
|
if (typeof selected === 'string') {
|
|
52
49
|
await (0, build_1.buildOne)(selected, ui);
|
|
53
50
|
}
|
package/dist/cli/cli.js
CHANGED
|
@@ -41,6 +41,7 @@ const dotenv = __importStar(require("dotenv"));
|
|
|
41
41
|
dotenv.config();
|
|
42
42
|
const arg_1 = __importDefault(require("arg"));
|
|
43
43
|
const chalk_1 = __importDefault(require("chalk"));
|
|
44
|
+
const snapshot_1 = require("./snapshot");
|
|
44
45
|
const create_1 = require("./create");
|
|
45
46
|
const run_1 = require("./run");
|
|
46
47
|
const build_1 = require("./build");
|
|
@@ -49,9 +50,11 @@ const test_1 = require("./test");
|
|
|
49
50
|
const verify_1 = require("./verify");
|
|
50
51
|
const convert_1 = require("./convert");
|
|
51
52
|
const help_1 = require("./help");
|
|
53
|
+
const pack_1 = require("./pack");
|
|
52
54
|
const InquirerUIProvider_1 = require("../ui/InquirerUIProvider");
|
|
53
55
|
const Runner_1 = require("./Runner");
|
|
54
56
|
const utils_1 = require("../config/utils");
|
|
57
|
+
const rename_1 = require("./rename");
|
|
55
58
|
const runners = {
|
|
56
59
|
create: create_1.create,
|
|
57
60
|
run: run_1.run,
|
|
@@ -61,6 +64,9 @@ const runners = {
|
|
|
61
64
|
help: help_1.help,
|
|
62
65
|
verify: verify_1.verify,
|
|
63
66
|
convert: convert_1.convert,
|
|
67
|
+
rename: rename_1.rename,
|
|
68
|
+
pack: pack_1.pack,
|
|
69
|
+
snapshot: snapshot_1.snapshot,
|
|
64
70
|
};
|
|
65
71
|
async function main() {
|
|
66
72
|
require('ts-node/register');
|
|
@@ -95,7 +101,8 @@ async function main() {
|
|
|
95
101
|
const command = args._[0];
|
|
96
102
|
const runner = effectiveRunners[command];
|
|
97
103
|
if (!runner) {
|
|
98
|
-
console.log(chalk_1.default.redBright(`Error: command ${command} not found.`) +
|
|
104
|
+
console.log(chalk_1.default.redBright(`Error: command ${command} not found.`) +
|
|
105
|
+
`\nRunning ${chalk_1.default.cyanBright('blueprint help')}...`);
|
|
99
106
|
const helpMessage = (0, help_1.buildHelpMessage)();
|
|
100
107
|
console.log(helpMessage);
|
|
101
108
|
process.exit(1);
|
package/dist/cli/constants.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const templateTypes: {
|
|
|
4
4
|
}[];
|
|
5
5
|
export declare const helpArgs: {
|
|
6
6
|
'--help': BooleanConstructor;
|
|
7
|
+
'-h': string;
|
|
7
8
|
};
|
|
8
9
|
export declare const helpMessages: {
|
|
9
10
|
help: string;
|
|
@@ -14,4 +15,7 @@ export declare const helpMessages: {
|
|
|
14
15
|
test: string;
|
|
15
16
|
verify: string;
|
|
16
17
|
convert: string;
|
|
18
|
+
rename: string;
|
|
19
|
+
pack: string;
|
|
20
|
+
snapshot: string;
|
|
17
21
|
};
|
package/dist/cli/constants.js
CHANGED
|
@@ -31,8 +31,20 @@ exports.templateTypes = [
|
|
|
31
31
|
value: 'tact-counter',
|
|
32
32
|
},
|
|
33
33
|
];
|
|
34
|
-
exports.helpArgs = { '--help': Boolean };
|
|
35
|
-
const availableCommands = [
|
|
34
|
+
exports.helpArgs = { '--help': Boolean, '-h': '--help' };
|
|
35
|
+
const availableCommands = [
|
|
36
|
+
'create',
|
|
37
|
+
'run',
|
|
38
|
+
'build',
|
|
39
|
+
'set',
|
|
40
|
+
'help',
|
|
41
|
+
'test',
|
|
42
|
+
'verify',
|
|
43
|
+
'convert',
|
|
44
|
+
'rename',
|
|
45
|
+
'pack',
|
|
46
|
+
'snapshot',
|
|
47
|
+
];
|
|
36
48
|
exports.helpMessages = {
|
|
37
49
|
help: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('help')} [${chalk_1.default.yellow('command')}]
|
|
38
50
|
|
|
@@ -54,7 +66,7 @@ ${chalk_1.default.cyan('--type')} <type> - specifies the template type to use wh
|
|
|
54
66
|
|
|
55
67
|
${chalk_1.default.bold('List of available types:')}
|
|
56
68
|
${exports.templateTypes.map((t) => `${chalk_1.default.cyan(t.value)} - ${t.name}`).join('\n')}`,
|
|
57
|
-
run: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('run')} ${chalk_1.default.yellow('[script name]')} ${chalk_1.default.gray('[flags]')}
|
|
69
|
+
run: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('run')} ${chalk_1.default.yellow('[script name]')} ${chalk_1.default.gray('[flags]')} ${chalk_1.default.gray('[...args]')}
|
|
58
70
|
|
|
59
71
|
Runs a script from the scripts directory.
|
|
60
72
|
|
|
@@ -67,7 +79,12 @@ ${chalk_1.default.cyan('--custom-version')} - API version (v2, v4)
|
|
|
67
79
|
${chalk_1.default.cyan('--custom-key')} - API key (v2 only)
|
|
68
80
|
${chalk_1.default.cyan('--custom-type')} - network type (custom, mainnet, testnet)
|
|
69
81
|
${chalk_1.default.cyan('--tonconnect')}, ${chalk_1.default.cyan('--deeplink')}, ${chalk_1.default.cyan('--mnemonic')} - deployer options
|
|
70
|
-
${chalk_1.default.cyan('--tonscan')}, ${chalk_1.default.cyan('--tonviewer')}, ${chalk_1.default.cyan('--toncx')}, ${chalk_1.default.cyan('--dton')} - explorer (default: tonviewer)
|
|
82
|
+
${chalk_1.default.cyan('--tonscan')}, ${chalk_1.default.cyan('--tonviewer')}, ${chalk_1.default.cyan('--toncx')}, ${chalk_1.default.cyan('--dton')} - explorer (default: tonviewer)
|
|
83
|
+
${chalk_1.default.gray('[...args]')} (array of strings, optional) - Arguments passed directly to the script.
|
|
84
|
+
|
|
85
|
+
${chalk_1.default.bold('Examples:')}
|
|
86
|
+
blueprint run ${chalk_1.default.yellow('deployCounter')} ${chalk_1.default.cyan('--testnet')} ${chalk_1.default.cyan('--tonconnect')}
|
|
87
|
+
blueprint run ${chalk_1.default.yellow('incrementCounter')} ${chalk_1.default.cyan('--testnet')} ${chalk_1.default.cyan('--tonconnect')} ${chalk_1.default.gray('0.05 1')}`,
|
|
71
88
|
build: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('build')} ${chalk_1.default.yellow('[contract name]')} ${chalk_1.default.gray('[flags]')}
|
|
72
89
|
|
|
73
90
|
Builds the specified contract according to the respective .compile.ts file. For Tact contracts, all generated files will be placed in the ${chalk_1.default.cyan('build/<contract name>')} folder.
|
|
@@ -78,9 +95,15 @@ ${chalk_1.default.cyan('--all')} - builds all available contracts.`,
|
|
|
78
95
|
|
|
79
96
|
${chalk_1.default.bold('Available keys:')}
|
|
80
97
|
- ${chalk_1.default.cyan('func')} - overrides @ton-community/func-js-bin version.`,
|
|
81
|
-
test: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('test')} [...args]
|
|
98
|
+
test: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('test')} ${chalk_1.default.yellow('[--gas-report|-g ...args]')}
|
|
99
|
+
Runs ${chalk_1.default.green('npm test [...args]')}, which by default executes ${chalk_1.default.green('jest')}
|
|
100
|
+
|
|
101
|
+
${chalk_1.default.bold('Options:')}
|
|
102
|
+
${chalk_1.default.cyan('--gas-report')}, ${chalk_1.default.cyan('-g')} - Run tests and compare with the last snapshot's metrics
|
|
82
103
|
|
|
83
|
-
|
|
104
|
+
${chalk_1.default.bold('SEE ALSO')}
|
|
105
|
+
${chalk_1.default.cyan('blueprint snapshot')}
|
|
106
|
+
`,
|
|
84
107
|
verify: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('verify')} ${chalk_1.default.yellow('[contract name]')} ${chalk_1.default.gray('[flags]')}
|
|
85
108
|
|
|
86
109
|
Verifies a deployed contract on ${chalk_1.default.underline('https://verifier.ton.org')}.
|
|
@@ -94,4 +117,19 @@ ${chalk_1.default.cyan('--custom-type')} - network type (mainnet, testnet)`,
|
|
|
94
117
|
convert: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('convert')} ${chalk_1.default.yellow('[path to build script]')}
|
|
95
118
|
|
|
96
119
|
Attempts to convert a legacy bash build script to a Blueprint compile wrapper.`,
|
|
120
|
+
rename: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('rename')} ${chalk_1.default.yellow('[old contract name (PascalCase)]')} ${chalk_1.default.yellow('[new contract name (PascalCase)]')}
|
|
121
|
+
|
|
122
|
+
Renames contract by exact matching in wrappers, scripts, tests and contracts folders.`,
|
|
123
|
+
pack: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('pack')}
|
|
124
|
+
|
|
125
|
+
Builds and prepares a publish-ready package of contract wrappers.
|
|
126
|
+
|
|
127
|
+
${chalk_1.default.bold('Flags:')}
|
|
128
|
+
${chalk_1.default.cyan('--no-warn')}, ${chalk_1.default.cyan('-n')} - ignore warnings about modifying tsconfig.json, package.json, and removing the dist directory.`,
|
|
129
|
+
snapshot: `${chalk_1.default.bold('Usage:')} blueprint ${chalk_1.default.cyan('snapshot')} ${chalk_1.default.yellow('[--label=<comment>|-l=<comment>]')}
|
|
130
|
+
|
|
131
|
+
Run with gas usage and cells' sizes collected and write a new snapshot
|
|
132
|
+
|
|
133
|
+
${chalk_1.default.bold('SEE ALSO')}
|
|
134
|
+
${chalk_1.default.cyan('blueprint test --gas-report')}`,
|
|
97
135
|
};
|
package/dist/cli/create.js
CHANGED
|
@@ -14,10 +14,6 @@ const template_1 = require("../template");
|
|
|
14
14
|
const utils_2 = require("../utils");
|
|
15
15
|
const build_1 = require("../build");
|
|
16
16
|
const constants_1 = require("./constants");
|
|
17
|
-
function toSnakeCase(v) {
|
|
18
|
-
const r = v.replace(/[A-Z]/g, (sub) => '_' + sub.toLowerCase());
|
|
19
|
-
return r[0] === '_' ? r.substring(1) : r;
|
|
20
|
-
}
|
|
21
17
|
async function createFile(templatePath, realPath, replaces) {
|
|
22
18
|
const template = (await (0, promises_1.readFile)(templatePath)).toString('utf-8');
|
|
23
19
|
const lines = template.split('\n');
|
|
@@ -84,21 +80,14 @@ const create = async (args, ui) => {
|
|
|
84
80
|
return;
|
|
85
81
|
}
|
|
86
82
|
const name = (0, Runner_1.extractFirstArg)(localArgs) ?? (await ui.input('Contract name (PascalCase)'));
|
|
87
|
-
|
|
88
|
-
throw new Error(`Cannot create a contract with an empty name`);
|
|
89
|
-
if (name.toLowerCase() === 'contract') {
|
|
90
|
-
throw new Error(`Cannot create a contract with the reserved name 'contract'. Please choose a different name.`);
|
|
91
|
-
}
|
|
92
|
-
if (!(0, utils_2.isPascalCase)(name)) {
|
|
93
|
-
throw new Error(`Contract name '${name}' is not in PascalCase. Please try ${(0, utils_2.toPascalCase)(name)}.`);
|
|
94
|
-
}
|
|
83
|
+
(0, utils_2.assertValidContractName)(name);
|
|
95
84
|
const which = (await (0, utils_2.selectOption)(constants_1.templateTypes, {
|
|
96
85
|
ui,
|
|
97
86
|
msg: 'What type of contract do you want to create?',
|
|
98
87
|
hint: localArgs['--type'],
|
|
99
88
|
})).value;
|
|
100
89
|
const [lang, template] = which.split('-');
|
|
101
|
-
const snakeName = toSnakeCase(name);
|
|
90
|
+
const snakeName = (0, utils_2.toSnakeCase)(name);
|
|
102
91
|
const contractPath = path_1.default.join('contracts', snakeName + '.' + getFileExtension(lang));
|
|
103
92
|
const replaces = {
|
|
104
93
|
name,
|
package/dist/cli/help.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.help = exports.additionalHelpMessages = void 0;
|
|
4
4
|
exports.buildHelpMessage = buildHelpMessage;
|
|
5
|
+
const Runner_1 = require("./Runner");
|
|
5
6
|
const constants_1 = require("./constants");
|
|
6
7
|
exports.additionalHelpMessages = {};
|
|
7
8
|
function buildHelpMessage(cmd = '') {
|
|
@@ -15,7 +16,7 @@ function buildHelpMessage(cmd = '') {
|
|
|
15
16
|
return cmd in effectiveHelpMessages ? effectiveHelpMessages[cmd] : effectiveHelpMessages['help'];
|
|
16
17
|
}
|
|
17
18
|
const help = async (args, ui) => {
|
|
18
|
-
const cmd =
|
|
19
|
+
const cmd = (0, Runner_1.extractFirstArg)(args)?.toLowerCase();
|
|
19
20
|
const helpMessage = buildHelpMessage(cmd);
|
|
20
21
|
ui.write(helpMessage);
|
|
21
22
|
};
|
package/dist/cli/pack.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.pack = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const arg_1 = __importDefault(require("arg"));
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const constants_1 = require("./constants");
|
|
12
|
+
const build_1 = require("../build");
|
|
13
|
+
const paths_1 = require("../paths");
|
|
14
|
+
const utils_1 = require("../utils");
|
|
15
|
+
const compile_1 = require("../compile/compile");
|
|
16
|
+
const CompilerConfig_1 = require("../compile/CompilerConfig");
|
|
17
|
+
const compile_tact_1 = require("../compile/tact/compile.tact");
|
|
18
|
+
async function correctTsConfig() {
|
|
19
|
+
if (!(0, fs_1.existsSync)(paths_1.TYPESCRIPT_CONFIG)) {
|
|
20
|
+
throw new Error('TypeScript config does not exist. Ensure the command runs in the correct environment.');
|
|
21
|
+
}
|
|
22
|
+
const tsConfig = JSON.parse(await fs_1.promises.readFile(paths_1.TYPESCRIPT_CONFIG, 'utf-8'));
|
|
23
|
+
const newConfig = {
|
|
24
|
+
...tsConfig,
|
|
25
|
+
compilerOptions: {
|
|
26
|
+
...tsConfig.compilerOptions,
|
|
27
|
+
outDir: 'dist',
|
|
28
|
+
declaration: true,
|
|
29
|
+
esModuleInterop: true,
|
|
30
|
+
},
|
|
31
|
+
include: (0, utils_1.distinct)([...(tsConfig.include ?? []), 'package.ts']),
|
|
32
|
+
};
|
|
33
|
+
await fs_1.promises.writeFile(paths_1.TYPESCRIPT_CONFIG, JSON.stringify(newConfig, null, 2), 'utf8');
|
|
34
|
+
}
|
|
35
|
+
async function getContractWrapperPath(contract) {
|
|
36
|
+
const config = await (0, compile_1.getCompilerConfigForContract)(contract);
|
|
37
|
+
if ((0, CompilerConfig_1.isCompilableConfig)(config)) {
|
|
38
|
+
return `./wrappers/${contract}`;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const contractConfig = (0, compile_tact_1.extractContractConfig)(config, contract);
|
|
42
|
+
return `./${contractConfig.output}/${contract}_${contract}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function generatePackageEntryPoint() {
|
|
46
|
+
const contracts = await (0, utils_1.findContracts)();
|
|
47
|
+
let entryPoint = 'import { Cell } from "@ton/core"\n';
|
|
48
|
+
for (const contract of contracts) {
|
|
49
|
+
const wrapperPath = await getContractWrapperPath(contract);
|
|
50
|
+
entryPoint += `import * as ${contract} from '${wrapperPath}';\n`;
|
|
51
|
+
entryPoint += `export { ${contract} };\n`;
|
|
52
|
+
const buildArtifactPath = path_1.default.join(paths_1.BUILD_DIR, `${contract}.compiled.json`);
|
|
53
|
+
const buildArtifact = JSON.parse(await fs_1.promises.readFile(buildArtifactPath, 'utf8'));
|
|
54
|
+
entryPoint += `export const ${contract}Code = Cell.fromHex("${buildArtifact.hex}");\n`;
|
|
55
|
+
}
|
|
56
|
+
await fs_1.promises.writeFile(paths_1.PACKAGE_ENTRY_POINT, entryPoint, 'utf8');
|
|
57
|
+
}
|
|
58
|
+
async function correctPackageJson() {
|
|
59
|
+
const packageJson = JSON.parse(await fs_1.promises.readFile(paths_1.PACKAGE_JSON, 'utf8'));
|
|
60
|
+
const newPackageJson = {
|
|
61
|
+
...packageJson,
|
|
62
|
+
main: 'dist/package.js',
|
|
63
|
+
files: ['dist/**/*'],
|
|
64
|
+
};
|
|
65
|
+
await fs_1.promises.writeFile(paths_1.PACKAGE_JSON, JSON.stringify(newPackageJson, null, 2));
|
|
66
|
+
}
|
|
67
|
+
const pack = async (args, ui, context) => {
|
|
68
|
+
const localArgs = (0, arg_1.default)({
|
|
69
|
+
'--no-warn': Boolean,
|
|
70
|
+
'-n': '--no-warn',
|
|
71
|
+
...constants_1.helpArgs,
|
|
72
|
+
});
|
|
73
|
+
if (localArgs['--help']) {
|
|
74
|
+
ui.write(constants_1.helpMessages['pack']);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!localArgs['--no-warn']) {
|
|
78
|
+
ui.write('🚨 WARNING: This command may modify tsconfig.json, package.json, and remove the dist directory. Make sure these files are committed to your repository. If you wish to ignore this warning, use the -n or --no-warn flag.');
|
|
79
|
+
const answer = await ui.input('Are you sure you want to continue? (y/N)');
|
|
80
|
+
if (answer.toLowerCase() !== 'y') {
|
|
81
|
+
ui.write('Aborting...');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
ui.write('🔨 Building contracts... Please wait...');
|
|
86
|
+
await (0, build_1.buildAll)(ui);
|
|
87
|
+
ui.write('📦 Generating package entry point...');
|
|
88
|
+
await generatePackageEntryPoint();
|
|
89
|
+
ui.write('🛠️ Updating tsconfig.json...');
|
|
90
|
+
await correctTsConfig();
|
|
91
|
+
ui.write('🏗️ Building package...');
|
|
92
|
+
await fs_1.promises.rm(path_1.default.join(process.cwd(), 'dist'), { recursive: true, force: true });
|
|
93
|
+
(0, child_process_1.execSync)(`tsc`, { stdio: 'inherit' });
|
|
94
|
+
ui.write('📝 Updating package.json...');
|
|
95
|
+
await correctPackageJson();
|
|
96
|
+
ui.write('🎉 Package is ready and packed successfully! You can now publish it 🚀');
|
|
97
|
+
};
|
|
98
|
+
exports.pack = pack;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.rename = void 0;
|
|
7
|
+
exports.renameExactIfRequired = renameExactIfRequired;
|
|
8
|
+
const arg_1 = __importDefault(require("arg"));
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const paths_1 = require("../paths");
|
|
12
|
+
const Runner_1 = require("./Runner");
|
|
13
|
+
const utils_1 = require("../utils");
|
|
14
|
+
const constants_1 = require("./constants");
|
|
15
|
+
const build_1 = require("./build");
|
|
16
|
+
function renameExactIfRequired(str, replaces) {
|
|
17
|
+
let renamedString = str;
|
|
18
|
+
let isRenamed = false;
|
|
19
|
+
for (const [oldValue, newValue] of Object.entries(replaces)) {
|
|
20
|
+
const regex = new RegExp(`\\b${oldValue}\\b`, 'g');
|
|
21
|
+
if (regex.test(renamedString)) {
|
|
22
|
+
isRenamed = true;
|
|
23
|
+
renamedString = renamedString.replace(regex, newValue);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { isRenamed, newValue: renamedString };
|
|
27
|
+
}
|
|
28
|
+
// Introduced this class to prevent fails in the middle of renaming, when the part is renamed and part is not
|
|
29
|
+
class RenameContext {
|
|
30
|
+
constructor(replaces) {
|
|
31
|
+
this.replaces = replaces;
|
|
32
|
+
this.effects = [];
|
|
33
|
+
}
|
|
34
|
+
async prepareRenameExactOccurrencesInDirectory(directory) {
|
|
35
|
+
if (!(0, fs_1.existsSync)(directory)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const dir = await fs_1.promises.readdir(directory, { recursive: true, withFileTypes: true });
|
|
39
|
+
await Promise.all(dir.map(async (dir) => {
|
|
40
|
+
if (!dir.isFile()) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const filePath = path_1.default.join(dir.path, dir.name);
|
|
44
|
+
await this.prepareRenameContentInFile(filePath);
|
|
45
|
+
const pathRenameResult = renameExactIfRequired(dir.name, this.replaces);
|
|
46
|
+
if (pathRenameResult.isRenamed) {
|
|
47
|
+
this.effects.push(() => fs_1.promises.rename(path_1.default.join(dir.path, dir.name), path_1.default.join(dir.path, pathRenameResult.newValue)));
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
async prepareRenameContentInFile(filePath) {
|
|
52
|
+
const content = await fs_1.promises.readFile(filePath, 'utf8');
|
|
53
|
+
const { isRenamed, newValue } = renameExactIfRequired(content, this.replaces);
|
|
54
|
+
if (isRenamed) {
|
|
55
|
+
this.effects.push(() => fs_1.promises.writeFile(filePath, newValue, 'utf8'));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async applyEffects() {
|
|
59
|
+
for (const effect of this.effects) {
|
|
60
|
+
await effect();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const rename = async (args, ui, context) => {
|
|
65
|
+
const localArgs = (0, arg_1.default)(constants_1.helpArgs);
|
|
66
|
+
if (localArgs['--help']) {
|
|
67
|
+
ui.write(constants_1.helpMessages['rename']);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const oldName = await (0, build_1.selectContract)(ui, (0, Runner_1.extractFirstArg)(localArgs));
|
|
71
|
+
const newName = (0, Runner_1.extractSecondArg)(localArgs) ?? (await ui.input('New contract name (PascalCase)'));
|
|
72
|
+
(0, utils_1.assertValidContractName)(newName);
|
|
73
|
+
const contracts = await (0, utils_1.findContracts)();
|
|
74
|
+
if (contracts.includes(newName)) {
|
|
75
|
+
ui.write(`Contract with name ${newName} already exists.`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
const modifiers = [
|
|
79
|
+
(name) => name,
|
|
80
|
+
utils_1.toSnakeCase,
|
|
81
|
+
utils_1.toLowerCase,
|
|
82
|
+
(name) => `deploy${name}`,
|
|
83
|
+
(name) => `${name}_${name}`,
|
|
84
|
+
(name) => `increment${name}`,
|
|
85
|
+
(name) => `${(0, utils_1.toLowerCase)(name)}ConfigToCell`,
|
|
86
|
+
(name) => `${name}Config`,
|
|
87
|
+
];
|
|
88
|
+
const replaces = Object.fromEntries(modifiers.map((modifier) => [modifier(oldName), modifier(newName)]));
|
|
89
|
+
ui.setActionPrompt('Renaming in progress...');
|
|
90
|
+
const renameContext = new RenameContext(replaces);
|
|
91
|
+
for (const directory of [paths_1.SCRIPTS_DIR, paths_1.WRAPPERS_DIR, paths_1.CONTRACTS_DIR, paths_1.TESTS_DIR, paths_1.COMPILABLES_DIR]) {
|
|
92
|
+
await renameContext.prepareRenameExactOccurrencesInDirectory(directory);
|
|
93
|
+
}
|
|
94
|
+
if ((0, fs_1.existsSync)(paths_1.TACT_ROOT_CONFIG)) {
|
|
95
|
+
await renameContext.prepareRenameContentInFile(paths_1.TACT_ROOT_CONFIG);
|
|
96
|
+
}
|
|
97
|
+
await renameContext.applyEffects();
|
|
98
|
+
ui.clearActionPrompt();
|
|
99
|
+
ui.write('Contract successfully renamed!');
|
|
100
|
+
};
|
|
101
|
+
exports.rename = rename;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|