@alephium/web3 0.2.0-rc.3 → 0.2.0-rc.30
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/.eslintignore +2 -2
- package/README.md +2 -135
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.LICENSE.txt +0 -17
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/api-alephium.d.ts +117 -17
- package/dist/src/api/api-alephium.js +145 -79
- package/dist/src/api/api-explorer.d.ts +163 -48
- package/dist/src/api/api-explorer.js +157 -34
- package/dist/src/api/index.d.ts +3 -2
- package/dist/src/api/index.js +22 -3
- package/dist/src/api/types.d.ts +23 -0
- package/dist/src/api/types.js +240 -0
- package/dist/src/api/utils.d.ts +6 -0
- package/dist/{scripts/rename-gitignore.js → src/api/utils.js} +11 -6
- package/dist/src/contract/contract.d.ts +107 -68
- package/dist/src/contract/contract.js +395 -451
- package/dist/src/contract/events.d.ts +4 -4
- package/dist/src/contract/events.js +2 -1
- package/dist/src/contract/index.js +5 -1
- package/dist/src/contract/ralph.d.ts +5 -4
- package/dist/src/contract/ralph.js +27 -1
- package/dist/src/global.d.ts +4 -0
- package/dist/{scripts/stop-devnet.js → src/global.js} +17 -11
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +23 -1
- package/dist/src/signer/index.d.ts +0 -1
- package/dist/src/signer/index.js +5 -2
- package/dist/src/signer/signer.d.ts +25 -13
- package/dist/src/signer/signer.js +51 -16
- package/dist/src/transaction/index.d.ts +0 -1
- package/dist/src/transaction/index.js +5 -2
- package/dist/src/transaction/status.d.ts +2 -1
- package/dist/src/transaction/status.js +2 -1
- package/dist/src/utils/bs58.d.ts +1 -0
- package/dist/src/utils/bs58.js +13 -1
- package/dist/src/utils/index.d.ts +0 -1
- package/dist/src/utils/index.js +5 -2
- package/dist/src/utils/subscription.d.ts +0 -3
- package/dist/src/utils/subscription.js +0 -1
- package/dist/src/utils/utils.d.ts +4 -9
- package/dist/src/utils/utils.js +20 -24
- package/jest-config.json +11 -0
- package/package.json +11 -47
- package/src/api/api-alephium.ts +169 -25
- package/src/api/api-explorer.ts +234 -51
- package/src/api/index.ts +14 -3
- package/src/api/types.ts +233 -0
- package/{scripts/rename-gitignore.js → src/api/utils.ts} +7 -6
- package/src/contract/contract.ts +579 -545
- package/src/contract/events.ts +6 -5
- package/src/contract/ralph.ts +29 -4
- package/src/{transaction/sign-verify.ts → global.ts} +14 -15
- package/src/index.ts +7 -0
- package/src/signer/index.ts +0 -1
- package/src/signer/signer.ts +79 -27
- package/src/transaction/index.ts +0 -1
- package/src/transaction/status.ts +5 -2
- package/src/utils/bs58.ts +11 -0
- package/src/utils/index.ts +0 -1
- package/src/utils/subscription.ts +1 -3
- package/src/utils/utils.ts +11 -19
- package/.eslintrc.json +0 -21
- package/LICENSE +0 -165
- package/contracts/add/add.ral +0 -16
- package/contracts/greeter/greeter.ral +0 -7
- package/contracts/greeter/greeter_interface.ral +0 -3
- package/contracts/greeter_main.ral +0 -9
- package/contracts/main.ral +0 -6
- package/contracts/sub/sub.ral +0 -9
- package/contracts/test/metadata.ral +0 -17
- package/contracts/test/warnings.ral +0 -5
- package/dev/user.conf +0 -29
- package/dist/scripts/create-project.d.ts +0 -2
- package/dist/scripts/create-project.js +0 -125
- package/dist/scripts/rename-gitignore.d.ts +0 -1
- package/dist/scripts/start-devnet.d.ts +0 -1
- package/dist/scripts/start-devnet.js +0 -131
- package/dist/scripts/stop-devnet.d.ts +0 -1
- package/dist/src/signer/node-wallet.d.ts +0 -13
- package/dist/src/signer/node-wallet.js +0 -60
- package/dist/src/test/index.d.ts +0 -7
- package/dist/src/test/index.js +0 -41
- package/dist/src/test/privatekey-wallet.d.ts +0 -12
- package/dist/src/test/privatekey-wallet.js +0 -68
- package/dist/src/transaction/sign-verify.d.ts +0 -2
- package/dist/src/transaction/sign-verify.js +0 -58
- package/dist/src/utils/password-crypto.d.ts +0 -2
- package/dist/src/utils/password-crypto.js +0 -69
- package/gitignore +0 -10
- package/scripts/create-project.ts +0 -137
- package/scripts/start-devnet.js +0 -141
- package/scripts/stop-devnet.js +0 -32
- package/src/contract/ralph.test.ts +0 -178
- package/src/fixtures/address.json +0 -36
- package/src/fixtures/balance.json +0 -9
- package/src/fixtures/self-clique.json +0 -19
- package/src/fixtures/transaction.json +0 -13
- package/src/fixtures/transactions.json +0 -179
- package/src/signer/fixtures/genesis.json +0 -26
- package/src/signer/fixtures/wallets.json +0 -26
- package/src/signer/node-wallet.ts +0 -74
- package/src/test/index.ts +0 -32
- package/src/test/privatekey-wallet.ts +0 -58
- package/src/transaction/sign-verify.test.ts +0 -50
- package/src/utils/address.test.ts +0 -47
- package/src/utils/djb2.test.ts +0 -35
- package/src/utils/password-crypto.test.ts +0 -27
- package/src/utils/password-crypto.ts +0 -77
- package/src/utils/utils.test.ts +0 -161
- package/templates/base/README.md +0 -34
- package/templates/base/package.json +0 -35
- package/templates/base/src/greeter.ts +0 -41
- package/templates/base/tsconfig.json +0 -19
- package/templates/react/README.md +0 -34
- package/templates/react/config-overrides.js +0 -18
- package/templates/react/package.json +0 -66
- package/templates/react/src/App.tsx +0 -42
- package/templates/react/src/artifacts/greeter.ral.json +0 -26
- package/templates/react/src/artifacts/greeter_main.ral.json +0 -22
- package/templates/shared/.eslintrc.json +0 -12
- package/templates/shared/scripts/header.js +0 -0
- package/test/contract.test.ts +0 -197
- package/test/events.test.ts +0 -138
- package/test/transaction.test.ts +0 -72
|
@@ -18,7 +18,11 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
18
18
|
*/
|
|
19
19
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
20
|
if (k2 === undefined) k2 = k;
|
|
21
|
-
Object.
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
22
26
|
}) : (function(o, m, k, k2) {
|
|
23
27
|
if (k2 === undefined) k2 = k;
|
|
24
28
|
o[k2] = m[k];
|
|
@@ -39,120 +43,341 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
43
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
44
|
};
|
|
41
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.
|
|
46
|
+
exports.Script = exports.Contract = exports.Artifact = exports.Project = exports.DEFAULT_COMPILER_OPTIONS = exports.DEFAULT_NODE_COMPILER_OPTIONS = void 0;
|
|
43
47
|
const buffer_1 = require("buffer/");
|
|
44
|
-
const
|
|
45
|
-
const crypto = __importStar(require("crypto"));
|
|
48
|
+
const crypto_1 = require("crypto");
|
|
46
49
|
const fs_1 = __importDefault(require("fs"));
|
|
47
50
|
const fs_2 = require("fs");
|
|
51
|
+
const api_1 = require("../api");
|
|
48
52
|
const ralph = __importStar(require("./ralph"));
|
|
49
53
|
const utils_1 = require("../utils");
|
|
54
|
+
const global_1 = require("../global");
|
|
55
|
+
const __1 = require("..");
|
|
56
|
+
var SourceType;
|
|
57
|
+
(function (SourceType) {
|
|
58
|
+
SourceType[SourceType["Contract"] = 0] = "Contract";
|
|
59
|
+
SourceType[SourceType["Script"] = 1] = "Script";
|
|
60
|
+
SourceType[SourceType["AbstractContract"] = 2] = "AbstractContract";
|
|
61
|
+
SourceType[SourceType["Interface"] = 3] = "Interface";
|
|
62
|
+
})(SourceType || (SourceType = {}));
|
|
63
|
+
exports.DEFAULT_NODE_COMPILER_OPTIONS = {
|
|
64
|
+
ignoreUnusedConstantsWarnings: false,
|
|
65
|
+
ignoreUnusedVariablesWarnings: false,
|
|
66
|
+
ignoreUnusedFieldsWarnings: false,
|
|
67
|
+
ignoreUnusedPrivateFunctionsWarnings: false,
|
|
68
|
+
ignoreReadonlyCheckWarnings: false,
|
|
69
|
+
ignoreExternalCallCheckWarnings: false
|
|
70
|
+
};
|
|
71
|
+
exports.DEFAULT_COMPILER_OPTIONS = { errorOnWarnings: true, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
72
|
+
class TypedMatcher {
|
|
73
|
+
constructor(pattern, type) {
|
|
74
|
+
this.matcher = new RegExp(pattern, 'mg');
|
|
75
|
+
this.type = type;
|
|
76
|
+
}
|
|
77
|
+
match(str) {
|
|
78
|
+
const results = str.match(this.matcher);
|
|
79
|
+
return results === null ? 0 : results.length;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
50
82
|
class SourceFile {
|
|
51
|
-
constructor(
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
constructor(type, sourceCode, sourceCodeHash, contractPath) {
|
|
84
|
+
this.type = type;
|
|
85
|
+
this.sourceCode = sourceCode;
|
|
86
|
+
this.sourceCodeHash = sourceCodeHash;
|
|
87
|
+
this.contractPath = contractPath;
|
|
88
|
+
}
|
|
89
|
+
getArtifactPath(artifactsRootDir) {
|
|
90
|
+
return artifactsRootDir + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
|
|
91
|
+
}
|
|
92
|
+
static async from(type, sourceCode, contractPath) {
|
|
93
|
+
const sourceCodeHash = await crypto_1.webcrypto.subtle.digest('SHA-256', buffer_1.Buffer.from(sourceCode));
|
|
94
|
+
return new SourceFile(type, sourceCode, buffer_1.Buffer.from(sourceCodeHash).toString('hex'), contractPath);
|
|
62
95
|
}
|
|
63
96
|
}
|
|
64
|
-
class
|
|
65
|
-
constructor(
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
97
|
+
class Compiled {
|
|
98
|
+
constructor(sourceFile, artifact, warnings) {
|
|
99
|
+
this.sourceFile = sourceFile;
|
|
100
|
+
this.artifact = artifact;
|
|
101
|
+
this.warnings = warnings;
|
|
68
102
|
}
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
}
|
|
104
|
+
class ProjectArtifact {
|
|
105
|
+
constructor(compilerOptionsUsed, infos) {
|
|
106
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed);
|
|
107
|
+
this.compilerOptionsUsed = compilerOptionsUsed;
|
|
108
|
+
this.infos = infos;
|
|
71
109
|
}
|
|
72
|
-
static
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
110
|
+
static checkCompilerOptionsParameter(compilerOptions) {
|
|
111
|
+
if (Object.keys(compilerOptions).length != Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
112
|
+
throw Error(`Not all compiler options are set: ${compilerOptions}`);
|
|
113
|
+
}
|
|
114
|
+
const combined = { ...compilerOptions, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
115
|
+
if (Object.keys(combined).length !== Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
116
|
+
throw Error(`There are unknown compiler options: ${compilerOptions}`);
|
|
79
117
|
}
|
|
80
118
|
}
|
|
81
|
-
|
|
82
|
-
|
|
119
|
+
async saveToFile(rootPath) {
|
|
120
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
121
|
+
const artifact = { compilerOptionsUsed: this.compilerOptionsUsed, infos: Object.fromEntries(this.infos) };
|
|
122
|
+
const content = JSON.stringify(artifact, null, 2);
|
|
123
|
+
return fs_2.promises.writeFile(filepath, content);
|
|
83
124
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
return
|
|
125
|
+
needToReCompile(compilerOptions, files) {
|
|
126
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptions);
|
|
127
|
+
const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
|
|
128
|
+
const usedOption = this.compilerOptionsUsed[`${key}`];
|
|
129
|
+
return usedOption === inputOption;
|
|
130
|
+
});
|
|
131
|
+
if (!optionsMatched) {
|
|
132
|
+
return true;
|
|
89
133
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
throw new Error('Invalid file path: ' + path);
|
|
98
|
-
}
|
|
99
|
-
dirs.pop();
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
default: {
|
|
103
|
-
dirs.push(part);
|
|
104
|
-
}
|
|
134
|
+
if (files.length !== this.infos.size) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
for (const file of files) {
|
|
138
|
+
const info = this.infos.get(file.contractPath);
|
|
139
|
+
if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
|
|
140
|
+
return true;
|
|
105
141
|
}
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
static async from(rootPath) {
|
|
146
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
147
|
+
if (!fs_1.default.existsSync(filepath)) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const content = await fs_2.promises.readFile(filepath);
|
|
151
|
+
const json = JSON.parse(content.toString());
|
|
152
|
+
const compilerOptionsUsed = json.compilerOptionsUsed;
|
|
153
|
+
const files = new Map(Object.entries(json.infos));
|
|
154
|
+
return new ProjectArtifact(compilerOptionsUsed, files);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
ProjectArtifact.artifactFileName = '.project.json';
|
|
158
|
+
class Project {
|
|
159
|
+
constructor(contractsRootDir, artifactsRootDir, sourceFiles, contracts, scripts, errorOnWarnings, projectArtifact) {
|
|
160
|
+
this.contractsRootDir = contractsRootDir;
|
|
161
|
+
this.artifactsRootDir = artifactsRootDir;
|
|
162
|
+
this.sourceFiles = sourceFiles;
|
|
163
|
+
this.contracts = contracts;
|
|
164
|
+
this.scripts = scripts;
|
|
165
|
+
this.projectArtifact = projectArtifact;
|
|
166
|
+
if (errorOnWarnings) {
|
|
167
|
+
Project.checkCompilerWarnings([...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()], errorOnWarnings);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
static buildProjectArtifact(sourceFiles, contracts, scripts, compilerOptions) {
|
|
171
|
+
const files = new Map();
|
|
172
|
+
contracts.forEach((c) => {
|
|
173
|
+
files.set(c.sourceFile.contractPath, {
|
|
174
|
+
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
175
|
+
bytecodeDebugPatch: c.artifact.bytecodeDebugPatch,
|
|
176
|
+
codeHashDebug: c.artifact.codeHashDebug,
|
|
177
|
+
warnings: c.warnings
|
|
178
|
+
});
|
|
106
179
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
180
|
+
scripts.forEach((s) => {
|
|
181
|
+
files.set(s.sourceFile.contractPath, {
|
|
182
|
+
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
183
|
+
bytecodeDebugPatch: s.artifact.bytecodeDebugPatch,
|
|
184
|
+
codeHashDebug: '',
|
|
185
|
+
warnings: s.warnings
|
|
186
|
+
});
|
|
114
187
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
188
|
+
const compiledSize = contracts.length + scripts.length;
|
|
189
|
+
sourceFiles.slice(compiledSize).forEach((c) => {
|
|
190
|
+
files.set(c.contractPath, {
|
|
191
|
+
sourceCodeHash: c.sourceCodeHash,
|
|
192
|
+
bytecodeDebugPatch: '',
|
|
193
|
+
codeHashDebug: '',
|
|
194
|
+
warnings: []
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
return new ProjectArtifact(compilerOptions, files);
|
|
198
|
+
}
|
|
199
|
+
getContractPath(path) {
|
|
200
|
+
return path.startsWith(`./${this.contractsRootDir}`)
|
|
201
|
+
? path.slice(2)
|
|
202
|
+
: path.startsWith(this.contractsRootDir)
|
|
203
|
+
? path
|
|
204
|
+
: this.contractsRootDir + '/' + path;
|
|
205
|
+
}
|
|
206
|
+
static checkCompilerWarnings(warnings, errorOnWarnings) {
|
|
207
|
+
if (warnings.length !== 0) {
|
|
208
|
+
const prefixPerWarning = ' - ';
|
|
209
|
+
const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning);
|
|
210
|
+
const output = `Compilation warnings:\n` + warningString + '\n';
|
|
211
|
+
if (errorOnWarnings) {
|
|
212
|
+
throw new Error(output);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(output);
|
|
122
216
|
}
|
|
123
217
|
}
|
|
124
|
-
return result;
|
|
125
218
|
}
|
|
126
|
-
static
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return
|
|
219
|
+
static contract(name) {
|
|
220
|
+
const contract = Project.currentProject.contracts.find((c) => c.artifact.name === name);
|
|
221
|
+
if (typeof contract === 'undefined') {
|
|
222
|
+
throw new Error(`Contract "${name}" does not exist`);
|
|
223
|
+
}
|
|
224
|
+
return contract.artifact;
|
|
132
225
|
}
|
|
133
|
-
static
|
|
134
|
-
|
|
135
|
-
|
|
226
|
+
static script(name) {
|
|
227
|
+
const script = Project.currentProject.scripts.find((c) => c.artifact.name === name);
|
|
228
|
+
if (typeof script === 'undefined') {
|
|
229
|
+
throw new Error(`Script "${name}" does not exist`);
|
|
136
230
|
}
|
|
231
|
+
return script.artifact;
|
|
137
232
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
233
|
+
async saveArtifactsToFile() {
|
|
234
|
+
const artifactsRootDir = this.artifactsRootDir;
|
|
235
|
+
const saveToFile = async function (compiled) {
|
|
236
|
+
const artifactDir = compiled.sourceFile.getArtifactPath(artifactsRootDir);
|
|
237
|
+
const folder = artifactDir.slice(0, artifactDir.lastIndexOf('/'));
|
|
238
|
+
if (!fs_1.default.existsSync(folder)) {
|
|
239
|
+
fs_1.default.mkdirSync(folder, { recursive: true });
|
|
240
|
+
}
|
|
241
|
+
return fs_2.promises.writeFile(artifactDir, compiled.artifact.toString());
|
|
242
|
+
};
|
|
243
|
+
for (const contract of this.contracts) {
|
|
244
|
+
await saveToFile(contract);
|
|
145
245
|
}
|
|
146
|
-
|
|
147
|
-
|
|
246
|
+
for (const script of this.scripts) {
|
|
247
|
+
await saveToFile(script);
|
|
148
248
|
}
|
|
249
|
+
await this.projectArtifact.saveToFile(this.artifactsRootDir);
|
|
149
250
|
}
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
|
|
251
|
+
contractByCodeHash(codeHash) {
|
|
252
|
+
const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash || c.artifact.codeHashDebug == codeHash);
|
|
253
|
+
if (typeof contract === 'undefined') {
|
|
254
|
+
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
154
255
|
}
|
|
155
|
-
return
|
|
256
|
+
return contract.artifact;
|
|
257
|
+
}
|
|
258
|
+
static async compile(provider, files, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions) {
|
|
259
|
+
const sourceStr = files.map((f) => f.sourceCode).join('\n');
|
|
260
|
+
const result = await provider.contracts.postContractsCompileProject({
|
|
261
|
+
code: sourceStr,
|
|
262
|
+
compilerOptions: compilerOptions
|
|
263
|
+
});
|
|
264
|
+
const contracts = [];
|
|
265
|
+
const scripts = [];
|
|
266
|
+
result.contracts.forEach((contractResult, index) => {
|
|
267
|
+
const sourceFile = files[`${index}`];
|
|
268
|
+
const contract = Contract.fromCompileResult(contractResult);
|
|
269
|
+
contracts.push(new Compiled(sourceFile, contract, contractResult.warnings));
|
|
270
|
+
});
|
|
271
|
+
result.scripts.forEach((scriptResult, index) => {
|
|
272
|
+
const sourceFile = files[index + contracts.length];
|
|
273
|
+
const script = Script.fromCompileResult(scriptResult);
|
|
274
|
+
scripts.push(new Compiled(sourceFile, script, scriptResult.warnings));
|
|
275
|
+
});
|
|
276
|
+
const projectArtifact = Project.buildProjectArtifact(files, contracts, scripts, compilerOptions);
|
|
277
|
+
const project = new Project(contractsRootDir, artifactsRootDir, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
278
|
+
await project.saveArtifactsToFile();
|
|
279
|
+
return project;
|
|
280
|
+
}
|
|
281
|
+
static async loadArtifacts(provider, files, projectArtifact, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions) {
|
|
282
|
+
try {
|
|
283
|
+
const contracts = [];
|
|
284
|
+
const scripts = [];
|
|
285
|
+
for (const file of files) {
|
|
286
|
+
const info = projectArtifact.infos.get(file.contractPath);
|
|
287
|
+
if (typeof info === 'undefined') {
|
|
288
|
+
throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`);
|
|
289
|
+
}
|
|
290
|
+
const warnings = info.warnings;
|
|
291
|
+
const artifactDir = file.getArtifactPath(artifactsRootDir);
|
|
292
|
+
if (file.type === SourceType.Contract) {
|
|
293
|
+
const artifact = await Contract.fromArtifactFile(artifactDir, info.bytecodeDebugPatch, info.codeHashDebug);
|
|
294
|
+
contracts.push(new Compiled(file, artifact, warnings));
|
|
295
|
+
}
|
|
296
|
+
else if (file.type === SourceType.Script) {
|
|
297
|
+
const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch);
|
|
298
|
+
scripts.push(new Compiled(file, artifact, warnings));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return new Project(contractsRootDir, artifactsRootDir, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`);
|
|
305
|
+
return Project.compile(provider, files, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
static async loadSourceFile(dirPath, filename) {
|
|
309
|
+
const contractPath = dirPath + '/' + filename;
|
|
310
|
+
if (!filename.endsWith('.ral')) {
|
|
311
|
+
throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`);
|
|
312
|
+
}
|
|
313
|
+
const sourceBuffer = await fs_2.promises.readFile(contractPath);
|
|
314
|
+
const sourceStr = sourceBuffer.toString();
|
|
315
|
+
const results = this.matchers.map((m) => m.match(sourceStr));
|
|
316
|
+
const matchNumber = results.reduce((a, b) => a + b, 0);
|
|
317
|
+
if (matchNumber === 0) {
|
|
318
|
+
throw new Error(`No contract defined in file: ${contractPath}`);
|
|
319
|
+
}
|
|
320
|
+
if (matchNumber > 1) {
|
|
321
|
+
throw new Error(`Multiple definitions in file: ${contractPath}`);
|
|
322
|
+
}
|
|
323
|
+
const matcherIndex = results.indexOf(1);
|
|
324
|
+
const type = this.matchers[`${matcherIndex}`].type;
|
|
325
|
+
return SourceFile.from(type, sourceStr, contractPath);
|
|
326
|
+
}
|
|
327
|
+
static async loadSourceFiles(contractsRootDir) {
|
|
328
|
+
const loadDir = async function (dirPath, results) {
|
|
329
|
+
const dirents = await fs_2.promises.readdir(dirPath, { withFileTypes: true });
|
|
330
|
+
for (const dirent of dirents) {
|
|
331
|
+
if (dirent.isFile()) {
|
|
332
|
+
const file = await Project.loadSourceFile(dirPath, dirent.name);
|
|
333
|
+
results.push(file);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const newPath = dirPath + '/' + dirent.name;
|
|
337
|
+
await loadDir(newPath, results);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const sourceFiles = [];
|
|
342
|
+
await loadDir(contractsRootDir, sourceFiles);
|
|
343
|
+
const contractAndScriptSize = sourceFiles.filter((f) => f.type === SourceType.Contract || f.type === SourceType.Script).length;
|
|
344
|
+
if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
|
|
345
|
+
throw new Error('Project have no source files');
|
|
346
|
+
}
|
|
347
|
+
return sourceFiles.sort((a, b) => a.type - b.type);
|
|
348
|
+
}
|
|
349
|
+
static async build(compilerOptionsPartial = {}, contractsRootDir = Project.DEFAULT_CONTRACTS_DIR, artifactsRootDir = Project.DEFAULT_ARTIFACTS_DIR) {
|
|
350
|
+
const provider = (0, global_1.getCurrentNodeProvider)();
|
|
351
|
+
const sourceFiles = await Project.loadSourceFiles(contractsRootDir);
|
|
352
|
+
const { errorOnWarnings, ...nodeCompilerOptions } = { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial };
|
|
353
|
+
const projectArtifact = await ProjectArtifact.from(artifactsRootDir);
|
|
354
|
+
if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
|
|
355
|
+
console.log(`Compiling contracts in folder "${contractsRootDir}"`);
|
|
356
|
+
Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootDir, artifactsRootDir, errorOnWarnings, nodeCompilerOptions);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
console.log(`Contracts are compiled already. Loading them from folder "${artifactsRootDir}"`);
|
|
360
|
+
Project.currentProject = await Project.loadArtifacts(provider, sourceFiles, projectArtifact, contractsRootDir, artifactsRootDir, errorOnWarnings, nodeCompilerOptions);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
exports.Project = Project;
|
|
365
|
+
Project.abstractContractMatcher = new TypedMatcher('^Abstract Contract [A-Z][a-zA-Z0-9]*', SourceType.AbstractContract);
|
|
366
|
+
Project.contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract);
|
|
367
|
+
Project.interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface);
|
|
368
|
+
Project.scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script);
|
|
369
|
+
Project.matchers = [
|
|
370
|
+
Project.abstractContractMatcher,
|
|
371
|
+
Project.contractMatcher,
|
|
372
|
+
Project.interfaceMatcher,
|
|
373
|
+
Project.scriptMatcher
|
|
374
|
+
];
|
|
375
|
+
Project.DEFAULT_CONTRACTS_DIR = 'contracts';
|
|
376
|
+
Project.DEFAULT_ARTIFACTS_DIR = 'artifacts';
|
|
377
|
+
class Artifact {
|
|
378
|
+
constructor(name, functions) {
|
|
379
|
+
this.name = name;
|
|
380
|
+
this.functions = functions;
|
|
156
381
|
}
|
|
157
382
|
publicFunctions() {
|
|
158
383
|
return this.functions.filter((func) => func.isPublic).map((func) => func.name);
|
|
@@ -163,77 +388,22 @@ class Common {
|
|
|
163
388
|
usingAssetsInContractFunctions() {
|
|
164
389
|
return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
|
|
165
390
|
}
|
|
166
|
-
static checkCompilerWarnings(compiled, errorOnWarnings) {
|
|
167
|
-
if (compiled.warnings.length !== 0) {
|
|
168
|
-
const prefixPerWarning = ' - ';
|
|
169
|
-
const warningString = prefixPerWarning + compiled.warnings.join('\n' + prefixPerWarning);
|
|
170
|
-
const output = 'Compilation warnings:\n' + warningString + '\n';
|
|
171
|
-
if (errorOnWarnings) {
|
|
172
|
-
throw new Error(output);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
console.log(output);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
391
|
}
|
|
180
|
-
exports.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Common.scriptRegex = new RegExp('^TxScript [A-Z][a-zA-Z0-9]*', 'mg');
|
|
185
|
-
Common._artifactCache = new Map();
|
|
186
|
-
Common.artifactCacheCapacity = 20;
|
|
187
|
-
class Contract extends Common {
|
|
188
|
-
constructor(sourceCodeSha256, bytecode, codeHash, fieldsSig, eventsSig, functions) {
|
|
189
|
-
super(sourceCodeSha256, functions);
|
|
392
|
+
exports.Artifact = Artifact;
|
|
393
|
+
class Contract extends Artifact {
|
|
394
|
+
constructor(name, bytecode, bytecodeDebugPatch, codeHash, codeHashDebug, fieldsSig, eventsSig, functions) {
|
|
395
|
+
super(name, functions);
|
|
190
396
|
this.bytecode = bytecode;
|
|
397
|
+
this.bytecodeDebugPatch = bytecodeDebugPatch;
|
|
191
398
|
this.codeHash = codeHash;
|
|
192
399
|
this.fieldsSig = fieldsSig;
|
|
193
400
|
this.eventsSig = eventsSig;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const interfaceMatches = contractStr.match(Contract.interfaceRegex);
|
|
197
|
-
const contractMatches = contractStr.match(Contract.contractRegex);
|
|
198
|
-
if (interfaceMatches === null && contractMatches === null) {
|
|
199
|
-
throw new Error(`No contract found in: ${fileName}`);
|
|
200
|
-
}
|
|
201
|
-
if (interfaceMatches && contractMatches) {
|
|
202
|
-
throw new Error(`Multiple contracts and interfaces in: ${fileName}`);
|
|
203
|
-
}
|
|
204
|
-
if (interfaceMatches === null) {
|
|
205
|
-
if (contractMatches !== null && contractMatches.length > 1) {
|
|
206
|
-
throw new Error(`Multiple contracts in: ${fileName}`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (contractMatches === null) {
|
|
210
|
-
if (interfaceMatches !== null && interfaceMatches.length > 1) {
|
|
211
|
-
throw new Error(`Multiple interfaces in: ${fileName}`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
static async loadContractStr(sourceFile) {
|
|
216
|
-
return Common._loadContractStr(sourceFile, [], (code) => Contract.checkCodeType(sourceFile.contractPath, code));
|
|
217
|
-
}
|
|
218
|
-
static async fromSource(provider, path, errorOnWarnings = true) {
|
|
219
|
-
if (!fs_1.default.existsSync(Common._artifactsFolder())) {
|
|
220
|
-
fs_1.default.mkdirSync(Common._artifactsFolder(), { recursive: true });
|
|
221
|
-
}
|
|
222
|
-
const sourceFile = this.getSourceFile(path, []);
|
|
223
|
-
const contract = await Common._from(provider, sourceFile, (sourceFile) => Contract.loadContractStr(sourceFile), Contract.compile, errorOnWarnings);
|
|
224
|
-
this._putArtifactToCache(contract);
|
|
225
|
-
return contract;
|
|
226
|
-
}
|
|
227
|
-
static async compile(provider, sourceFile, contractStr, contractHash, errorOnWarnings) {
|
|
228
|
-
const compiled = await provider.contracts.postContractsCompileContract({ code: contractStr });
|
|
229
|
-
Common.checkCompilerWarnings(compiled, errorOnWarnings);
|
|
230
|
-
const artifact = new Contract(contractHash, compiled.bytecode, compiled.codeHash, compiled.fields, compiled.events, compiled.functions);
|
|
231
|
-
await artifact._saveToFile(sourceFile);
|
|
232
|
-
return artifact;
|
|
401
|
+
this.bytecodeDebug = ralph.buildDebugBytecode(this.bytecode, this.bytecodeDebugPatch);
|
|
402
|
+
this.codeHashDebug = codeHashDebug;
|
|
233
403
|
}
|
|
234
404
|
// TODO: safely parse json
|
|
235
|
-
static fromJson(artifact) {
|
|
236
|
-
if (artifact.
|
|
405
|
+
static fromJson(artifact, bytecodeDebugPatch = '', codeHashDebug = '') {
|
|
406
|
+
if (artifact.name == null ||
|
|
237
407
|
artifact.bytecode == null ||
|
|
238
408
|
artifact.codeHash == null ||
|
|
239
409
|
artifact.fieldsSig == null ||
|
|
@@ -241,31 +411,34 @@ class Contract extends Common {
|
|
|
241
411
|
artifact.functions == null) {
|
|
242
412
|
throw Error('The artifact JSON for contract is incomplete');
|
|
243
413
|
}
|
|
244
|
-
const contract = new Contract(artifact.
|
|
245
|
-
this._putArtifactToCache(contract);
|
|
414
|
+
const contract = new Contract(artifact.name, artifact.bytecode, bytecodeDebugPatch, artifact.codeHash, codeHashDebug ? codeHashDebug : artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
|
|
246
415
|
return contract;
|
|
247
416
|
}
|
|
417
|
+
static fromCompileResult(result) {
|
|
418
|
+
return new Contract(result.name, result.bytecode, result.bytecodeDebugPatch, result.codeHash, result.codeHashDebug, result.fields, result.events, result.functions);
|
|
419
|
+
}
|
|
248
420
|
// support both 'code.ral' and 'code.ral.json'
|
|
249
|
-
static async fromArtifactFile(path) {
|
|
250
|
-
const
|
|
251
|
-
const artifactPath = sourceFile.artifactPath;
|
|
252
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
421
|
+
static async fromArtifactFile(path, bytecodeDebugPatch, codeHashDebug) {
|
|
422
|
+
const content = await fs_2.promises.readFile(path);
|
|
253
423
|
const artifact = JSON.parse(content.toString());
|
|
254
|
-
return Contract.fromJson(artifact);
|
|
424
|
+
return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug);
|
|
255
425
|
}
|
|
256
|
-
async fetchState(
|
|
257
|
-
const state = await
|
|
426
|
+
async fetchState(address, group) {
|
|
427
|
+
const state = await __1.web3.getCurrentNodeProvider().contracts.getContractsAddressState(address, {
|
|
428
|
+
group: group
|
|
429
|
+
});
|
|
258
430
|
return this.fromApiContractState(state);
|
|
259
431
|
}
|
|
260
432
|
toString() {
|
|
261
|
-
|
|
262
|
-
|
|
433
|
+
const object = {
|
|
434
|
+
name: this.name,
|
|
263
435
|
bytecode: this.bytecode,
|
|
264
436
|
codeHash: this.codeHash,
|
|
265
437
|
fieldsSig: this.fieldsSig,
|
|
266
438
|
eventsSig: this.eventsSig,
|
|
267
439
|
functions: this.functions
|
|
268
|
-
}
|
|
440
|
+
};
|
|
441
|
+
return JSON.stringify(object, null, 2);
|
|
269
442
|
}
|
|
270
443
|
toState(fields, asset, address) {
|
|
271
444
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
|
|
@@ -279,16 +452,27 @@ class Contract extends Common {
|
|
|
279
452
|
asset: asset
|
|
280
453
|
};
|
|
281
454
|
}
|
|
455
|
+
// no need to be cryptographically strong random
|
|
282
456
|
static randomAddress() {
|
|
283
|
-
const bytes =
|
|
457
|
+
const bytes = new Uint8Array(33);
|
|
458
|
+
crypto_1.webcrypto.getRandomValues(bytes);
|
|
284
459
|
bytes[0] = 3;
|
|
285
460
|
return utils_1.bs58.encode(bytes);
|
|
286
461
|
}
|
|
287
|
-
|
|
462
|
+
_printDebugMessages(funcName, messages) {
|
|
463
|
+
if (messages.length != 0) {
|
|
464
|
+
console.log(`Testing ${this.name}.${funcName}:`);
|
|
465
|
+
messages.forEach((m) => console.log(`Debug - ${m.contractAddress} - ${m.message}`));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async _test(funcName, params, expectPublic, accessType, printDebugMessages) {
|
|
288
469
|
const apiParams = this.toTestContract(funcName, params);
|
|
289
|
-
const apiResult = await
|
|
470
|
+
const apiResult = await __1.web3.getCurrentNodeProvider().contracts.postContractsTestContract(apiParams);
|
|
290
471
|
const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
|
|
291
472
|
const isPublic = this.functions[`${methodIndex}`].isPublic;
|
|
473
|
+
if (printDebugMessages) {
|
|
474
|
+
this._printDebugMessages(funcName, apiResult.debugMessages);
|
|
475
|
+
}
|
|
292
476
|
if (isPublic === expectPublic) {
|
|
293
477
|
const result = await this.fromTestContractResult(methodIndex, apiResult);
|
|
294
478
|
return result;
|
|
@@ -297,11 +481,11 @@ class Contract extends Common {
|
|
|
297
481
|
throw new Error(`The test method ${funcName} is not ${accessType}`);
|
|
298
482
|
}
|
|
299
483
|
}
|
|
300
|
-
async testPublicMethod(
|
|
301
|
-
return this._test(
|
|
484
|
+
async testPublicMethod(funcName, params, printDebugMessages = true) {
|
|
485
|
+
return this._test(funcName, params, true, 'public', printDebugMessages);
|
|
302
486
|
}
|
|
303
|
-
async testPrivateMethod(
|
|
304
|
-
return this._test(
|
|
487
|
+
async testPrivateMethod(funcName, params, printDebugMessages = true) {
|
|
488
|
+
return this._test(funcName, params, false, 'private', printDebugMessages);
|
|
305
489
|
}
|
|
306
490
|
toApiFields(fields) {
|
|
307
491
|
if (typeof fields === 'undefined') {
|
|
@@ -333,7 +517,7 @@ class Contract extends Common {
|
|
|
333
517
|
return {
|
|
334
518
|
group: params.group,
|
|
335
519
|
address: params.address,
|
|
336
|
-
bytecode: this.
|
|
520
|
+
bytecode: this.bytecodeDebug,
|
|
337
521
|
initialFields: this.toApiFields(params.initialFields),
|
|
338
522
|
initialAsset: typeof params.initialAsset !== 'undefined' ? toApiAsset(params.initialAsset) : undefined,
|
|
339
523
|
methodIndex: this.getMethodIndex(funcName),
|
|
@@ -342,30 +526,8 @@ class Contract extends Common {
|
|
|
342
526
|
inputAssets: toApiInputAssets(params.inputAssets)
|
|
343
527
|
};
|
|
344
528
|
}
|
|
345
|
-
static async fromCodeHash(codeHash) {
|
|
346
|
-
const cached = this._getArtifactFromCache(codeHash);
|
|
347
|
-
if (typeof cached !== 'undefined') {
|
|
348
|
-
return cached;
|
|
349
|
-
}
|
|
350
|
-
const files = await fs_2.promises.readdir(Common._artifactsFolder());
|
|
351
|
-
for (const file of files) {
|
|
352
|
-
if (file.endsWith('.ral.json')) {
|
|
353
|
-
try {
|
|
354
|
-
const contract = await Contract.fromArtifactFile(file);
|
|
355
|
-
if (contract.codeHash === codeHash) {
|
|
356
|
-
return contract;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
catch (_) { }
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
363
|
-
}
|
|
364
|
-
static async getFieldsSig(state) {
|
|
365
|
-
return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig);
|
|
366
|
-
}
|
|
367
529
|
async fromApiContractState(state) {
|
|
368
|
-
const contract =
|
|
530
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash);
|
|
369
531
|
return {
|
|
370
532
|
address: state.address,
|
|
371
533
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
|
|
@@ -373,7 +535,7 @@ class Contract extends Common {
|
|
|
373
535
|
initialStateHash: state.initialStateHash,
|
|
374
536
|
codeHash: state.codeHash,
|
|
375
537
|
fields: fromApiFields(state.fields, contract.fieldsSig),
|
|
376
|
-
fieldsSig:
|
|
538
|
+
fieldsSig: contract.fieldsSig,
|
|
377
539
|
asset: fromApiAsset(state.asset)
|
|
378
540
|
};
|
|
379
541
|
}
|
|
@@ -386,7 +548,7 @@ class Contract extends Common {
|
|
|
386
548
|
eventSig = this.ContractDestroyedEvent;
|
|
387
549
|
}
|
|
388
550
|
else {
|
|
389
|
-
const contract =
|
|
551
|
+
const contract = Project.currentProject.contractByCodeHash(codeHash);
|
|
390
552
|
eventSig = contract.eventsSig[event.eventIndex];
|
|
391
553
|
}
|
|
392
554
|
return {
|
|
@@ -401,9 +563,9 @@ class Contract extends Common {
|
|
|
401
563
|
addressToCodeHash.set(result.address, result.codeHash);
|
|
402
564
|
result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash));
|
|
403
565
|
return {
|
|
404
|
-
address: result.address,
|
|
405
566
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(result.address)),
|
|
406
|
-
|
|
567
|
+
contractAddress: result.address,
|
|
568
|
+
returns: (0, api_1.fromApiArray)(result.returns, this.functions[`${methodIndex}`].returnTypes),
|
|
407
569
|
gasUsed: result.gasUsed,
|
|
408
570
|
contracts: await Promise.all(result.contracts.map((contract) => this.fromApiContractState(contract))),
|
|
409
571
|
txOutputs: result.txOutputs.map(fromApiOutput),
|
|
@@ -416,7 +578,8 @@ class Contract extends Common {
|
|
|
416
578
|
else {
|
|
417
579
|
throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`);
|
|
418
580
|
}
|
|
419
|
-
}))
|
|
581
|
+
})),
|
|
582
|
+
debugMessages: result.debugMessages
|
|
420
583
|
};
|
|
421
584
|
}
|
|
422
585
|
async paramsForDeployment(params) {
|
|
@@ -426,7 +589,7 @@ class Contract extends Common {
|
|
|
426
589
|
bytecode: bytecode,
|
|
427
590
|
initialAttoAlphAmount: extractOptionalNumber256(params.initialAttoAlphAmount),
|
|
428
591
|
issueTokenAmount: extractOptionalNumber256(params.issueTokenAmount),
|
|
429
|
-
initialTokenAmounts: params.initialTokenAmounts
|
|
592
|
+
initialTokenAmounts: (0, api_1.toApiTokens)(params.initialTokenAmounts),
|
|
430
593
|
gasAmount: params.gasAmount,
|
|
431
594
|
gasPrice: extractOptionalNumber256(params.gasPrice)
|
|
432
595
|
};
|
|
@@ -435,7 +598,7 @@ class Contract extends Common {
|
|
|
435
598
|
async transactionForDeployment(signer, params) {
|
|
436
599
|
const signerParams = await this.paramsForDeployment({
|
|
437
600
|
...params,
|
|
438
|
-
signerAddress: (await signer.
|
|
601
|
+
signerAddress: (await signer.getActiveAccount()).address
|
|
439
602
|
});
|
|
440
603
|
const response = await signer.buildContractCreationTx(signerParams);
|
|
441
604
|
return fromApiDeployContractUnsignedTx(response);
|
|
@@ -455,69 +618,46 @@ Contract.ContractDestroyedEvent = {
|
|
|
455
618
|
fieldNames: ['address'],
|
|
456
619
|
fieldTypes: ['Address']
|
|
457
620
|
};
|
|
458
|
-
class Script extends
|
|
459
|
-
constructor(
|
|
460
|
-
super(
|
|
621
|
+
class Script extends Artifact {
|
|
622
|
+
constructor(name, bytecodeTemplate, bytecodeDebugPatch, fieldsSig, functions) {
|
|
623
|
+
super(name, functions);
|
|
461
624
|
this.bytecodeTemplate = bytecodeTemplate;
|
|
625
|
+
this.bytecodeDebugPatch = bytecodeDebugPatch;
|
|
462
626
|
this.fieldsSig = fieldsSig;
|
|
463
627
|
}
|
|
464
|
-
static
|
|
465
|
-
|
|
466
|
-
if (scriptMatches === null) {
|
|
467
|
-
throw new Error(`No script found in: ${fileName}`);
|
|
468
|
-
}
|
|
469
|
-
else if (scriptMatches.length > 1) {
|
|
470
|
-
throw new Error(`Multiple scripts in: ${fileName}`);
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
static async loadContractStr(sourceFile) {
|
|
477
|
-
return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code));
|
|
478
|
-
}
|
|
479
|
-
static async fromSource(provider, path, errorOnWarnings = true) {
|
|
480
|
-
const sourceFile = this.getSourceFile(path, []);
|
|
481
|
-
return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile, errorOnWarnings);
|
|
482
|
-
}
|
|
483
|
-
static async compile(provider, sourceFile, scriptStr, contractHash, errorOnWarnings = true) {
|
|
484
|
-
const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr });
|
|
485
|
-
Common.checkCompilerWarnings(compiled, errorOnWarnings);
|
|
486
|
-
const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions);
|
|
487
|
-
await artifact._saveToFile(sourceFile);
|
|
488
|
-
return artifact;
|
|
628
|
+
static fromCompileResult(result) {
|
|
629
|
+
return new Script(result.name, result.bytecodeTemplate, result.bytecodeDebugPatch, result.fields, result.functions);
|
|
489
630
|
}
|
|
490
631
|
// TODO: safely parse json
|
|
491
|
-
static fromJson(artifact) {
|
|
492
|
-
if (artifact.
|
|
632
|
+
static fromJson(artifact, bytecodeDebugPatch = '') {
|
|
633
|
+
if (artifact.name == null ||
|
|
493
634
|
artifact.bytecodeTemplate == null ||
|
|
494
635
|
artifact.fieldsSig == null ||
|
|
495
636
|
artifact.functions == null) {
|
|
496
637
|
throw Error('The artifact JSON for script is incomplete');
|
|
497
638
|
}
|
|
498
|
-
return new Script(artifact.
|
|
639
|
+
return new Script(artifact.name, artifact.bytecodeTemplate, bytecodeDebugPatch, artifact.fieldsSig, artifact.functions);
|
|
499
640
|
}
|
|
500
|
-
static async fromArtifactFile(path) {
|
|
501
|
-
const
|
|
502
|
-
const artifactPath = sourceFile.artifactPath;
|
|
503
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
641
|
+
static async fromArtifactFile(path, bytecodeDebugPatch) {
|
|
642
|
+
const content = await fs_2.promises.readFile(path);
|
|
504
643
|
const artifact = JSON.parse(content.toString());
|
|
505
|
-
return this.fromJson(artifact);
|
|
644
|
+
return this.fromJson(artifact, bytecodeDebugPatch);
|
|
506
645
|
}
|
|
507
646
|
toString() {
|
|
508
|
-
|
|
509
|
-
|
|
647
|
+
const object = {
|
|
648
|
+
name: this.name,
|
|
510
649
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
511
650
|
fieldsSig: this.fieldsSig,
|
|
512
651
|
functions: this.functions
|
|
513
|
-
}
|
|
652
|
+
};
|
|
653
|
+
return JSON.stringify(object, null, 2);
|
|
514
654
|
}
|
|
515
655
|
async paramsForDeployment(params) {
|
|
516
656
|
const signerParams = {
|
|
517
657
|
signerAddress: params.signerAddress,
|
|
518
658
|
bytecode: this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {}),
|
|
519
659
|
attoAlphAmount: extractOptionalNumber256(params.attoAlphAmount),
|
|
520
|
-
tokens:
|
|
660
|
+
tokens: (0, api_1.toApiTokens)(params.tokens),
|
|
521
661
|
gasAmount: params.gasAmount,
|
|
522
662
|
gasPrice: extractOptionalNumber256(params.gasPrice)
|
|
523
663
|
};
|
|
@@ -526,7 +666,7 @@ class Script extends Common {
|
|
|
526
666
|
async transactionForDeployment(signer, params) {
|
|
527
667
|
const signerParams = await this.paramsForDeployment({
|
|
528
668
|
...params,
|
|
529
|
-
signerAddress: (await signer.
|
|
669
|
+
signerAddress: (await signer.getActiveAccount()).address
|
|
530
670
|
});
|
|
531
671
|
return await signer.buildScriptTx(signerParams);
|
|
532
672
|
}
|
|
@@ -535,221 +675,25 @@ class Script extends Common {
|
|
|
535
675
|
}
|
|
536
676
|
}
|
|
537
677
|
exports.Script = Script;
|
|
538
|
-
function extractBoolean(v) {
|
|
539
|
-
if (typeof v === 'boolean') {
|
|
540
|
-
return v;
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
throw new Error(`Invalid boolean value: ${v}`);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
// TODO: check integer bounds
|
|
547
|
-
function extractNumber256(v) {
|
|
548
|
-
if ((typeof v === 'number' && Number.isInteger(v)) || typeof v === 'bigint') {
|
|
549
|
-
return v.toString();
|
|
550
|
-
}
|
|
551
|
-
else if (typeof v === 'string') {
|
|
552
|
-
return v;
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
throw new Error(`Invalid 256 bit number: ${v}`);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
678
|
function extractOptionalNumber256(v) {
|
|
559
|
-
return typeof v !== 'undefined' ?
|
|
560
|
-
}
|
|
561
|
-
// TODO: check hex string
|
|
562
|
-
function extractByteVec(v) {
|
|
563
|
-
if (typeof v === 'string') {
|
|
564
|
-
// try to convert from address to contract id
|
|
565
|
-
try {
|
|
566
|
-
const address = utils_1.bs58.decode(v);
|
|
567
|
-
if (address.length == 33 && address[0] == 3) {
|
|
568
|
-
return buffer_1.Buffer.from(address.slice(1)).toString('hex');
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
catch (_) {
|
|
572
|
-
return v;
|
|
573
|
-
}
|
|
574
|
-
return v;
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
throw new Error(`Invalid string: ${v}`);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
function extractBs58(v) {
|
|
581
|
-
if (typeof v === 'string') {
|
|
582
|
-
try {
|
|
583
|
-
utils_1.bs58.decode(v);
|
|
584
|
-
return v;
|
|
585
|
-
}
|
|
586
|
-
catch (error) {
|
|
587
|
-
throw new Error(`Invalid base58 string: ${v}`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
else {
|
|
591
|
-
throw new Error(`Invalid string: ${v}`);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
function decodeNumber256(n) {
|
|
595
|
-
if (Number.isSafeInteger(Number.parseInt(n))) {
|
|
596
|
-
return Number(n);
|
|
597
|
-
}
|
|
598
|
-
else {
|
|
599
|
-
return BigInt(n);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
function extractArray(tpe, v) {
|
|
603
|
-
if (!Array.isArray(v)) {
|
|
604
|
-
throw new Error(`Expected array, got ${v}`);
|
|
605
|
-
}
|
|
606
|
-
const semiColonIndex = tpe.lastIndexOf(';');
|
|
607
|
-
if (semiColonIndex == -1) {
|
|
608
|
-
throw new Error(`Invalid Val type: ${tpe}`);
|
|
609
|
-
}
|
|
610
|
-
const subType = tpe.slice(1, semiColonIndex);
|
|
611
|
-
const dim = parseInt(tpe.slice(semiColonIndex + 1, -1));
|
|
612
|
-
if (v.length != dim) {
|
|
613
|
-
throw new Error(`Invalid val dimension: ${v}`);
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
return { value: v.map((v) => toApiVal(v, subType)), type: 'Array' };
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
exports.extractArray = extractArray;
|
|
620
|
-
function toApiVal(v, tpe) {
|
|
621
|
-
if (tpe === 'Bool') {
|
|
622
|
-
return { value: extractBoolean(v), type: tpe };
|
|
623
|
-
}
|
|
624
|
-
else if (tpe === 'U256' || tpe === 'I256') {
|
|
625
|
-
return { value: extractNumber256(v), type: tpe };
|
|
626
|
-
}
|
|
627
|
-
else if (tpe === 'ByteVec') {
|
|
628
|
-
return { value: extractByteVec(v), type: tpe };
|
|
629
|
-
}
|
|
630
|
-
else if (tpe === 'Address') {
|
|
631
|
-
return { value: extractBs58(v), type: tpe };
|
|
632
|
-
}
|
|
633
|
-
else {
|
|
634
|
-
return extractArray(tpe, v);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
exports.toApiVal = toApiVal;
|
|
638
|
-
function decodeArrayType(tpe) {
|
|
639
|
-
const semiColonIndex = tpe.lastIndexOf(';');
|
|
640
|
-
if (semiColonIndex === -1) {
|
|
641
|
-
throw new Error(`Invalid Val type: ${tpe}`);
|
|
642
|
-
}
|
|
643
|
-
const subType = tpe.slice(1, semiColonIndex);
|
|
644
|
-
const dim = parseInt(tpe.slice(semiColonIndex + 1, -1));
|
|
645
|
-
if (subType[0] == '[') {
|
|
646
|
-
const [baseType, subDim] = decodeArrayType(subType);
|
|
647
|
-
return [baseType, (subDim.unshift(dim), subDim)];
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
return [subType, [dim]];
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
function foldVals(vals, dims) {
|
|
654
|
-
if (dims.length == 1) {
|
|
655
|
-
return vals;
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
const result = [];
|
|
659
|
-
const chunkSize = vals.length / dims[0];
|
|
660
|
-
const chunkDims = dims.slice(1);
|
|
661
|
-
for (let i = 0; i < vals.length; i += chunkSize) {
|
|
662
|
-
const chunk = vals.slice(i, i + chunkSize);
|
|
663
|
-
result.push(foldVals(chunk, chunkDims));
|
|
664
|
-
}
|
|
665
|
-
return result;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
function _fromApiVal(vals, valIndex, tpe) {
|
|
669
|
-
if (vals.length === 0) {
|
|
670
|
-
throw new Error('Not enough Vals');
|
|
671
|
-
}
|
|
672
|
-
const firstVal = vals[`${valIndex}`];
|
|
673
|
-
if (tpe === 'Bool' && firstVal.type === tpe) {
|
|
674
|
-
return [firstVal.value, valIndex + 1];
|
|
675
|
-
}
|
|
676
|
-
else if ((tpe === 'U256' || tpe === 'I256') && firstVal.type === tpe) {
|
|
677
|
-
return [decodeNumber256(firstVal.value), valIndex + 1];
|
|
678
|
-
}
|
|
679
|
-
else if ((tpe === 'ByteVec' || tpe === 'Address') && firstVal.type === tpe) {
|
|
680
|
-
return [firstVal.value, valIndex + 1];
|
|
681
|
-
}
|
|
682
|
-
else {
|
|
683
|
-
const [baseType, dims] = decodeArrayType(tpe);
|
|
684
|
-
const arraySize = dims.reduce((a, b) => a * b);
|
|
685
|
-
const nextIndex = valIndex + arraySize;
|
|
686
|
-
const valsToUse = vals.slice(valIndex, nextIndex);
|
|
687
|
-
if (valsToUse.length == arraySize && valsToUse.every((val) => val.type === baseType)) {
|
|
688
|
-
const localVals = valsToUse.map((val) => fromApiVal(val, baseType));
|
|
689
|
-
return [foldVals(localVals, dims), nextIndex];
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
throw new Error(`Invalid array Val type: ${valsToUse}, ${tpe}`);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
679
|
+
return typeof v !== 'undefined' ? (0, api_1.toApiNumber256)(v) : undefined;
|
|
695
680
|
}
|
|
696
681
|
function fromApiFields(vals, fieldsSig) {
|
|
697
|
-
return fromApiVals(vals, fieldsSig.names, fieldsSig.types);
|
|
682
|
+
return (0, api_1.fromApiVals)(vals, fieldsSig.names, fieldsSig.types);
|
|
698
683
|
}
|
|
699
684
|
function fromApiEventFields(vals, eventSig) {
|
|
700
|
-
return fromApiVals(vals, eventSig.fieldNames, eventSig.fieldTypes);
|
|
701
|
-
}
|
|
702
|
-
function fromApiVals(vals, names, types) {
|
|
703
|
-
let valIndex = 0;
|
|
704
|
-
const result = {};
|
|
705
|
-
types.forEach((currentType, index) => {
|
|
706
|
-
const currentName = names[`${index}`];
|
|
707
|
-
const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType);
|
|
708
|
-
valIndex = nextIndex;
|
|
709
|
-
result[`${currentName}`] = val;
|
|
710
|
-
});
|
|
711
|
-
return result;
|
|
712
|
-
}
|
|
713
|
-
function fromApiArray(vals, types) {
|
|
714
|
-
let valIndex = 0;
|
|
715
|
-
const result = [];
|
|
716
|
-
for (const currentType of types) {
|
|
717
|
-
const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType);
|
|
718
|
-
result.push(val);
|
|
719
|
-
valIndex = nextIndex;
|
|
720
|
-
}
|
|
721
|
-
return result;
|
|
722
|
-
}
|
|
723
|
-
function fromApiVal(v, tpe) {
|
|
724
|
-
if (v.type === 'Bool' && v.type === tpe) {
|
|
725
|
-
return v.value;
|
|
726
|
-
}
|
|
727
|
-
else if ((v.type === 'U256' || v.type === 'I256') && v.type === tpe) {
|
|
728
|
-
return decodeNumber256(v.value);
|
|
729
|
-
}
|
|
730
|
-
else if ((v.type === 'ByteVec' || v.type === 'Address') && v.type === tpe) {
|
|
731
|
-
return v.value;
|
|
732
|
-
}
|
|
733
|
-
else {
|
|
734
|
-
throw new Error(`Invalid node.Val type: ${v}`);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
function toApiToken(token) {
|
|
738
|
-
return { id: token.id, amount: extractNumber256(token.amount) };
|
|
739
|
-
}
|
|
740
|
-
function fromApiToken(token) {
|
|
741
|
-
return { id: token.id, amount: decodeNumber256(token.amount) };
|
|
685
|
+
return (0, api_1.fromApiVals)(vals, eventSig.fieldNames, eventSig.fieldTypes);
|
|
742
686
|
}
|
|
743
687
|
function toApiAsset(asset) {
|
|
744
688
|
return {
|
|
745
|
-
attoAlphAmount:
|
|
746
|
-
tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(toApiToken) : []
|
|
689
|
+
attoAlphAmount: (0, api_1.toApiNumber256)(asset.alphAmount),
|
|
690
|
+
tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(api_1.toApiToken) : []
|
|
747
691
|
};
|
|
748
692
|
}
|
|
749
693
|
function fromApiAsset(asset) {
|
|
750
694
|
return {
|
|
751
|
-
alphAmount:
|
|
752
|
-
tokens:
|
|
695
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
696
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens)
|
|
753
697
|
};
|
|
754
698
|
}
|
|
755
699
|
function getVal(vals, name) {
|
|
@@ -780,7 +724,7 @@ function toApiVals(fields, names, types) {
|
|
|
780
724
|
return names.map((name, index) => {
|
|
781
725
|
const val = getVal(fields, name);
|
|
782
726
|
const tpe = types[`${index}`];
|
|
783
|
-
return toApiVal(val, tpe);
|
|
727
|
+
return (0, api_1.toApiVal)(val, tpe);
|
|
784
728
|
});
|
|
785
729
|
}
|
|
786
730
|
function toApiInputAsset(inputAsset) {
|
|
@@ -795,8 +739,8 @@ function fromApiOutput(output) {
|
|
|
795
739
|
return {
|
|
796
740
|
type: 'AssetOutput',
|
|
797
741
|
address: asset.address,
|
|
798
|
-
alphAmount:
|
|
799
|
-
tokens: asset.tokens
|
|
742
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
743
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens),
|
|
800
744
|
lockTime: asset.lockTime,
|
|
801
745
|
message: asset.message
|
|
802
746
|
};
|
|
@@ -806,8 +750,8 @@ function fromApiOutput(output) {
|
|
|
806
750
|
return {
|
|
807
751
|
type: 'ContractOutput',
|
|
808
752
|
address: asset.address,
|
|
809
|
-
alphAmount:
|
|
810
|
-
tokens: asset.tokens
|
|
753
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
754
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens)
|
|
811
755
|
};
|
|
812
756
|
}
|
|
813
757
|
else {
|