@alephium/web3 0.2.0-rc.4 → 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.
@@ -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 = 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,284 @@ 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
+ 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;
65
+ }
66
+ }
50
67
  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
- }
68
+ constructor(type, sourceCode, contractPath) {
69
+ this.type = type;
70
+ this.sourceCode = sourceCode;
71
+ this.sourceCodeHash = cryptojs.SHA256(sourceCode).toString();
72
+ this.contractPath = contractPath;
73
+ }
74
+ getArtifactPath(artifactsRootPath) {
75
+ return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
62
76
  }
63
77
  }
64
- class Common {
65
- constructor(sourceCodeSha256, functions) {
66
- this.sourceCodeSha256 = sourceCodeSha256;
67
- this.functions = functions;
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;
68
88
  }
69
- static _getArtifactFromCache(codeHash) {
70
- return this._artifactCache.get(codeHash);
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);
71
93
  }
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);
94
+ sourceHasChanged(files) {
95
+ if (files.length !== this.infos.size) {
96
+ return true;
97
+ }
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;
102
+ }
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);
77
144
  }
78
- this._artifactCache.set(contract.codeHash, contract);
79
145
  }
80
146
  }
81
- static _artifactsFolder() {
82
- return './artifacts/';
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;
83
155
  }
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);
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`);
89
161
  }
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]);
162
+ Project.checkCompilerWarnings(script.warnings, errorOnWarnings, ignoreUnusedConstantsWarnings);
163
+ return script.artifact;
108
164
  }
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);
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 });
122
172
  }
173
+ return fs_2.promises.writeFile(artifactPath, compiled.artifact.toString());
174
+ };
175
+ for (const contract of this.contracts) {
176
+ await saveToFile(contract);
177
+ }
178
+ for (const script of this.scripts) {
179
+ await saveToFile(script);
123
180
  }
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
181
  }
133
- static checkFileNameExtension(fileName) {
134
- if (!fileName.endsWith('.ral')) {
135
- throw new Error('Smart contract file name should end with ".ral"');
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}`);
136
186
  }
187
+ return contract.artifact;
188
+ }
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);
212
+ }
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;
137
234
  }
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;
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
+ }
254
+ }
255
+ return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts);
145
256
  }
146
- else {
147
- return compile(provider, sourceFile, contractStr, contractHash, errorOnWarnings, ignoreUnusedConstantsWarnings);
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
+ }
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');
148
300
  }
301
+ return sourceFiles.sort((a, b) => a.type - b.type);
149
302
  }
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 });
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);
154
308
  }
155
- return fs_2.promises.writeFile(sourceFile.artifactPath, this.toString());
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;
156
328
  }
157
329
  publicFunctions() {
158
330
  return this.functions.filter((func) => func.isPublic).map((func) => func.name);
@@ -163,112 +335,52 @@ class Common {
163
335
  usingAssetsInContractFunctions() {
164
336
  return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
165
337
  }
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
338
  }
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);
339
+ exports.Artifact = Artifact;
340
+ class Contract extends Artifact {
341
+ constructor(bytecode, codeHash, fieldsSig, eventsSig, functions) {
342
+ super(functions);
193
343
  this.bytecode = bytecode;
194
344
  this.codeHash = codeHash;
195
345
  this.fieldsSig = fieldsSig;
196
346
  this.eventsSig = eventsSig;
197
347
  }
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
348
  // TODO: safely parse json
238
349
  static fromJson(artifact) {
239
- if (artifact.sourceCodeSha256 == null ||
240
- artifact.bytecode == null ||
350
+ if (artifact.bytecode == null ||
241
351
  artifact.codeHash == null ||
242
352
  artifact.fieldsSig == null ||
243
353
  artifact.eventsSig == null ||
244
354
  artifact.functions == null) {
245
355
  throw Error('The artifact JSON for contract is incomplete');
246
356
  }
247
- const contract = new Contract(artifact.sourceCodeSha256, artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
248
- this._putArtifactToCache(contract);
357
+ const contract = new Contract(artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
249
358
  return contract;
250
359
  }
360
+ static fromCompileResult(result) {
361
+ return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions);
362
+ }
251
363
  // support both 'code.ral' and 'code.ral.json'
252
364
  static async fromArtifactFile(path) {
253
- const sourceFile = this.getSourceFile(path, []);
254
- const artifactPath = sourceFile.artifactPath;
255
- const content = await fs_2.promises.readFile(artifactPath);
365
+ const content = await fs_2.promises.readFile(path);
256
366
  const artifact = JSON.parse(content.toString());
257
367
  return Contract.fromJson(artifact);
258
368
  }
259
- async fetchState(provider, address, group) {
260
- const state = await provider.contracts.getContractsAddressState(address, { group: group });
369
+ async fetchState(address, group) {
370
+ const state = await Project.currentProject.nodeProvider.contracts.getContractsAddressState(address, {
371
+ group: group
372
+ });
261
373
  return this.fromApiContractState(state);
262
374
  }
263
375
  toString() {
264
- return JSON.stringify({
265
- sourceCodeSha256: this.sourceCodeSha256,
376
+ const object = {
266
377
  bytecode: this.bytecode,
267
378
  codeHash: this.codeHash,
268
379
  fieldsSig: this.fieldsSig,
269
380
  eventsSig: this.eventsSig,
270
381
  functions: this.functions
271
- }, null, 2);
382
+ };
383
+ return JSON.stringify(object, null, 2);
272
384
  }
273
385
  toState(fields, asset, address) {
274
386
  const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
@@ -287,9 +399,9 @@ class Contract extends Common {
287
399
  bytes[0] = 3;
288
400
  return utils_1.bs58.encode(bytes);
289
401
  }
290
- async _test(provider, funcName, params, expectPublic, accessType) {
402
+ async _test(funcName, params, expectPublic, accessType) {
291
403
  const apiParams = this.toTestContract(funcName, params);
292
- const apiResult = await provider.contracts.postContractsTestContract(apiParams);
404
+ const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
293
405
  const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
294
406
  const isPublic = this.functions[`${methodIndex}`].isPublic;
295
407
  if (isPublic === expectPublic) {
@@ -300,11 +412,11 @@ class Contract extends Common {
300
412
  throw new Error(`The test method ${funcName} is not ${accessType}`);
301
413
  }
302
414
  }
303
- async testPublicMethod(provider, funcName, params) {
304
- return this._test(provider, funcName, params, true, 'public');
415
+ async testPublicMethod(funcName, params) {
416
+ return this._test(funcName, params, true, 'public');
305
417
  }
306
- async testPrivateMethod(provider, funcName, params) {
307
- return this._test(provider, funcName, params, false, 'private');
418
+ async testPrivateMethod(funcName, params) {
419
+ return this._test(funcName, params, false, 'private');
308
420
  }
309
421
  toApiFields(fields) {
310
422
  if (typeof fields === 'undefined') {
@@ -345,30 +457,8 @@ class Contract extends Common {
345
457
  inputAssets: toApiInputAssets(params.inputAssets)
346
458
  };
347
459
  }
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
460
  async fromApiContractState(state) {
371
- const contract = await Contract.fromCodeHash(state.codeHash);
461
+ const contract = Project.currentProject.contractByCodeHash(state.codeHash);
372
462
  return {
373
463
  address: state.address,
374
464
  contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
@@ -376,7 +466,7 @@ class Contract extends Common {
376
466
  initialStateHash: state.initialStateHash,
377
467
  codeHash: state.codeHash,
378
468
  fields: fromApiFields(state.fields, contract.fieldsSig),
379
- fieldsSig: await Contract.getFieldsSig(state),
469
+ fieldsSig: contract.fieldsSig,
380
470
  asset: fromApiAsset(state.asset)
381
471
  };
382
472
  }
@@ -389,7 +479,7 @@ class Contract extends Common {
389
479
  eventSig = this.ContractDestroyedEvent;
390
480
  }
391
481
  else {
392
- const contract = await Contract.fromCodeHash(codeHash);
482
+ const contract = Project.currentProject.contractByCodeHash(codeHash);
393
483
  eventSig = contract.eventsSig[event.eventIndex];
394
484
  }
395
485
  return {
@@ -458,62 +548,34 @@ Contract.ContractDestroyedEvent = {
458
548
  fieldNames: ['address'],
459
549
  fieldTypes: ['Address']
460
550
  };
461
- class Script extends Common {
462
- constructor(sourceCodeSha256, bytecodeTemplate, fieldsSig, functions) {
463
- super(sourceCodeSha256, functions);
551
+ class Script extends Artifact {
552
+ constructor(bytecodeTemplate, fieldsSig, functions) {
553
+ super(functions);
464
554
  this.bytecodeTemplate = bytecodeTemplate;
465
555
  this.fieldsSig = fieldsSig;
466
556
  }
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;
557
+ static fromCompileResult(result) {
558
+ return new Script(result.bytecodeTemplate, result.fields, result.functions);
492
559
  }
493
560
  // TODO: safely parse json
494
561
  static fromJson(artifact) {
495
- if (artifact.sourceCodeSha256 == null ||
496
- artifact.bytecodeTemplate == null ||
497
- artifact.fieldsSig == null ||
498
- artifact.functions == null) {
562
+ if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
499
563
  throw Error('The artifact JSON for script is incomplete');
500
564
  }
501
- return new Script(artifact.sourceCodeSha256, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
565
+ return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
502
566
  }
503
567
  static async fromArtifactFile(path) {
504
- const sourceFile = this.getSourceFile(path, []);
505
- const artifactPath = sourceFile.artifactPath;
506
- const content = await fs_2.promises.readFile(artifactPath);
568
+ const content = await fs_2.promises.readFile(path);
507
569
  const artifact = JSON.parse(content.toString());
508
570
  return this.fromJson(artifact);
509
571
  }
510
572
  toString() {
511
- return JSON.stringify({
512
- sourceCodeSha256: this.sourceCodeSha256,
573
+ const object = {
513
574
  bytecodeTemplate: this.bytecodeTemplate,
514
575
  fieldsSig: this.fieldsSig,
515
576
  functions: this.functions
516
- }, null, 2);
577
+ };
578
+ return JSON.stringify(object, null, 2);
517
579
  }
518
580
  async paramsForDeployment(params) {
519
581
  const signerParams = {
package/gitignore CHANGED
@@ -7,4 +7,3 @@ web/
7
7
  coverage/
8
8
  /dev/
9
9
  !dev/user.conf
10
- /artifacts/