@ton/blueprint 0.15.0 → 0.16.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 +12 -0
- package/README.md +35 -5
- package/dist/cli/Runner.d.ts +5 -1
- package/dist/cli/cli.js +6 -2
- package/dist/cli/convert.d.ts +2 -0
- package/dist/cli/convert.js +133 -0
- package/dist/cli/help.js +4 -1
- package/dist/cli/run.js +2 -2
- package/dist/cli/verify.js +83 -7
- package/dist/compile/CompilerConfig.d.ts +5 -2
- package/dist/compile/compile.d.ts +5 -2
- package/dist/compile/compile.js +9 -5
- package/dist/config/Config.d.ts +3 -1
- package/dist/config/CustomNetwork.d.ts +6 -0
- package/dist/config/CustomNetwork.js +2 -0
- package/dist/index.d.ts +4 -3
- package/dist/network/createNetworkProvider.d.ts +2 -1
- package/dist/network/createNetworkProvider.js +50 -21
- package/dist/templates/func/legacy/wrappers/compile.ts.template +7 -0
- package/dist/ui/InquirerUIProvider.d.ts +2 -0
- package/dist/ui/InquirerUIProvider.js +13 -0
- package/dist/ui/UIProvider.d.ts +2 -0
- package/package.json +1 -1
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.16.0] - 2024-02-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added the `network` entry to the global config, which allows one to specify a custom network to be used instead of having to add `--custom` flags on each run
|
|
13
|
+
- Added the `convert` command which attempts to convert a legacy bash build script into a blueprint `.compile.ts` file
|
|
14
|
+
- Added the ability to pass any user data into the compile hooks
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Improved the `verify` command
|
|
19
|
+
|
|
8
20
|
## [0.15.0] - 2023-12-15
|
|
9
21
|
|
|
10
22
|
### Added
|
package/README.md
CHANGED
|
@@ -103,26 +103,56 @@ Run in terminal: `npx blueprint help` or `yarn blueprint he
|
|
|
103
103
|
2. Implement a deployment script in `scripts/deploy<CONTRACT>.ts`
|
|
104
104
|
3. Rely on the wrapper TypeScript class from `wrappers/<CONTRACT>.ts` to initialize the contract
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## Config
|
|
107
|
+
|
|
108
|
+
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:
|
|
109
|
+
```typescript
|
|
110
|
+
import { Config } from '@ton/blueprint';
|
|
111
|
+
|
|
112
|
+
export const config: Config = {
|
|
113
|
+
// config contents
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
It is important that the config is exported, is named `config`, and is not `default` exported.
|
|
117
|
+
|
|
118
|
+
Config's features are explained below.
|
|
119
|
+
|
|
120
|
+
### Plugins
|
|
107
121
|
|
|
108
122
|
Blueprint has a plugin system to allow the community to develop their own additions for the ecosystem without the need to change blueprint's code.
|
|
109
123
|
|
|
110
|
-
In order to use plugins,
|
|
124
|
+
In order to use plugins, add a `plugins` array to your config:
|
|
111
125
|
```typescript
|
|
112
126
|
import { Config } from '@ton/blueprint';
|
|
113
127
|
import { ScaffoldPlugin } from 'blueprint-scaffold';
|
|
114
128
|
|
|
115
129
|
export const config: Config = {
|
|
116
|
-
|
|
130
|
+
plugins: [new ScaffoldPlugin()],
|
|
117
131
|
};
|
|
118
132
|
```
|
|
119
133
|
(This example shows how to add the [scaffold](https://github.com/1IxI1/blueprint-scaffold) plugin)
|
|
120
134
|
|
|
121
|
-
It is important that the config is exported, is named `config`, and is not `default` exported.
|
|
122
|
-
|
|
123
135
|
Here are some of the plugins developed by the community:
|
|
124
136
|
- [scaffold](https://github.com/1IxI1/blueprint-scaffold) - allows developers to quickly create a simple dapp automatically using the wrappers' code
|
|
125
137
|
|
|
138
|
+
### Custom network
|
|
139
|
+
|
|
140
|
+
A custom network may be specified by using the `--custom` flags, which you can read about by running `blueprint help run`, but it can be tiresome to use these at all times. Instead, to specify a custom network to always be used (unless `--custom` flags are present), add a `network` object to your config:
|
|
141
|
+
```typescript
|
|
142
|
+
import { Config } from '@ton/blueprint';
|
|
143
|
+
|
|
144
|
+
export const config: Config = {
|
|
145
|
+
network: {
|
|
146
|
+
endpoint: 'https://toncenter.com/api/v2/',
|
|
147
|
+
type: 'mainnet',
|
|
148
|
+
version: 'v2',
|
|
149
|
+
key: 'YOUR_API_KEY',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Properties of the `network` object have the same semantics as the `--custom` flags with respective names (see `blueprint help run`).
|
|
155
|
+
|
|
126
156
|
## Contributors
|
|
127
157
|
|
|
128
158
|
Special thanks to [@qdevstudio](https://t.me/qdevstudio) for their logo for blueprint.
|
package/dist/cli/Runner.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import arg from 'arg';
|
|
2
2
|
import { UIProvider } from '../ui/UIProvider';
|
|
3
|
+
import { Config } from '../config/Config';
|
|
3
4
|
export declare const argSpec: {};
|
|
4
5
|
export type Args = arg.Result<typeof argSpec>;
|
|
5
|
-
export type
|
|
6
|
+
export type RunnerContext = {
|
|
7
|
+
config?: Config;
|
|
8
|
+
};
|
|
9
|
+
export type Runner = (args: Args, ui: UIProvider, context: RunnerContext) => Promise<void>;
|
package/dist/cli/cli.js
CHANGED
|
@@ -36,6 +36,7 @@ const run_1 = require("./run");
|
|
|
36
36
|
const build_1 = require("./build");
|
|
37
37
|
const test_1 = require("./test");
|
|
38
38
|
const verify_1 = require("./verify");
|
|
39
|
+
const convert_1 = require("./convert");
|
|
39
40
|
const help_1 = require("./help");
|
|
40
41
|
const InquirerUIProvider_1 = require("../ui/InquirerUIProvider");
|
|
41
42
|
const Runner_1 = require("./Runner");
|
|
@@ -47,6 +48,7 @@ const runners = {
|
|
|
47
48
|
test: test_1.test,
|
|
48
49
|
help: help_1.help,
|
|
49
50
|
verify: verify_1.verify,
|
|
51
|
+
convert: convert_1.convert,
|
|
50
52
|
};
|
|
51
53
|
async function main() {
|
|
52
54
|
var _a;
|
|
@@ -59,12 +61,14 @@ async function main() {
|
|
|
59
61
|
process.exit(0);
|
|
60
62
|
}
|
|
61
63
|
let effectiveRunners = {};
|
|
64
|
+
const runnerContext = {};
|
|
62
65
|
try {
|
|
63
66
|
const configModule = await (_a = path_1.default.join(process.cwd(), 'blueprint.config.ts'), Promise.resolve().then(() => __importStar(require(_a))));
|
|
64
67
|
try {
|
|
65
68
|
if ('config' in configModule && typeof configModule.config === 'object') {
|
|
66
69
|
const config = configModule.config;
|
|
67
|
-
|
|
70
|
+
runnerContext.config = config;
|
|
71
|
+
for (const plugin of config.plugins ?? []) {
|
|
68
72
|
for (const runner of plugin.runners()) {
|
|
69
73
|
effectiveRunners[runner.name] = runner.runner;
|
|
70
74
|
help_1.additionalHelpMessages[runner.name] = runner.help;
|
|
@@ -91,7 +95,7 @@ async function main() {
|
|
|
91
95
|
process.exit(1);
|
|
92
96
|
}
|
|
93
97
|
const ui = new InquirerUIProvider_1.InquirerUIProvider();
|
|
94
|
-
await runner(args, ui);
|
|
98
|
+
await runner(args, ui, runnerContext);
|
|
95
99
|
ui.close();
|
|
96
100
|
}
|
|
97
101
|
process.on('SIGINT', () => {
|
|
@@ -0,0 +1,133 @@
|
|
|
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.convert = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const arg_1 = __importDefault(require("arg"));
|
|
10
|
+
const createNetworkProvider_1 = require("../network/createNetworkProvider");
|
|
11
|
+
const template_1 = require("../template");
|
|
12
|
+
const paths_1 = require("../paths");
|
|
13
|
+
function createWrapperName(old) {
|
|
14
|
+
return old
|
|
15
|
+
.split(/[-_]/)
|
|
16
|
+
.map((x) => x.replace(x[0], x[0].toUpperCase()))
|
|
17
|
+
.join('');
|
|
18
|
+
}
|
|
19
|
+
function quoteString(str) {
|
|
20
|
+
const quote = "'";
|
|
21
|
+
const quoted = str.startsWith(quote) && str.endsWith(quote);
|
|
22
|
+
return quoted ? str : quote + str + quote;
|
|
23
|
+
}
|
|
24
|
+
function findFile(dir, filename) {
|
|
25
|
+
const contents = (0, fs_1.readdirSync)(dir);
|
|
26
|
+
let hasFile = contents.includes(filename);
|
|
27
|
+
let foundPath = '';
|
|
28
|
+
if (hasFile) {
|
|
29
|
+
foundPath = path_1.default.join(dir, filename);
|
|
30
|
+
if ((0, fs_1.statSync)(foundPath).isFile()) {
|
|
31
|
+
return foundPath;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (let entry of contents) {
|
|
35
|
+
const entryPath = path_1.default.join(dir, entry);
|
|
36
|
+
const stat = (0, fs_1.statSync)(entryPath);
|
|
37
|
+
if (stat.isDirectory()) {
|
|
38
|
+
foundPath = findFile(entryPath, filename);
|
|
39
|
+
if (foundPath !== '') {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return foundPath;
|
|
45
|
+
}
|
|
46
|
+
function parseCompileString(str, src_dir, ui) {
|
|
47
|
+
// Naive but does the job
|
|
48
|
+
const tokens = str.split(/\\?\s+/).filter((t) => t != '\\');
|
|
49
|
+
const outputIdx = tokens.indexOf('-o');
|
|
50
|
+
if (outputIdx < 0) {
|
|
51
|
+
throw new Error('No output flag (-o) found in command:' + str);
|
|
52
|
+
}
|
|
53
|
+
const outFile = tokens[outputIdx + 1];
|
|
54
|
+
const outputName = outFile.match(/([A-Za-z0-9\-_\\\/]*)/);
|
|
55
|
+
if (outputName === null) {
|
|
56
|
+
throw new Error(`Something went wrong when parsing output from ${outFile}`);
|
|
57
|
+
}
|
|
58
|
+
const wrapperName = createWrapperName(path_1.default.basename(outputName[1]));
|
|
59
|
+
const sourceFiles = tokens.filter((x) => x.match(/\.func|\.fc['"]?$/) !== null).map((t) => t.replace(/['"`]/g, ''));
|
|
60
|
+
if (sourceFiles.length === 0) {
|
|
61
|
+
throw new Error(`No source files found in command:${str}`);
|
|
62
|
+
}
|
|
63
|
+
for (let i = 0; i < sourceFiles.length; i++) {
|
|
64
|
+
const testPath = path_1.default.join(src_dir, sourceFiles[i]);
|
|
65
|
+
if ((0, fs_1.existsSync)(testPath)) {
|
|
66
|
+
sourceFiles[i] = quoteString(testPath);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const foundPath = findFile(src_dir, sourceFiles[i]);
|
|
70
|
+
if (foundPath === '') {
|
|
71
|
+
throw new Error(`${sourceFiles[i]} is not found anywhere`);
|
|
72
|
+
}
|
|
73
|
+
src_dir = path_1.default.dirname(foundPath);
|
|
74
|
+
sourceFiles[i] = quoteString(foundPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
name: wrapperName,
|
|
79
|
+
targets: sourceFiles.join(','),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const convert = async (args, ui) => {
|
|
83
|
+
const localArgs = (0, arg_1.default)(createNetworkProvider_1.argSpec);
|
|
84
|
+
let filePath;
|
|
85
|
+
if (localArgs._.length < 2) {
|
|
86
|
+
filePath = await ui.input('Please specify path to convert from:');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
filePath = localArgs._[1];
|
|
90
|
+
}
|
|
91
|
+
const content = (0, fs_1.readFileSync)(filePath, { encoding: 'utf-8' });
|
|
92
|
+
const srcDir = path_1.default.dirname(filePath);
|
|
93
|
+
const compileStrings = content.replace(/\\[\r?\n]+/g, '').matchAll(/\s?func\s+(.*)\n/g);
|
|
94
|
+
if (compileStrings === null) {
|
|
95
|
+
throw new Error(`No func related commands found in ${filePath}`);
|
|
96
|
+
}
|
|
97
|
+
const templatePath = path_1.default.join(template_1.TEMPLATES_DIR, 'func', 'legacy', 'wrappers', 'compile.ts.template');
|
|
98
|
+
const templateContent = (0, fs_1.readFileSync)(templatePath, { encoding: 'utf-8' });
|
|
99
|
+
if (!(0, fs_1.existsSync)(paths_1.WRAPPERS_DIR)) {
|
|
100
|
+
ui.write('Creating wrappers directory...');
|
|
101
|
+
(0, fs_1.mkdirSync)(paths_1.WRAPPERS_DIR);
|
|
102
|
+
}
|
|
103
|
+
for (let compileStr of compileStrings) {
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = parseCompileString(compileStr[1], srcDir, ui);
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
ui.write(e.toString());
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const resTemplate = (0, template_1.executeTemplate)(templateContent, parsed);
|
|
113
|
+
let lineIdx = resTemplate.indexOf('\n');
|
|
114
|
+
const contentIdx = lineIdx + 1;
|
|
115
|
+
if (resTemplate[lineIdx - 1] === '\r') {
|
|
116
|
+
lineIdx--;
|
|
117
|
+
}
|
|
118
|
+
const wrapperName = resTemplate.substring(0, lineIdx);
|
|
119
|
+
const fileName = path_1.default.join(paths_1.WRAPPERS_DIR, wrapperName);
|
|
120
|
+
const content = resTemplate.substring(contentIdx);
|
|
121
|
+
if ((0, fs_1.existsSync)(fileName)) {
|
|
122
|
+
ui.write(`File ${wrapperName} already exists!`);
|
|
123
|
+
const overwrite = await ui.prompt('Do you want to overwrite it?');
|
|
124
|
+
if (!overwrite) {
|
|
125
|
+
ui.write(`Skipping ${wrapperName}`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
(0, fs_1.writeFileSync)(fileName, content, { encoding: 'utf-8' });
|
|
130
|
+
ui.write(`${wrapperName} wrapper created!`);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
exports.convert = convert;
|
package/dist/cli/help.js
CHANGED
|
@@ -15,7 +15,8 @@ List of available commands:
|
|
|
15
15
|
- build
|
|
16
16
|
- help
|
|
17
17
|
- test
|
|
18
|
-
- verify
|
|
18
|
+
- verify
|
|
19
|
+
- convert`,
|
|
19
20
|
create: `Usage: blueprint create [contract name] [flags]
|
|
20
21
|
|
|
21
22
|
Creates a new contract together with supporting files according to a template.
|
|
@@ -61,6 +62,8 @@ Flags:
|
|
|
61
62
|
--custom-version - specifies the API version to use with the custom API. Options: v2 (defualt), v4.
|
|
62
63
|
--custom-key - specifies the API key to use with the custom API, can only be used with API v2.
|
|
63
64
|
--custom-type - specifies the network type to be indicated to scripts. Options: mainnet, testnet.`,
|
|
65
|
+
convert: `Usage: blueprint convert [path to build script]
|
|
66
|
+
Atempts to convert legacy bash build script to a blueprint compile wrapper.`,
|
|
64
67
|
};
|
|
65
68
|
exports.additionalHelpMessages = {};
|
|
66
69
|
const help = async (args, ui) => {
|
package/dist/cli/run.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.run = void 0;
|
|
|
7
7
|
const createNetworkProvider_1 = require("../network/createNetworkProvider");
|
|
8
8
|
const utils_1 = require("../utils");
|
|
9
9
|
const arg_1 = __importDefault(require("arg"));
|
|
10
|
-
const run = async (args, ui) => {
|
|
10
|
+
const run = async (args, ui, context) => {
|
|
11
11
|
const localArgs = (0, arg_1.default)(createNetworkProvider_1.argSpec);
|
|
12
12
|
const { module: mod } = await (0, utils_1.selectFile)(await (0, utils_1.findScripts)(), {
|
|
13
13
|
ui,
|
|
@@ -16,7 +16,7 @@ const run = async (args, ui) => {
|
|
|
16
16
|
if (typeof mod.run !== 'function') {
|
|
17
17
|
throw new Error('Function `run` is missing!');
|
|
18
18
|
}
|
|
19
|
-
const networkProvider = await (0, createNetworkProvider_1.createNetworkProvider)(ui, localArgs);
|
|
19
|
+
const networkProvider = await (0, createNetworkProvider_1.createNetworkProvider)(ui, localArgs, context.config);
|
|
20
20
|
await mod.run(networkProvider, localArgs._.slice(2));
|
|
21
21
|
};
|
|
22
22
|
exports.run = run;
|
package/dist/cli/verify.js
CHANGED
|
@@ -9,6 +9,7 @@ const compile_1 = require("../compile/compile");
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const createNetworkProvider_1 = require("../network/createNetworkProvider");
|
|
11
11
|
const build_1 = require("./build");
|
|
12
|
+
const utils_1 = require("../utils");
|
|
12
13
|
const arg_1 = __importDefault(require("arg"));
|
|
13
14
|
const backends = {
|
|
14
15
|
mainnet: {
|
|
@@ -57,10 +58,62 @@ class VerifierRegistry {
|
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
async function lookupCodeHash(hash, ui, retryCount = 5) {
|
|
62
|
+
let queryResponse;
|
|
63
|
+
let foundAddr;
|
|
64
|
+
let done = false;
|
|
65
|
+
const graphqlUrl = 'https://dton.io/graphql/';
|
|
66
|
+
const query = `{
|
|
67
|
+
account_states(page:0, page_size:1, account_state_state_init_code_hash: "${hash.toString('hex').toUpperCase()}")
|
|
68
|
+
{
|
|
69
|
+
address
|
|
70
|
+
workchain
|
|
71
|
+
}
|
|
72
|
+
}`;
|
|
73
|
+
do {
|
|
74
|
+
try {
|
|
75
|
+
ui.write('Checking if such a contract is already deployed...');
|
|
76
|
+
const resp = await fetch(graphqlUrl, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: JSON.stringify({ query }),
|
|
79
|
+
headers: { 'Content-Type': 'application/json' },
|
|
80
|
+
});
|
|
81
|
+
if (resp.ok) {
|
|
82
|
+
queryResponse = await resp.json();
|
|
83
|
+
const states = queryResponse.data.account_states;
|
|
84
|
+
if (states.length > 0) {
|
|
85
|
+
const state = states[0];
|
|
86
|
+
foundAddr = core_1.Address.parseRaw(`${state.workchain}:${state.address}`).toString();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
ui.write('No such contract was found!');
|
|
90
|
+
}
|
|
91
|
+
done = true;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
retryCount--;
|
|
95
|
+
}
|
|
96
|
+
// Meh
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
retryCount--;
|
|
100
|
+
if (e.cause) {
|
|
101
|
+
if (e.cause.code == 'ETIMEDOUT') {
|
|
102
|
+
ui.write('API timed out, waiting...');
|
|
103
|
+
await (0, utils_1.sleep)(5000);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
ui.write(e);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} while (!done && retryCount > 0);
|
|
111
|
+
return foundAddr;
|
|
112
|
+
}
|
|
113
|
+
const verify = async (args, ui, context) => {
|
|
61
114
|
const localArgs = (0, arg_1.default)(createNetworkProvider_1.argSpec);
|
|
62
115
|
const sel = await (0, build_1.selectCompile)(ui, localArgs);
|
|
63
|
-
const networkProvider = await (0, createNetworkProvider_1.createNetworkProvider)(ui, localArgs, false);
|
|
116
|
+
const networkProvider = await (0, createNetworkProvider_1.createNetworkProvider)(ui, localArgs, context.config, false);
|
|
64
117
|
const sender = networkProvider.sender();
|
|
65
118
|
const senderAddress = sender.address;
|
|
66
119
|
if (senderAddress === undefined) {
|
|
@@ -70,8 +123,27 @@ const verify = async (args, ui) => {
|
|
|
70
123
|
if (network === 'custom') {
|
|
71
124
|
throw new Error('Cannot use custom network');
|
|
72
125
|
}
|
|
73
|
-
const addr = await ui.input('Deployed contract address');
|
|
74
126
|
const result = await (0, compile_1.doCompile)(sel.name);
|
|
127
|
+
const resHash = result.code.hash();
|
|
128
|
+
ui.write(`Compiled code hash hex:${resHash.toString('hex')}`);
|
|
129
|
+
ui.write('We can look up the address with such code hash in the blockchain automatically');
|
|
130
|
+
const passManually = await ui.prompt('Do you want to specify the address manually?');
|
|
131
|
+
let addr;
|
|
132
|
+
if (passManually) {
|
|
133
|
+
addr = (await ui.inputAddress('Deployed contract address')).toString();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const alreadyDeployed = await lookupCodeHash(resHash, ui);
|
|
137
|
+
if (alreadyDeployed) {
|
|
138
|
+
ui.write(`Contract is already deployed at: ${alreadyDeployed}\nUsing that address.`);
|
|
139
|
+
ui.write(`https://tonscan.org/address/${alreadyDeployed}`);
|
|
140
|
+
addr = alreadyDeployed;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
ui.write("Please enter the contract's address manually");
|
|
144
|
+
addr = (await ui.inputAddress('Deployed contract address')).toString();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
75
147
|
let src;
|
|
76
148
|
const fd = new FormData();
|
|
77
149
|
if (result.lang === 'func') {
|
|
@@ -149,23 +221,26 @@ const verify = async (args, ui) => {
|
|
|
149
221
|
body: fd,
|
|
150
222
|
});
|
|
151
223
|
if (sourceResponse.status !== 200) {
|
|
152
|
-
throw new Error('Could not compile on backend:\n' + (await sourceResponse.
|
|
224
|
+
throw new Error('Could not compile on backend:\n' + (await sourceResponse.json()));
|
|
153
225
|
}
|
|
154
226
|
const sourceResult = await sourceResponse.json();
|
|
155
227
|
if (sourceResult.compileResult.result !== 'similar') {
|
|
156
|
-
throw new Error(
|
|
228
|
+
throw new Error(sourceResult.compileResult.error);
|
|
157
229
|
}
|
|
158
230
|
let msgCell = sourceResult.msgCell;
|
|
159
231
|
let acquiredSigs = 1;
|
|
160
232
|
while (acquiredSigs < verifier.quorum) {
|
|
161
|
-
const
|
|
233
|
+
const curBackend = removeRandom(remainingBackends);
|
|
234
|
+
ui.write(`Using backend: ${curBackend}`);
|
|
235
|
+
const signResponse = await fetch(curBackend + '/sign', {
|
|
162
236
|
method: 'POST',
|
|
163
237
|
body: JSON.stringify({
|
|
164
238
|
messageCell: msgCell,
|
|
165
239
|
}),
|
|
240
|
+
headers: { 'Content-Type': 'application/json' },
|
|
166
241
|
});
|
|
167
242
|
if (signResponse.status !== 200) {
|
|
168
|
-
throw new Error('Could not
|
|
243
|
+
throw new Error('Could not sign on backend:\n' + (await signResponse.text()));
|
|
169
244
|
}
|
|
170
245
|
const signResult = await signResponse.json();
|
|
171
246
|
msgCell = signResult.msgCell;
|
|
@@ -177,5 +252,6 @@ const verify = async (args, ui) => {
|
|
|
177
252
|
value: (0, core_1.toNano)('0.5'),
|
|
178
253
|
body: c,
|
|
179
254
|
});
|
|
255
|
+
ui.write(`Contract successfully verified at https://verifier.ton.org/${addr}`);
|
|
180
256
|
};
|
|
181
257
|
exports.verify = verify;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { SourceResolver, SourcesMap, SourcesArray } from '@ton-community/func-js';
|
|
2
2
|
import { Cell } from '@ton/core';
|
|
3
3
|
import { ConfigProject } from '@tact-lang/compiler';
|
|
4
|
+
export type HookParams = {
|
|
5
|
+
userData?: any;
|
|
6
|
+
};
|
|
4
7
|
export type CommonCompilerConfig = {
|
|
5
|
-
preCompileHook?: () => Promise<void>;
|
|
6
|
-
postCompileHook?: (code: Cell) => Promise<void>;
|
|
8
|
+
preCompileHook?: (params: HookParams) => Promise<void>;
|
|
9
|
+
postCompileHook?: (code: Cell, params: HookParams) => Promise<void>;
|
|
7
10
|
};
|
|
8
11
|
export type TactCompilerConfig = {
|
|
9
12
|
lang: 'tact';
|
|
@@ -14,5 +14,8 @@ export type TactCompileResult = {
|
|
|
14
14
|
code: Cell;
|
|
15
15
|
};
|
|
16
16
|
export type CompileResult = TactCompileResult | FuncCompileResult;
|
|
17
|
-
export declare function doCompile(name: string): Promise<CompileResult>;
|
|
18
|
-
export
|
|
17
|
+
export declare function doCompile(name: string, opts?: CompileOpts): Promise<CompileResult>;
|
|
18
|
+
export type CompileOpts = {
|
|
19
|
+
hookUserData?: any;
|
|
20
|
+
};
|
|
21
|
+
export declare function compile(name: string, opts?: CompileOpts): Promise<Cell>;
|
package/dist/compile/compile.js
CHANGED
|
@@ -106,20 +106,24 @@ async function doCompileInner(name, config) {
|
|
|
106
106
|
optLevel: config.optLevel,
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
|
-
async function doCompile(name) {
|
|
109
|
+
async function doCompile(name, opts) {
|
|
110
110
|
const config = await getCompilerConfigForContract(name);
|
|
111
111
|
if (config.preCompileHook !== undefined) {
|
|
112
|
-
await config.preCompileHook(
|
|
112
|
+
await config.preCompileHook({
|
|
113
|
+
userData: opts?.hookUserData,
|
|
114
|
+
});
|
|
113
115
|
}
|
|
114
116
|
const res = await doCompileInner(name, config);
|
|
115
117
|
if (config.postCompileHook !== undefined) {
|
|
116
|
-
await config.postCompileHook(res.code
|
|
118
|
+
await config.postCompileHook(res.code, {
|
|
119
|
+
userData: opts?.hookUserData,
|
|
120
|
+
});
|
|
117
121
|
}
|
|
118
122
|
return res;
|
|
119
123
|
}
|
|
120
124
|
exports.doCompile = doCompile;
|
|
121
|
-
async function compile(name) {
|
|
122
|
-
const result = await doCompile(name);
|
|
125
|
+
async function compile(name, opts) {
|
|
126
|
+
const result = await doCompile(name, opts);
|
|
123
127
|
return result.code;
|
|
124
128
|
}
|
|
125
129
|
exports.compile = compile;
|
package/dist/config/Config.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export { tonDeepLink, sleep } from './utils';
|
|
2
2
|
export { NetworkProvider } from './network/NetworkProvider';
|
|
3
3
|
export { createNetworkProvider } from './network/createNetworkProvider';
|
|
4
|
-
export { compile } from './compile/compile';
|
|
5
|
-
export { CompilerConfig } from './compile/CompilerConfig';
|
|
4
|
+
export { compile, CompileOpts } from './compile/compile';
|
|
5
|
+
export { CompilerConfig, HookParams } from './compile/CompilerConfig';
|
|
6
6
|
export { UIProvider } from './ui/UIProvider';
|
|
7
7
|
export { Config } from './config/Config';
|
|
8
|
-
export { Args, Runner } from './cli/Runner';
|
|
8
|
+
export { Args, Runner, RunnerContext } from './cli/Runner';
|
|
9
9
|
export { PluginRunner, Plugin } from './config/Plugin';
|
|
10
|
+
export { CustomNetwork } from './config/CustomNetwork';
|
|
10
11
|
export { buildOne, buildAll } from './build';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import arg from 'arg';
|
|
2
2
|
import { UIProvider } from '../ui/UIProvider';
|
|
3
3
|
import { NetworkProvider } from './NetworkProvider';
|
|
4
|
+
import { Config } from '../config/Config';
|
|
4
5
|
export declare const argSpec: {
|
|
5
6
|
'--mainnet': BooleanConstructor;
|
|
6
7
|
'--testnet': BooleanConstructor;
|
|
@@ -18,4 +19,4 @@ export declare const argSpec: {
|
|
|
18
19
|
'--dton': BooleanConstructor;
|
|
19
20
|
};
|
|
20
21
|
export type Args = arg.Result<typeof argSpec>;
|
|
21
|
-
export declare function createNetworkProvider(ui: UIProvider, args: Args, allowCustom?: boolean): Promise<NetworkProvider>;
|
|
22
|
+
export declare function createNetworkProvider(ui: UIProvider, args: Args, config?: Config, allowCustom?: boolean): Promise<NetworkProvider>;
|
|
@@ -198,9 +198,10 @@ async function createMnemonicProvider(client, ui) {
|
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
200
|
class NetworkProviderBuilder {
|
|
201
|
-
constructor(args, ui, allowCustom = true) {
|
|
201
|
+
constructor(args, ui, config, allowCustom = true) {
|
|
202
202
|
this.args = args;
|
|
203
203
|
this.ui = ui;
|
|
204
|
+
this.config = config;
|
|
204
205
|
this.allowCustom = allowCustom;
|
|
205
206
|
}
|
|
206
207
|
async chooseNetwork() {
|
|
@@ -209,14 +210,18 @@ class NetworkProviderBuilder {
|
|
|
209
210
|
testnet: this.args['--testnet'],
|
|
210
211
|
custom: this.args['--custom'] !== undefined,
|
|
211
212
|
});
|
|
212
|
-
if (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
if (network !== undefined) {
|
|
214
|
+
return network;
|
|
215
|
+
}
|
|
216
|
+
if (this.config?.network !== undefined) {
|
|
217
|
+
return typeof this.config.network === 'string' ? this.config.network : 'custom';
|
|
218
|
+
}
|
|
219
|
+
network = await this.ui.choose('Which network do you want to use?', ['mainnet', 'testnet', 'custom'], (c) => c);
|
|
220
|
+
if (network === 'custom') {
|
|
221
|
+
const defaultCustomEndpoint = 'http://localhost:8081/';
|
|
222
|
+
this.args['--custom'] = (await this.ui.input(`Provide a custom API v2 endpoint (default is ${defaultCustomEndpoint})`)).trim();
|
|
223
|
+
if (this.args['--custom'] === '')
|
|
224
|
+
this.args['--custom'] = defaultCustomEndpoint;
|
|
220
225
|
}
|
|
221
226
|
return network;
|
|
222
227
|
}
|
|
@@ -290,26 +295,50 @@ class NetworkProviderBuilder {
|
|
|
290
295
|
}
|
|
291
296
|
let tc;
|
|
292
297
|
if (network === 'custom') {
|
|
293
|
-
|
|
294
|
-
if (this.
|
|
298
|
+
let configNetwork = undefined;
|
|
299
|
+
if (this.config?.network !== undefined && typeof this.config.network !== 'string') {
|
|
300
|
+
configNetwork = this.config.network;
|
|
301
|
+
}
|
|
302
|
+
if (this.args['--custom'] !== undefined) {
|
|
303
|
+
const inputVer = this.args['--custom-version'];
|
|
304
|
+
let version = undefined;
|
|
305
|
+
if (inputVer !== undefined) {
|
|
306
|
+
version = inputVer.toLowerCase(); // checks come later
|
|
307
|
+
}
|
|
308
|
+
const inputType = this.args['--custom-type'];
|
|
309
|
+
let type = undefined;
|
|
310
|
+
if (inputType !== undefined) {
|
|
311
|
+
type = inputType; // checks come later
|
|
312
|
+
}
|
|
313
|
+
configNetwork = {
|
|
314
|
+
endpoint: this.args['--custom'],
|
|
315
|
+
version,
|
|
316
|
+
key: this.args['--custom-key'],
|
|
317
|
+
type,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (configNetwork === undefined) {
|
|
321
|
+
throw new Error('Custom network is (somehow) undefined');
|
|
322
|
+
}
|
|
323
|
+
if (configNetwork.version === undefined || configNetwork.version === 'v2') {
|
|
295
324
|
tc = new ton_1.TonClient({
|
|
296
|
-
endpoint: endpoint + 'jsonRPC',
|
|
297
|
-
apiKey:
|
|
325
|
+
endpoint: configNetwork.endpoint + 'jsonRPC',
|
|
326
|
+
apiKey: configNetwork.key,
|
|
298
327
|
});
|
|
299
328
|
}
|
|
300
|
-
else if (
|
|
301
|
-
if (
|
|
329
|
+
else if (configNetwork.version === 'v4') {
|
|
330
|
+
if (configNetwork.key !== undefined) {
|
|
302
331
|
throw new Error('Cannot use a custom API key with a v4 API');
|
|
303
332
|
}
|
|
304
333
|
tc = new ton_1.TonClient4({
|
|
305
|
-
endpoint,
|
|
334
|
+
endpoint: configNetwork.endpoint,
|
|
306
335
|
});
|
|
307
336
|
}
|
|
308
337
|
else {
|
|
309
|
-
throw new Error('Unknown API version: ' +
|
|
338
|
+
throw new Error('Unknown API version: ' + configNetwork.version);
|
|
310
339
|
}
|
|
311
|
-
if (
|
|
312
|
-
const ct =
|
|
340
|
+
if (configNetwork.type !== undefined) {
|
|
341
|
+
const ct = configNetwork.type.toLowerCase();
|
|
313
342
|
if (!['mainnet', 'testnet', 'custom'].includes(ct)) {
|
|
314
343
|
throw new Error('Unknown network type: ' + ct);
|
|
315
344
|
}
|
|
@@ -339,7 +368,7 @@ class NetworkProviderBuilder {
|
|
|
339
368
|
return new NetworkProviderImpl(tc, sender, network, explorer, this.ui);
|
|
340
369
|
}
|
|
341
370
|
}
|
|
342
|
-
async function createNetworkProvider(ui, args, allowCustom = true) {
|
|
343
|
-
return await new NetworkProviderBuilder(args, ui, allowCustom).build();
|
|
371
|
+
async function createNetworkProvider(ui, args, config, allowCustom = true) {
|
|
372
|
+
return await new NetworkProviderBuilder(args, ui, config, allowCustom).build();
|
|
344
373
|
}
|
|
345
374
|
exports.createNetworkProvider = createNetworkProvider;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { UIProvider } from '../ui/UIProvider';
|
|
2
|
+
import { Address } from '@ton/core';
|
|
2
3
|
export declare class InquirerUIProvider implements UIProvider {
|
|
3
4
|
#private;
|
|
4
5
|
constructor();
|
|
5
6
|
write(message: string): void;
|
|
6
7
|
prompt(message: string): Promise<boolean>;
|
|
8
|
+
inputAddress(message: string, fallback?: Address): Promise<Address>;
|
|
7
9
|
input(message: string): Promise<string>;
|
|
8
10
|
choose<T>(message: string, choices: T[], display: (v: T) => string): Promise<T>;
|
|
9
11
|
setActionPrompt(message: string): void;
|
|
@@ -17,6 +17,7 @@ var _InquirerUIProvider_bottomBar;
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.InquirerUIProvider = void 0;
|
|
19
19
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
20
|
+
const core_1 = require("@ton/core");
|
|
20
21
|
class DestroyableBottomBar extends inquirer_1.default.ui.BottomBar {
|
|
21
22
|
destroy() {
|
|
22
23
|
this.close();
|
|
@@ -38,6 +39,18 @@ class InquirerUIProvider {
|
|
|
38
39
|
});
|
|
39
40
|
return prompt;
|
|
40
41
|
}
|
|
42
|
+
async inputAddress(message, fallback) {
|
|
43
|
+
const prompt = message + (fallback === undefined ? '' : ` (default: ${fallback})`);
|
|
44
|
+
while (true) {
|
|
45
|
+
const addr = (await this.input(prompt)).trim();
|
|
46
|
+
try {
|
|
47
|
+
return addr === '' && fallback !== undefined ? fallback : core_1.Address.parse(addr);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
this.write(addr + ' is not valid!\n');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
41
54
|
async input(message) {
|
|
42
55
|
const { val } = await inquirer_1.default.prompt({
|
|
43
56
|
name: 'val',
|
package/dist/ui/UIProvider.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { Address } from '@ton/core';
|
|
1
2
|
export interface UIProvider {
|
|
2
3
|
write(message: string): void;
|
|
3
4
|
prompt(message: string): Promise<boolean>;
|
|
5
|
+
inputAddress(message: string, fallback?: Address): Promise<Address>;
|
|
4
6
|
input(message: string): Promise<string>;
|
|
5
7
|
choose<T>(message: string, choices: T[], display: (v: T) => string): Promise<T>;
|
|
6
8
|
setActionPrompt(message: string): void;
|