@ton/blueprint 0.33.1 → 0.35.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +164 -16
  3. package/dist/cli/Runner.d.ts +2 -0
  4. package/dist/cli/Runner.js +9 -1
  5. package/dist/cli/build.d.ts +1 -2
  6. package/dist/cli/build.js +3 -6
  7. package/dist/cli/cli.js +8 -1
  8. package/dist/cli/constants.d.ts +4 -0
  9. package/dist/cli/constants.js +44 -6
  10. package/dist/cli/create.js +2 -13
  11. package/dist/cli/help.js +2 -1
  12. package/dist/cli/pack.d.ts +2 -0
  13. package/dist/cli/pack.js +98 -0
  14. package/dist/cli/rename.d.ts +6 -0
  15. package/dist/cli/rename.js +101 -0
  16. package/dist/cli/rename.spec.d.ts +1 -0
  17. package/dist/cli/rename.spec.js +59 -0
  18. package/dist/cli/run.js +2 -1
  19. package/dist/cli/snapshot.d.ts +6 -0
  20. package/dist/cli/snapshot.js +36 -0
  21. package/dist/cli/test.d.ts +4 -0
  22. package/dist/cli/test.js +20 -4
  23. package/dist/cli/verify.js +21 -0
  24. package/dist/compile/compile.d.ts +16 -0
  25. package/dist/compile/compile.js +23 -7
  26. package/dist/compile/tact/compile.tact.d.ts +2 -1
  27. package/dist/compile/tact/compile.tact.js +9 -5
  28. package/dist/config/Config.d.ts +21 -0
  29. package/dist/config/CustomNetwork.d.ts +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +3 -1
  32. package/dist/network/Network.d.ts +1 -0
  33. package/dist/network/Network.js +2 -0
  34. package/dist/network/NetworkProvider.d.ts +2 -1
  35. package/dist/network/createNetworkProvider.js +51 -6
  36. package/dist/network/send/DeeplinkProvider.d.ts +2 -1
  37. package/dist/network/send/DeeplinkProvider.js +6 -4
  38. package/dist/network/send/MnemonicProvider.d.ts +16 -8
  39. package/dist/network/send/MnemonicProvider.js +31 -22
  40. package/dist/network/send/TonConnectProvider.d.ts +2 -1
  41. package/dist/network/send/TonConnectProvider.js +11 -5
  42. package/dist/network/send/wallets.d.ts +25 -0
  43. package/dist/network/send/wallets.js +30 -0
  44. package/dist/paths.d.ts +3 -0
  45. package/dist/paths.js +4 -1
  46. package/dist/templates/func/common/contracts/imports/stdlib.fc.template +8 -7
  47. package/dist/templates/func/not-separated-common/contracts/imports/stdlib.fc.template +8 -7
  48. package/dist/templates/tact/counter/scripts/deploy.ts.template +1 -1
  49. package/dist/templates/tact/counter/scripts/increment.ts.template +1 -1
  50. package/dist/templates/tact/empty/scripts/deploy.ts.template +1 -1
  51. package/dist/templates/tolk/counter/contracts/contract.tolk.template +41 -38
  52. package/dist/utils/selection.utils.js +5 -4
  53. package/dist/utils/string.utils.d.ts +3 -0
  54. package/dist/utils/string.utils.js +20 -0
  55. package/dist/utils/ton.utils.d.ts +2 -1
  56. package/dist/utils/ton.utils.js +3 -1
  57. package/package.json +7 -6
@@ -0,0 +1,6 @@
1
+ import { Runner } from './Runner';
2
+ export declare function renameExactIfRequired(str: string, replaces: Record<string, string>): {
3
+ isRenamed: boolean;
4
+ newValue: string;
5
+ };
6
+ export declare const rename: Runner;
@@ -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 {};
@@ -0,0 +1,59 @@
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
+ const node_test_1 = require("node:test");
7
+ const node_assert_1 = __importDefault(require("node:assert"));
8
+ const rename_1 = require("./rename");
9
+ (0, node_test_1.describe)('Rename', function () {
10
+ (0, node_test_1.it)('It should rename exact match', function () {
11
+ const replaces = {
12
+ a: 'b',
13
+ };
14
+ const result = (0, rename_1.renameExactIfRequired)('a a', replaces);
15
+ node_assert_1.default.strictEqual(result.isRenamed, true);
16
+ node_assert_1.default.strictEqual(result.newValue, 'b b');
17
+ });
18
+ (0, node_test_1.it)('It should not rename not exact match', function () {
19
+ const replaces = {
20
+ a: 'b',
21
+ };
22
+ const result = (0, rename_1.renameExactIfRequired)('and', replaces);
23
+ node_assert_1.default.strictEqual(result.isRenamed, false);
24
+ node_assert_1.default.strictEqual(result.newValue, 'and');
25
+ });
26
+ (0, node_test_1.it)('It should not rename another case', function () {
27
+ const replaces = {
28
+ a: 'b',
29
+ };
30
+ const result = (0, rename_1.renameExactIfRequired)('A', replaces);
31
+ node_assert_1.default.strictEqual(result.isRenamed, false);
32
+ node_assert_1.default.strictEqual(result.newValue, 'A');
33
+ });
34
+ (0, node_test_1.it)('It should rename contract name in brackets', function () {
35
+ const replaces = {
36
+ ['MyContract']: 'NotMyContract',
37
+ };
38
+ const result = (0, rename_1.renameExactIfRequired)(`compile('MyContract')`, replaces);
39
+ node_assert_1.default.strictEqual(result.isRenamed, true);
40
+ node_assert_1.default.strictEqual(result.newValue, `compile('NotMyContract')`);
41
+ });
42
+ (0, node_test_1.it)('It should not rename contract name if not exact match', function () {
43
+ const replaces = {
44
+ ['MyContract']: 'NotMyContract',
45
+ };
46
+ const result = (0, rename_1.renameExactIfRequired)(`compile('MyContract2')`, replaces);
47
+ node_assert_1.default.strictEqual(result.isRenamed, false);
48
+ node_assert_1.default.strictEqual(result.newValue, `compile('MyContract2')`);
49
+ });
50
+ (0, node_test_1.it)('It should do multiple replaces', function () {
51
+ const replaces = {
52
+ ['myContract']: 'notMyContract',
53
+ ['MyContract']: 'NotMyContract',
54
+ };
55
+ const result = (0, rename_1.renameExactIfRequired)(`let myContract: MyContract;`, replaces);
56
+ node_assert_1.default.strictEqual(result.isRenamed, true);
57
+ node_assert_1.default.strictEqual(result.newValue, `let notMyContract: NotMyContract;`);
58
+ });
59
+ });
package/dist/cli/run.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.run = void 0;
7
+ const Runner_1 = require("./Runner");
7
8
  const createNetworkProvider_1 = require("../network/createNetworkProvider");
8
9
  const utils_1 = require("../utils");
9
10
  const arg_1 = __importDefault(require("arg"));
@@ -16,7 +17,7 @@ const run = async (args, ui, context) => {
16
17
  }
17
18
  const { module: mod } = await (0, utils_1.selectFile)(await (0, utils_1.findScripts)(), {
18
19
  ui,
19
- hint: localArgs._.length > 1 && localArgs._[1].length > 0 ? localArgs._[1] : undefined,
20
+ hint: (0, Runner_1.extractFirstArg)(localArgs),
20
21
  });
21
22
  if (typeof mod.run !== 'function') {
22
23
  throw new Error('Function `run` is missing!');
@@ -0,0 +1,6 @@
1
+ import { Runner } from './Runner';
2
+ export declare const argSpec: {
3
+ '--label': StringConstructor;
4
+ '-l': string;
5
+ };
6
+ export declare const snapshot: Runner;
@@ -0,0 +1,36 @@
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.snapshot = exports.argSpec = void 0;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const arg_1 = __importDefault(require("arg"));
9
+ const constants_1 = require("./constants");
10
+ exports.argSpec = {
11
+ '--label': String,
12
+ '-l': '--label',
13
+ };
14
+ const snapshot = async (args, ui) => {
15
+ const localArgs = (0, arg_1.default)({ ...exports.argSpec, ...constants_1.helpArgs });
16
+ if (localArgs['--help']) {
17
+ ui.write(constants_1.helpMessages['snapshot']);
18
+ return;
19
+ }
20
+ let comment = localArgs['--label'];
21
+ let testArgs = args._.slice(1); // first argument is `snapshot`, need to get rid of it
22
+ if (typeof comment === 'undefined') {
23
+ comment = await ui.input('Enter comment:');
24
+ }
25
+ else {
26
+ testArgs = testArgs.slice(2);
27
+ }
28
+ (0, node_child_process_1.execSync)(`npm test -- ${testArgs.join(' ')}`, {
29
+ stdio: 'inherit',
30
+ env: {
31
+ ...process.env,
32
+ BENCH_NEW: comment,
33
+ },
34
+ });
35
+ };
36
+ exports.snapshot = snapshot;
@@ -1,2 +1,6 @@
1
1
  import { Runner } from './Runner';
2
+ export declare const argSpec: {
3
+ '--gas-report': BooleanConstructor;
4
+ '-g': string;
5
+ };
2
6
  export declare const test: Runner;
package/dist/cli/test.js CHANGED
@@ -3,17 +3,33 @@ 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.test = void 0;
6
+ exports.test = exports.argSpec = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const arg_1 = __importDefault(require("arg"));
9
9
  const constants_1 = require("./constants");
10
+ exports.argSpec = {
11
+ '--gas-report': Boolean,
12
+ '-g': '--gas-report',
13
+ };
10
14
  const test = async (args, ui) => {
11
- const localArgs = (0, arg_1.default)(constants_1.helpArgs);
15
+ const localArgs = (0, arg_1.default)({
16
+ ...constants_1.helpArgs,
17
+ ...exports.argSpec,
18
+ });
12
19
  if (localArgs['--help']) {
13
20
  ui.write(constants_1.helpMessages['test']);
14
21
  return;
15
22
  }
16
- const testArgs = args._.slice(1); // first argument is `test`, need to get rid of it
17
- (0, child_process_1.execSync)(`npm test ${testArgs.join(' ')}`, { stdio: 'inherit' });
23
+ let testArgs = args._.slice(1); // first argument is `test`, need to get rid of it
24
+ if (localArgs['--gas-report']) {
25
+ testArgs = testArgs.slice(1);
26
+ }
27
+ (0, child_process_1.execSync)(`npm test -- ${testArgs.join(' ')}`, {
28
+ stdio: 'inherit',
29
+ env: {
30
+ ...process.env,
31
+ BENCH_DIFF: localArgs['--gas-report'] ? 'true' : 'false',
32
+ },
33
+ });
18
34
  };
19
35
  exports.test = test;
@@ -217,6 +217,27 @@ const verify = async (args, ui, context) => {
217
217
  senderAddress: senderAddress.toString(),
218
218
  };
219
219
  }
220
+ else if (result.lang === 'tolk') {
221
+ for (const f of result.snapshot) {
222
+ fd.append(f.filename, new Blob([f.content]), path_1.default.basename(f.filename));
223
+ }
224
+ src = {
225
+ compiler: 'tolk',
226
+ compilerSettings: {
227
+ tolkVersion: result.version,
228
+ },
229
+ knownContractAddress: addr,
230
+ knownContractHash: result.code.hash().toString('base64'),
231
+ sources: result.snapshot.map((s) => ({
232
+ includeInCommand: true,
233
+ isStdLib: false,
234
+ hasIncludeDirectives: true,
235
+ isEntrypoint: s === result.snapshot[0],
236
+ folder: path_1.default.dirname(s.filename),
237
+ })),
238
+ senderAddress: senderAddress.toString(),
239
+ };
240
+ }
220
241
  else {
221
242
  // future proofing
222
243
  throw new Error('Unsupported language ' + result.lang);
@@ -6,6 +6,22 @@ import { TolkCompileResult } from './tolk/compile.tolk';
6
6
  export declare function getCompilablesDirectory(): Promise<string>;
7
7
  export declare function extractCompilableConfig(path: string): CompilableConfig;
8
8
  export declare const COMPILE_END = ".compile.ts";
9
+ /**
10
+ * Retrieves the compiler configuration for a specific contract.
11
+ *
12
+ * This function checks if a Tact configuration exists for the given contract
13
+ * `tact.config.json`. If found, it returns that configuration. Otherwise, it falls back
14
+ * to loading and extracting the `.compile.ts` configuration file from the appropriate
15
+ * compilables directory (`compilables/` or `wrappers/`).
16
+ *
17
+ * @param {string} name - The name of the contract
18
+ *
19
+ * @throws Error Throws if configuration is invalid or not found.
20
+ *
21
+ * @example
22
+ * const config = await getCompilerConfigForContract('MyContract');
23
+ * console.log('Compiler config:', config);
24
+ */
9
25
  export declare function getCompilerConfigForContract(name: string): Promise<CompilerConfig>;
10
26
  export type CompileResult = TactCompileResult | FuncCompileResult | TolkCompileResult;
11
27
  export declare function getCompilerOptions(config: CompilerConfig): Promise<{
@@ -1,7 +1,4 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.COMPILE_END = void 0;
7
4
  exports.getCompilablesDirectory = getCompilablesDirectory;
@@ -11,13 +8,13 @@ exports.getCompilerOptions = getCompilerOptions;
11
8
  exports.doCompile = doCompile;
12
9
  exports.compile = compile;
13
10
  const fs_1 = require("fs");
14
- const path_1 = __importDefault(require("path"));
15
11
  const paths_1 = require("../paths");
16
12
  const CompilerConfig_1 = require("./CompilerConfig");
17
13
  const utils_1 = require("../config/utils");
18
14
  const compile_func_1 = require("./func/compile.func");
19
15
  const compile_tact_1 = require("./tact/compile.tact");
20
16
  const compile_tolk_1 = require("./tolk/compile.tolk");
17
+ const utils_2 = require("../utils");
21
18
  async function getCompilablesDirectory() {
22
19
  const config = await (0, utils_1.getConfig)();
23
20
  if (config?.separateCompilables) {
@@ -34,14 +31,33 @@ function extractCompilableConfig(path) {
34
31
  return mod.compile;
35
32
  }
36
33
  exports.COMPILE_END = '.compile.ts';
37
- // contracts in tact.config.json and .compile.ts may overlap. In this case configuration from tact.config.json would be taken
34
+ /**
35
+ * Retrieves the compiler configuration for a specific contract.
36
+ *
37
+ * This function checks if a Tact configuration exists for the given contract
38
+ * `tact.config.json`. If found, it returns that configuration. Otherwise, it falls back
39
+ * to loading and extracting the `.compile.ts` configuration file from the appropriate
40
+ * compilables directory (`compilables/` or `wrappers/`).
41
+ *
42
+ * @param {string} name - The name of the contract
43
+ *
44
+ * @throws Error Throws if configuration is invalid or not found.
45
+ *
46
+ * @example
47
+ * const config = await getCompilerConfigForContract('MyContract');
48
+ * console.log('Compiler config:', config);
49
+ */
38
50
  async function getCompilerConfigForContract(name) {
39
51
  const tactConfig = (0, compile_tact_1.getTactConfigForContract)(name);
40
52
  if (tactConfig) {
41
53
  return tactConfig;
42
54
  }
43
- const compilablesDirectory = await getCompilablesDirectory();
44
- return extractCompilableConfig(path_1.default.join(compilablesDirectory, name + exports.COMPILE_END));
55
+ const compilables = await (0, utils_2.findCompiles)();
56
+ const compilable = compilables.find((c) => c.name === name);
57
+ if (compilable === undefined) {
58
+ throw new Error(`Contract '${name}' not found`);
59
+ }
60
+ return extractCompilableConfig(compilable.path);
45
61
  }
46
62
  async function doCompileInner(name, config) {
47
63
  if ((0, CompilerConfig_1.isCompilableConfig)(config)) {
@@ -1,4 +1,4 @@
1
- import { Options } from '@tact-lang/compiler';
1
+ import { Options, Project } from '@tact-lang/compiler';
2
2
  import { Cell } from '@ton/core';
3
3
  import { TactCompilerConfig, TactLegacyCompilerConfig } from './config';
4
4
  export type TactCompileResult = {
@@ -10,4 +10,5 @@ export type TactCompileResult = {
10
10
  };
11
11
  export declare function getTactConfigForContract(name: string): TactCompilerConfig | undefined;
12
12
  export declare function getTactVersion(): Promise<any>;
13
+ export declare function extractContractConfig(config: TactCompilerConfig, name: string): Project;
13
14
  export declare function doCompileTact(config: TactLegacyCompilerConfig | TactCompilerConfig, name: string): Promise<TactCompileResult>;
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.getTactConfigForContract = getTactConfigForContract;
40
40
  exports.getTactVersion = getTactVersion;
41
+ exports.extractContractConfig = extractContractConfig;
41
42
  exports.doCompileTact = doCompileTact;
42
43
  const path_1 = __importDefault(require("path"));
43
44
  const compiler_1 = require("@tact-lang/compiler");
@@ -85,6 +86,13 @@ async function getTactVersion() {
85
86
  function isLegacyTactConfig(config) {
86
87
  return 'lang' in config;
87
88
  }
89
+ function extractContractConfig(config, name) {
90
+ const project = config.projects.find((p) => p.name === name);
91
+ if (!project) {
92
+ throw new Error(`Config for project ${name} not found`);
93
+ }
94
+ return project;
95
+ }
88
96
  function getTactBuildProject(config, name) {
89
97
  if (isLegacyTactConfig(config)) {
90
98
  const rootConfigOptions = getRootTactConfigOptionsForContract(name);
@@ -95,11 +103,7 @@ function getTactBuildProject(config, name) {
95
103
  options: { ...rootConfigOptions, ...config.options },
96
104
  };
97
105
  }
98
- const project = config.projects.find((p) => p.name === name);
99
- if (!project) {
100
- throw new Error(`Config for project ${name} not found`);
101
- }
102
- return project;
106
+ return extractContractConfig(config, name);
103
107
  }
104
108
  async function doCompileTact(config, name) {
105
109
  const fs = new OverwritableVirtualFileSystem_1.OverwritableVirtualFileSystem(process.cwd());
@@ -37,4 +37,25 @@ export interface Config {
37
37
  * @default false
38
38
  */
39
39
  separateCompilables?: boolean;
40
+ /**
41
+ * HTTP request timeout in milliseconds.
42
+ *
43
+ * @example
44
+ * export const config: Config = {
45
+ * requestTimeout: 10000 // 10 seconds
46
+ * };
47
+ */
48
+ requestTimeout?: number;
49
+ /**
50
+ * If true, the `wrappers`/`compilables` directory will be searched recursively for contracts.
51
+ *
52
+ * @default false
53
+ */
54
+ recursiveWrappers?: boolean;
55
+ /**
56
+ * Manifest url passed to TonConnect provider.
57
+ *
58
+ * @default https://raw.githubusercontent.com/ton-org/blueprint/main/tonconnect/manifest.json
59
+ */
60
+ manifestUrl?: string;
40
61
  }
@@ -1,6 +1,6 @@
1
1
  export type CustomNetwork = {
2
2
  endpoint: string;
3
- version?: 'v2' | 'v4' | 'tonapi';
3
+ version?: 'v2' | 'v4' | 'tonapi' | 'liteclient';
4
4
  key?: string;
5
5
  type?: 'mainnet' | 'testnet' | 'custom';
6
6
  };
package/dist/index.d.ts CHANGED
@@ -10,3 +10,4 @@ export { PluginRunner, Plugin } from './config/Plugin';
10
10
  export { CustomNetwork } from './config/CustomNetwork';
11
11
  export { buildOne, buildAll, buildAllTact } from './build';
12
12
  export { SourceSnapshot } from "./compile/SourceSnapshot";
13
+ export { getCompilerConfigForContract } from './compile/compile';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildAllTact = exports.buildAll = exports.buildOne = exports.compile = exports.createNetworkProvider = exports.sleep = exports.tonDeepLink = void 0;
3
+ exports.getCompilerConfigForContract = exports.buildAllTact = 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; } });
@@ -12,3 +12,5 @@ var build_1 = require("./build");
12
12
  Object.defineProperty(exports, "buildOne", { enumerable: true, get: function () { return build_1.buildOne; } });
13
13
  Object.defineProperty(exports, "buildAll", { enumerable: true, get: function () { return build_1.buildAll; } });
14
14
  Object.defineProperty(exports, "buildAllTact", { enumerable: true, get: function () { return build_1.buildAllTact; } });
15
+ var compile_2 = require("./compile/compile");
16
+ Object.defineProperty(exports, "getCompilerConfigForContract", { enumerable: true, get: function () { return compile_2.getCompilerConfigForContract; } });
@@ -0,0 +1 @@
1
+ export type Network = 'mainnet' | 'testnet' | 'custom';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,7 +2,8 @@ import { TonClient, TonClient4 } from '@ton/ton';
2
2
  import { Address, Cell, Contract, ContractProvider, OpenedContract, Sender } from '@ton/core';
3
3
  import { ContractAdapter } from '@ton-api/ton-adapter';
4
4
  import { UIProvider } from '../ui/UIProvider';
5
- export type BlueprintTonClient = TonClient4 | TonClient | ContractAdapter;
5
+ import { LiteClient } from "ton-lite-client";
6
+ export type BlueprintTonClient = TonClient4 | TonClient | ContractAdapter | LiteClient;
6
7
  /**
7
8
  * Interface representing a network provider for interacting with TON blockchain.
8
9
  */
@@ -30,6 +30,7 @@ const paths_1 = require("../paths");
30
30
  const crypto_1 = require("@ton/crypto");
31
31
  const MnemonicProvider_1 = require("./send/MnemonicProvider");
32
32
  const axios_1 = __importDefault(require("axios"));
33
+ const ton_lite_client_1 = require("ton-lite-client");
33
34
  const INITIAL_DELAY = 400;
34
35
  const MAX_ATTEMPTS = 4;
35
36
  exports.argSpec = {
@@ -148,9 +149,10 @@ class NetworkProviderImpl {
148
149
  __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").setActionPrompt(`Awaiting contract deployment... [Attempt ${i}/${attempts}]`);
149
150
  const isDeployed = await this.isContractDeployed(address);
150
151
  if (isDeployed) {
152
+ const formattedAddress = address.toString({ testOnly: __classPrivateFieldGet(this, _NetworkProviderImpl_network, "f") === 'testnet' });
151
153
  __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").clearActionPrompt();
152
- __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").write(`Contract deployed at address ${address.toString()}`);
153
- __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").write(`You can view it at ${(0, utils_1.getExplorerLink)(address.toString(), __classPrivateFieldGet(this, _NetworkProviderImpl_network, "f"), __classPrivateFieldGet(this, _NetworkProviderImpl_explorer, "f"))}`);
154
+ __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").write(`Contract deployed at address ${formattedAddress}`);
155
+ __classPrivateFieldGet(this, _NetworkProviderImpl_ui, "f").write(`You can view it at ${(0, utils_1.getExplorerLink)(formattedAddress, __classPrivateFieldGet(this, _NetworkProviderImpl_network, "f"), __classPrivateFieldGet(this, _NetworkProviderImpl_explorer, "f"))}`);
154
156
  return;
155
157
  }
156
158
  await (0, utils_1.sleep)(sleepDuration);
@@ -189,20 +191,59 @@ class NetworkProviderImpl {
189
191
  }
190
192
  }
191
193
  _NetworkProviderImpl_tc = new WeakMap(), _NetworkProviderImpl_sender = new WeakMap(), _NetworkProviderImpl_network = new WeakMap(), _NetworkProviderImpl_explorer = new WeakMap(), _NetworkProviderImpl_ui = new WeakMap();
192
- async function createMnemonicProvider(client, ui) {
194
+ function getOptionalNumberEnv(envName) {
195
+ const value = process.env[envName] ? Number(process.env[envName]) : undefined;
196
+ if (value !== undefined && Number.isNaN(value)) {
197
+ throw new Error(`Invalid ${envName} provided`);
198
+ }
199
+ return value;
200
+ }
201
+ async function createMnemonicProvider(client, network, ui) {
193
202
  const mnemonic = process.env.WALLET_MNEMONIC ?? '';
194
203
  const walletVersion = process.env.WALLET_VERSION ?? '';
195
204
  if (mnemonic.length === 0 || walletVersion.length === 0) {
196
205
  throw new Error('Mnemonic deployer was chosen, but env variables WALLET_MNEMONIC and WALLET_VERSION are not set');
197
206
  }
207
+ const walletId = getOptionalNumberEnv('WALLET_ID');
208
+ const subwalletNumber = getOptionalNumberEnv('SUBWALLET_NUMBER');
198
209
  const keyPair = await (0, crypto_1.mnemonicToPrivateKey)(mnemonic.split(' '));
199
210
  return new MnemonicProvider_1.MnemonicProvider({
200
211
  version: walletVersion.toLowerCase(),
201
212
  client,
202
213
  secretKey: keyPair.secretKey,
203
214
  ui,
215
+ walletId,
216
+ subwalletNumber,
217
+ network,
204
218
  });
205
219
  }
220
+ function intToIP(int) {
221
+ const part1 = int & 255;
222
+ const part2 = (int >> 8) & 255;
223
+ const part3 = (int >> 16) & 255;
224
+ const part4 = (int >> 24) & 255;
225
+ return `${(part4 + 256) % 256}.${(part3 + 256) % 256}.${(part2 + 256) % 256}.${(part1 + 256) % 256}`;
226
+ }
227
+ async function buildLiteClient(configEndpoint) {
228
+ const { data } = await axios_1.default.get(configEndpoint);
229
+ if (!Array.isArray(data.liteservers)) {
230
+ throw new Error(`Invalid liteclient configuration on ${configEndpoint}. Use https://ton.org/testnet-global.config.json for testnet or https://ton.org/global.config.json for mainnet.`);
231
+ }
232
+ const engines = data.liteservers.map((server) => {
233
+ if (typeof server?.ip !== 'number' ||
234
+ typeof server?.port !== 'number' ||
235
+ typeof server?.id !== 'object' ||
236
+ typeof server?.id?.key !== 'string') {
237
+ throw new Error(`Invalid liteclient configuration on ${configEndpoint}`);
238
+ }
239
+ return new ton_lite_client_1.LiteSingleEngine({
240
+ host: `tcp://${intToIP(server.ip)}:${server.port}`,
241
+ publicKey: Buffer.from(server.id.key, 'base64'),
242
+ });
243
+ });
244
+ const engine = new ton_lite_client_1.LiteRoundRobinEngine(engines);
245
+ return new ton_lite_client_1.LiteClient({ engine });
246
+ }
206
247
  class NetworkProviderBuilder {
207
248
  constructor(args, ui, config, allowCustom = true) {
208
249
  this.args = args;
@@ -265,15 +306,15 @@ class NetworkProviderBuilder {
265
306
  let provider;
266
307
  switch (deployUsing) {
267
308
  case 'deeplink':
268
- provider = new DeeplinkProvider_1.DeeplinkProvider(this.ui);
309
+ provider = new DeeplinkProvider_1.DeeplinkProvider(network, this.ui);
269
310
  break;
270
311
  case 'tonconnect':
271
312
  if (network === 'custom')
272
313
  throw new Error('Tonkeeper cannot work with custom network.');
273
- provider = new TonConnectProvider_1.TonConnectProvider(new FSStorage_1.FSStorage(storagePath), this.ui);
314
+ provider = new TonConnectProvider_1.TonConnectProvider(new FSStorage_1.FSStorage(storagePath), this.ui, network, this.config?.manifestUrl);
274
315
  break;
275
316
  case 'mnemonic':
276
- provider = await createMnemonicProvider(client, this.ui);
317
+ provider = await createMnemonicProvider(client, network, this.ui);
277
318
  break;
278
319
  default:
279
320
  throw new Error('Unknown deploy option');
@@ -336,6 +377,9 @@ class NetworkProviderBuilder {
336
377
  apiKey: configNetwork.key,
337
378
  }));
338
379
  }
380
+ else if (configNetwork.version === 'liteclient') {
381
+ tc = await buildLiteClient(configNetwork.endpoint);
382
+ }
339
383
  else {
340
384
  throw new Error('Unknown API version: ' + configNetwork.version);
341
385
  }
@@ -373,6 +417,7 @@ class NetworkProviderBuilder {
373
417
  }
374
418
  };
375
419
  tc = new ton_1.TonClient({
420
+ timeout: this.config?.requestTimeout,
376
421
  endpoint: network === 'mainnet'
377
422
  ? 'https://toncenter.com/api/v2/jsonRPC'
378
423
  : 'https://testnet.toncenter.com/api/v2/jsonRPC',
@@ -1,9 +1,10 @@
1
1
  import { Address, Cell, StateInit } from '@ton/core';
2
2
  import { SendProvider } from './SendProvider';
3
3
  import { UIProvider } from '../../ui/UIProvider';
4
+ import { Network } from '../Network';
4
5
  export declare class DeeplinkProvider implements SendProvider {
5
6
  #private;
6
- constructor(ui: UIProvider);
7
+ constructor(network: Network, ui: UIProvider);
7
8
  connect(): Promise<void>;
8
9
  sendTransaction(address: Address, amount: bigint, payload?: Cell, stateInit?: StateInit): Promise<void>;
9
10
  address(): Address | undefined;