@ton/blueprint 0.12.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 CHANGED
@@ -5,6 +5,18 @@ 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-11-05
9
+
10
+ ### Added
11
+
12
+ - Added plugin support
13
+ - Added custom API v2 endpoints
14
+
15
+ ### Changed
16
+
17
+ - Improved docs
18
+ - Changed deployed contract explorer link to use tonviewer
19
+ - Moved `deployer` to the global `describe` context in default tests
8
20
 
9
21
  ## [0.12.1] - 2023-07-31
10
22
 
package/README.md CHANGED
@@ -30,7 +30,7 @@ npm create ton@latest
30
30
  ### Requirements
31
31
 
32
32
  * [Node.js](https://nodejs.org) with a recent version like v18, verify version with `node -v`
33
- * IDE with TypeScript and FunC support like [Visual Studio Code](https://code.visualstudio.com/) with the [FunC plugin](https://marketplace.visualstudio.com/items?itemName=tonwhales.func-vscode)
33
+ * IDE with TypeScript and FunC support like [Visual Studio Code](https://code.visualstudio.com/) with the [FunC plugin](https://marketplace.visualstudio.com/items?itemName=tonwhales.func-vscode) or [IntelliJ Idea](https://www.jetbrains.com/idea/) with the [TON Development plugin](https://plugins.jetbrains.com/plugin/18541-ton-development)
34
34
 
35
35
   
36
36
 
@@ -49,11 +49,11 @@ npm create ton@latest
49
49
  * `scripts/` - Deployment scripts to mainnet/testnet and other scripts interacting with live contracts
50
50
  * `build/` - Compilation artifacts created here after running a build command
51
51
 
52
- ### Build one of the contracts
52
+ ### Build contracts
53
53
 
54
54
  1. You need a compilation script in `wrappers/<CONTRACT>.compile.ts` - [example](/example/wrappers/Counter.compile.ts)
55
55
  2. Run interactive: &nbsp;&nbsp; `npx blueprint build` &nbsp; or &nbsp; `yarn blueprint build`
56
- 3. Non-interactive: &nbsp; `npx/yarn blueprint build <CONTRACT>`
56
+ 3. Non-interactive: &nbsp; `npx/yarn blueprint build <CONTRACT>` &nbsp; OR build all contracts &nbsp; `yarn blueprint build --all`
57
57
  * Example: `yarn blueprint build counter`
58
58
  4. Build results are generated in `build/<CONTRACT>.compiled.json`
59
59
 
@@ -62,6 +62,8 @@ npm create ton@latest
62
62
  1. Run in terminal: &nbsp; `npx blueprint test` &nbsp; or &nbsp; `yarn blueprint test`
63
63
  2. Alternative method: &nbsp; `npm test` &nbsp; or &nbsp; `yarn test`
64
64
 
65
+ > Learn more about writing tests from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#writing-tests).
66
+
65
67
  ### Deploy one of the contracts
66
68
 
67
69
  1. You need a deploy script in `scripts/deploy<CONTRACT>.ts` - [example](/example/scripts/deployCounter.ts)
@@ -93,6 +95,8 @@ Run in terminal: &nbsp; `npx blueprint help` &nbsp; or &nbsp; `yarn blueprint he
93
95
  1. Implement TypeScript tests in `tests/<CONTRACT>.spec.ts`
94
96
  2. Rely on the wrapper TypeScript class from `wrappers/<CONTRACT>.ts` to interact with the contract
95
97
 
98
+ > Learn more about writing tests from the Sandbox's documentation - [here](https://github.com/ton-org/sandbox#writing-tests).
99
+
96
100
  ### Compilation and deployment
97
101
 
98
102
  1. Implement a compilation script in `wrappers/<CONTRACT>.compile.ts`
@@ -0,0 +1,3 @@
1
+ import { UIProvider } from './ui/UIProvider';
2
+ export declare function buildOne(contract: string, ui?: UIProvider): Promise<void>;
3
+ export declare function buildAll(ui?: UIProvider): Promise<void>;
package/dist/build.js ADDED
@@ -0,0 +1,57 @@
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.buildAll = exports.buildOne = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const compile_1 = require("./compile/compile");
10
+ const paths_1 = require("./paths");
11
+ const utils_1 = require("./utils");
12
+ async function buildOne(contract, ui) {
13
+ ui?.write(`Build script running, compiling ${contract}`);
14
+ const buildArtifactPath = path_1.default.join(paths_1.BUILD_DIR, `${contract}.compiled.json`);
15
+ try {
16
+ await promises_1.default.unlink(buildArtifactPath);
17
+ }
18
+ catch (e) { }
19
+ ui?.setActionPrompt('⏳ Compiling...');
20
+ try {
21
+ const result = await (0, compile_1.doCompile)(contract);
22
+ if (result.lang === 'tact') {
23
+ for (const [k, v] of result.fs) {
24
+ await promises_1.default.mkdir(path_1.default.dirname(k), {
25
+ recursive: true,
26
+ });
27
+ await promises_1.default.writeFile(k, v);
28
+ }
29
+ }
30
+ const cell = result.code;
31
+ ui?.clearActionPrompt();
32
+ ui?.write('\n✅ Compiled successfully! Cell BOC hex result:\n\n');
33
+ ui?.write(cell.toBoc().toString('hex'));
34
+ await promises_1.default.mkdir(paths_1.BUILD_DIR, { recursive: true });
35
+ await promises_1.default.writeFile(buildArtifactPath, JSON.stringify({
36
+ hex: cell.toBoc().toString('hex'),
37
+ }));
38
+ ui?.write(`\n✅ Wrote compilation artifact to ${path_1.default.relative(process.cwd(), buildArtifactPath)}`);
39
+ }
40
+ catch (e) {
41
+ if (ui) {
42
+ ui?.clearActionPrompt();
43
+ ui?.write(e.toString());
44
+ process.exit(1);
45
+ }
46
+ else {
47
+ throw e;
48
+ }
49
+ }
50
+ }
51
+ exports.buildOne = buildOne;
52
+ async function buildAll(ui) {
53
+ for (const file of await (0, utils_1.findCompiles)()) {
54
+ await buildOne(file.name, ui);
55
+ }
56
+ }
57
+ exports.buildAll = buildAll;
@@ -0,0 +1,5 @@
1
+ import arg from 'arg';
2
+ import { UIProvider } from '../ui/UIProvider';
3
+ export declare const argSpec: {};
4
+ export type Args = arg.Result<typeof argSpec>;
5
+ export type Runner = (args: Args, ui: UIProvider) => Promise<void>;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.argSpec = void 0;
4
+ exports.argSpec = {};
@@ -1,4 +1,2 @@
1
- import { Runner } from './cli';
2
- import { UIProvider } from '../ui/UIProvider';
3
- export declare function buildOne(contract: string, ui: UIProvider): Promise<void>;
1
+ import { Runner } from './Runner';
4
2
  export declare const build: Runner;
package/dist/cli/build.js CHANGED
@@ -3,64 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.build = exports.buildOne = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const paths_1 = require("../paths");
6
+ exports.build = void 0;
9
7
  const utils_1 = require("../utils");
10
- const promises_1 = __importDefault(require("fs/promises"));
11
- const compile_1 = require("../compile/compile");
12
8
  const arg_1 = __importDefault(require("arg"));
13
- async function buildOne(contract, ui) {
14
- ui.write(`Build script running, compiling ${contract}\n`);
15
- const buildArtifactPath = path_1.default.join(paths_1.BUILD_DIR, `${contract}.compiled.json`);
16
- try {
17
- await promises_1.default.unlink(buildArtifactPath);
18
- }
19
- catch (e) { }
20
- ui.write('⏳ Compiling...\n');
21
- try {
22
- const result = await (0, compile_1.doCompile)(contract);
23
- if (result.lang === 'tact') {
24
- for (const [k, v] of result.fs) {
25
- await promises_1.default.mkdir(path_1.default.dirname(k), {
26
- recursive: true,
27
- });
28
- await promises_1.default.writeFile(k, v);
29
- }
30
- }
31
- const cell = result.code;
32
- ui.write('✅ Compiled successfully! Cell BOC hex result:\n\n');
33
- ui.write(cell.toBoc().toString('hex'));
34
- await promises_1.default.mkdir(paths_1.BUILD_DIR, { recursive: true });
35
- await promises_1.default.writeFile(buildArtifactPath, JSON.stringify({
36
- hex: cell.toBoc().toString('hex'),
37
- }));
38
- ui.write(`\n✅ Wrote compilation artifact to ${path_1.default.relative(process.cwd(), buildArtifactPath)}`);
39
- }
40
- catch (e) {
41
- ui.write(e.toString());
42
- process.exit(1);
43
- }
44
- }
45
- exports.buildOne = buildOne;
9
+ const build_1 = require("../build");
46
10
  const build = async (args, ui) => {
47
11
  require('ts-node/register');
48
12
  const localArgs = (0, arg_1.default)({
49
13
  '--all': Boolean,
50
14
  });
51
- const files = await (0, utils_1.findCompiles)();
52
15
  if (localArgs['--all']) {
53
- for (const file of files) {
54
- await buildOne(file.name, ui);
55
- }
16
+ await (0, build_1.buildAll)();
56
17
  }
57
18
  else {
58
- const sel = await (0, utils_1.selectFile)(files, {
19
+ const sel = await (0, utils_1.selectFile)(await (0, utils_1.findCompiles)(), {
59
20
  ui,
60
21
  hint: args._.length > 1 && args._[1].length > 0 ? args._[1] : undefined,
61
22
  import: false,
62
23
  });
63
- await buildOne(sel.name, ui);
24
+ await (0, build_1.buildOne)(sel.name, ui);
64
25
  }
65
26
  };
66
27
  exports.build = build;
package/dist/cli/cli.d.ts CHANGED
@@ -1,7 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import arg from 'arg';
3
- import { UIProvider } from '../ui/UIProvider';
4
- declare const argSpec: {};
5
- export type Args = arg.Result<typeof argSpec>;
6
- export type Runner = (args: Args, ui: UIProvider) => Promise<void>;
7
2
  export {};
package/dist/cli/cli.js CHANGED
@@ -37,7 +37,8 @@ const build_1 = require("./build");
37
37
  const test_1 = require("./test");
38
38
  const help_1 = require("./help");
39
39
  const InquirerUIProvider_1 = require("../ui/InquirerUIProvider");
40
- const argSpec = {};
40
+ const Runner_1 = require("./Runner");
41
+ const path_1 = __importDefault(require("path"));
41
42
  const runners = {
42
43
  create: create_1.create,
43
44
  run: run_1.run,
@@ -46,22 +47,63 @@ const runners = {
46
47
  help: help_1.help,
47
48
  };
48
49
  async function main() {
49
- const args = (0, arg_1.default)(argSpec, {
50
+ var _a;
51
+ require('ts-node/register');
52
+ const args = (0, arg_1.default)(Runner_1.argSpec, {
50
53
  permissive: true,
51
54
  });
52
55
  if (args._.length === 0) {
53
56
  showHelp();
54
57
  process.exit(0);
55
58
  }
56
- const runner = runners[args._[0]];
59
+ let effectiveRunners = {};
60
+ try {
61
+ const configModule = await (_a = path_1.default.join(process.cwd(), 'blueprint.config.ts'), Promise.resolve().then(() => __importStar(require(_a))));
62
+ try {
63
+ if ('config' in configModule && typeof configModule.config === 'object') {
64
+ const config = configModule.config;
65
+ for (const plugin of config.plugins) {
66
+ for (const runner of plugin.runners()) {
67
+ effectiveRunners[runner.name] = runner.runner;
68
+ help_1.additionalHelpMessages[runner.name] = runner.help;
69
+ }
70
+ }
71
+ }
72
+ }
73
+ catch (e) {
74
+ // if plugin.runners() throws
75
+ console.error('Could not load one or more plugins');
76
+ console.error(e);
77
+ }
78
+ }
79
+ catch (e) {
80
+ // no config
81
+ }
82
+ effectiveRunners = {
83
+ ...effectiveRunners,
84
+ ...runners,
85
+ };
86
+ const runner = effectiveRunners[args._[0]];
57
87
  if (!runner) {
58
88
  console.log(chalk_1.default.redBright(` Error: command not found.`) + ` Run 'blueprint help' to see available commands\n`);
59
89
  process.exit(1);
60
90
  }
61
91
  const ui = new InquirerUIProvider_1.InquirerUIProvider();
92
+ const waitingForCustomLink = args._.includes('--custom');
62
93
  await runner({
63
94
  ...args,
64
- _: args._.filter((a) => !(a.length > 1 && a[0] === '-')), // filter out the flags pushed by `permissive`
95
+ _: args._.filter((a, inx) => {
96
+ // filter out the flags
97
+ if (a.length > 1 && a[0] === '-')
98
+ return false;
99
+ // and endpoint urls
100
+ if (waitingForCustomLink) {
101
+ if (args._[inx - 1] === '--custom' && // url goes after --custom
102
+ a.startsWith('http'))
103
+ return false;
104
+ }
105
+ return true;
106
+ }),
65
107
  }, ui);
66
108
  ui.close();
67
109
  }
@@ -1,4 +1,4 @@
1
- import { Runner } from './cli';
1
+ import { Runner } from './Runner';
2
2
  export declare const templateTypes: {
3
3
  name: string;
4
4
  value: string;
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
9
9
  const template_1 = require("../template");
10
10
  const utils_1 = require("../utils");
11
11
  const arg_1 = __importDefault(require("arg"));
12
- const build_1 = require("./build");
12
+ const build_1 = require("../build");
13
13
  function toSnakeCase(v) {
14
14
  const r = v.replace(/[A-Z]/g, (sub) => '_' + sub.toLowerCase());
15
15
  return r[0] === '_' ? r.substring(1) : r;
@@ -1,2 +1,3 @@
1
- import { Runner } from './cli';
1
+ import { Runner } from './Runner';
2
+ export declare let additionalHelpMessages: Record<string, string>;
2
3
  export declare const help: Runner;
package/dist/cli/help.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.help = void 0;
3
+ exports.help = exports.additionalHelpMessages = void 0;
4
4
  const create_1 = require("./create");
5
5
  const helpMessages = {
6
6
  help: `Usage: blueprint help [command]
@@ -33,8 +33,9 @@ Script name is matched (ignoring case) to a file in the scripts directory. If no
33
33
 
34
34
  Flags:
35
35
  --mainnet, --testnet - specifies the network to use when running the script. If not specified on the command line, it will be asked interactively.
36
+ --custom [api-v2-endpoint] - indicates that a custom API should be used when running the script, and the API URL optionally.
36
37
  --tonconnect, --tonhub, --deeplink, --mnemonic - specifies the deployer to use when running the script. If not specified on the command line, it will be asked interactively.
37
- --tonscan, --tonapi, --toncx, --dton - specifies the network explorer to use when displaying links to the deployed contracts. Default: tonscan.`,
38
+ --tonscan, --tonviewer, --toncx, --dton - specifies the network explorer to use when displaying links to the deployed contracts. Default: tonscan.`,
38
39
  build: `Usage: blueprint build [contract name] [flags]
39
40
 
40
41
  Builds the specified contract according to the respective .compile.ts file. If the contract is written in TACT, all TACT-generated files (wrapper class, etc) will be placed in the build/<contract name> folder.
@@ -47,9 +48,17 @@ Flags:
47
48
 
48
49
  Just runs \`npm test\`, which by default runs \`jest\`.`,
49
50
  };
51
+ exports.additionalHelpMessages = {};
50
52
  const help = async (args, ui) => {
51
53
  const cmd = args._.length >= 2 ? args._[1].toLowerCase() : '';
52
- const helpMessage = cmd in helpMessages ? helpMessages[cmd] : helpMessages['help'];
54
+ const effectiveHelpMessages = {
55
+ ...exports.additionalHelpMessages,
56
+ ...helpMessages,
57
+ };
58
+ for (const k in exports.additionalHelpMessages) {
59
+ effectiveHelpMessages.help += '\n- ' + k;
60
+ }
61
+ const helpMessage = cmd in effectiveHelpMessages ? effectiveHelpMessages[cmd] : effectiveHelpMessages['help'];
53
62
  ui.write(helpMessage);
54
63
  };
55
64
  exports.help = help;
package/dist/cli/run.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { Runner } from './cli';
1
+ import { Runner } from './Runner';
2
2
  export declare const run: Runner;
@@ -1,2 +1,2 @@
1
- import { Runner } from './cli';
1
+ import { Runner } from './Runner';
2
2
  export declare const test: Runner;
@@ -0,0 +1,4 @@
1
+ import { Plugin } from './Plugin';
2
+ export interface Config {
3
+ plugins: Plugin[];
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import { Runner } from '../cli/Runner';
2
+ export interface PluginRunner {
3
+ name: string;
4
+ runner: Runner;
5
+ help: string;
6
+ }
7
+ export interface Plugin {
8
+ runners(): PluginRunner[];
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -4,3 +4,7 @@ export { createNetworkProvider } from './network/createNetworkProvider';
4
4
  export { compile } from './compile/compile';
5
5
  export { CompilerConfig } from './compile/CompilerConfig';
6
6
  export { UIProvider } from './ui/UIProvider';
7
+ export { Config } from './config/Config';
8
+ export { Args, Runner } from './cli/Runner';
9
+ export { PluginRunner, Plugin } from './config/Plugin';
10
+ export { buildOne, buildAll } from './build';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.compile = exports.createNetworkProvider = exports.sleep = exports.tonDeepLink = void 0;
3
+ exports.buildAll = exports.buildOne = exports.compile = exports.createNetworkProvider = exports.sleep = exports.tonDeepLink = void 0;
4
4
  var utils_1 = require("./utils");
5
5
  Object.defineProperty(exports, "tonDeepLink", { enumerable: true, get: function () { return utils_1.tonDeepLink; } });
6
6
  Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return utils_1.sleep; } });
@@ -8,3 +8,6 @@ var createNetworkProvider_1 = require("./network/createNetworkProvider");
8
8
  Object.defineProperty(exports, "createNetworkProvider", { enumerable: true, get: function () { return createNetworkProvider_1.createNetworkProvider; } });
9
9
  var compile_1 = require("./compile/compile");
10
10
  Object.defineProperty(exports, "compile", { enumerable: true, get: function () { return compile_1.compile; } });
11
+ var build_1 = require("./build");
12
+ Object.defineProperty(exports, "buildOne", { enumerable: true, get: function () { return build_1.buildOne; } });
13
+ Object.defineProperty(exports, "buildAll", { enumerable: true, get: function () { return build_1.buildAll; } });
@@ -1,10 +1,10 @@
1
- import { TonClient4 } from '@ton/ton';
1
+ import { TonClient, TonClient4 } from '@ton/ton';
2
2
  import { Address, Cell, Contract, ContractProvider, OpenedContract, Sender } from '@ton/core';
3
3
  import { UIProvider } from '../ui/UIProvider';
4
4
  export interface NetworkProvider {
5
- network(): 'mainnet' | 'testnet';
5
+ network(): 'mainnet' | 'testnet' | 'custom';
6
6
  sender(): Sender;
7
- api(): TonClient4;
7
+ api(): TonClient4 | TonClient;
8
8
  provider(address: Address, init?: {
9
9
  code?: Cell;
10
10
  data?: Cell;
@@ -32,12 +32,13 @@ const MnemonicProvider_1 = require("./send/MnemonicProvider");
32
32
  const argSpec = {
33
33
  '--mainnet': Boolean,
34
34
  '--testnet': Boolean,
35
+ '--custom': String,
35
36
  '--tonconnect': Boolean,
36
37
  '--deeplink': Boolean,
37
38
  '--tonhub': Boolean,
38
39
  '--mnemonic': Boolean,
39
40
  '--tonscan': Boolean,
40
- '--tonapi': Boolean,
41
+ '--tonviewer': Boolean,
41
42
  '--toncx': Boolean,
42
43
  '--dton': Boolean,
43
44
  };
@@ -52,7 +53,7 @@ class SendProviderSender {
52
53
  console.warn("Warning: blueprint's Sender does not support `bounce` flag, because it is ignored by all used Sender APIs");
53
54
  console.warn('To silence this warning, change your `bounce` flags passed to Senders to unset or undefined');
54
55
  }
55
- if (!(args.sendMode === undefined || args.sendMode == core_1.SendMode.PAY_GAS_SEPARATELY)) {
56
+ if (!(args.sendMode === undefined || args.sendMode === core_1.SendMode.PAY_GAS_SEPARATELY)) {
56
57
  throw new Error('Deployer sender does not support `sendMode` other than `PAY_GAS_SEPARATELY`');
57
58
  }
58
59
  await __classPrivateFieldGet(this, _SendProviderSender_provider, "f").sendTransaction(args.to, args.value, args.body ?? undefined, args.init ?? undefined);
@@ -116,10 +117,20 @@ class NetworkProviderImpl {
116
117
  return __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f");
117
118
  }
118
119
  provider(address, init) {
119
- return new WrappedContractProvider(address, __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").provider(address, init ? { code: init.code ?? new core_1.Cell(), data: init.data ?? new core_1.Cell() } : undefined), init);
120
+ if (__classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f") instanceof ton_1.TonClient4) {
121
+ return new WrappedContractProvider(address, __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").provider(address, init ? { code: init.code ?? new core_1.Cell(), data: init.data ?? new core_1.Cell() } : undefined), init);
122
+ }
123
+ else {
124
+ return new WrappedContractProvider(address, __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").provider(address, { code: init?.code ?? new core_1.Cell(), data: init?.data ?? new core_1.Cell() }), init);
125
+ }
120
126
  }
121
127
  async isContractDeployed(address) {
122
- return __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").isContractDeployed((await __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").getLastBlock()).last.seqno, address);
128
+ if (__classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f") instanceof ton_1.TonClient4) {
129
+ return __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").isContractDeployed((await __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").getLastBlock()).last.seqno, address);
130
+ }
131
+ else {
132
+ return (await __classPrivateFieldGet(this, _NetworkProviderImpl_tc, "f").getContractState(address)).state === 'active';
133
+ }
123
134
  }
124
135
  async waitForDeploy(address, attempts = 10, sleepDuration = 2000) {
125
136
  if (attempts <= 0) {
@@ -193,16 +204,24 @@ class NetworkProviderBuilder {
193
204
  let network = (0, utils_1.oneOrZeroOf)({
194
205
  mainnet: this.args['--mainnet'],
195
206
  testnet: this.args['--testnet'],
207
+ custom: this.args['--custom'] !== undefined,
196
208
  });
197
209
  if (!network) {
198
- network = await this.ui.choose('Which network do you want to use?', ['mainnet', 'testnet'], (c) => c);
210
+ network = await this.ui.choose('Which network do you want to use?', ['mainnet', 'testnet', 'custom'], (c) => c);
211
+ if (network === 'custom') {
212
+ const defaultCustomEndpoint = 'http://localhost:8081/';
213
+ this.args['--custom'] = (await this.ui.input(`Provide a custom API v2 endpoint (default is ${defaultCustomEndpoint})`)).trim();
214
+ if (this.args['--custom'] === '')
215
+ this.args['--custom'] = defaultCustomEndpoint;
216
+ this.args['--custom'] += 'jsonRPC';
217
+ }
199
218
  }
200
219
  return network;
201
220
  }
202
221
  chooseExplorer() {
203
222
  return ((0, utils_1.oneOrZeroOf)({
204
223
  tonscan: this.args['--tonscan'],
205
- tonapi: this.args['--tonapi'],
224
+ tonviewer: this.args['--tonviewer'],
206
225
  toncx: this.args['--toncx'],
207
226
  dton: this.args['--dton'],
208
227
  }) ?? 'tonscan');
@@ -241,9 +260,13 @@ class NetworkProviderBuilder {
241
260
  provider = new DeeplinkProvider_1.DeeplinkProvider(this.ui);
242
261
  break;
243
262
  case 'tonconnect':
263
+ if (network === 'custom')
264
+ throw new Error('Tonkeeper cannot work with custom network.');
244
265
  provider = new TonConnectProvider_1.TonConnectProvider(new FSStorage_1.FSStorage(storagePath), this.ui);
245
266
  break;
246
267
  case 'tonhub':
268
+ if (network === 'custom')
269
+ throw new Error('TonHub cannot work with custom network.');
247
270
  provider = new TonHubProvider_1.TonHubProvider(network, new FSStorage_1.FSStorage(storagePath), this.ui);
248
271
  break;
249
272
  case 'mnemonic':
@@ -257,9 +280,15 @@ class NetworkProviderBuilder {
257
280
  async build() {
258
281
  const network = await this.chooseNetwork();
259
282
  const explorer = this.chooseExplorer();
260
- const tc = new ton_1.TonClient4({
261
- endpoint: await (0, ton_access_1.getHttpV4Endpoint)({ network }),
262
- });
283
+ let tc;
284
+ if (network === 'custom') {
285
+ tc = new ton_1.TonClient({ endpoint: this.args['--custom'] });
286
+ }
287
+ else {
288
+ tc = new ton_1.TonClient4({
289
+ endpoint: await (0, ton_access_1.getHttpV4Endpoint)({ network }),
290
+ });
291
+ }
263
292
  const sendProvider = await this.chooseSendProvider(network, tc);
264
293
  try {
265
294
  await sendProvider.connect();
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { TonClient4 } from '@ton/ton';
2
+ import { TonClient, TonClient4 } from '@ton/ton';
3
3
  import { Address, Cell, StateInit } from '@ton/core';
4
4
  import { SendProvider } from './SendProvider';
5
5
  import { UIProvider } from '../../ui/UIProvider';
@@ -10,7 +10,7 @@ export declare class MnemonicProvider implements SendProvider {
10
10
  version: WalletVersion;
11
11
  workchain?: number;
12
12
  secretKey: Buffer;
13
- client: TonClient4;
13
+ client: TonClient4 | TonClient;
14
14
  ui: UIProvider;
15
15
  });
16
16
  connect(): Promise<void>;
@@ -13,6 +13,7 @@ describe('{{name}}', () => {
13
13
  });
14
14
 
15
15
  let blockchain: Blockchain;
16
+ let deployer: SandboxContract<TreasuryContract>;
16
17
  let {{loweredName}}: SandboxContract<{{name}}>;
17
18
 
18
19
  beforeEach(async () => {
@@ -28,7 +29,7 @@ describe('{{name}}', () => {
28
29
  )
29
30
  );
30
31
 
31
- const deployer = await blockchain.treasury('deployer');
32
+ deployer = await blockchain.treasury('deployer');
32
33
 
33
34
  const deployResult = await {{loweredName}}.sendDeploy(deployer.getSender(), toNano('0.05'));
34
35
 
@@ -13,6 +13,7 @@ describe('{{name}}', () => {
13
13
  });
14
14
 
15
15
  let blockchain: Blockchain;
16
+ let deployer: SandboxContract<TreasuryContract>;
16
17
  let {{loweredName}}: SandboxContract<{{name}}>;
17
18
 
18
19
  beforeEach(async () => {
@@ -20,7 +21,7 @@ describe('{{name}}', () => {
20
21
 
21
22
  {{loweredName}} = blockchain.openContract({{name}}.createFromConfig({}, code));
22
23
 
23
- const deployer = await blockchain.treasury('deployer');
24
+ deployer = await blockchain.treasury('deployer');
24
25
 
25
26
  const deployResult = await {{loweredName}}.sendDeploy(deployer.getSender(), toNano('0.05'));
26
27
 
@@ -6,6 +6,7 @@ import '@ton/test-utils';
6
6
 
7
7
  describe('{{name}}', () => {
8
8
  let blockchain: Blockchain;
9
+ let deployer: SandboxContract<TreasuryContract>;
9
10
  let {{loweredName}}: SandboxContract<{{name}}>;
10
11
 
11
12
  beforeEach(async () => {
@@ -13,7 +14,7 @@ describe('{{name}}', () => {
13
14
 
14
15
  {{loweredName}} = blockchain.openContract(await {{name}}.fromInit(0n));
15
16
 
16
- const deployer = await blockchain.treasury('deployer');
17
+ deployer = await blockchain.treasury('deployer');
17
18
 
18
19
  const deployResult = await {{loweredName}}.send(
19
20
  deployer.getSender(),
@@ -6,6 +6,7 @@ import '@ton/test-utils';
6
6
 
7
7
  describe('{{name}}', () => {
8
8
  let blockchain: Blockchain;
9
+ let deployer: SandboxContract<TreasuryContract>;
9
10
  let {{loweredName}}: SandboxContract<{{name}}>;
10
11
 
11
12
  beforeEach(async () => {
@@ -13,7 +14,7 @@ describe('{{name}}', () => {
13
14
 
14
15
  {{loweredName}} = blockchain.openContract(await {{name}}.fromInit());
15
16
 
16
- const deployer = await blockchain.treasury('deployer');
17
+ deployer = await blockchain.treasury('deployer');
17
18
 
18
19
  const deployResult = await {{loweredName}}.send(
19
20
  deployer.getSender(),
package/dist/utils.js CHANGED
@@ -109,8 +109,8 @@ function getExplorerLink(address, network, explorer) {
109
109
  switch (explorer) {
110
110
  case 'tonscan':
111
111
  return `https://${networkPrefix}tonscan.org/address/${address}`;
112
- case 'tonapi':
113
- return `https://${networkPrefix}tonapi.io/account/${address}`;
112
+ case 'tonviewer':
113
+ return `https://${networkPrefix}tonviewer.com/${address}`;
114
114
  case 'toncx':
115
115
  return `https://${networkPrefix}ton.cx/address/${address}`;
116
116
  case 'dton':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ton/blueprint",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Framework for development of TON smart contracts",
5
5
  "main": "dist/index.js",
6
6
  "bin": "./dist/cli/cli.js",
@@ -25,7 +25,7 @@
25
25
  "@types/inquirer": "^8.2.6",
26
26
  "@types/node": "^20.2.5",
27
27
  "@types/qrcode-terminal": "^0.12.0",
28
- "prettier": "^2.8.8",
28
+ "prettier": "^3.0.3",
29
29
  "typescript": "^4.9.5"
30
30
  },
31
31
  "peerDependencies": {