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

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.
@@ -46,12 +46,16 @@ class SourceFile {
46
46
  }
47
47
  }
48
48
 
49
+ type FieldsSig = node.FieldsSig
50
+ type EventSig = node.EventSig
51
+ type FunctionSig = node.FunctionSig
52
+
49
53
  export abstract class Common {
50
54
  readonly sourceCodeSha256: string
51
- readonly functions: node.FunctionSig[]
55
+ readonly functions: FunctionSig[]
52
56
 
53
57
  static readonly importRegex = new RegExp('^import "([^"/]+/(([^"]+)/)?)?[a-z][a-z_0-9]*.ral"', 'mg')
54
- static readonly contractRegex = new RegExp('^TxContract [A-Z][a-zA-Z0-9]*', 'mg')
58
+ static readonly contractRegex = new RegExp('^(Abstract[ ]+)?Contract [A-Z][a-zA-Z0-9]*', 'mg')
55
59
  static readonly interfaceRegex = new RegExp('^Interface [A-Z][a-zA-Z0-9]* \\{', 'mg')
56
60
  static readonly scriptRegex = new RegExp('^TxScript [A-Z][a-zA-Z0-9]*', 'mg')
57
61
 
@@ -70,7 +74,7 @@ export abstract class Common {
70
74
  }
71
75
  }
72
76
 
73
- constructor(sourceCodeSha256: string, functions: node.FunctionSig[]) {
77
+ constructor(sourceCodeSha256: string, functions: FunctionSig[]) {
74
78
  this.sourceCodeSha256 = sourceCodeSha256
75
79
  this.functions = functions
76
80
  }
@@ -152,7 +156,14 @@ export abstract class Common {
152
156
  provider: NodeProvider,
153
157
  sourceFile: SourceFile,
154
158
  loadContractStr: (sourceFile: SourceFile, importsCache: string[]) => Promise<string>,
155
- compile: (provider: NodeProvider, sourceFile: SourceFile, contractStr: string, contractHash: string) => Promise<T>
159
+ compile: (
160
+ provider: NodeProvider,
161
+ sourceFile: SourceFile,
162
+ contractStr: string,
163
+ contractHash: string,
164
+ errorOnWarnings: boolean
165
+ ) => Promise<T>,
166
+ errorOnWarnings: boolean
156
167
  ): Promise<T> {
157
168
  Common.checkFileNameExtension(sourceFile.contractPath)
158
169
 
@@ -162,7 +173,7 @@ export abstract class Common {
162
173
  if (typeof existingContract !== 'undefined') {
163
174
  return existingContract as unknown as T
164
175
  } else {
165
- return compile(provider, sourceFile, contractStr, contractHash)
176
+ return compile(provider, sourceFile, contractStr, contractHash, errorOnWarnings)
166
177
  }
167
178
  }
168
179
 
@@ -175,21 +186,46 @@ export abstract class Common {
175
186
  }
176
187
 
177
188
  abstract buildByteCodeToDeploy(initialFields?: Fields): string
189
+
190
+ publicFunctions(): string[] {
191
+ return this.functions.filter((func) => func.isPublic).map((func) => func.name)
192
+ }
193
+
194
+ usingPreapprovedAssetsFunctions(): string[] {
195
+ return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name)
196
+ }
197
+
198
+ usingAssetsInContractFunctions(): string[] {
199
+ return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name)
200
+ }
201
+
202
+ protected static checkCompilerWarnings(compiled: { warnings: string[] }, errorOnWarnings: boolean): void {
203
+ if (compiled.warnings.length !== 0) {
204
+ const prefixPerWarning = ' - '
205
+ const warningString = prefixPerWarning + compiled.warnings.join('\n' + prefixPerWarning)
206
+ const output = 'Compilation warnings:\n' + warningString + '\n'
207
+ if (errorOnWarnings) {
208
+ throw new Error(output)
209
+ } else {
210
+ console.log(output)
211
+ }
212
+ }
213
+ }
178
214
  }
179
215
 
180
216
  export class Contract extends Common {
181
217
  readonly bytecode: string
182
218
  readonly codeHash: string
183
- readonly fieldsSig: node.FieldsSig
184
- readonly eventsSig: node.EventSig[]
219
+ readonly fieldsSig: FieldsSig
220
+ readonly eventsSig: EventSig[]
185
221
 
186
222
  constructor(
187
223
  sourceCodeSha256: string,
188
224
  bytecode: string,
189
225
  codeHash: string,
190
- fieldsSig: node.FieldsSig,
191
- eventsSig: node.EventSig[],
192
- functions: node.FunctionSig[]
226
+ fieldsSig: FieldsSig,
227
+ eventsSig: EventSig[],
228
+ functions: FunctionSig[]
193
229
  ) {
194
230
  super(sourceCodeSha256, functions)
195
231
  this.bytecode = bytecode
@@ -223,7 +259,7 @@ export class Contract extends Common {
223
259
  return Common._loadContractStr(sourceFile, [], (code) => Contract.checkCodeType(sourceFile.contractPath, code))
224
260
  }
225
261
 
226
- static async fromSource(provider: NodeProvider, path: string): Promise<Contract> {
262
+ static async fromSource(provider: NodeProvider, path: string, errorOnWarnings = true): Promise<Contract> {
227
263
  if (!fs.existsSync(Common._artifactsFolder())) {
228
264
  fs.mkdirSync(Common._artifactsFolder(), { recursive: true })
229
265
  }
@@ -232,7 +268,8 @@ export class Contract extends Common {
232
268
  provider,
233
269
  sourceFile,
234
270
  (sourceFile) => Contract.loadContractStr(sourceFile),
235
- Contract.compile
271
+ Contract.compile,
272
+ errorOnWarnings
236
273
  )
237
274
  this._putArtifactToCache(contract)
238
275
  return contract
@@ -242,9 +279,12 @@ export class Contract extends Common {
242
279
  provider: NodeProvider,
243
280
  sourceFile: SourceFile,
244
281
  contractStr: string,
245
- contractHash: string
282
+ contractHash: string,
283
+ errorOnWarnings: boolean
246
284
  ): Promise<Contract> {
247
285
  const compiled = await provider.contracts.postContractsCompileContract({ code: contractStr })
286
+ Common.checkCompilerWarnings(compiled, errorOnWarnings)
287
+
248
288
  const artifact = new Contract(
249
289
  contractHash,
250
290
  compiled.bytecode,
@@ -341,7 +381,7 @@ export class Contract extends Common {
341
381
 
342
382
  const methodIndex =
343
383
  typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName)
344
- const isPublic = this.functions[`${methodIndex}`].signature.indexOf('pub ') !== -1
384
+ const isPublic = this.functions[`${methodIndex}`].isPublic
345
385
  if (isPublic === expectPublic) {
346
386
  const result = await this.fromTestContractResult(methodIndex, apiResult)
347
387
  return result
@@ -430,7 +470,7 @@ export class Contract extends Common {
430
470
  throw new Error(`Unknown code with code hash: ${codeHash}`)
431
471
  }
432
472
 
433
- static async getFieldsSig(state: node.ContractState): Promise<node.FieldsSig> {
473
+ static async getFieldsSig(state: node.ContractState): Promise<FieldsSig> {
434
474
  return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig)
435
475
  }
436
476
 
@@ -448,16 +488,14 @@ export class Contract extends Common {
448
488
  }
449
489
  }
450
490
 
451
- static ContractCreatedEvent: node.EventSig = {
491
+ static ContractCreatedEvent: EventSig = {
452
492
  name: 'ContractCreated',
453
- signature: 'event ContractCreated(address:Address)',
454
493
  fieldNames: ['address'],
455
494
  fieldTypes: ['Address']
456
495
  }
457
496
 
458
- static ContractDestroyedEvent: node.EventSig = {
497
+ static ContractDestroyedEvent: EventSig = {
459
498
  name: 'ContractDestroyed',
460
- signature: 'event ContractDestroyed(address:Address)',
461
499
  fieldNames: ['address'],
462
500
  fieldTypes: ['Address']
463
501
  }
@@ -466,7 +504,7 @@ export class Contract extends Common {
466
504
  event: node.ContractEventByTxId,
467
505
  codeHash: string | undefined
468
506
  ): Promise<ContractEventByTxId> {
469
- let eventSig: node.EventSig
507
+ let eventSig: EventSig
470
508
 
471
509
  if (event.eventIndex == -1) {
472
510
  eventSig = this.ContractCreatedEvent
@@ -543,14 +581,9 @@ export class Contract extends Common {
543
581
 
544
582
  export class Script extends Common {
545
583
  readonly bytecodeTemplate: string
546
- readonly fieldsSig: node.FieldsSig
584
+ readonly fieldsSig: FieldsSig
547
585
 
548
- constructor(
549
- sourceCodeSha256: string,
550
- bytecodeTemplate: string,
551
- fieldsSig: node.FieldsSig,
552
- functions: node.FunctionSig[]
553
- ) {
586
+ constructor(sourceCodeSha256: string, bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
554
587
  super(sourceCodeSha256, functions)
555
588
  this.bytecodeTemplate = bytecodeTemplate
556
589
  this.fieldsSig = fieldsSig
@@ -571,18 +604,26 @@ export class Script extends Common {
571
604
  return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code))
572
605
  }
573
606
 
574
- static async fromSource(provider: NodeProvider, path: string): Promise<Script> {
607
+ static async fromSource(provider: NodeProvider, path: string, errorOnWarnings = true): Promise<Script> {
575
608
  const sourceFile = this.getSourceFile(path, [])
576
- return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile)
609
+ return Common._from(
610
+ provider,
611
+ sourceFile,
612
+ (sourceFile) => Script.loadContractStr(sourceFile),
613
+ Script.compile,
614
+ errorOnWarnings
615
+ )
577
616
  }
578
617
 
579
618
  private static async compile(
580
619
  provider: NodeProvider,
581
620
  sourceFile: SourceFile,
582
621
  scriptStr: string,
583
- contractHash: string
622
+ contractHash: string,
623
+ errorOnWarnings = true
584
624
  ): Promise<Script> {
585
625
  const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr })
626
+ Common.checkCompilerWarnings(compiled, errorOnWarnings)
586
627
  const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions)
587
628
  await artifact._saveToFile(sourceFile)
588
629
  return artifact
@@ -895,7 +936,7 @@ export interface ContractState {
895
936
  initialStateHash?: string
896
937
  codeHash: string
897
938
  fields: Fields
898
- fieldsSig: node.FieldsSig
939
+ fieldsSig: FieldsSig
899
940
  asset: Asset
900
941
  }
901
942
 
@@ -918,12 +959,12 @@ function toApiContractState(state: ContractState): node.ContractState {
918
959
  }
919
960
  }
920
961
 
921
- function toApiFields(fields: Fields, fieldsSig: node.FieldsSig): node.Val[] {
962
+ function toApiFields(fields: Fields, fieldsSig: FieldsSig): node.Val[] {
922
963
  return toApiVals(fields, fieldsSig.names, fieldsSig.types)
923
964
  }
924
965
 
925
- function toApiArgs(args: Arguments, funcSig: node.FunctionSig): node.Val[] {
926
- return toApiVals(args, funcSig.argNames, funcSig.argTypes)
966
+ function toApiArgs(args: Arguments, funcSig: FunctionSig): node.Val[] {
967
+ return toApiVals(args, funcSig.paramNames, funcSig.paramTypes)
927
968
  }
928
969
 
929
970
  function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
@@ -31,7 +31,7 @@ export class EventSubscription extends Subscription<ContractEvent> {
31
31
  this.startPolling()
32
32
  }
33
33
 
34
- override startPolling() {
34
+ override startPolling(): void {
35
35
  this.eventEmitter.on('tick', async () => {
36
36
  await this.polling()
37
37
  })
@@ -42,7 +42,7 @@ export class EventSubscription extends Subscription<ContractEvent> {
42
42
  return this.fromCount
43
43
  }
44
44
 
45
- override async polling() {
45
+ override async polling(): Promise<void> {
46
46
  try {
47
47
  const events = await this.provider.events.getEventsContractContractaddress(this.contractAddress, {
48
48
  start: this.fromCount
@@ -133,9 +133,9 @@ describe('contract', function () {
133
133
  it('should test buildScriptByteCode', async () => {
134
134
  const variables = { x: true, y: 0x05, z: 'ff', a: '1C2RAVWSuaXw8xtUxqVERR7ChKBE1XgscNFw73NSHE1v3' }
135
135
  const fieldsSig: node.FieldsSig = {
136
- signature: 'Not really',
137
136
  names: ['x', 'y', 'z', 'a'],
138
- types: ['Bool', 'U256', 'ByteVec', 'Address']
137
+ types: ['Bool', 'U256', 'ByteVec', 'Address'],
138
+ isMutable: [false, false, false, false]
139
139
  }
140
140
  const bytecode = ralph.buildScriptByteCode('-{0}-{1}-{2}-{3}-', variables, fieldsSig)
141
141
  expect(bytecode).toEqual('-03-1305-1401ff-1500a3cd757be03c7dac8d48bf79e2a7d6e735e018a9c054b99138c7b29738c437ec-')
@@ -150,9 +150,9 @@ describe('contract', function () {
150
150
  e: [false, true]
151
151
  }
152
152
  const fieldsSig: node.FieldsSig = {
153
- signature: 'Not really',
154
153
  names: ['a', 'b', 'c', 'd', 'e'],
155
- types: ['I256', 'U256', 'ByteVec', 'Address', '[Bool;2]']
154
+ types: ['I256', 'U256', 'ByteVec', 'Address', '[Bool;2]'],
155
+ isMutable: [false, false, false, false]
156
156
  }
157
157
  const encoded = ralph.buildContractByteCode('ff', fields, fieldsSig)
158
158
  expect(encoded).toEqual(
@@ -33,7 +33,7 @@ export class TxStatusSubscription extends Subscription<TxStatus> {
33
33
  this.startPolling()
34
34
  }
35
35
 
36
- override async polling() {
36
+ override async polling(): Promise<void> {
37
37
  try {
38
38
  const txStatus = await this.provider.transactions.getTransactionsStatus({
39
39
  txId: this.txId,
@@ -49,7 +49,7 @@ export abstract class Subscription<Message> {
49
49
  this.eventEmitter = new EventEmitter()
50
50
  }
51
51
 
52
- startPolling() {
52
+ startPolling(): void {
53
53
  this.eventEmitter.on('tick', async () => {
54
54
  await this.polling()
55
55
 
@@ -151,7 +151,7 @@ describe('utils', function () {
151
151
  '0a38bc48fbb4300f1e305b201cd6129372d867122efb814d871d18c0bfe43b56',
152
152
  '4f51cd1f0af97cf5ec9c7a3397eaeea549d55a93c216e54f2ab4a8cf29f6f865'
153
153
  )
154
- ).toBe('293c948c81c5a9495178fff8b8c9f29f4f3e09e1728c40e9253c87adf5e18770')
154
+ ).toBe('0e28f15ca290002c31d691aa008aa56ac12356b0380efb6c88fff929b6a268a9')
155
155
  })
156
156
 
157
157
  it('should convert from string to hex and back', () => {
@@ -190,7 +190,7 @@ export function contractIdFromTx(txId: string, outputIndex: number): string {
190
190
  }
191
191
 
192
192
  export function subContractId(parentContractId: string, pathInHex: string): string {
193
- const data = Buffer.concat([hexToBinUnsafe(pathInHex), hexToBinUnsafe(parentContractId)])
193
+ const data = Buffer.concat([hexToBinUnsafe(parentContractId), hexToBinUnsafe(pathInHex)])
194
194
 
195
195
  return binToHex(blake.blake2b(blake.blake2b(data, undefined, 32), undefined, 32))
196
196
  }
@@ -203,11 +203,11 @@ export function stringToHex(str: string): string {
203
203
  return hex
204
204
  }
205
205
 
206
- export function hexToString(str: any): string {
207
- return Buffer.from(str.toString(), 'hex').toString()
206
+ export function hexToString(str: string): string {
207
+ return Buffer.from(str, 'hex').toString()
208
208
  }
209
209
 
210
- export function timeout(ms: number) {
210
+ export function timeout(ms: number): Promise<void> {
211
211
  return new Promise((resolve) => setTimeout(resolve, ms))
212
212
  }
213
213
 
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "license": "GPL",
5
5
  "config": {
6
- "alephium_version": "1.5.0-rc0"
6
+ "alephium_version": "1.5.0-rc4"
7
7
  },
8
8
  "scripts": {
9
9
  "build": "rm -rf dist && npx tsc --build .",
@@ -12,7 +12,7 @@
12
12
  "stop-devnet": "node scripts/stop-devnet.js"
13
13
  },
14
14
  "dependencies": {
15
- "@alephium/web3": "0.2.0-rc.0"
15
+ "@alephium/web3": "0.2.0-rc.3"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/elliptic": "^6.4.13",
@@ -2,7 +2,7 @@
2
2
  "name": "my-dapp",
3
3
  "version": "0.1.0",
4
4
  "config": {
5
- "alephium_version": "1.5.0-rc0"
5
+ "alephium_version": "1.5.0-rc4"
6
6
  },
7
7
  "dependencies": {
8
8
  "@testing-library/jest-dom": "^5.16.4",
@@ -12,7 +12,7 @@
12
12
  "@types/node": "^16.11.26",
13
13
  "@types/react": "^18.0.3",
14
14
  "@types/react-dom": "^18.0.0",
15
- "@alephium/web3": "0.2.0-rc.0",
15
+ "@alephium/web3": "0.2.0-rc.3",
16
16
  "react": "^18.0.0",
17
17
  "react-dom": "^18.0.0",
18
18
  "react-scripts": "5.0.1",
@@ -175,4 +175,23 @@ describe('contract', function () {
175
175
  loadContract('./artifacts/greeter/greeter.ral.json')
176
176
  loadScript('./artifacts/greeter_main.ral.json')
177
177
  })
178
+
179
+ it('should extract metadata of contracts', async () => {
180
+ const provider = new NodeProvider('http://127.0.0.1:22973')
181
+ const contract = await Contract.fromSource(provider, 'test/metadata.ral')
182
+ expect(contract.functions.map((func) => func.name)).toEqual(['foo', 'bar', 'baz'])
183
+ expect(contract.publicFunctions()).toEqual(['foo'])
184
+ expect(contract.usingPreapprovedAssetsFunctions()).toEqual(['foo'])
185
+ expect(contract.usingAssetsInContractFunctions()).toEqual(['bar'])
186
+ })
187
+
188
+ it('should handle compiler warnings', async () => {
189
+ const provider = new NodeProvider('http://127.0.0.1:22973')
190
+ const contract = await Contract.fromSource(provider, 'test/warnings.ral', false)
191
+ expect(contract.publicFunctions()).toEqual(['foo'])
192
+
193
+ await expect(Contract.fromSource(provider, 'test/warnings.ral')).rejects.toThrowError(
194
+ 'Compilation warnings:\n - Found unused variables in function foo: foo.y\n - Found unused fields: b'
195
+ )
196
+ })
178
197
  })
@@ -56,7 +56,7 @@ describe('transactions', function () {
56
56
  await timeout(1500)
57
57
  expect(txStatus).toMatchObject({ type: 'TxNotFound' })
58
58
 
59
- const subSubmitResult = await signer.submitTransaction(subDeployTx.unsignedTx, subDeployTx.txId)
59
+ await signer.submitTransaction(subDeployTx.unsignedTx, subDeployTx.txId)
60
60
  await timeout(1500)
61
61
  expect(txStatus).toMatchObject({ type: 'Confirmed' })
62
62