@alephium/web3 0.2.0-rc.3 → 0.2.0-rc.6

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.
@@ -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.Common = void 0;
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,112 +47,290 @@ 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
+ 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
+ exports.DEFAULT_COMPILER_OPTIONS = {
58
+ errorOnWarnings: true,
59
+ ignoreUnusedConstantsWarnings: true
60
+ };
61
+ class TypedMatcher {
62
+ constructor(pattern, type) {
63
+ this.matcher = new RegExp(pattern, 'mg');
64
+ this.type = type;
65
+ }
66
+ match(str) {
67
+ const results = str.match(this.matcher);
68
+ return results === null ? 0 : results.length;
69
+ }
70
+ }
50
71
  class SourceFile {
51
- constructor(dirs, fileName) {
52
- this.dirs = dirs;
53
- this.dirPath = dirs.length === 0 ? '' : dirs.join('/') + '/';
54
- if (fileName.endsWith('.json')) {
55
- this.contractPath = './contracts/' + this.dirPath + fileName.slice(0, -5);
56
- this.artifactPath = './artifacts/' + this.dirPath + fileName;
57
- }
58
- else {
59
- this.contractPath = './contracts/' + this.dirPath + fileName;
60
- this.artifactPath = './artifacts/' + this.dirPath + fileName + '.json';
61
- }
72
+ constructor(type, sourceCode, contractPath) {
73
+ this.type = type;
74
+ this.sourceCode = sourceCode;
75
+ this.sourceCodeHash = cryptojs.SHA256(sourceCode).toString();
76
+ this.contractPath = contractPath;
77
+ }
78
+ getArtifactPath(artifactsRootPath) {
79
+ return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
62
80
  }
63
81
  }
64
- class Common {
65
- constructor(sourceCodeSha256, functions) {
66
- this.sourceCodeSha256 = sourceCodeSha256;
67
- this.functions = functions;
82
+ class Compiled {
83
+ constructor(sourceFile, artifact, warnings) {
84
+ this.sourceFile = sourceFile;
85
+ this.artifact = artifact;
86
+ this.warnings = warnings;
68
87
  }
69
- static _getArtifactFromCache(codeHash) {
70
- return this._artifactCache.get(codeHash);
88
+ }
89
+ class ProjectArtifact {
90
+ constructor(infos) {
91
+ this.infos = infos;
92
+ }
93
+ async saveToFile(rootPath) {
94
+ const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
95
+ const content = JSON.stringify(Object.fromEntries(this.infos), null, 2);
96
+ return fs_2.promises.writeFile(filepath, content);
71
97
  }
72
- static _putArtifactToCache(contract) {
73
- if (!this._artifactCache.has(contract.codeHash)) {
74
- if (this._artifactCache.size >= this.artifactCacheCapacity) {
75
- const keyToDelete = this._artifactCache.keys().next().value;
76
- this._artifactCache.delete(keyToDelete);
98
+ sourceHasChanged(files) {
99
+ if (files.length !== this.infos.size) {
100
+ return true;
101
+ }
102
+ for (const file of files) {
103
+ const info = this.infos.get(file.contractPath);
104
+ if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
105
+ return true;
106
+ }
107
+ }
108
+ return false;
109
+ }
110
+ static async from(rootPath) {
111
+ const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
112
+ if (!fs_1.default.existsSync(filepath)) {
113
+ return undefined;
114
+ }
115
+ const content = await fs_2.promises.readFile(filepath);
116
+ const files = new Map(Object.entries(JSON.parse(content.toString())));
117
+ return new ProjectArtifact(files);
118
+ }
119
+ }
120
+ ProjectArtifact.artifactFileName = '.project.json';
121
+ class Project {
122
+ constructor(provider, contractsRootPath, artifactsRootPath, sourceFiles, contracts, scripts) {
123
+ this.nodeProvider = provider;
124
+ this.contractsRootPath = contractsRootPath;
125
+ this.artifactsRootPath = artifactsRootPath;
126
+ this.sourceFiles = sourceFiles;
127
+ this.contracts = contracts;
128
+ this.scripts = scripts;
129
+ }
130
+ getContractPath(path) {
131
+ return path.startsWith(`./${this.contractsRootPath}`)
132
+ ? path.slice(2)
133
+ : path.startsWith(this.contractsRootPath)
134
+ ? path
135
+ : this.contractsRootPath + '/' + path;
136
+ }
137
+ static checkCompilerWarnings(warnings, compilerOptions) {
138
+ const remains = compilerOptions.ignoreUnusedConstantsWarnings
139
+ ? warnings.filter((s) => !s.includes('unused constants'))
140
+ : warnings;
141
+ if (remains.length !== 0) {
142
+ const prefixPerWarning = ' - ';
143
+ const warningString = prefixPerWarning + remains.join('\n' + prefixPerWarning);
144
+ const output = 'Compilation warnings:\n' + warningString + '\n';
145
+ if (compilerOptions.errorOnWarnings) {
146
+ throw new Error(output);
147
+ }
148
+ else {
149
+ console.log(output);
77
150
  }
78
- this._artifactCache.set(contract.codeHash, contract);
79
151
  }
80
152
  }
81
- static _artifactsFolder() {
82
- return './artifacts/';
153
+ static contract(path, compilerOptions) {
154
+ const contractPath = Project.currentProject.getContractPath(path);
155
+ const contract = Project.currentProject.contracts.find((c) => c.sourceFile.contractPath === contractPath);
156
+ if (typeof contract === 'undefined') {
157
+ throw new Error(`Contract ${contractPath} does not exist`);
158
+ }
159
+ Project.checkCompilerWarnings(contract.warnings, { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptions });
160
+ return contract.artifact;
83
161
  }
84
- static getSourceFile(path, _dirs) {
85
- const parts = path.split('/');
86
- const dirs = Array.from(_dirs);
87
- if (parts.length === 1) {
88
- return new SourceFile(dirs, path);
162
+ static script(path, compilerOptions) {
163
+ const contractPath = Project.currentProject.getContractPath(path);
164
+ const script = Project.currentProject.scripts.find((c) => c.sourceFile.contractPath === contractPath);
165
+ if (typeof script === 'undefined') {
166
+ throw new Error(`Script ${contractPath} does not exist`);
89
167
  }
90
- parts.slice(0, parts.length - 1).forEach((part) => {
91
- switch (part) {
92
- case '.': {
93
- break;
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
- }
105
- }
106
- });
107
- return new SourceFile(dirs, parts[parts.length - 1]);
168
+ Project.checkCompilerWarnings(script.warnings, { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptions });
169
+ return script.artifact;
108
170
  }
109
- static async _handleImports(pathes, contractStr, importsCache) {
110
- const localImportsCache = [];
111
- let result = contractStr.replace(Common.importRegex, (match) => {
112
- localImportsCache.push(match);
113
- return '';
114
- });
115
- for (const myImport of localImportsCache) {
116
- const relativePath = myImport.slice(8, -1);
117
- const importSourceFile = this.getSourceFile(relativePath, pathes);
118
- if (!importsCache.includes(importSourceFile.contractPath)) {
119
- importsCache.push(importSourceFile.contractPath);
120
- const importContractStr = await Common._loadContractStr(importSourceFile, importsCache, (code) => Contract.checkCodeType(importSourceFile.contractPath, code));
121
- result = result.concat('\n', importContractStr);
171
+ async saveArtifactsToFile() {
172
+ const artifactsRootPath = this.artifactsRootPath;
173
+ const saveToFile = async function (compiled) {
174
+ const artifactPath = compiled.sourceFile.getArtifactPath(artifactsRootPath);
175
+ const folder = artifactPath.slice(0, artifactPath.lastIndexOf('/'));
176
+ if (!fs_1.default.existsSync(folder)) {
177
+ fs_1.default.mkdirSync(folder, { recursive: true });
122
178
  }
179
+ return fs_2.promises.writeFile(artifactPath, compiled.artifact.toString());
180
+ };
181
+ for (const contract of this.contracts) {
182
+ await saveToFile(contract);
183
+ }
184
+ for (const script of this.scripts) {
185
+ await saveToFile(script);
123
186
  }
124
- return result;
125
- }
126
- static async _loadContractStr(sourceFile, importsCache, validate) {
127
- const contractPath = sourceFile.contractPath;
128
- const contractBuffer = await fs_2.promises.readFile(contractPath);
129
- const contractStr = contractBuffer.toString();
130
- validate(contractStr);
131
- return Common._handleImports(sourceFile.dirs, contractStr, importsCache);
132
187
  }
133
- static checkFileNameExtension(fileName) {
134
- if (!fileName.endsWith('.ral')) {
135
- throw new Error('Smart contract file name should end with ".ral"');
188
+ contractByCodeHash(codeHash) {
189
+ const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash);
190
+ if (typeof contract === 'undefined') {
191
+ throw new Error(`Unknown code with code hash: ${codeHash}`);
136
192
  }
193
+ return contract.artifact;
194
+ }
195
+ async saveProjectArtifactToFile() {
196
+ const files = new Map();
197
+ this.contracts.forEach((c) => {
198
+ files.set(c.sourceFile.contractPath, {
199
+ sourceCodeHash: c.sourceFile.sourceCodeHash,
200
+ warnings: c.warnings
201
+ });
202
+ });
203
+ this.scripts.forEach((s) => {
204
+ files.set(s.sourceFile.contractPath, {
205
+ sourceCodeHash: s.sourceFile.sourceCodeHash,
206
+ warnings: s.warnings
207
+ });
208
+ });
209
+ const compiledSize = this.contracts.length + this.scripts.length;
210
+ this.sourceFiles.slice(compiledSize).forEach((c) => {
211
+ files.set(c.contractPath, {
212
+ sourceCodeHash: c.sourceCodeHash,
213
+ warnings: []
214
+ });
215
+ });
216
+ const projectArtifact = new ProjectArtifact(files);
217
+ await projectArtifact.saveToFile(this.artifactsRootPath);
137
218
  }
138
- static async _from(provider, sourceFile, loadContractStr, compile, errorOnWarnings) {
139
- Common.checkFileNameExtension(sourceFile.contractPath);
140
- const contractStr = await loadContractStr(sourceFile, []);
141
- const contractHash = cryptojs.SHA256(contractStr).toString();
142
- const existingContract = this._getArtifactFromCache(contractHash);
143
- if (typeof existingContract !== 'undefined') {
144
- return existingContract;
219
+ static async compile(provider, files, contractsRootPath, artifactsRootPath) {
220
+ const sourceStr = files.map((f) => f.sourceCode).join('\n');
221
+ const result = await provider.contracts.postContractsCompileProject({
222
+ code: sourceStr
223
+ });
224
+ const contracts = [];
225
+ const scripts = [];
226
+ result.contracts.forEach((contractResult, index) => {
227
+ const sourceFile = files[`${index}`];
228
+ const contract = Contract.fromCompileResult(contractResult);
229
+ contracts.push(new Compiled(sourceFile, contract, contractResult.warnings));
230
+ });
231
+ result.scripts.forEach((scriptResult, index) => {
232
+ const sourceFile = files[index + contracts.length];
233
+ const script = Script.fromCompileResult(scriptResult);
234
+ scripts.push(new Compiled(sourceFile, script, scriptResult.warnings));
235
+ });
236
+ const project = new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts);
237
+ await project.saveArtifactsToFile();
238
+ await project.saveProjectArtifactToFile();
239
+ return project;
240
+ }
241
+ static async loadArtifacts(provider, files, projectArtifact, contractsRootPath, artifactsRootPath) {
242
+ try {
243
+ const contracts = [];
244
+ const scripts = [];
245
+ for (const file of files) {
246
+ const info = projectArtifact.infos.get(file.contractPath);
247
+ if (typeof info === 'undefined') {
248
+ throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`);
249
+ }
250
+ const warnings = info.warnings;
251
+ const artifactPath = file.getArtifactPath(artifactsRootPath);
252
+ if (file.type === SourceType.Contract) {
253
+ const artifact = await Contract.fromArtifactFile(artifactPath);
254
+ contracts.push(new Compiled(file, artifact, warnings));
255
+ }
256
+ else if (file.type === SourceType.Script) {
257
+ const artifact = await Script.fromArtifactFile(artifactPath);
258
+ scripts.push(new Compiled(file, artifact, warnings));
259
+ }
260
+ }
261
+ return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts);
145
262
  }
146
- else {
147
- return compile(provider, sourceFile, contractStr, contractHash, errorOnWarnings);
263
+ catch (error) {
264
+ console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`);
265
+ return Project.compile(provider, files, contractsRootPath, artifactsRootPath);
266
+ }
267
+ }
268
+ static async loadSourceFile(dirPath, filename) {
269
+ const contractPath = dirPath + '/' + filename;
270
+ if (!filename.endsWith('.ral')) {
271
+ throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`);
272
+ }
273
+ const sourceBuffer = await fs_2.promises.readFile(contractPath);
274
+ const sourceStr = sourceBuffer.toString();
275
+ const results = this.matchers.map((m) => m.match(sourceStr));
276
+ const matchNumber = results.reduce((a, b) => a + b, 0);
277
+ if (matchNumber === 0) {
278
+ throw new Error(`No contract defined in file: ${contractPath}`);
279
+ }
280
+ if (matchNumber > 1) {
281
+ throw new Error(`Multiple definitions in file: ${contractPath}`);
282
+ }
283
+ const matcherIndex = results.indexOf(1);
284
+ const type = this.matchers[`${matcherIndex}`].type;
285
+ return new SourceFile(type, sourceStr, contractPath);
286
+ }
287
+ static async loadSourceFiles(contractsRootPath) {
288
+ const loadDir = async function (dirPath, results) {
289
+ const dirents = await fs_2.promises.readdir(dirPath, { withFileTypes: true });
290
+ for (const dirent of dirents) {
291
+ if (dirent.isFile()) {
292
+ const file = await Project.loadSourceFile(dirPath, dirent.name);
293
+ results.push(file);
294
+ }
295
+ else {
296
+ const newPath = dirPath + '/' + dirent.name;
297
+ await loadDir(newPath, results);
298
+ }
299
+ }
300
+ };
301
+ const sourceFiles = [];
302
+ await loadDir(contractsRootPath, sourceFiles);
303
+ const contractAndScriptSize = sourceFiles.filter((f) => f.type === SourceType.Contract || f.type === SourceType.Script).length;
304
+ if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
305
+ throw new Error('Project have no source files');
148
306
  }
307
+ return sourceFiles.sort((a, b) => a.type - b.type);
149
308
  }
150
- _saveToFile(sourceFile) {
151
- const folder = Common._artifactsFolder() + sourceFile.dirPath;
152
- if (!fs_1.default.existsSync(folder)) {
153
- fs_1.default.mkdirSync(folder, { recursive: true });
309
+ static async build(provider, contractsRootPath = 'contracts', artifactsRootPath = 'artifacts') {
310
+ const sourceFiles = await Project.loadSourceFiles(contractsRootPath);
311
+ const projectArtifact = await ProjectArtifact.from(artifactsRootPath);
312
+ if (typeof projectArtifact === 'undefined' || projectArtifact.sourceHasChanged(sourceFiles)) {
313
+ Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootPath, artifactsRootPath);
154
314
  }
155
- return fs_2.promises.writeFile(sourceFile.artifactPath, this.toString());
315
+ else {
316
+ Project.currentProject = await Project.loadArtifacts(provider, sourceFiles, projectArtifact, contractsRootPath, artifactsRootPath);
317
+ }
318
+ }
319
+ }
320
+ exports.Project = Project;
321
+ Project.abstractContractMatcher = new TypedMatcher('^Abstract Contract [A-Z][a-zA-Z0-9]*', SourceType.AbstractContract);
322
+ Project.contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract);
323
+ Project.interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface);
324
+ Project.scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script);
325
+ Project.matchers = [
326
+ Project.abstractContractMatcher,
327
+ Project.contractMatcher,
328
+ Project.interfaceMatcher,
329
+ Project.scriptMatcher
330
+ ];
331
+ class Artifact {
332
+ constructor(functions) {
333
+ this.functions = functions;
156
334
  }
157
335
  publicFunctions() {
158
336
  return this.functions.filter((func) => func.isPublic).map((func) => func.name);
@@ -163,109 +341,52 @@ class Common {
163
341
  usingAssetsInContractFunctions() {
164
342
  return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
165
343
  }
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
344
  }
180
- exports.Common = Common;
181
- Common.importRegex = new RegExp('^import "([^"/]+/(([^"]+)/)?)?[a-z][a-z_0-9]*.ral"', 'mg');
182
- Common.contractRegex = new RegExp('^(Abstract[ ]+)?Contract [A-Z][a-zA-Z0-9]*', 'mg');
183
- Common.interfaceRegex = new RegExp('^Interface [A-Z][a-zA-Z0-9]* \\{', 'mg');
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);
345
+ exports.Artifact = Artifact;
346
+ class Contract extends Artifact {
347
+ constructor(bytecode, codeHash, fieldsSig, eventsSig, functions) {
348
+ super(functions);
190
349
  this.bytecode = bytecode;
191
350
  this.codeHash = codeHash;
192
351
  this.fieldsSig = fieldsSig;
193
352
  this.eventsSig = eventsSig;
194
353
  }
195
- static checkCodeType(fileName, contractStr) {
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;
233
- }
234
354
  // TODO: safely parse json
235
355
  static fromJson(artifact) {
236
- if (artifact.sourceCodeSha256 == null ||
237
- artifact.bytecode == null ||
356
+ if (artifact.bytecode == null ||
238
357
  artifact.codeHash == null ||
239
358
  artifact.fieldsSig == null ||
240
359
  artifact.eventsSig == null ||
241
360
  artifact.functions == null) {
242
361
  throw Error('The artifact JSON for contract is incomplete');
243
362
  }
244
- const contract = new Contract(artifact.sourceCodeSha256, artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
245
- this._putArtifactToCache(contract);
363
+ const contract = new Contract(artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
246
364
  return contract;
247
365
  }
366
+ static fromCompileResult(result) {
367
+ return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions);
368
+ }
248
369
  // support both 'code.ral' and 'code.ral.json'
249
370
  static async fromArtifactFile(path) {
250
- const sourceFile = this.getSourceFile(path, []);
251
- const artifactPath = sourceFile.artifactPath;
252
- const content = await fs_2.promises.readFile(artifactPath);
371
+ const content = await fs_2.promises.readFile(path);
253
372
  const artifact = JSON.parse(content.toString());
254
373
  return Contract.fromJson(artifact);
255
374
  }
256
- async fetchState(provider, address, group) {
257
- const state = await provider.contracts.getContractsAddressState(address, { group: group });
375
+ async fetchState(address, group) {
376
+ const state = await Project.currentProject.nodeProvider.contracts.getContractsAddressState(address, {
377
+ group: group
378
+ });
258
379
  return this.fromApiContractState(state);
259
380
  }
260
381
  toString() {
261
- return JSON.stringify({
262
- sourceCodeSha256: this.sourceCodeSha256,
382
+ const object = {
263
383
  bytecode: this.bytecode,
264
384
  codeHash: this.codeHash,
265
385
  fieldsSig: this.fieldsSig,
266
386
  eventsSig: this.eventsSig,
267
387
  functions: this.functions
268
- }, null, 2);
388
+ };
389
+ return JSON.stringify(object, null, 2);
269
390
  }
270
391
  toState(fields, asset, address) {
271
392
  const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
@@ -284,9 +405,9 @@ class Contract extends Common {
284
405
  bytes[0] = 3;
285
406
  return utils_1.bs58.encode(bytes);
286
407
  }
287
- async _test(provider, funcName, params, expectPublic, accessType) {
408
+ async _test(funcName, params, expectPublic, accessType) {
288
409
  const apiParams = this.toTestContract(funcName, params);
289
- const apiResult = await provider.contracts.postContractsTestContract(apiParams);
410
+ const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
290
411
  const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
291
412
  const isPublic = this.functions[`${methodIndex}`].isPublic;
292
413
  if (isPublic === expectPublic) {
@@ -297,11 +418,11 @@ class Contract extends Common {
297
418
  throw new Error(`The test method ${funcName} is not ${accessType}`);
298
419
  }
299
420
  }
300
- async testPublicMethod(provider, funcName, params) {
301
- return this._test(provider, funcName, params, true, 'public');
421
+ async testPublicMethod(funcName, params) {
422
+ return this._test(funcName, params, true, 'public');
302
423
  }
303
- async testPrivateMethod(provider, funcName, params) {
304
- return this._test(provider, funcName, params, false, 'private');
424
+ async testPrivateMethod(funcName, params) {
425
+ return this._test(funcName, params, false, 'private');
305
426
  }
306
427
  toApiFields(fields) {
307
428
  if (typeof fields === 'undefined') {
@@ -342,30 +463,8 @@ class Contract extends Common {
342
463
  inputAssets: toApiInputAssets(params.inputAssets)
343
464
  };
344
465
  }
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
466
  async fromApiContractState(state) {
368
- const contract = await Contract.fromCodeHash(state.codeHash);
467
+ const contract = Project.currentProject.contractByCodeHash(state.codeHash);
369
468
  return {
370
469
  address: state.address,
371
470
  contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
@@ -373,7 +472,7 @@ class Contract extends Common {
373
472
  initialStateHash: state.initialStateHash,
374
473
  codeHash: state.codeHash,
375
474
  fields: fromApiFields(state.fields, contract.fieldsSig),
376
- fieldsSig: await Contract.getFieldsSig(state),
475
+ fieldsSig: contract.fieldsSig,
377
476
  asset: fromApiAsset(state.asset)
378
477
  };
379
478
  }
@@ -386,7 +485,7 @@ class Contract extends Common {
386
485
  eventSig = this.ContractDestroyedEvent;
387
486
  }
388
487
  else {
389
- const contract = await Contract.fromCodeHash(codeHash);
488
+ const contract = Project.currentProject.contractByCodeHash(codeHash);
390
489
  eventSig = contract.eventsSig[event.eventIndex];
391
490
  }
392
491
  return {
@@ -455,62 +554,34 @@ Contract.ContractDestroyedEvent = {
455
554
  fieldNames: ['address'],
456
555
  fieldTypes: ['Address']
457
556
  };
458
- class Script extends Common {
459
- constructor(sourceCodeSha256, bytecodeTemplate, fieldsSig, functions) {
460
- super(sourceCodeSha256, functions);
557
+ class Script extends Artifact {
558
+ constructor(bytecodeTemplate, fieldsSig, functions) {
559
+ super(functions);
461
560
  this.bytecodeTemplate = bytecodeTemplate;
462
561
  this.fieldsSig = fieldsSig;
463
562
  }
464
- static checkCodeType(fileName, contractStr) {
465
- const scriptMatches = contractStr.match(this.scriptRegex);
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;
563
+ static fromCompileResult(result) {
564
+ return new Script(result.bytecodeTemplate, result.fields, result.functions);
489
565
  }
490
566
  // TODO: safely parse json
491
567
  static fromJson(artifact) {
492
- if (artifact.sourceCodeSha256 == null ||
493
- artifact.bytecodeTemplate == null ||
494
- artifact.fieldsSig == null ||
495
- artifact.functions == null) {
568
+ if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
496
569
  throw Error('The artifact JSON for script is incomplete');
497
570
  }
498
- return new Script(artifact.sourceCodeSha256, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
571
+ return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
499
572
  }
500
573
  static async fromArtifactFile(path) {
501
- const sourceFile = this.getSourceFile(path, []);
502
- const artifactPath = sourceFile.artifactPath;
503
- const content = await fs_2.promises.readFile(artifactPath);
574
+ const content = await fs_2.promises.readFile(path);
504
575
  const artifact = JSON.parse(content.toString());
505
576
  return this.fromJson(artifact);
506
577
  }
507
578
  toString() {
508
- return JSON.stringify({
509
- sourceCodeSha256: this.sourceCodeSha256,
579
+ const object = {
510
580
  bytecodeTemplate: this.bytecodeTemplate,
511
581
  fieldsSig: this.fieldsSig,
512
582
  functions: this.functions
513
- }, null, 2);
583
+ };
584
+ return JSON.stringify(object, null, 2);
514
585
  }
515
586
  async paramsForDeployment(params) {
516
587
  const signerParams = {
package/gitignore CHANGED
@@ -7,4 +7,3 @@ web/
7
7
  coverage/
8
8
  /dev/
9
9
  !dev/user.conf
10
- /artifacts/