@alephium/web3 0.2.0-rc.4 → 0.2.0-rc.7

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, ignoreUnusedConstantsWarnings) {
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, ignoreUnusedConstantsWarnings);
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,112 +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, ignoreUnusedConstantsWarnings) {
167
- const warnings = ignoreUnusedConstantsWarnings
168
- ? compiled.warnings.filter((s) => !s.includes('unused constants'))
169
- : compiled.warnings;
170
- if (warnings.length !== 0) {
171
- const prefixPerWarning = ' - ';
172
- const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning);
173
- const output = 'Compilation warnings:\n' + warningString + '\n';
174
- if (errorOnWarnings) {
175
- throw new Error(output);
176
- }
177
- else {
178
- console.log(output);
179
- }
180
- }
181
- }
182
344
  }
183
- exports.Common = Common;
184
- Common.importRegex = new RegExp('^import "([^"/]+/(([^"]+)/)?)?[a-z][a-z_0-9]*.ral"', 'mg');
185
- Common.contractRegex = new RegExp('^(Abstract[ ]+)?Contract [A-Z][a-zA-Z0-9]*', 'mg');
186
- Common.interfaceRegex = new RegExp('^Interface [A-Z][a-zA-Z0-9]* \\{', 'mg');
187
- Common.scriptRegex = new RegExp('^TxScript [A-Z][a-zA-Z0-9]*', 'mg');
188
- Common._artifactCache = new Map();
189
- Common.artifactCacheCapacity = 20;
190
- class Contract extends Common {
191
- constructor(sourceCodeSha256, bytecode, codeHash, fieldsSig, eventsSig, functions) {
192
- super(sourceCodeSha256, functions);
345
+ exports.Artifact = Artifact;
346
+ class Contract extends Artifact {
347
+ constructor(bytecode, codeHash, fieldsSig, eventsSig, functions) {
348
+ super(functions);
193
349
  this.bytecode = bytecode;
194
350
  this.codeHash = codeHash;
195
351
  this.fieldsSig = fieldsSig;
196
352
  this.eventsSig = eventsSig;
197
353
  }
198
- static checkCodeType(fileName, contractStr) {
199
- const interfaceMatches = contractStr.match(Contract.interfaceRegex);
200
- const contractMatches = contractStr.match(Contract.contractRegex);
201
- if (interfaceMatches === null && contractMatches === null) {
202
- throw new Error(`No contract found in: ${fileName}`);
203
- }
204
- if (interfaceMatches && contractMatches) {
205
- throw new Error(`Multiple contracts and interfaces in: ${fileName}`);
206
- }
207
- if (interfaceMatches === null) {
208
- if (contractMatches !== null && contractMatches.length > 1) {
209
- throw new Error(`Multiple contracts in: ${fileName}`);
210
- }
211
- }
212
- if (contractMatches === null) {
213
- if (interfaceMatches !== null && interfaceMatches.length > 1) {
214
- throw new Error(`Multiple interfaces in: ${fileName}`);
215
- }
216
- }
217
- }
218
- static async loadContractStr(sourceFile) {
219
- return Common._loadContractStr(sourceFile, [], (code) => Contract.checkCodeType(sourceFile.contractPath, code));
220
- }
221
- static async fromSource(provider, path, errorOnWarnings = true, ignoreUnusedConstantsWarnings = true) {
222
- if (!fs_1.default.existsSync(Common._artifactsFolder())) {
223
- fs_1.default.mkdirSync(Common._artifactsFolder(), { recursive: true });
224
- }
225
- const sourceFile = this.getSourceFile(path, []);
226
- const contract = await Common._from(provider, sourceFile, Contract.loadContractStr, Contract.compile, errorOnWarnings, ignoreUnusedConstantsWarnings);
227
- this._putArtifactToCache(contract);
228
- return contract;
229
- }
230
- static async compile(provider, sourceFile, contractStr, contractHash, errorOnWarnings, ignoreUnusedConstantsWarnings) {
231
- const compiled = await provider.contracts.postContractsCompileContract({ code: contractStr });
232
- Common.checkCompilerWarnings(compiled, errorOnWarnings, ignoreUnusedConstantsWarnings);
233
- const artifact = new Contract(contractHash, compiled.bytecode, compiled.codeHash, compiled.fields, compiled.events, compiled.functions);
234
- await artifact._saveToFile(sourceFile);
235
- return artifact;
236
- }
237
354
  // TODO: safely parse json
238
355
  static fromJson(artifact) {
239
- if (artifact.sourceCodeSha256 == null ||
240
- artifact.bytecode == null ||
356
+ if (artifact.bytecode == null ||
241
357
  artifact.codeHash == null ||
242
358
  artifact.fieldsSig == null ||
243
359
  artifact.eventsSig == null ||
244
360
  artifact.functions == null) {
245
361
  throw Error('The artifact JSON for contract is incomplete');
246
362
  }
247
- const contract = new Contract(artifact.sourceCodeSha256, artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
248
- this._putArtifactToCache(contract);
363
+ const contract = new Contract(artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
249
364
  return contract;
250
365
  }
366
+ static fromCompileResult(result) {
367
+ return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions);
368
+ }
251
369
  // support both 'code.ral' and 'code.ral.json'
252
370
  static async fromArtifactFile(path) {
253
- const sourceFile = this.getSourceFile(path, []);
254
- const artifactPath = sourceFile.artifactPath;
255
- const content = await fs_2.promises.readFile(artifactPath);
371
+ const content = await fs_2.promises.readFile(path);
256
372
  const artifact = JSON.parse(content.toString());
257
373
  return Contract.fromJson(artifact);
258
374
  }
259
- async fetchState(provider, address, group) {
260
- 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
+ });
261
379
  return this.fromApiContractState(state);
262
380
  }
263
381
  toString() {
264
- return JSON.stringify({
265
- sourceCodeSha256: this.sourceCodeSha256,
382
+ const object = {
266
383
  bytecode: this.bytecode,
267
384
  codeHash: this.codeHash,
268
385
  fieldsSig: this.fieldsSig,
269
386
  eventsSig: this.eventsSig,
270
387
  functions: this.functions
271
- }, null, 2);
388
+ };
389
+ return JSON.stringify(object, null, 2);
272
390
  }
273
391
  toState(fields, asset, address) {
274
392
  const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
@@ -287,9 +405,9 @@ class Contract extends Common {
287
405
  bytes[0] = 3;
288
406
  return utils_1.bs58.encode(bytes);
289
407
  }
290
- async _test(provider, funcName, params, expectPublic, accessType) {
408
+ async _test(funcName, params, expectPublic, accessType) {
291
409
  const apiParams = this.toTestContract(funcName, params);
292
- const apiResult = await provider.contracts.postContractsTestContract(apiParams);
410
+ const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
293
411
  const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
294
412
  const isPublic = this.functions[`${methodIndex}`].isPublic;
295
413
  if (isPublic === expectPublic) {
@@ -300,11 +418,11 @@ class Contract extends Common {
300
418
  throw new Error(`The test method ${funcName} is not ${accessType}`);
301
419
  }
302
420
  }
303
- async testPublicMethod(provider, funcName, params) {
304
- return this._test(provider, funcName, params, true, 'public');
421
+ async testPublicMethod(funcName, params) {
422
+ return this._test(funcName, params, true, 'public');
305
423
  }
306
- async testPrivateMethod(provider, funcName, params) {
307
- return this._test(provider, funcName, params, false, 'private');
424
+ async testPrivateMethod(funcName, params) {
425
+ return this._test(funcName, params, false, 'private');
308
426
  }
309
427
  toApiFields(fields) {
310
428
  if (typeof fields === 'undefined') {
@@ -345,30 +463,8 @@ class Contract extends Common {
345
463
  inputAssets: toApiInputAssets(params.inputAssets)
346
464
  };
347
465
  }
348
- static async fromCodeHash(codeHash) {
349
- const cached = this._getArtifactFromCache(codeHash);
350
- if (typeof cached !== 'undefined') {
351
- return cached;
352
- }
353
- const files = await fs_2.promises.readdir(Common._artifactsFolder());
354
- for (const file of files) {
355
- if (file.endsWith('.ral.json')) {
356
- try {
357
- const contract = await Contract.fromArtifactFile(file);
358
- if (contract.codeHash === codeHash) {
359
- return contract;
360
- }
361
- }
362
- catch (_) { }
363
- }
364
- }
365
- throw new Error(`Unknown code with code hash: ${codeHash}`);
366
- }
367
- static async getFieldsSig(state) {
368
- return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig);
369
- }
370
466
  async fromApiContractState(state) {
371
- const contract = await Contract.fromCodeHash(state.codeHash);
467
+ const contract = Project.currentProject.contractByCodeHash(state.codeHash);
372
468
  return {
373
469
  address: state.address,
374
470
  contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
@@ -376,7 +472,7 @@ class Contract extends Common {
376
472
  initialStateHash: state.initialStateHash,
377
473
  codeHash: state.codeHash,
378
474
  fields: fromApiFields(state.fields, contract.fieldsSig),
379
- fieldsSig: await Contract.getFieldsSig(state),
475
+ fieldsSig: contract.fieldsSig,
380
476
  asset: fromApiAsset(state.asset)
381
477
  };
382
478
  }
@@ -389,7 +485,7 @@ class Contract extends Common {
389
485
  eventSig = this.ContractDestroyedEvent;
390
486
  }
391
487
  else {
392
- const contract = await Contract.fromCodeHash(codeHash);
488
+ const contract = Project.currentProject.contractByCodeHash(codeHash);
393
489
  eventSig = contract.eventsSig[event.eventIndex];
394
490
  }
395
491
  return {
@@ -458,62 +554,34 @@ Contract.ContractDestroyedEvent = {
458
554
  fieldNames: ['address'],
459
555
  fieldTypes: ['Address']
460
556
  };
461
- class Script extends Common {
462
- constructor(sourceCodeSha256, bytecodeTemplate, fieldsSig, functions) {
463
- super(sourceCodeSha256, functions);
557
+ class Script extends Artifact {
558
+ constructor(bytecodeTemplate, fieldsSig, functions) {
559
+ super(functions);
464
560
  this.bytecodeTemplate = bytecodeTemplate;
465
561
  this.fieldsSig = fieldsSig;
466
562
  }
467
- static checkCodeType(fileName, contractStr) {
468
- const scriptMatches = contractStr.match(this.scriptRegex);
469
- if (scriptMatches === null) {
470
- throw new Error(`No script found in: ${fileName}`);
471
- }
472
- else if (scriptMatches.length > 1) {
473
- throw new Error(`Multiple scripts in: ${fileName}`);
474
- }
475
- else {
476
- return;
477
- }
478
- }
479
- static async loadContractStr(sourceFile) {
480
- return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code));
481
- }
482
- static async fromSource(provider, path, errorOnWarnings = true, ignoreUnusedConstantsWarnings = true) {
483
- const sourceFile = this.getSourceFile(path, []);
484
- return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile, errorOnWarnings, ignoreUnusedConstantsWarnings);
485
- }
486
- static async compile(provider, sourceFile, scriptStr, contractHash, errorOnWarnings = true, ignoreUnusedConstantsWarnings = true) {
487
- const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr });
488
- Common.checkCompilerWarnings(compiled, errorOnWarnings, ignoreUnusedConstantsWarnings);
489
- const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions);
490
- await artifact._saveToFile(sourceFile);
491
- return artifact;
563
+ static fromCompileResult(result) {
564
+ return new Script(result.bytecodeTemplate, result.fields, result.functions);
492
565
  }
493
566
  // TODO: safely parse json
494
567
  static fromJson(artifact) {
495
- if (artifact.sourceCodeSha256 == null ||
496
- artifact.bytecodeTemplate == null ||
497
- artifact.fieldsSig == null ||
498
- artifact.functions == null) {
568
+ if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
499
569
  throw Error('The artifact JSON for script is incomplete');
500
570
  }
501
- return new Script(artifact.sourceCodeSha256, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
571
+ return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
502
572
  }
503
573
  static async fromArtifactFile(path) {
504
- const sourceFile = this.getSourceFile(path, []);
505
- const artifactPath = sourceFile.artifactPath;
506
- const content = await fs_2.promises.readFile(artifactPath);
574
+ const content = await fs_2.promises.readFile(path);
507
575
  const artifact = JSON.parse(content.toString());
508
576
  return this.fromJson(artifact);
509
577
  }
510
578
  toString() {
511
- return JSON.stringify({
512
- sourceCodeSha256: this.sourceCodeSha256,
579
+ const object = {
513
580
  bytecodeTemplate: this.bytecodeTemplate,
514
581
  fieldsSig: this.fieldsSig,
515
582
  functions: this.functions
516
- }, null, 2);
583
+ };
584
+ return JSON.stringify(object, null, 2);
517
585
  }
518
586
  async paramsForDeployment(params) {
519
587
  const signerParams = {