@alephium/web3 0.35.1 → 0.36.0
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.
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/api-alephium.d.ts +8 -1
- package/dist/src/api/api-alephium.js +1 -1
- package/dist/src/api/types.d.ts +7 -6
- package/dist/src/api/types.js +19 -100
- package/dist/src/contract/contract.d.ts +31 -11
- package/dist/src/contract/contract.js +167 -89
- package/dist/src/contract/ralph.d.ts +6 -5
- package/dist/src/contract/ralph.js +68 -80
- package/package.json +2 -2
- package/src/api/api-alephium.ts +9 -1
- package/src/api/types.ts +20 -103
- package/src/contract/contract.ts +218 -92
- package/src/contract/ralph.ts +95 -81
package/src/contract/contract.ts
CHANGED
|
@@ -20,7 +20,6 @@ import { Buffer } from 'buffer/'
|
|
|
20
20
|
import fs from 'fs'
|
|
21
21
|
import { promises as fsPromises } from 'fs'
|
|
22
22
|
import {
|
|
23
|
-
fromApiArray,
|
|
24
23
|
fromApiNumber256,
|
|
25
24
|
toApiNumber256,
|
|
26
25
|
NamedVals,
|
|
@@ -32,9 +31,10 @@ import {
|
|
|
32
31
|
Token,
|
|
33
32
|
Val,
|
|
34
33
|
fromApiTokens,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
getDefaultPrimitiveValue,
|
|
35
|
+
PrimitiveTypes,
|
|
36
|
+
decodeArrayType,
|
|
37
|
+
fromApiPrimitiveVal
|
|
38
38
|
} from '../api'
|
|
39
39
|
import { CompileProjectResult } from '../api/api-alephium'
|
|
40
40
|
import {
|
|
@@ -84,7 +84,8 @@ enum SourceKind {
|
|
|
84
84
|
Contract = 0,
|
|
85
85
|
Script = 1,
|
|
86
86
|
AbstractContract = 2,
|
|
87
|
-
Interface = 3
|
|
87
|
+
Interface = 3,
|
|
88
|
+
Struct = 4
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
export type CompilerOptions = node.CompilerOptions & {
|
|
@@ -327,10 +328,45 @@ function removeOldArtifacts(dir: string) {
|
|
|
327
328
|
}
|
|
328
329
|
}
|
|
329
330
|
|
|
331
|
+
export class Struct {
|
|
332
|
+
name: string
|
|
333
|
+
fieldNames: string[]
|
|
334
|
+
fieldTypes: string[]
|
|
335
|
+
isMutable: boolean[]
|
|
336
|
+
|
|
337
|
+
constructor(name: string, fieldNames: string[], fieldTypes: string[], isMutable: boolean[]) {
|
|
338
|
+
this.name = name
|
|
339
|
+
this.fieldNames = fieldNames
|
|
340
|
+
this.fieldTypes = fieldTypes
|
|
341
|
+
this.isMutable = isMutable
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
static fromJson(json: any): Struct {
|
|
345
|
+
if (json.name === null || json.fieldNames === null || json.fieldTypes === null || json.isMutable === null) {
|
|
346
|
+
throw Error('The JSON for struct is incomplete')
|
|
347
|
+
}
|
|
348
|
+
return new Struct(json.name, json.fieldNames, json.fieldTypes, json.isMutable)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static fromStructSig(sig: node.StructSig): Struct {
|
|
352
|
+
return new Struct(sig.name, sig.fieldNames, sig.fieldTypes, sig.isMutable)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
toJson(): any {
|
|
356
|
+
return {
|
|
357
|
+
name: this.name,
|
|
358
|
+
fieldNames: this.fieldNames,
|
|
359
|
+
fieldTypes: this.fieldTypes,
|
|
360
|
+
isMutable: this.isMutable
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
330
365
|
export class Project {
|
|
331
366
|
sourceInfos: SourceInfo[]
|
|
332
367
|
contracts: Map<string, Compiled<Contract>>
|
|
333
368
|
scripts: Map<string, Compiled<Script>>
|
|
369
|
+
structs: Struct[]
|
|
334
370
|
projectArtifact: ProjectArtifact
|
|
335
371
|
|
|
336
372
|
readonly contractsRootDir: string
|
|
@@ -346,11 +382,13 @@ export class Project {
|
|
|
346
382
|
static readonly contractMatcher = new TypedMatcher('^Contract ([A-Z][a-zA-Z0-9]*)', SourceKind.Contract)
|
|
347
383
|
static readonly interfaceMatcher = new TypedMatcher('^Interface ([A-Z][a-zA-Z0-9]*)', SourceKind.Interface)
|
|
348
384
|
static readonly scriptMatcher = new TypedMatcher('^TxScript ([A-Z][a-zA-Z0-9]*)', SourceKind.Script)
|
|
385
|
+
static readonly structMatcher = new TypedMatcher('struct ([A-Z][a-zA-Z0-9]*)', SourceKind.Struct)
|
|
349
386
|
static readonly matchers = [
|
|
350
387
|
Project.abstractContractMatcher,
|
|
351
388
|
Project.contractMatcher,
|
|
352
389
|
Project.interfaceMatcher,
|
|
353
|
-
Project.scriptMatcher
|
|
390
|
+
Project.scriptMatcher,
|
|
391
|
+
Project.structMatcher
|
|
354
392
|
]
|
|
355
393
|
|
|
356
394
|
static buildProjectArtifact(
|
|
@@ -398,6 +436,7 @@ export class Project {
|
|
|
398
436
|
sourceInfos: SourceInfo[],
|
|
399
437
|
contracts: Map<string, Compiled<Contract>>,
|
|
400
438
|
scripts: Map<string, Compiled<Script>>,
|
|
439
|
+
structs: Struct[],
|
|
401
440
|
errorOnWarnings: boolean,
|
|
402
441
|
projectArtifact: ProjectArtifact
|
|
403
442
|
) {
|
|
@@ -406,6 +445,7 @@ export class Project {
|
|
|
406
445
|
this.sourceInfos = sourceInfos
|
|
407
446
|
this.contracts = contracts
|
|
408
447
|
this.scripts = scripts
|
|
448
|
+
this.structs = structs
|
|
409
449
|
this.projectArtifact = projectArtifact
|
|
410
450
|
|
|
411
451
|
if (errorOnWarnings) {
|
|
@@ -448,6 +488,24 @@ export class Project {
|
|
|
448
488
|
return script.artifact
|
|
449
489
|
}
|
|
450
490
|
|
|
491
|
+
private static async loadStructs(artifactsRootDir: string): Promise<Struct[]> {
|
|
492
|
+
const filePath = path.join(artifactsRootDir, 'structs.ral.json')
|
|
493
|
+
if (!fs.existsSync(filePath)) return []
|
|
494
|
+
const content = await fsPromises.readFile(filePath)
|
|
495
|
+
const json = JSON.parse(content.toString())
|
|
496
|
+
if (!Array.isArray(json)) {
|
|
497
|
+
throw Error(`Invalid structs JSON: ${content}`)
|
|
498
|
+
}
|
|
499
|
+
return Array.from(json).map((item) => Struct.fromJson(item))
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private async saveStructsToFile(): Promise<void> {
|
|
503
|
+
if (this.structs.length === 0) return
|
|
504
|
+
const structs = this.structs.map((s) => s.toJson())
|
|
505
|
+
const filePath = path.join(this.artifactsRootDir, 'structs.ral.json')
|
|
506
|
+
return fsPromises.writeFile(filePath, JSON.stringify(structs, null, 2))
|
|
507
|
+
}
|
|
508
|
+
|
|
451
509
|
private async saveArtifactsToFile(projectRootDir: string): Promise<void> {
|
|
452
510
|
const artifactsRootDir = this.artifactsRootDir
|
|
453
511
|
const saveToFile = async function (compiled: Compiled<Artifact>): Promise<void> {
|
|
@@ -460,6 +518,7 @@ export class Project {
|
|
|
460
518
|
}
|
|
461
519
|
this.contracts.forEach((contract) => saveToFile(contract))
|
|
462
520
|
this.scripts.forEach((script) => saveToFile(script))
|
|
521
|
+
this.saveStructsToFile()
|
|
463
522
|
await this.projectArtifact.saveToFile(projectRootDir)
|
|
464
523
|
}
|
|
465
524
|
|
|
@@ -525,6 +584,7 @@ export class Project {
|
|
|
525
584
|
const result = await Project.getCompileResult(provider, compilerOptions, removeDuplicates)
|
|
526
585
|
const contracts = new Map<string, Compiled<Contract>>()
|
|
527
586
|
const scripts = new Map<string, Compiled<Script>>()
|
|
587
|
+
const structs = result.structs === undefined ? [] : result.structs.map((item) => Struct.fromStructSig(item))
|
|
528
588
|
result.contracts.forEach((contractResult) => {
|
|
529
589
|
const sourceInfo = sourceInfos.find(
|
|
530
590
|
(sourceInfo) => sourceInfo.type === SourceKind.Contract && sourceInfo.name === contractResult.name
|
|
@@ -533,7 +593,7 @@ export class Project {
|
|
|
533
593
|
// this should never happen
|
|
534
594
|
throw new Error(`SourceInfo does not exist for contract ${contractResult.name}`)
|
|
535
595
|
}
|
|
536
|
-
const contract = Contract.fromCompileResult(contractResult)
|
|
596
|
+
const contract = Contract.fromCompileResult(contractResult, structs)
|
|
537
597
|
contracts.set(contract.name, new Compiled(sourceInfo, contract, contractResult.warnings))
|
|
538
598
|
})
|
|
539
599
|
result.scripts.forEach((scriptResult) => {
|
|
@@ -544,7 +604,7 @@ export class Project {
|
|
|
544
604
|
// this should never happen
|
|
545
605
|
throw new Error(`SourceInfo does not exist for script ${scriptResult.name}`)
|
|
546
606
|
}
|
|
547
|
-
const script = Script.fromCompileResult(scriptResult)
|
|
607
|
+
const script = Script.fromCompileResult(scriptResult, structs)
|
|
548
608
|
scripts.set(script.name, new Compiled(sourceInfo, script, scriptResult.warnings))
|
|
549
609
|
})
|
|
550
610
|
const projectArtifact = Project.buildProjectArtifact(
|
|
@@ -560,6 +620,7 @@ export class Project {
|
|
|
560
620
|
sourceInfos,
|
|
561
621
|
contracts,
|
|
562
622
|
scripts,
|
|
623
|
+
structs,
|
|
563
624
|
errorOnWarnings,
|
|
564
625
|
projectArtifact
|
|
565
626
|
)
|
|
@@ -580,6 +641,7 @@ export class Project {
|
|
|
580
641
|
try {
|
|
581
642
|
const contracts = new Map<string, Compiled<Contract>>()
|
|
582
643
|
const scripts = new Map<string, Compiled<Script>>()
|
|
644
|
+
const structs = await Project.loadStructs(artifactsRootDir)
|
|
583
645
|
for (const sourceInfo of sourceInfos) {
|
|
584
646
|
const info = projectArtifact.infos.get(sourceInfo.name)
|
|
585
647
|
if (typeof info === 'undefined') {
|
|
@@ -588,10 +650,15 @@ export class Project {
|
|
|
588
650
|
const warnings = info.warnings
|
|
589
651
|
const artifactDir = sourceInfo.getArtifactPath(artifactsRootDir)
|
|
590
652
|
if (sourceInfo.type === SourceKind.Contract) {
|
|
591
|
-
const artifact = await Contract.fromArtifactFile(
|
|
653
|
+
const artifact = await Contract.fromArtifactFile(
|
|
654
|
+
artifactDir,
|
|
655
|
+
info.bytecodeDebugPatch,
|
|
656
|
+
info.codeHashDebug,
|
|
657
|
+
structs
|
|
658
|
+
)
|
|
592
659
|
contracts.set(artifact.name, new Compiled(sourceInfo, artifact, warnings))
|
|
593
660
|
} else if (sourceInfo.type === SourceKind.Script) {
|
|
594
|
-
const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch)
|
|
661
|
+
const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch, structs)
|
|
595
662
|
scripts.set(artifact.name, new Compiled(sourceInfo, artifact, warnings))
|
|
596
663
|
}
|
|
597
664
|
}
|
|
@@ -602,6 +669,7 @@ export class Project {
|
|
|
602
669
|
sourceInfos,
|
|
603
670
|
contracts,
|
|
604
671
|
scripts,
|
|
672
|
+
structs,
|
|
605
673
|
errorOnWarnings,
|
|
606
674
|
projectArtifact
|
|
607
675
|
)
|
|
@@ -821,6 +889,7 @@ export class Contract extends Artifact {
|
|
|
821
889
|
readonly eventsSig: EventSig[]
|
|
822
890
|
readonly constants: Constant[]
|
|
823
891
|
readonly enums: Enum[]
|
|
892
|
+
readonly structs: Struct[]
|
|
824
893
|
readonly stdInterfaceId?: HexString
|
|
825
894
|
|
|
826
895
|
readonly bytecodeDebug: string
|
|
@@ -838,6 +907,7 @@ export class Contract extends Artifact {
|
|
|
838
907
|
functions: FunctionSig[],
|
|
839
908
|
constants: Constant[],
|
|
840
909
|
enums: Enum[],
|
|
910
|
+
structs: Struct[],
|
|
841
911
|
stdInterfaceId?: HexString
|
|
842
912
|
) {
|
|
843
913
|
super(version, name, functions)
|
|
@@ -848,6 +918,7 @@ export class Contract extends Artifact {
|
|
|
848
918
|
this.eventsSig = eventsSig
|
|
849
919
|
this.constants = constants
|
|
850
920
|
this.enums = enums
|
|
921
|
+
this.structs = structs
|
|
851
922
|
this.stdInterfaceId = stdInterfaceId
|
|
852
923
|
|
|
853
924
|
this.bytecodeDebug = ralph.buildDebugBytecode(this.bytecode, this.bytecodeDebugPatch)
|
|
@@ -855,7 +926,7 @@ export class Contract extends Artifact {
|
|
|
855
926
|
}
|
|
856
927
|
|
|
857
928
|
// TODO: safely parse json
|
|
858
|
-
static fromJson(artifact: any, bytecodeDebugPatch = '', codeHashDebug = ''): Contract {
|
|
929
|
+
static fromJson(artifact: any, bytecodeDebugPatch = '', codeHashDebug = '', structs: Struct[] = []): Contract {
|
|
859
930
|
if (
|
|
860
931
|
artifact.version == null ||
|
|
861
932
|
artifact.name == null ||
|
|
@@ -881,12 +952,13 @@ export class Contract extends Artifact {
|
|
|
881
952
|
artifact.functions,
|
|
882
953
|
artifact.constants,
|
|
883
954
|
artifact.enums,
|
|
955
|
+
structs,
|
|
884
956
|
artifact.stdInterfaceId === null ? undefined : artifact.stdInterfaceId
|
|
885
957
|
)
|
|
886
958
|
return contract
|
|
887
959
|
}
|
|
888
960
|
|
|
889
|
-
static fromCompileResult(result: node.CompileContractResult): Contract {
|
|
961
|
+
static fromCompileResult(result: node.CompileContractResult, structs: Struct[] = []): Contract {
|
|
890
962
|
return new Contract(
|
|
891
963
|
result.version,
|
|
892
964
|
result.name,
|
|
@@ -899,15 +971,21 @@ export class Contract extends Artifact {
|
|
|
899
971
|
result.functions,
|
|
900
972
|
result.constants,
|
|
901
973
|
result.enums,
|
|
974
|
+
structs,
|
|
902
975
|
result.stdInterfaceId
|
|
903
976
|
)
|
|
904
977
|
}
|
|
905
978
|
|
|
906
979
|
// support both 'code.ral' and 'code.ral.json'
|
|
907
|
-
static async fromArtifactFile(
|
|
980
|
+
static async fromArtifactFile(
|
|
981
|
+
path: string,
|
|
982
|
+
bytecodeDebugPatch: string,
|
|
983
|
+
codeHashDebug: string,
|
|
984
|
+
structs: Struct[] = []
|
|
985
|
+
): Promise<Contract> {
|
|
908
986
|
const content = await fsPromises.readFile(path)
|
|
909
987
|
const artifact = JSON.parse(content.toString())
|
|
910
|
-
return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug)
|
|
988
|
+
return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug, structs)
|
|
911
989
|
}
|
|
912
990
|
|
|
913
991
|
override toString(): string {
|
|
@@ -937,10 +1015,7 @@ export class Contract extends Artifact {
|
|
|
937
1015
|
types: this.fieldsSig.types.slice(0, -1),
|
|
938
1016
|
isMutable: this.fieldsSig.isMutable.slice(0, -1)
|
|
939
1017
|
}
|
|
940
|
-
return fields
|
|
941
|
-
acc[`${key}`] = getDefaultValue(fields.types[`${index}`])
|
|
942
|
-
return acc
|
|
943
|
-
}, {})
|
|
1018
|
+
return getDefaultValue(fields, this.structs)
|
|
944
1019
|
}
|
|
945
1020
|
|
|
946
1021
|
toState<T extends Fields>(fields: T, asset: Asset, address?: string): ContractState<T> {
|
|
@@ -975,7 +1050,7 @@ export class Contract extends Artifact {
|
|
|
975
1050
|
if (typeof fields === 'undefined') {
|
|
976
1051
|
return []
|
|
977
1052
|
} else {
|
|
978
|
-
return toApiFields(fields, this.fieldsSig)
|
|
1053
|
+
return toApiFields(fields, this.fieldsSig, this.structs)
|
|
979
1054
|
}
|
|
980
1055
|
}
|
|
981
1056
|
|
|
@@ -986,7 +1061,7 @@ export class Contract extends Artifact {
|
|
|
986
1061
|
throw new Error(`Invalid function name: ${funcName}`)
|
|
987
1062
|
}
|
|
988
1063
|
|
|
989
|
-
return toApiArgs(args, func)
|
|
1064
|
+
return toApiArgs(args, func, this.structs)
|
|
990
1065
|
} else {
|
|
991
1066
|
return []
|
|
992
1067
|
}
|
|
@@ -997,14 +1072,22 @@ export class Contract extends Artifact {
|
|
|
997
1072
|
}
|
|
998
1073
|
|
|
999
1074
|
toApiContractStates(states?: ContractState[]): node.ContractState[] | undefined {
|
|
1000
|
-
return typeof states != 'undefined' ? states.map((state) => toApiContractState(state)) : undefined
|
|
1075
|
+
return typeof states != 'undefined' ? states.map((state) => toApiContractState(state, this.structs)) : undefined
|
|
1001
1076
|
}
|
|
1002
1077
|
|
|
1003
1078
|
toApiTestContractParams(funcName: string, params: TestContractParams): node.TestContract {
|
|
1004
|
-
const
|
|
1005
|
-
params.initialFields === undefined
|
|
1006
|
-
|
|
1007
|
-
|
|
1079
|
+
const allFields =
|
|
1080
|
+
params.initialFields === undefined
|
|
1081
|
+
? []
|
|
1082
|
+
: ralph.flattenFields(
|
|
1083
|
+
params.initialFields,
|
|
1084
|
+
this.fieldsSig.names,
|
|
1085
|
+
this.fieldsSig.types,
|
|
1086
|
+
this.fieldsSig.isMutable,
|
|
1087
|
+
this.structs
|
|
1088
|
+
)
|
|
1089
|
+
const immFields = allFields.filter((f) => !f.isMutable).map((f) => toApiVal(f.value, f.type))
|
|
1090
|
+
const mutFields = allFields.filter((f) => f.isMutable).map((f) => toApiVal(f.value, f.type))
|
|
1008
1091
|
return {
|
|
1009
1092
|
group: params.group,
|
|
1010
1093
|
blockHash: params.blockHash,
|
|
@@ -1030,7 +1113,7 @@ export class Contract extends Artifact {
|
|
|
1030
1113
|
bytecode: state.bytecode,
|
|
1031
1114
|
initialStateHash: state.initialStateHash,
|
|
1032
1115
|
codeHash: state.codeHash,
|
|
1033
|
-
fields: fromApiFields(state.immFields, state.mutFields, this.fieldsSig),
|
|
1116
|
+
fields: fromApiFields(state.immFields, state.mutFields, this.fieldsSig, this.structs),
|
|
1034
1117
|
fieldsSig: this.fieldsSig,
|
|
1035
1118
|
asset: fromApiAsset(state.asset)
|
|
1036
1119
|
}
|
|
@@ -1101,7 +1184,7 @@ export class Contract extends Artifact {
|
|
|
1101
1184
|
): TestContractResult<unknown> {
|
|
1102
1185
|
const methodIndex = this.functions.findIndex((sig) => sig.name === methodName)
|
|
1103
1186
|
const returnTypes = this.functions[`${methodIndex}`].returnTypes
|
|
1104
|
-
const rawReturn = fromApiArray(result.returns, returnTypes)
|
|
1187
|
+
const rawReturn = fromApiArray(result.returns, returnTypes, this.structs)
|
|
1105
1188
|
const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn
|
|
1106
1189
|
|
|
1107
1190
|
const addressToCodeHash = new Map<string, string>()
|
|
@@ -1143,7 +1226,12 @@ export class Contract extends Artifact {
|
|
|
1143
1226
|
|
|
1144
1227
|
buildByteCodeToDeploy(initialFields: Fields, isDevnet: boolean): string {
|
|
1145
1228
|
try {
|
|
1146
|
-
return ralph.buildContractByteCode(
|
|
1229
|
+
return ralph.buildContractByteCode(
|
|
1230
|
+
isDevnet ? this.bytecodeDebug : this.bytecode,
|
|
1231
|
+
initialFields,
|
|
1232
|
+
this.fieldsSig,
|
|
1233
|
+
this.structs
|
|
1234
|
+
)
|
|
1147
1235
|
} catch (error) {
|
|
1148
1236
|
throw new Error(`Failed to build bytecode for contract ${this.name}, error: ${error}`)
|
|
1149
1237
|
}
|
|
@@ -1173,7 +1261,7 @@ export class Contract extends Artifact {
|
|
|
1173
1261
|
methodIndex: number
|
|
1174
1262
|
): node.CallContract {
|
|
1175
1263
|
const functionSig = this.functions[`${methodIndex}`]
|
|
1176
|
-
const args =
|
|
1264
|
+
const args = toApiArgs(params.args ?? {}, functionSig, this.structs)
|
|
1177
1265
|
return {
|
|
1178
1266
|
...params,
|
|
1179
1267
|
group: groupIndex,
|
|
@@ -1191,7 +1279,7 @@ export class Contract extends Artifact {
|
|
|
1191
1279
|
): CallContractResult<unknown> {
|
|
1192
1280
|
const returnTypes = this.functions[`${methodIndex}`].returnTypes
|
|
1193
1281
|
const callResult = tryGetCallResult(result)
|
|
1194
|
-
const rawReturn = fromApiArray(callResult.returns, returnTypes)
|
|
1282
|
+
const rawReturn = fromApiArray(callResult.returns, returnTypes, this.structs)
|
|
1195
1283
|
const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn
|
|
1196
1284
|
|
|
1197
1285
|
const addressToCodeHash = new Map<string, string>()
|
|
@@ -1212,6 +1300,7 @@ export class Script extends Artifact {
|
|
|
1212
1300
|
readonly bytecodeTemplate: string
|
|
1213
1301
|
readonly bytecodeDebugPatch: string
|
|
1214
1302
|
readonly fieldsSig: FieldsSig
|
|
1303
|
+
readonly structs: Struct[]
|
|
1215
1304
|
|
|
1216
1305
|
constructor(
|
|
1217
1306
|
version: string,
|
|
@@ -1219,27 +1308,30 @@ export class Script extends Artifact {
|
|
|
1219
1308
|
bytecodeTemplate: string,
|
|
1220
1309
|
bytecodeDebugPatch: string,
|
|
1221
1310
|
fieldsSig: FieldsSig,
|
|
1222
|
-
functions: FunctionSig[]
|
|
1311
|
+
functions: FunctionSig[],
|
|
1312
|
+
structs: Struct[]
|
|
1223
1313
|
) {
|
|
1224
1314
|
super(version, name, functions)
|
|
1225
1315
|
this.bytecodeTemplate = bytecodeTemplate
|
|
1226
1316
|
this.bytecodeDebugPatch = bytecodeDebugPatch
|
|
1227
1317
|
this.fieldsSig = fieldsSig
|
|
1318
|
+
this.structs = structs
|
|
1228
1319
|
}
|
|
1229
1320
|
|
|
1230
|
-
static fromCompileResult(result: node.CompileScriptResult): Script {
|
|
1321
|
+
static fromCompileResult(result: node.CompileScriptResult, structs: Struct[] = []): Script {
|
|
1231
1322
|
return new Script(
|
|
1232
1323
|
result.version,
|
|
1233
1324
|
result.name,
|
|
1234
1325
|
result.bytecodeTemplate,
|
|
1235
1326
|
result.bytecodeDebugPatch,
|
|
1236
1327
|
result.fields,
|
|
1237
|
-
result.functions
|
|
1328
|
+
result.functions,
|
|
1329
|
+
structs
|
|
1238
1330
|
)
|
|
1239
1331
|
}
|
|
1240
1332
|
|
|
1241
1333
|
// TODO: safely parse json
|
|
1242
|
-
static fromJson(artifact: any, bytecodeDebugPatch = ''): Script {
|
|
1334
|
+
static fromJson(artifact: any, bytecodeDebugPatch = '', structs: Struct[] = []): Script {
|
|
1243
1335
|
if (
|
|
1244
1336
|
artifact.version == null ||
|
|
1245
1337
|
artifact.name == null ||
|
|
@@ -1255,14 +1347,15 @@ export class Script extends Artifact {
|
|
|
1255
1347
|
artifact.bytecodeTemplate,
|
|
1256
1348
|
bytecodeDebugPatch,
|
|
1257
1349
|
artifact.fieldsSig,
|
|
1258
|
-
artifact.functions
|
|
1350
|
+
artifact.functions,
|
|
1351
|
+
structs
|
|
1259
1352
|
)
|
|
1260
1353
|
}
|
|
1261
1354
|
|
|
1262
|
-
static async fromArtifactFile(path: string, bytecodeDebugPatch: string): Promise<Script> {
|
|
1355
|
+
static async fromArtifactFile(path: string, bytecodeDebugPatch: string, structs: Struct[] = []): Promise<Script> {
|
|
1263
1356
|
const content = await fsPromises.readFile(path)
|
|
1264
1357
|
const artifact = JSON.parse(content.toString())
|
|
1265
|
-
return this.fromJson(artifact, bytecodeDebugPatch)
|
|
1358
|
+
return this.fromJson(artifact, bytecodeDebugPatch, structs)
|
|
1266
1359
|
}
|
|
1267
1360
|
|
|
1268
1361
|
override toString(): string {
|
|
@@ -1295,34 +1388,86 @@ export class Script extends Artifact {
|
|
|
1295
1388
|
|
|
1296
1389
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
1297
1390
|
try {
|
|
1298
|
-
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig)
|
|
1391
|
+
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig, this.structs)
|
|
1299
1392
|
} catch (error) {
|
|
1300
1393
|
throw new Error(`Failed to build bytecode for script ${this.name}, error: ${error}`)
|
|
1301
1394
|
}
|
|
1302
1395
|
}
|
|
1303
1396
|
}
|
|
1304
1397
|
|
|
1305
|
-
function fromApiFields(
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
isMutable
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1398
|
+
export function fromApiFields(
|
|
1399
|
+
immFields: node.Val[],
|
|
1400
|
+
mutFields: node.Val[],
|
|
1401
|
+
fieldsSig: FieldsSig,
|
|
1402
|
+
structs: Struct[]
|
|
1403
|
+
): NamedVals {
|
|
1404
|
+
let [immIndex, mutIndex] = [0, 0]
|
|
1405
|
+
const func = (type: string, isMutable: boolean): Val => {
|
|
1406
|
+
const nodeVal = isMutable ? mutFields[mutIndex++] : immFields[immIndex++]
|
|
1407
|
+
return fromApiPrimitiveVal(nodeVal, type)
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
return fieldsSig.names.reduce((acc, name, index) => {
|
|
1411
|
+
const fieldType = fieldsSig.types[`${index}`]
|
|
1412
|
+
const isMutable = fieldsSig.isMutable[`${index}`]
|
|
1413
|
+
acc[`${name}`] = buildVal(isMutable, fieldType, structs, func)
|
|
1414
|
+
return acc
|
|
1415
|
+
}, {})
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function buildVal(
|
|
1419
|
+
isMutable: boolean,
|
|
1420
|
+
type: string,
|
|
1421
|
+
structs: Struct[],
|
|
1422
|
+
func: (primitiveType: string, isMutable: boolean) => Val
|
|
1423
|
+
): Val {
|
|
1424
|
+
if (type.startsWith('[')) {
|
|
1425
|
+
const [baseType, size] = decodeArrayType(type)
|
|
1426
|
+
return Array.from(Array(size).keys()).map(() => buildVal(isMutable, baseType, structs, func))
|
|
1427
|
+
}
|
|
1428
|
+
const struct = structs.find((s) => s.name === type)
|
|
1429
|
+
if (struct !== undefined) {
|
|
1430
|
+
return struct.fieldNames.reduce((acc, name, index) => {
|
|
1431
|
+
const fieldType = struct.fieldTypes[`${index}`]
|
|
1432
|
+
const isFieldMutable = isMutable && struct.isMutable[`${index}`]
|
|
1433
|
+
acc[`${name}`] = buildVal(isFieldMutable, fieldType, structs, func)
|
|
1434
|
+
return acc
|
|
1435
|
+
}, {})
|
|
1436
|
+
}
|
|
1437
|
+
const primitiveType = PrimitiveTypes.includes(type) ? type : 'ByteVec' // contract type
|
|
1438
|
+
return func(primitiveType, isMutable)
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
export function getDefaultValue(fieldsSig: FieldsSig, structs: Struct[]): Fields {
|
|
1442
|
+
return fieldsSig.names.reduce((acc, name, index) => {
|
|
1443
|
+
const type = fieldsSig.types[`${index}`]
|
|
1444
|
+
acc[`${name}`] = buildVal(false, type, structs, getDefaultPrimitiveValue)
|
|
1445
|
+
return acc
|
|
1446
|
+
}, {})
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
function fromApiVal(iter: IterableIterator<node.Val>, type: string, structs: Struct[], systemEvent = false): Val {
|
|
1450
|
+
const func = (primitiveType: string): Val => {
|
|
1451
|
+
const currentValue = iter.next()
|
|
1452
|
+
if (currentValue.done) throw Error('Not enough vals')
|
|
1453
|
+
return fromApiPrimitiveVal(currentValue.value, primitiveType, systemEvent)
|
|
1454
|
+
}
|
|
1455
|
+
return buildVal(false, type, structs, func)
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
export function fromApiArray(values: node.Val[], types: string[], structs: Struct[]): Val[] {
|
|
1459
|
+
const iter = values.values()
|
|
1460
|
+
return types.map((type) => fromApiVal(iter, type, structs))
|
|
1322
1461
|
}
|
|
1323
1462
|
|
|
1324
|
-
function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig, systemEvent = false): Fields {
|
|
1325
|
-
|
|
1463
|
+
export function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig, systemEvent = false): Fields {
|
|
1464
|
+
const iter = vals.values()
|
|
1465
|
+
return eventSig.fieldNames.reduce((acc, name, index) => {
|
|
1466
|
+
const type = eventSig.fieldTypes[`${index}`]
|
|
1467
|
+
// currently event does not support struct type
|
|
1468
|
+
acc[`${name}`] = fromApiVal(iter, type, [], systemEvent)
|
|
1469
|
+
return acc
|
|
1470
|
+
}, {})
|
|
1326
1471
|
}
|
|
1327
1472
|
|
|
1328
1473
|
export interface Asset {
|
|
@@ -1360,50 +1505,33 @@ export interface ContractState<T extends Fields = Fields> {
|
|
|
1360
1505
|
asset: Asset
|
|
1361
1506
|
}
|
|
1362
1507
|
|
|
1363
|
-
function
|
|
1364
|
-
if (name in vals) {
|
|
1365
|
-
return vals[`${name}`]
|
|
1366
|
-
} else {
|
|
1367
|
-
throw Error(`No Val exists for ${name}`)
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
function extractFields(fields: NamedVals, fieldsSig: FieldsSig, mutable: boolean) {
|
|
1372
|
-
const fieldIndexes = fieldsSig.names
|
|
1373
|
-
.map((_, index) => index)
|
|
1374
|
-
.filter((index) => fieldsSig.isMutable[`${index}`] === mutable)
|
|
1375
|
-
const fieldNames = fieldIndexes.map((index) => fieldsSig.names[`${index}`])
|
|
1376
|
-
const fieldTypes = fieldIndexes.map((index) => fieldsSig.types[`${index}`])
|
|
1377
|
-
return toApiVals(fields, fieldNames, fieldTypes)
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
function toApiContractState(state: ContractState): node.ContractState {
|
|
1508
|
+
function toApiContractState(state: ContractState, structs: Struct[]): node.ContractState {
|
|
1381
1509
|
const stateFields = state.fields ?? {}
|
|
1510
|
+
const fieldsSig = state.fieldsSig
|
|
1511
|
+
const allFields = ralph.flattenFields(stateFields, fieldsSig.names, fieldsSig.types, fieldsSig.isMutable, structs)
|
|
1512
|
+
const immFields = allFields.filter((f) => !f.isMutable).map((f) => toApiVal(f.value, f.type))
|
|
1513
|
+
const mutFields = allFields.filter((f) => f.isMutable).map((f) => toApiVal(f.value, f.type))
|
|
1382
1514
|
return {
|
|
1383
1515
|
address: state.address,
|
|
1384
1516
|
bytecode: state.bytecode,
|
|
1385
1517
|
codeHash: state.codeHash,
|
|
1386
1518
|
initialStateHash: state.initialStateHash,
|
|
1387
|
-
immFields
|
|
1388
|
-
mutFields
|
|
1519
|
+
immFields,
|
|
1520
|
+
mutFields,
|
|
1389
1521
|
asset: toApiAsset(state.asset)
|
|
1390
1522
|
}
|
|
1391
1523
|
}
|
|
1392
1524
|
|
|
1393
|
-
function toApiFields(fields: Fields, fieldsSig: FieldsSig): node.Val[] {
|
|
1394
|
-
return
|
|
1525
|
+
function toApiFields(fields: Fields, fieldsSig: FieldsSig, structs: Struct[]): node.Val[] {
|
|
1526
|
+
return ralph
|
|
1527
|
+
.flattenFields(fields, fieldsSig.names, fieldsSig.types, fieldsSig.isMutable, structs)
|
|
1528
|
+
.map((f) => toApiVal(f.value, f.type))
|
|
1395
1529
|
}
|
|
1396
1530
|
|
|
1397
|
-
function toApiArgs(args: Arguments, funcSig: FunctionSig): node.Val[] {
|
|
1398
|
-
return
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
export function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
|
|
1402
|
-
return names.map((name, index) => {
|
|
1403
|
-
const val = getVal(fields, name)
|
|
1404
|
-
const tpe = types[`${index}`]
|
|
1405
|
-
return toApiVal(val, tpe)
|
|
1406
|
-
})
|
|
1531
|
+
function toApiArgs(args: Arguments, funcSig: FunctionSig, structs: Struct[]): node.Val[] {
|
|
1532
|
+
return ralph
|
|
1533
|
+
.flattenFields(args, funcSig.paramNames, funcSig.paramTypes, funcSig.paramIsMutable, structs)
|
|
1534
|
+
.map((f) => toApiVal(f.value, f.type))
|
|
1407
1535
|
}
|
|
1408
1536
|
|
|
1409
1537
|
function toApiInputAsset(inputAsset: InputAsset): node.TestInputAsset {
|
|
@@ -1783,9 +1911,7 @@ export function decodeEvent<F extends Fields, M extends ContractEvent<F>>(
|
|
|
1783
1911
|
throw new Error('Invalid event index: ' + event.eventIndex + ', expected: ' + targetEventIndex)
|
|
1784
1912
|
}
|
|
1785
1913
|
const eventSig = contract.eventsSig[`${targetEventIndex}`]
|
|
1786
|
-
const
|
|
1787
|
-
const fieldTypes = eventSig.fieldTypes
|
|
1788
|
-
const fields = fromApiVals(event.fields, fieldNames, fieldTypes)
|
|
1914
|
+
const fields = fromApiEventFields(event.fields, eventSig)
|
|
1789
1915
|
return {
|
|
1790
1916
|
contractAddress: instance.address,
|
|
1791
1917
|
blockHash: event.blockHash,
|