@alephium/web3 0.2.0-test.0 → 0.2.0-test.1
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/contracts/add/add.ral +5 -8
- package/contracts/greeter/greeter.ral +3 -3
- package/contracts/greeter/greeter_interface.ral +1 -0
- package/contracts/greeter_main.ral +3 -5
- package/contracts/main.ral +0 -2
- package/contracts/sub/sub.ral +2 -1
- package/contracts/test/metadata.ral +18 -0
- package/contracts/test/warnings.ral +8 -0
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/scripts/create-project.js +2 -1
- package/dist/src/api/api-alephium.d.ts +37 -7
- package/dist/src/api/api-alephium.js +19 -3
- package/dist/src/api/api-explorer.d.ts +16 -0
- package/dist/src/api/api-explorer.js +26 -0
- package/dist/src/contract/contract.d.ts +86 -52
- package/dist/src/contract/contract.js +325 -218
- package/dist/src/global.d.ts +3 -0
- package/dist/src/global.js +38 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/signer/node-wallet.d.ts +1 -3
- package/dist/src/signer/node-wallet.js +2 -5
- package/dist/src/signer/signer.d.ts +1 -1
- package/dist/src/signer/signer.js +3 -2
- package/dist/src/test/index.d.ts +1 -2
- package/dist/src/test/index.js +4 -4
- package/dist/src/test/privatekey-wallet.d.ts +2 -3
- package/dist/src/test/privatekey-wallet.js +4 -4
- package/dist/src/utils/subscription.d.ts +0 -1
- package/dist/src/utils/subscription.js +2 -1
- package/dist/src/utils/utils.d.ts +2 -2
- package/dist/src/utils/utils.js +2 -2
- package/gitignore +0 -1
- package/package.json +3 -5
- package/scripts/create-project.ts +2 -1
- package/src/api/api-alephium.ts +57 -8
- package/src/api/api-explorer.ts +30 -0
- package/src/contract/contract.ts +430 -317
- package/src/contract/events.ts +2 -2
- package/src/contract/ralph.test.ts +4 -4
- package/src/global.ts +36 -0
- package/src/index.ts +1 -0
- package/src/signer/node-wallet.ts +2 -11
- package/src/signer/signer.ts +4 -3
- package/src/test/index.ts +2 -3
- package/src/test/privatekey-wallet.ts +4 -5
- package/src/transaction/status.ts +1 -1
- package/src/utils/subscription.ts +3 -3
- package/src/utils/utils.test.ts +1 -1
- package/src/utils/utils.ts +4 -4
- package/templates/base/package.json +2 -2
- package/templates/base/src/greeter.ts +8 -7
- package/templates/react/package.json +2 -2
- package/templates/react/src/App.tsx +2 -2
- package/test/contract.test.ts +60 -25
- package/test/events.test.ts +20 -17
- package/test/transaction.test.ts +10 -9
|
@@ -39,7 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
39
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
40
|
};
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.toApiVal = exports.extractArray = exports.Script = exports.Contract = exports.
|
|
42
|
+
exports.toApiVal = exports.extractArray = exports.Script = exports.Contract = exports.Artifact = exports.Project = exports.DEFAULT_COMPILER_OPTIONS = void 0;
|
|
43
43
|
const buffer_1 = require("buffer/");
|
|
44
44
|
const cryptojs = __importStar(require("crypto-js"));
|
|
45
45
|
const crypto = __importStar(require("crypto"));
|
|
@@ -47,202 +47,359 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
47
47
|
const fs_2 = require("fs");
|
|
48
48
|
const ralph = __importStar(require("./ralph"));
|
|
49
49
|
const utils_1 = require("../utils");
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
const global_1 = require("../global");
|
|
51
|
+
var SourceType;
|
|
52
|
+
(function (SourceType) {
|
|
53
|
+
SourceType[SourceType["Contract"] = 0] = "Contract";
|
|
54
|
+
SourceType[SourceType["Script"] = 1] = "Script";
|
|
55
|
+
SourceType[SourceType["AbstractContract"] = 2] = "AbstractContract";
|
|
56
|
+
SourceType[SourceType["Interface"] = 3] = "Interface";
|
|
57
|
+
})(SourceType || (SourceType = {}));
|
|
58
|
+
exports.DEFAULT_COMPILER_OPTIONS = {
|
|
59
|
+
errorOnWarnings: true,
|
|
60
|
+
ignoreUnusedConstantsWarnings: true
|
|
61
|
+
};
|
|
62
|
+
class TypedMatcher {
|
|
63
|
+
constructor(pattern, type) {
|
|
64
|
+
this.matcher = new RegExp(pattern, 'mg');
|
|
65
|
+
this.type = type;
|
|
66
|
+
this.name = undefined;
|
|
67
|
+
}
|
|
68
|
+
match(str) {
|
|
69
|
+
const results = [...str.matchAll(this.matcher)];
|
|
70
|
+
if (results.length > 0) {
|
|
71
|
+
this.name = results[0][1];
|
|
61
72
|
}
|
|
73
|
+
return results.length;
|
|
62
74
|
}
|
|
63
75
|
}
|
|
64
|
-
class
|
|
65
|
-
constructor(
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
76
|
+
class SourceFile {
|
|
77
|
+
constructor(type, typeId, sourceCode, contractPath) {
|
|
78
|
+
this.type = type;
|
|
79
|
+
this.typeId = typeId;
|
|
80
|
+
this.sourceCode = sourceCode;
|
|
81
|
+
this.sourceCodeHash = cryptojs.SHA256(sourceCode).toString();
|
|
82
|
+
this.contractPath = contractPath;
|
|
68
83
|
}
|
|
69
|
-
|
|
70
|
-
return this.
|
|
84
|
+
getArtifactPath(artifactsRootPath) {
|
|
85
|
+
return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
|
|
71
86
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this._artifactCache.set(contract.codeHash, contract);
|
|
79
|
-
}
|
|
87
|
+
}
|
|
88
|
+
class Compiled {
|
|
89
|
+
constructor(sourceFile, artifact, warnings) {
|
|
90
|
+
this.sourceFile = sourceFile;
|
|
91
|
+
this.artifact = artifact;
|
|
92
|
+
this.warnings = warnings;
|
|
80
93
|
}
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
}
|
|
95
|
+
class ProjectArtifact {
|
|
96
|
+
constructor(infos) {
|
|
97
|
+
this.infos = infos;
|
|
83
98
|
}
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
99
|
+
async saveToFile(rootPath) {
|
|
100
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
101
|
+
const content = JSON.stringify(Object.fromEntries(this.infos), null, 2);
|
|
102
|
+
return fs_2.promises.writeFile(filepath, content);
|
|
103
|
+
}
|
|
104
|
+
sourceHasChanged(files) {
|
|
105
|
+
if (files.length !== this.infos.size) {
|
|
106
|
+
return true;
|
|
89
107
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
case '..': {
|
|
96
|
-
if (dirs.length === 0) {
|
|
97
|
-
throw new Error('Invalid file path: ' + path);
|
|
98
|
-
}
|
|
99
|
-
dirs.pop();
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
default: {
|
|
103
|
-
dirs.push(part);
|
|
104
|
-
}
|
|
108
|
+
for (const file of files) {
|
|
109
|
+
const info = this.infos.get(file.contractPath);
|
|
110
|
+
if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
|
|
111
|
+
return true;
|
|
105
112
|
}
|
|
106
|
-
}
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
static async
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
static async from(rootPath) {
|
|
117
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
118
|
+
if (!fs_1.default.existsSync(filepath)) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const content = await fs_2.promises.readFile(filepath);
|
|
122
|
+
const files = new Map(Object.entries(JSON.parse(content.toString())));
|
|
123
|
+
return new ProjectArtifact(files);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
ProjectArtifact.artifactFileName = '.project.json';
|
|
127
|
+
class Project {
|
|
128
|
+
constructor(provider, contractsRootPath, artifactsRootPath, sourceFiles, contracts, scripts) {
|
|
129
|
+
this.nodeProvider = provider;
|
|
130
|
+
this.contractsRootPath = contractsRootPath;
|
|
131
|
+
this.artifactsRootPath = artifactsRootPath;
|
|
132
|
+
this.sourceFiles = sourceFiles;
|
|
133
|
+
this.contracts = contracts;
|
|
134
|
+
this.scripts = scripts;
|
|
135
|
+
}
|
|
136
|
+
getContractPath(path) {
|
|
137
|
+
return path.startsWith(`./${this.contractsRootPath}`)
|
|
138
|
+
? path.slice(2)
|
|
139
|
+
: path.startsWith(this.contractsRootPath)
|
|
140
|
+
? path
|
|
141
|
+
: this.contractsRootPath + '/' + path;
|
|
142
|
+
}
|
|
143
|
+
static checkCompilerWarnings(warnings, compilerOptions) {
|
|
144
|
+
const remains = compilerOptions.ignoreUnusedConstantsWarnings
|
|
145
|
+
? warnings.filter((s) => !s.includes('unused constants'))
|
|
146
|
+
: warnings;
|
|
147
|
+
if (remains.length !== 0) {
|
|
148
|
+
const prefixPerWarning = ' - ';
|
|
149
|
+
const warningString = prefixPerWarning + remains.join('\n' + prefixPerWarning);
|
|
150
|
+
const output = 'Compilation warnings:\n' + warningString + '\n';
|
|
151
|
+
if (compilerOptions.errorOnWarnings) {
|
|
152
|
+
throw new Error(output);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(output);
|
|
122
156
|
}
|
|
123
157
|
}
|
|
124
|
-
return result;
|
|
125
158
|
}
|
|
126
|
-
static
|
|
127
|
-
const contractPath =
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
static contract(path, compilerOptions) {
|
|
160
|
+
const contractPath = Project.currentProject.getContractPath(path);
|
|
161
|
+
const contract = Project.currentProject.contracts.find((c) => c.sourceFile.contractPath === contractPath);
|
|
162
|
+
if (typeof contract === 'undefined') {
|
|
163
|
+
throw new Error(`Contract ${contractPath} does not exist`);
|
|
164
|
+
}
|
|
165
|
+
Project.checkCompilerWarnings(contract.warnings, { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptions });
|
|
166
|
+
return contract.artifact;
|
|
132
167
|
}
|
|
133
|
-
static
|
|
134
|
-
|
|
135
|
-
|
|
168
|
+
static script(path, compilerOptions) {
|
|
169
|
+
const contractPath = Project.currentProject.getContractPath(path);
|
|
170
|
+
const script = Project.currentProject.scripts.find((c) => c.sourceFile.contractPath === contractPath);
|
|
171
|
+
if (typeof script === 'undefined') {
|
|
172
|
+
throw new Error(`Script ${contractPath} does not exist`);
|
|
136
173
|
}
|
|
174
|
+
Project.checkCompilerWarnings(script.warnings, { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptions });
|
|
175
|
+
return script.artifact;
|
|
137
176
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
177
|
+
async saveArtifactsToFile() {
|
|
178
|
+
const artifactsRootPath = this.artifactsRootPath;
|
|
179
|
+
const saveToFile = async function (compiled) {
|
|
180
|
+
const artifactPath = compiled.sourceFile.getArtifactPath(artifactsRootPath);
|
|
181
|
+
const folder = artifactPath.slice(0, artifactPath.lastIndexOf('/'));
|
|
182
|
+
if (!fs_1.default.existsSync(folder)) {
|
|
183
|
+
fs_1.default.mkdirSync(folder, { recursive: true });
|
|
184
|
+
}
|
|
185
|
+
return fs_2.promises.writeFile(artifactPath, compiled.artifact.toString());
|
|
186
|
+
};
|
|
187
|
+
for (const contract of this.contracts) {
|
|
188
|
+
await saveToFile(contract);
|
|
145
189
|
}
|
|
146
|
-
|
|
147
|
-
|
|
190
|
+
for (const script of this.scripts) {
|
|
191
|
+
await saveToFile(script);
|
|
148
192
|
}
|
|
149
193
|
}
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
|
|
194
|
+
contractByCodeHash(codeHash) {
|
|
195
|
+
const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash);
|
|
196
|
+
if (typeof contract === 'undefined') {
|
|
197
|
+
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
154
198
|
}
|
|
155
|
-
return
|
|
199
|
+
return contract.artifact;
|
|
156
200
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
this.
|
|
201
|
+
async saveProjectArtifactToFile() {
|
|
202
|
+
const files = new Map();
|
|
203
|
+
this.contracts.forEach((c) => {
|
|
204
|
+
files.set(c.sourceFile.contractPath, {
|
|
205
|
+
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
206
|
+
warnings: c.warnings
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
this.scripts.forEach((s) => {
|
|
210
|
+
files.set(s.sourceFile.contractPath, {
|
|
211
|
+
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
212
|
+
warnings: s.warnings
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
const compiledSize = this.contracts.length + this.scripts.length;
|
|
216
|
+
this.sourceFiles.slice(compiledSize).forEach((c) => {
|
|
217
|
+
files.set(c.contractPath, {
|
|
218
|
+
sourceCodeHash: c.sourceCodeHash,
|
|
219
|
+
warnings: []
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
const projectArtifact = new ProjectArtifact(files);
|
|
223
|
+
await projectArtifact.saveToFile(this.artifactsRootPath);
|
|
172
224
|
}
|
|
173
|
-
static
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
225
|
+
static async compile(provider, files, contractsRootPath, artifactsRootPath) {
|
|
226
|
+
const sourceStr = files.map((f) => f.sourceCode).join('\n');
|
|
227
|
+
const result = await provider.contracts.postContractsCompileProject({
|
|
228
|
+
code: sourceStr
|
|
229
|
+
});
|
|
230
|
+
const contracts = [];
|
|
231
|
+
const scripts = [];
|
|
232
|
+
result.contracts.forEach((contractResult, index) => {
|
|
233
|
+
const sourceFile = files[`${index}`];
|
|
234
|
+
const contract = Contract.fromCompileResult(sourceFile.typeId, contractResult);
|
|
235
|
+
contracts.push(new Compiled(sourceFile, contract, contractResult.warnings));
|
|
236
|
+
});
|
|
237
|
+
result.scripts.forEach((scriptResult, index) => {
|
|
238
|
+
const sourceFile = files[index + contracts.length];
|
|
239
|
+
const script = Script.fromCompileResult(sourceFile.typeId, scriptResult);
|
|
240
|
+
scripts.push(new Compiled(sourceFile, script, scriptResult.warnings));
|
|
241
|
+
});
|
|
242
|
+
const project = new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts);
|
|
243
|
+
await project.saveArtifactsToFile();
|
|
244
|
+
await project.saveProjectArtifactToFile();
|
|
245
|
+
return project;
|
|
246
|
+
}
|
|
247
|
+
static async loadArtifacts(provider, files, projectArtifact, contractsRootPath, artifactsRootPath) {
|
|
248
|
+
try {
|
|
249
|
+
const contracts = [];
|
|
250
|
+
const scripts = [];
|
|
251
|
+
for (const file of files) {
|
|
252
|
+
const info = projectArtifact.infos.get(file.contractPath);
|
|
253
|
+
if (typeof info === 'undefined') {
|
|
254
|
+
throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`);
|
|
255
|
+
}
|
|
256
|
+
const warnings = info.warnings;
|
|
257
|
+
const artifactPath = file.getArtifactPath(artifactsRootPath);
|
|
258
|
+
if (file.type === SourceType.Contract) {
|
|
259
|
+
const artifact = await Contract.fromArtifactFile(artifactPath);
|
|
260
|
+
contracts.push(new Compiled(file, artifact, warnings));
|
|
261
|
+
}
|
|
262
|
+
else if (file.type === SourceType.Script) {
|
|
263
|
+
const artifact = await Script.fromArtifactFile(artifactPath);
|
|
264
|
+
scripts.push(new Compiled(file, artifact, warnings));
|
|
265
|
+
}
|
|
185
266
|
}
|
|
267
|
+
return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts);
|
|
186
268
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
269
|
+
catch (error) {
|
|
270
|
+
console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`);
|
|
271
|
+
return Project.compile(provider, files, contractsRootPath, artifactsRootPath);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
static async loadSourceFile(dirPath, filename) {
|
|
275
|
+
const contractPath = dirPath + '/' + filename;
|
|
276
|
+
if (!filename.endsWith('.ral')) {
|
|
277
|
+
throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`);
|
|
278
|
+
}
|
|
279
|
+
const sourceBuffer = await fs_2.promises.readFile(contractPath);
|
|
280
|
+
const sourceStr = sourceBuffer.toString();
|
|
281
|
+
const results = this.matchers.map((m) => m.match(sourceStr));
|
|
282
|
+
const matchNumber = results.reduce((a, b) => a + b, 0);
|
|
283
|
+
if (matchNumber === 0) {
|
|
284
|
+
throw new Error(`No contract defined in file: ${contractPath}`);
|
|
285
|
+
}
|
|
286
|
+
if (matchNumber > 1) {
|
|
287
|
+
throw new Error(`Multiple definitions in file: ${contractPath}`);
|
|
288
|
+
}
|
|
289
|
+
const matcherIndex = results.indexOf(1);
|
|
290
|
+
const matcher = this.matchers[`${matcherIndex}`];
|
|
291
|
+
const type = matcher.type;
|
|
292
|
+
if (matcher.name === undefined) {
|
|
293
|
+
throw new Error(`Invalid definition in file: ${contractPath}`);
|
|
294
|
+
}
|
|
295
|
+
return new SourceFile(type, matcher.name, sourceStr, contractPath);
|
|
296
|
+
}
|
|
297
|
+
static async loadSourceFiles(contractsRootPath) {
|
|
298
|
+
const loadDir = async function (dirPath, results) {
|
|
299
|
+
const dirents = await fs_2.promises.readdir(dirPath, { withFileTypes: true });
|
|
300
|
+
for (const dirent of dirents) {
|
|
301
|
+
if (dirent.isFile()) {
|
|
302
|
+
const file = await Project.loadSourceFile(dirPath, dirent.name);
|
|
303
|
+
results.push(file);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const newPath = dirPath + '/' + dirent.name;
|
|
307
|
+
await loadDir(newPath, results);
|
|
308
|
+
}
|
|
190
309
|
}
|
|
310
|
+
};
|
|
311
|
+
const sourceFiles = [];
|
|
312
|
+
await loadDir(contractsRootPath, sourceFiles);
|
|
313
|
+
const contractAndScriptSize = sourceFiles.filter((f) => f.type === SourceType.Contract || f.type === SourceType.Script).length;
|
|
314
|
+
if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
|
|
315
|
+
throw new Error('Project have no source files');
|
|
191
316
|
}
|
|
317
|
+
return sourceFiles.sort((a, b) => a.type - b.type);
|
|
192
318
|
}
|
|
193
|
-
static async
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
|
|
319
|
+
static async build(contractsRootPath = 'contracts', artifactsRootPath = 'artifacts') {
|
|
320
|
+
const provider = (0, global_1.getCurrentNodeProvider)();
|
|
321
|
+
const sourceFiles = await Project.loadSourceFiles(contractsRootPath);
|
|
322
|
+
const projectArtifact = await ProjectArtifact.from(artifactsRootPath);
|
|
323
|
+
if (typeof projectArtifact === 'undefined' || projectArtifact.sourceHasChanged(sourceFiles)) {
|
|
324
|
+
Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootPath, artifactsRootPath);
|
|
199
325
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
326
|
+
else {
|
|
327
|
+
Project.currentProject = await Project.loadArtifacts(provider, sourceFiles, projectArtifact, contractsRootPath, artifactsRootPath);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
exports.Project = Project;
|
|
332
|
+
Project.abstractContractMatcher = new TypedMatcher('^Abstract Contract ([A-Z][a-zA-Z0-9]*)\\(*', SourceType.AbstractContract);
|
|
333
|
+
Project.contractMatcher = new TypedMatcher('^Contract ([A-Z][a-zA-Z0-9]*)\\(*', SourceType.Contract);
|
|
334
|
+
Project.interfaceMatcher = new TypedMatcher('^Interface ([A-Z][a-zA-Z0-9]*) \\{', SourceType.Interface);
|
|
335
|
+
Project.scriptMatcher = new TypedMatcher('^TxScript ([A-Z][a-zA-Z0-9]*)( \\{*|\\(*)', SourceType.Script);
|
|
336
|
+
Project.matchers = [
|
|
337
|
+
Project.abstractContractMatcher,
|
|
338
|
+
Project.contractMatcher,
|
|
339
|
+
Project.interfaceMatcher,
|
|
340
|
+
Project.scriptMatcher
|
|
341
|
+
];
|
|
342
|
+
class Artifact {
|
|
343
|
+
constructor(typeId, functions) {
|
|
344
|
+
this.typeId = typeId;
|
|
345
|
+
this.functions = functions;
|
|
346
|
+
}
|
|
347
|
+
publicFunctions() {
|
|
348
|
+
return this.functions.filter((func) => func.isPublic).map((func) => func.name);
|
|
349
|
+
}
|
|
350
|
+
usingPreapprovedAssetsFunctions() {
|
|
351
|
+
return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name);
|
|
352
|
+
}
|
|
353
|
+
usingAssetsInContractFunctions() {
|
|
354
|
+
return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
|
|
204
355
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
356
|
+
}
|
|
357
|
+
exports.Artifact = Artifact;
|
|
358
|
+
class Contract extends Artifact {
|
|
359
|
+
constructor(typeId, bytecode, codeHash, fieldsSig, eventsSig, functions) {
|
|
360
|
+
super(typeId, functions);
|
|
361
|
+
this.bytecode = bytecode;
|
|
362
|
+
this.codeHash = codeHash;
|
|
363
|
+
this.fieldsSig = fieldsSig;
|
|
364
|
+
this.eventsSig = eventsSig;
|
|
210
365
|
}
|
|
211
366
|
// TODO: safely parse json
|
|
212
367
|
static fromJson(artifact) {
|
|
213
|
-
if (artifact.
|
|
214
|
-
artifact.bytecode == null ||
|
|
368
|
+
if (artifact.bytecode == null ||
|
|
215
369
|
artifact.codeHash == null ||
|
|
216
370
|
artifact.fieldsSig == null ||
|
|
217
371
|
artifact.eventsSig == null ||
|
|
218
372
|
artifact.functions == null) {
|
|
219
373
|
throw Error('The artifact JSON for contract is incomplete');
|
|
220
374
|
}
|
|
221
|
-
const contract = new Contract(artifact.
|
|
222
|
-
this._putArtifactToCache(contract);
|
|
375
|
+
const contract = new Contract(artifact.typeId, artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
|
|
223
376
|
return contract;
|
|
224
377
|
}
|
|
378
|
+
static fromCompileResult(typeId, result) {
|
|
379
|
+
return new Contract(typeId, result.bytecode, result.codeHash, result.fields, result.events, result.functions);
|
|
380
|
+
}
|
|
225
381
|
// support both 'code.ral' and 'code.ral.json'
|
|
226
382
|
static async fromArtifactFile(path) {
|
|
227
|
-
const
|
|
228
|
-
const artifactPath = sourceFile.artifactPath;
|
|
229
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
383
|
+
const content = await fs_2.promises.readFile(path);
|
|
230
384
|
const artifact = JSON.parse(content.toString());
|
|
231
385
|
return Contract.fromJson(artifact);
|
|
232
386
|
}
|
|
233
|
-
async fetchState(
|
|
234
|
-
const state = await
|
|
387
|
+
async fetchState(address, group) {
|
|
388
|
+
const state = await Project.currentProject.nodeProvider.contracts.getContractsAddressState(address, {
|
|
389
|
+
group: group
|
|
390
|
+
});
|
|
235
391
|
return this.fromApiContractState(state);
|
|
236
392
|
}
|
|
237
393
|
toString() {
|
|
238
|
-
|
|
239
|
-
|
|
394
|
+
const object = {
|
|
395
|
+
typeId: this.typeId,
|
|
240
396
|
bytecode: this.bytecode,
|
|
241
397
|
codeHash: this.codeHash,
|
|
242
398
|
fieldsSig: this.fieldsSig,
|
|
243
399
|
eventsSig: this.eventsSig,
|
|
244
400
|
functions: this.functions
|
|
245
|
-
}
|
|
401
|
+
};
|
|
402
|
+
return JSON.stringify(object, null, 2);
|
|
246
403
|
}
|
|
247
404
|
toState(fields, asset, address) {
|
|
248
405
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
|
|
@@ -261,11 +418,11 @@ class Contract extends Common {
|
|
|
261
418
|
bytes[0] = 3;
|
|
262
419
|
return utils_1.bs58.encode(bytes);
|
|
263
420
|
}
|
|
264
|
-
async _test(
|
|
421
|
+
async _test(funcName, params, expectPublic, accessType) {
|
|
265
422
|
const apiParams = this.toTestContract(funcName, params);
|
|
266
|
-
const apiResult = await
|
|
423
|
+
const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
|
|
267
424
|
const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
|
|
268
|
-
const isPublic = this.functions[`${methodIndex}`].
|
|
425
|
+
const isPublic = this.functions[`${methodIndex}`].isPublic;
|
|
269
426
|
if (isPublic === expectPublic) {
|
|
270
427
|
const result = await this.fromTestContractResult(methodIndex, apiResult);
|
|
271
428
|
return result;
|
|
@@ -274,11 +431,11 @@ class Contract extends Common {
|
|
|
274
431
|
throw new Error(`The test method ${funcName} is not ${accessType}`);
|
|
275
432
|
}
|
|
276
433
|
}
|
|
277
|
-
async testPublicMethod(
|
|
278
|
-
return this._test(
|
|
434
|
+
async testPublicMethod(funcName, params) {
|
|
435
|
+
return this._test(funcName, params, true, 'public');
|
|
279
436
|
}
|
|
280
|
-
async testPrivateMethod(
|
|
281
|
-
return this._test(
|
|
437
|
+
async testPrivateMethod(funcName, params) {
|
|
438
|
+
return this._test(funcName, params, false, 'private');
|
|
282
439
|
}
|
|
283
440
|
toApiFields(fields) {
|
|
284
441
|
if (typeof fields === 'undefined') {
|
|
@@ -319,30 +476,8 @@ class Contract extends Common {
|
|
|
319
476
|
inputAssets: toApiInputAssets(params.inputAssets)
|
|
320
477
|
};
|
|
321
478
|
}
|
|
322
|
-
static async fromCodeHash(codeHash) {
|
|
323
|
-
const cached = this._getArtifactFromCache(codeHash);
|
|
324
|
-
if (typeof cached !== 'undefined') {
|
|
325
|
-
return cached;
|
|
326
|
-
}
|
|
327
|
-
const files = await fs_2.promises.readdir(Common._artifactsFolder());
|
|
328
|
-
for (const file of files) {
|
|
329
|
-
if (file.endsWith('.ral.json')) {
|
|
330
|
-
try {
|
|
331
|
-
const contract = await Contract.fromArtifactFile(file);
|
|
332
|
-
if (contract.codeHash === codeHash) {
|
|
333
|
-
return contract;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
catch (_) { }
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
340
|
-
}
|
|
341
|
-
static async getFieldsSig(state) {
|
|
342
|
-
return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig);
|
|
343
|
-
}
|
|
344
479
|
async fromApiContractState(state) {
|
|
345
|
-
const contract =
|
|
480
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash);
|
|
346
481
|
return {
|
|
347
482
|
address: state.address,
|
|
348
483
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
|
|
@@ -350,7 +485,7 @@ class Contract extends Common {
|
|
|
350
485
|
initialStateHash: state.initialStateHash,
|
|
351
486
|
codeHash: state.codeHash,
|
|
352
487
|
fields: fromApiFields(state.fields, contract.fieldsSig),
|
|
353
|
-
fieldsSig:
|
|
488
|
+
fieldsSig: contract.fieldsSig,
|
|
354
489
|
asset: fromApiAsset(state.asset)
|
|
355
490
|
};
|
|
356
491
|
}
|
|
@@ -363,7 +498,7 @@ class Contract extends Common {
|
|
|
363
498
|
eventSig = this.ContractDestroyedEvent;
|
|
364
499
|
}
|
|
365
500
|
else {
|
|
366
|
-
const contract =
|
|
501
|
+
const contract = Project.currentProject.contractByCodeHash(codeHash);
|
|
367
502
|
eventSig = contract.eventsSig[event.eventIndex];
|
|
368
503
|
}
|
|
369
504
|
return {
|
|
@@ -424,71 +559,43 @@ class Contract extends Common {
|
|
|
424
559
|
exports.Contract = Contract;
|
|
425
560
|
Contract.ContractCreatedEvent = {
|
|
426
561
|
name: 'ContractCreated',
|
|
427
|
-
signature: 'event ContractCreated(address:Address)',
|
|
428
562
|
fieldNames: ['address'],
|
|
429
563
|
fieldTypes: ['Address']
|
|
430
564
|
};
|
|
431
565
|
Contract.ContractDestroyedEvent = {
|
|
432
566
|
name: 'ContractDestroyed',
|
|
433
|
-
signature: 'event ContractDestroyed(address:Address)',
|
|
434
567
|
fieldNames: ['address'],
|
|
435
568
|
fieldTypes: ['Address']
|
|
436
569
|
};
|
|
437
|
-
class Script extends
|
|
438
|
-
constructor(
|
|
439
|
-
super(
|
|
570
|
+
class Script extends Artifact {
|
|
571
|
+
constructor(typeId, bytecodeTemplate, fieldsSig, functions) {
|
|
572
|
+
super(typeId, functions);
|
|
440
573
|
this.bytecodeTemplate = bytecodeTemplate;
|
|
441
574
|
this.fieldsSig = fieldsSig;
|
|
442
575
|
}
|
|
443
|
-
static
|
|
444
|
-
|
|
445
|
-
if (scriptMatches === null) {
|
|
446
|
-
throw new Error(`No script found in: ${fileName}`);
|
|
447
|
-
}
|
|
448
|
-
else if (scriptMatches.length > 1) {
|
|
449
|
-
throw new Error(`Multiple scripts in: ${fileName}`);
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
static async loadContractStr(sourceFile) {
|
|
456
|
-
return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code));
|
|
457
|
-
}
|
|
458
|
-
static async fromSource(provider, path) {
|
|
459
|
-
const sourceFile = this.getSourceFile(path, []);
|
|
460
|
-
return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile);
|
|
461
|
-
}
|
|
462
|
-
static async compile(provider, sourceFile, scriptStr, contractHash) {
|
|
463
|
-
const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr });
|
|
464
|
-
const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions);
|
|
465
|
-
await artifact._saveToFile(sourceFile);
|
|
466
|
-
return artifact;
|
|
576
|
+
static fromCompileResult(typeId, result) {
|
|
577
|
+
return new Script(typeId, result.bytecodeTemplate, result.fields, result.functions);
|
|
467
578
|
}
|
|
468
579
|
// TODO: safely parse json
|
|
469
580
|
static fromJson(artifact) {
|
|
470
|
-
if (artifact.
|
|
471
|
-
artifact.bytecodeTemplate == null ||
|
|
472
|
-
artifact.fieldsSig == null ||
|
|
473
|
-
artifact.functions == null) {
|
|
581
|
+
if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
|
|
474
582
|
throw Error('The artifact JSON for script is incomplete');
|
|
475
583
|
}
|
|
476
|
-
return new Script(artifact.
|
|
584
|
+
return new Script(artifact.typeId, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
|
|
477
585
|
}
|
|
478
586
|
static async fromArtifactFile(path) {
|
|
479
|
-
const
|
|
480
|
-
const artifactPath = sourceFile.artifactPath;
|
|
481
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
587
|
+
const content = await fs_2.promises.readFile(path);
|
|
482
588
|
const artifact = JSON.parse(content.toString());
|
|
483
589
|
return this.fromJson(artifact);
|
|
484
590
|
}
|
|
485
591
|
toString() {
|
|
486
|
-
|
|
487
|
-
|
|
592
|
+
const object = {
|
|
593
|
+
typeId: this.typeId,
|
|
488
594
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
489
595
|
fieldsSig: this.fieldsSig,
|
|
490
596
|
functions: this.functions
|
|
491
|
-
}
|
|
597
|
+
};
|
|
598
|
+
return JSON.stringify(object, null, 2);
|
|
492
599
|
}
|
|
493
600
|
async paramsForDeployment(params) {
|
|
494
601
|
const signerParams = {
|
|
@@ -752,7 +859,7 @@ function toApiFields(fields, fieldsSig) {
|
|
|
752
859
|
return toApiVals(fields, fieldsSig.names, fieldsSig.types);
|
|
753
860
|
}
|
|
754
861
|
function toApiArgs(args, funcSig) {
|
|
755
|
-
return toApiVals(args, funcSig.
|
|
862
|
+
return toApiVals(args, funcSig.paramNames, funcSig.paramTypes);
|
|
756
863
|
}
|
|
757
864
|
function toApiVals(fields, names, types) {
|
|
758
865
|
return names.map((name, index) => {
|