@alephium/web3 0.2.0-rc.8 → 0.2.0-test.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/.eslintignore +2 -2
  2. package/.eslintrc.json +21 -0
  3. package/LICENSE +165 -0
  4. package/README.md +135 -2
  5. package/contracts/add/add.ral +13 -0
  6. package/contracts/greeter_main.ral +1 -1
  7. package/contracts/main.ral +4 -0
  8. package/contracts/sub/sub.ral +10 -0
  9. package/contracts/test/metadata.ral +18 -0
  10. package/contracts/test/warnings.ral +8 -0
  11. package/dist/alephium-web3.min.js +1 -1
  12. package/dist/alephium-web3.min.js.LICENSE.txt +17 -0
  13. package/dist/alephium-web3.min.js.map +1 -1
  14. package/dist/scripts/create-project.js +1 -1
  15. package/dist/src/api/api-alephium.d.ts +6 -19
  16. package/dist/src/api/api-explorer.d.ts +16 -16
  17. package/dist/src/api/index.js +1 -5
  18. package/dist/src/contract/contract.d.ts +16 -31
  19. package/dist/src/contract/contract.js +96 -123
  20. package/dist/src/contract/index.js +1 -5
  21. package/dist/src/index.d.ts +0 -1
  22. package/dist/src/index.js +1 -19
  23. package/dist/src/signer/index.d.ts +1 -0
  24. package/dist/src/signer/index.js +2 -5
  25. package/dist/src/signer/node-wallet.d.ts +11 -0
  26. package/dist/src/signer/node-wallet.js +57 -0
  27. package/dist/src/signer/signer.js +1 -5
  28. package/dist/src/test/index.d.ts +6 -0
  29. package/dist/src/test/index.js +41 -0
  30. package/dist/src/test/privatekey-wallet.d.ts +11 -0
  31. package/dist/src/test/privatekey-wallet.js +68 -0
  32. package/dist/src/transaction/index.d.ts +1 -0
  33. package/dist/src/transaction/index.js +2 -5
  34. package/dist/src/transaction/sign-verify.d.ts +2 -0
  35. package/dist/src/transaction/sign-verify.js +58 -0
  36. package/dist/src/utils/index.d.ts +1 -0
  37. package/dist/src/utils/index.js +2 -5
  38. package/dist/src/utils/password-crypto.d.ts +2 -0
  39. package/dist/src/utils/password-crypto.js +69 -0
  40. package/dist/src/utils/utils.d.ts +2 -3
  41. package/dist/src/utils/utils.js +15 -16
  42. package/gitignore +9 -0
  43. package/package.json +32 -6
  44. package/scripts/create-project.ts +1 -1
  45. package/src/api/api-alephium.ts +0 -14
  46. package/src/contract/contract.ts +102 -176
  47. package/src/contract/ralph.test.ts +178 -0
  48. package/src/fixtures/address.json +36 -0
  49. package/src/fixtures/balance.json +9 -0
  50. package/src/fixtures/self-clique.json +19 -0
  51. package/src/fixtures/transaction.json +13 -0
  52. package/src/fixtures/transactions.json +179 -0
  53. package/src/index.ts +0 -2
  54. package/src/signer/fixtures/genesis.json +26 -0
  55. package/src/signer/fixtures/wallets.json +26 -0
  56. package/src/signer/index.ts +1 -0
  57. package/src/signer/node-wallet.ts +65 -0
  58. package/src/test/index.ts +31 -0
  59. package/src/test/privatekey-wallet.ts +57 -0
  60. package/src/transaction/index.ts +1 -0
  61. package/src/transaction/sign-verify.test.ts +50 -0
  62. package/src/transaction/sign-verify.ts +39 -0
  63. package/src/utils/address.test.ts +47 -0
  64. package/src/utils/djb2.test.ts +35 -0
  65. package/src/utils/index.ts +1 -0
  66. package/src/utils/password-crypto.test.ts +27 -0
  67. package/src/utils/password-crypto.ts +77 -0
  68. package/src/utils/utils.test.ts +161 -0
  69. package/src/utils/utils.ts +7 -7
  70. package/templates/base/package.json +1 -1
  71. package/templates/react/package.json +1 -1
  72. package/test/contract.test.ts +213 -0
  73. package/test/events.test.ts +141 -0
  74. package/test/transaction.test.ts +73 -0
  75. package/jest-config.json +0 -11
@@ -17,7 +17,8 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
 
19
19
  import { Buffer } from 'buffer/'
20
- import { webcrypto as crypto } from 'crypto'
20
+ import * as cryptojs from 'crypto-js'
21
+ import * as crypto from 'crypto'
21
22
  import fs from 'fs'
22
23
  import { promises as fsPromises } from 'fs'
23
24
  import { node, NodeProvider } from '../api'
@@ -38,38 +39,39 @@ enum SourceType {
38
39
  Interface = 3
39
40
  }
40
41
 
41
- export type CompilerOptions = node.CompilerOptions & {
42
+ export type CompilerOptions = {
42
43
  errorOnWarnings: boolean
44
+ ignoreUnusedConstantsWarnings: boolean
43
45
  }
44
46
 
45
- export const DEFAULT_NODE_COMPILER_OPTIONS: node.CompilerOptions = {
46
- ignoreUnusedConstantsWarnings: false,
47
- ignoreUnusedVariablesWarnings: false,
48
- ignoreUnusedFieldsWarnings: false,
49
- ignoreUnusedPrivateFunctionsWarnings: false,
50
- ignoreReadonlyCheckWarnings: false,
51
- ignoreExternalCallCheckWarnings: false
47
+ export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = {
48
+ errorOnWarnings: true,
49
+ ignoreUnusedConstantsWarnings: true
52
50
  }
53
51
 
54
- export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = { errorOnWarnings: true, ...DEFAULT_NODE_COMPILER_OPTIONS }
55
-
56
52
  class TypedMatcher<T extends SourceType> {
57
53
  matcher: RegExp
58
54
  type: T
55
+ name: string | undefined
59
56
 
60
57
  constructor(pattern: string, type: T) {
61
58
  this.matcher = new RegExp(pattern, 'mg')
62
59
  this.type = type
60
+ this.name = undefined
63
61
  }
64
62
 
65
63
  match(str: string): number {
66
- const results = str.match(this.matcher)
67
- return results === null ? 0 : results.length
64
+ const results = [...str.matchAll(this.matcher)]
65
+ if (results.length > 0) {
66
+ this.name = results[0][1]
67
+ }
68
+ return results.length
68
69
  }
69
70
  }
70
71
 
71
72
  class SourceFile {
72
73
  type: SourceType
74
+ typeId: string
73
75
  contractPath: string
74
76
  sourceCode: string
75
77
  sourceCodeHash: string
@@ -78,17 +80,13 @@ class SourceFile {
78
80
  return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json'
79
81
  }
80
82
 
81
- constructor(type: SourceType, sourceCode: string, sourceCodeHash: string, contractPath: string) {
83
+ constructor(type: SourceType, typeId: string, sourceCode: string, contractPath: string) {
82
84
  this.type = type
85
+ this.typeId = typeId
83
86
  this.sourceCode = sourceCode
84
- this.sourceCodeHash = sourceCodeHash
87
+ this.sourceCodeHash = cryptojs.SHA256(sourceCode).toString()
85
88
  this.contractPath = contractPath
86
89
  }
87
-
88
- static async from(type: SourceType, sourceCode: string, contractPath: string): Promise<SourceFile> {
89
- const sourceCodeHash = await crypto.subtle.digest('SHA-256', Buffer.from(sourceCode))
90
- return new SourceFile(type, sourceCode, Buffer.from(sourceCodeHash).toString('hex'), contractPath)
91
- }
92
90
  }
93
91
 
94
92
  class Compiled<T extends Artifact> {
@@ -106,47 +104,19 @@ class Compiled<T extends Artifact> {
106
104
  class ProjectArtifact {
107
105
  static readonly artifactFileName = '.project.json'
108
106
 
109
- compilerOptionsUsed: node.CompilerOptions
110
107
  infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
111
108
 
112
- static checkCompilerOptionsParameter(compilerOptions: node.CompilerOptions): void {
113
- if (Object.keys(compilerOptions).length != Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
114
- throw Error(`Not all compiler options are set: ${compilerOptions}`)
115
- }
116
-
117
- const combined = { ...compilerOptions, ...DEFAULT_NODE_COMPILER_OPTIONS }
118
- if (Object.keys(combined).length !== Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
119
- throw Error(`There are unknown compiler options: ${compilerOptions}`)
120
- }
121
- }
122
-
123
- constructor(
124
- compilerOptionsUsed: node.CompilerOptions,
125
- infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
126
- ) {
127
- ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed)
128
- this.compilerOptionsUsed = compilerOptionsUsed
109
+ constructor(infos: Map<string, { sourceCodeHash: string; warnings: string[] }>) {
129
110
  this.infos = infos
130
111
  }
131
112
 
132
113
  async saveToFile(rootPath: string): Promise<void> {
133
114
  const filepath = rootPath + '/' + ProjectArtifact.artifactFileName
134
- const artifact = { compilerOptionsUsed: this.compilerOptionsUsed, infos: Object.fromEntries(this.infos) }
135
- const content = JSON.stringify(artifact, null, 2)
115
+ const content = JSON.stringify(Object.fromEntries(this.infos), null, 2)
136
116
  return fsPromises.writeFile(filepath, content)
137
117
  }
138
118
 
139
- needToReCompile(compilerOptions: node.CompilerOptions, files: SourceFile[]): boolean {
140
- ProjectArtifact.checkCompilerOptionsParameter(compilerOptions)
141
-
142
- const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
143
- const usedOption = this.compilerOptionsUsed[`${key}`]
144
- return usedOption === inputOption
145
- })
146
- if (!optionsMatched) {
147
- return true
148
- }
149
-
119
+ sourceHasChanged(files: SourceFile[]): boolean {
150
120
  if (files.length !== this.infos.size) {
151
121
  return true
152
122
  }
@@ -156,7 +126,6 @@ class ProjectArtifact {
156
126
  return true
157
127
  }
158
128
  }
159
-
160
129
  return false
161
130
  }
162
131
 
@@ -166,10 +135,10 @@ class ProjectArtifact {
166
135
  return undefined
167
136
  }
168
137
  const content = await fsPromises.readFile(filepath)
169
- const json = JSON.parse(content.toString())
170
- const compilerOptionsUsed = json.compilerOptionsUsed as node.CompilerOptions
171
- const files = new Map(Object.entries<{ sourceCodeHash: string; warnings: string[] }>(json.infos))
172
- return new ProjectArtifact(compilerOptionsUsed, files)
138
+ const files = new Map(
139
+ Object.entries<{ sourceCodeHash: string; warnings: string[] }>(JSON.parse(content.toString()))
140
+ )
141
+ return new ProjectArtifact(files)
173
142
  }
174
143
  }
175
144
 
@@ -177,7 +146,6 @@ export class Project {
177
146
  sourceFiles: SourceFile[]
178
147
  contracts: Compiled<Contract>[]
179
148
  scripts: Compiled<Script>[]
180
- projectArtifact: ProjectArtifact
181
149
 
182
150
  readonly contractsRootPath: string
183
151
  readonly artifactsRootPath: string
@@ -186,12 +154,12 @@ export class Project {
186
154
  static currentProject: Project
187
155
 
188
156
  static readonly abstractContractMatcher = new TypedMatcher<SourceType>(
189
- '^Abstract Contract [A-Z][a-zA-Z0-9]*',
157
+ '^Abstract Contract ([A-Z][a-zA-Z0-9]*)\\(*',
190
158
  SourceType.AbstractContract
191
159
  )
192
- static readonly contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract)
193
- static readonly interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface)
194
- static readonly scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script)
160
+ static readonly contractMatcher = new TypedMatcher('^Contract ([A-Z][a-zA-Z0-9]*)\\(*', SourceType.Contract)
161
+ static readonly interfaceMatcher = new TypedMatcher('^Interface ([A-Z][a-zA-Z0-9]*) \\{', SourceType.Interface)
162
+ static readonly scriptMatcher = new TypedMatcher('^TxScript ([A-Z][a-zA-Z0-9]*)( \\{*|\\(*)', SourceType.Script)
195
163
  static readonly matchers = [
196
164
  Project.abstractContractMatcher,
197
165
  Project.contractMatcher,
@@ -199,44 +167,13 @@ export class Project {
199
167
  Project.scriptMatcher
200
168
  ]
201
169
 
202
- static buildProjectArtifact(
203
- sourceFiles: SourceFile[],
204
- contracts: Compiled<Contract>[],
205
- scripts: Compiled<Script>[],
206
- compilerOptions: node.CompilerOptions
207
- ): ProjectArtifact {
208
- const files: Map<string, { sourceCodeHash: string; warnings: string[] }> = new Map()
209
- contracts.forEach((c) => {
210
- files.set(c.sourceFile.contractPath, {
211
- sourceCodeHash: c.sourceFile.sourceCodeHash,
212
- warnings: c.warnings
213
- })
214
- })
215
- scripts.forEach((s) => {
216
- files.set(s.sourceFile.contractPath, {
217
- sourceCodeHash: s.sourceFile.sourceCodeHash,
218
- warnings: s.warnings
219
- })
220
- })
221
- const compiledSize = contracts.length + scripts.length
222
- sourceFiles.slice(compiledSize).forEach((c) => {
223
- files.set(c.contractPath, {
224
- sourceCodeHash: c.sourceCodeHash,
225
- warnings: []
226
- })
227
- })
228
- return new ProjectArtifact(compilerOptions, files)
229
- }
230
-
231
170
  private constructor(
232
171
  provider: NodeProvider,
233
172
  contractsRootPath: string,
234
173
  artifactsRootPath: string,
235
174
  sourceFiles: SourceFile[],
236
175
  contracts: Compiled<Contract>[],
237
- scripts: Compiled<Script>[],
238
- errorOnWarnings: boolean,
239
- projectArtifact: ProjectArtifact
176
+ scripts: Compiled<Script>[]
240
177
  ) {
241
178
  this.nodeProvider = provider
242
179
  this.contractsRootPath = contractsRootPath
@@ -244,14 +181,6 @@ export class Project {
244
181
  this.sourceFiles = sourceFiles
245
182
  this.contracts = contracts
246
183
  this.scripts = scripts
247
- this.projectArtifact = projectArtifact
248
-
249
- if (errorOnWarnings) {
250
- Project.checkCompilerWarnings(
251
- [...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()],
252
- errorOnWarnings
253
- )
254
- }
255
184
  }
256
185
 
257
186
  private getContractPath(path: string): string {
@@ -262,12 +191,15 @@ export class Project {
262
191
  : this.contractsRootPath + '/' + path
263
192
  }
264
193
 
265
- static checkCompilerWarnings(warnings: string[], errorOnWarnings: boolean): void {
266
- if (warnings.length !== 0) {
194
+ private static checkCompilerWarnings(warnings: string[], compilerOptions: CompilerOptions): void {
195
+ const remains = compilerOptions.ignoreUnusedConstantsWarnings
196
+ ? warnings.filter((s) => !s.includes('unused constants'))
197
+ : warnings
198
+ if (remains.length !== 0) {
267
199
  const prefixPerWarning = ' - '
268
- const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning)
269
- const output = `Compilation warnings:\n` + warningString + '\n'
270
- if (errorOnWarnings) {
200
+ const warningString = prefixPerWarning + remains.join('\n' + prefixPerWarning)
201
+ const output = 'Compilation warnings:\n' + warningString + '\n'
202
+ if (compilerOptions.errorOnWarnings) {
271
203
  throw new Error(output)
272
204
  } else {
273
205
  console.log(output)
@@ -275,21 +207,23 @@ export class Project {
275
207
  }
276
208
  }
277
209
 
278
- static contract(path: string): Contract {
210
+ static contract(path: string, compilerOptions?: Partial<CompilerOptions>): Contract {
279
211
  const contractPath = Project.currentProject.getContractPath(path)
280
212
  const contract = Project.currentProject.contracts.find((c) => c.sourceFile.contractPath === contractPath)
281
213
  if (typeof contract === 'undefined') {
282
214
  throw new Error(`Contract ${contractPath} does not exist`)
283
215
  }
216
+ Project.checkCompilerWarnings(contract.warnings, { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptions })
284
217
  return contract.artifact
285
218
  }
286
219
 
287
- static script(path: string): Script {
220
+ static script(path: string, compilerOptions?: Partial<CompilerOptions>): Script {
288
221
  const contractPath = Project.currentProject.getContractPath(path)
289
222
  const script = Project.currentProject.scripts.find((c) => c.sourceFile.contractPath === contractPath)
290
223
  if (typeof script === 'undefined') {
291
224
  throw new Error(`Script ${contractPath} does not exist`)
292
225
  }
226
+ Project.checkCompilerWarnings(script.warnings, { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptions })
293
227
  return script.artifact
294
228
  }
295
229
 
@@ -309,7 +243,6 @@ export class Project {
309
243
  for (const script of this.scripts) {
310
244
  await saveToFile(script)
311
245
  }
312
- await this.projectArtifact.saveToFile(this.artifactsRootPath)
313
246
  }
314
247
 
315
248
  contractByCodeHash(codeHash: string): Contract {
@@ -320,43 +253,56 @@ export class Project {
320
253
  return contract.artifact
321
254
  }
322
255
 
256
+ private async saveProjectArtifactToFile(): Promise<void> {
257
+ const files: Map<string, { sourceCodeHash: string; warnings: string[] }> = new Map()
258
+ this.contracts.forEach((c) => {
259
+ files.set(c.sourceFile.contractPath, {
260
+ sourceCodeHash: c.sourceFile.sourceCodeHash,
261
+ warnings: c.warnings
262
+ })
263
+ })
264
+ this.scripts.forEach((s) => {
265
+ files.set(s.sourceFile.contractPath, {
266
+ sourceCodeHash: s.sourceFile.sourceCodeHash,
267
+ warnings: s.warnings
268
+ })
269
+ })
270
+ const compiledSize = this.contracts.length + this.scripts.length
271
+ this.sourceFiles.slice(compiledSize).forEach((c) => {
272
+ files.set(c.contractPath, {
273
+ sourceCodeHash: c.sourceCodeHash,
274
+ warnings: []
275
+ })
276
+ })
277
+ const projectArtifact = new ProjectArtifact(files)
278
+ await projectArtifact.saveToFile(this.artifactsRootPath)
279
+ }
280
+
323
281
  private static async compile(
324
282
  provider: NodeProvider,
325
283
  files: SourceFile[],
326
284
  contractsRootPath: string,
327
- artifactsRootPath: string,
328
- errorOnWarnings: boolean,
329
- compilerOptions: node.CompilerOptions
285
+ artifactsRootPath: string
330
286
  ): Promise<Project> {
331
287
  const sourceStr = files.map((f) => f.sourceCode).join('\n')
332
288
  const result = await provider.contracts.postContractsCompileProject({
333
- code: sourceStr,
334
- compilerOptions: compilerOptions
289
+ code: sourceStr
335
290
  })
336
291
  const contracts: Compiled<Contract>[] = []
337
292
  const scripts: Compiled<Script>[] = []
338
293
  result.contracts.forEach((contractResult, index) => {
339
294
  const sourceFile = files[`${index}`]
340
- const contract = Contract.fromCompileResult(contractResult)
295
+ const contract = Contract.fromCompileResult(sourceFile.typeId, contractResult)
341
296
  contracts.push(new Compiled(sourceFile, contract, contractResult.warnings))
342
297
  })
343
298
  result.scripts.forEach((scriptResult, index) => {
344
299
  const sourceFile = files[index + contracts.length]
345
- const script = Script.fromCompileResult(scriptResult)
300
+ const script = Script.fromCompileResult(sourceFile.typeId, scriptResult)
346
301
  scripts.push(new Compiled(sourceFile, script, scriptResult.warnings))
347
302
  })
348
- const projectArtifact = Project.buildProjectArtifact(files, contracts, scripts, compilerOptions)
349
- const project = new Project(
350
- provider,
351
- contractsRootPath,
352
- artifactsRootPath,
353
- files,
354
- contracts,
355
- scripts,
356
- errorOnWarnings,
357
- projectArtifact
358
- )
303
+ const project = new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts)
359
304
  await project.saveArtifactsToFile()
305
+ await project.saveProjectArtifactToFile()
360
306
  return project
361
307
  }
362
308
 
@@ -365,9 +311,7 @@ export class Project {
365
311
  files: SourceFile[],
366
312
  projectArtifact: ProjectArtifact,
367
313
  contractsRootPath: string,
368
- artifactsRootPath: string,
369
- errorOnWarnings: boolean,
370
- compilerOptions: node.CompilerOptions
314
+ artifactsRootPath: string
371
315
  ): Promise<Project> {
372
316
  try {
373
317
  const contracts: Compiled<Contract>[] = []
@@ -387,20 +331,10 @@ export class Project {
387
331
  scripts.push(new Compiled(file, artifact, warnings))
388
332
  }
389
333
  }
390
-
391
- return new Project(
392
- provider,
393
- contractsRootPath,
394
- artifactsRootPath,
395
- files,
396
- contracts,
397
- scripts,
398
- errorOnWarnings,
399
- projectArtifact
400
- )
334
+ return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts)
401
335
  } catch (error) {
402
336
  console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`)
403
- return Project.compile(provider, files, contractsRootPath, artifactsRootPath, errorOnWarnings, compilerOptions)
337
+ return Project.compile(provider, files, contractsRootPath, artifactsRootPath)
404
338
  }
405
339
  }
406
340
 
@@ -421,8 +355,12 @@ export class Project {
421
355
  throw new Error(`Multiple definitions in file: ${contractPath}`)
422
356
  }
423
357
  const matcherIndex = results.indexOf(1)
424
- const type = this.matchers[`${matcherIndex}`].type
425
- return SourceFile.from(type, sourceStr, contractPath)
358
+ const matcher = this.matchers[`${matcherIndex}`]
359
+ const type = matcher.type
360
+ if (matcher.name === undefined) {
361
+ throw new Error(`Invalid definition in file: ${contractPath}`)
362
+ }
363
+ return new SourceFile(type, matcher.name, sourceStr, contractPath)
426
364
  }
427
365
 
428
366
  private static async loadSourceFiles(contractsRootPath: string): Promise<SourceFile[]> {
@@ -449,44 +387,30 @@ export class Project {
449
387
  return sourceFiles.sort((a, b) => a.type - b.type)
450
388
  }
451
389
 
452
- static async build(
453
- compilerOptionsPartial: Partial<CompilerOptions> = {},
454
- contractsRootPath = 'contracts',
455
- artifactsRootPath = 'artifacts'
456
- ): Promise<void> {
390
+ static async build(contractsRootPath = 'contracts', artifactsRootPath = 'artifacts'): Promise<void> {
457
391
  const provider = getCurrentNodeProvider()
458
392
  const sourceFiles = await Project.loadSourceFiles(contractsRootPath)
459
- const { errorOnWarnings, ...nodeCompilerOptions } = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial }
460
393
  const projectArtifact = await ProjectArtifact.from(artifactsRootPath)
461
- if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
462
- console.log(`Compile contracts in folder "${contractsRootPath}"`)
463
- Project.currentProject = await Project.compile(
464
- provider,
465
- sourceFiles,
466
- contractsRootPath,
467
- artifactsRootPath,
468
- errorOnWarnings,
469
- nodeCompilerOptions
470
- )
394
+ if (typeof projectArtifact === 'undefined' || projectArtifact.sourceHasChanged(sourceFiles)) {
395
+ Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootPath, artifactsRootPath)
471
396
  } else {
472
- console.log(`Load compiled contracts from folder "${artifactsRootPath}"`)
473
397
  Project.currentProject = await Project.loadArtifacts(
474
398
  provider,
475
399
  sourceFiles,
476
400
  projectArtifact,
477
401
  contractsRootPath,
478
- artifactsRootPath,
479
- errorOnWarnings,
480
- nodeCompilerOptions
402
+ artifactsRootPath
481
403
  )
482
404
  }
483
405
  }
484
406
  }
485
407
 
486
408
  export abstract class Artifact {
409
+ readonly typeId: string
487
410
  readonly functions: FunctionSig[]
488
411
 
489
- constructor(functions: FunctionSig[]) {
412
+ constructor(typeId: string, functions: FunctionSig[]) {
413
+ this.typeId = typeId
490
414
  this.functions = functions
491
415
  }
492
416
 
@@ -512,13 +436,14 @@ export class Contract extends Artifact {
512
436
  readonly eventsSig: EventSig[]
513
437
 
514
438
  constructor(
439
+ typeId: string,
515
440
  bytecode: string,
516
441
  codeHash: string,
517
442
  fieldsSig: FieldsSig,
518
443
  eventsSig: EventSig[],
519
444
  functions: FunctionSig[]
520
445
  ) {
521
- super(functions)
446
+ super(typeId, functions)
522
447
  this.bytecode = bytecode
523
448
  this.codeHash = codeHash
524
449
  this.fieldsSig = fieldsSig
@@ -537,6 +462,7 @@ export class Contract extends Artifact {
537
462
  throw Error('The artifact JSON for contract is incomplete')
538
463
  }
539
464
  const contract = new Contract(
465
+ artifact.typeId,
540
466
  artifact.bytecode,
541
467
  artifact.codeHash,
542
468
  artifact.fieldsSig,
@@ -546,8 +472,8 @@ export class Contract extends Artifact {
546
472
  return contract
547
473
  }
548
474
 
549
- static fromCompileResult(result: CompileContractResult): Contract {
550
- return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions)
475
+ static fromCompileResult(typeId: string, result: CompileContractResult): Contract {
476
+ return new Contract(typeId, result.bytecode, result.codeHash, result.fields, result.events, result.functions)
551
477
  }
552
478
 
553
479
  // support both 'code.ral' and 'code.ral.json'
@@ -566,6 +492,7 @@ export class Contract extends Artifact {
566
492
 
567
493
  override toString(): string {
568
494
  const object = {
495
+ typeId: this.typeId,
569
496
  bytecode: this.bytecode,
570
497
  codeHash: this.codeHash,
571
498
  fieldsSig: this.fieldsSig,
@@ -588,10 +515,8 @@ export class Contract extends Artifact {
588
515
  }
589
516
  }
590
517
 
591
- // no need to be cryptographically strong random
592
518
  static randomAddress(): string {
593
- const bytes = new Uint8Array(33)
594
- crypto.getRandomValues(bytes)
519
+ const bytes = crypto.randomBytes(33)
595
520
  bytes[0] = 3
596
521
  return bs58.encode(bytes)
597
522
  }
@@ -776,14 +701,14 @@ export class Script extends Artifact {
776
701
  readonly bytecodeTemplate: string
777
702
  readonly fieldsSig: FieldsSig
778
703
 
779
- constructor(bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
780
- super(functions)
704
+ constructor(typeId: string, bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
705
+ super(typeId, functions)
781
706
  this.bytecodeTemplate = bytecodeTemplate
782
707
  this.fieldsSig = fieldsSig
783
708
  }
784
709
 
785
- static fromCompileResult(result: CompileScriptResult): Script {
786
- return new Script(result.bytecodeTemplate, result.fields, result.functions)
710
+ static fromCompileResult(typeId: string, result: CompileScriptResult): Script {
711
+ return new Script(typeId, result.bytecodeTemplate, result.fields, result.functions)
787
712
  }
788
713
 
789
714
  // TODO: safely parse json
@@ -791,7 +716,7 @@ export class Script extends Artifact {
791
716
  if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
792
717
  throw Error('The artifact JSON for script is incomplete')
793
718
  }
794
- return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
719
+ return new Script(artifact.typeId, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
795
720
  }
796
721
 
797
722
  static async fromArtifactFile(path: string): Promise<Script> {
@@ -802,6 +727,7 @@ export class Script extends Artifact {
802
727
 
803
728
  override toString(): string {
804
729
  const object = {
730
+ typeId: this.typeId,
805
731
  bytecodeTemplate: this.bytecodeTemplate,
806
732
  fieldsSig: this.fieldsSig,
807
733
  functions: this.functions