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