@alephium/web3 0.35.0 → 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 +168 -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 +219 -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>()
|
|
@@ -1133,6 +1216,7 @@ export class Contract extends Artifact {
|
|
|
1133
1216
|
bytecode: bytecode,
|
|
1134
1217
|
initialAttoAlphAmount: params?.initialAttoAlphAmount,
|
|
1135
1218
|
issueTokenAmount: params?.issueTokenAmount,
|
|
1219
|
+
issueTokenTo: params?.issueTokenTo,
|
|
1136
1220
|
initialTokenAmounts: params?.initialTokenAmounts,
|
|
1137
1221
|
gasAmount: params?.gasAmount,
|
|
1138
1222
|
gasPrice: params?.gasPrice
|
|
@@ -1142,7 +1226,12 @@ export class Contract extends Artifact {
|
|
|
1142
1226
|
|
|
1143
1227
|
buildByteCodeToDeploy(initialFields: Fields, isDevnet: boolean): string {
|
|
1144
1228
|
try {
|
|
1145
|
-
return ralph.buildContractByteCode(
|
|
1229
|
+
return ralph.buildContractByteCode(
|
|
1230
|
+
isDevnet ? this.bytecodeDebug : this.bytecode,
|
|
1231
|
+
initialFields,
|
|
1232
|
+
this.fieldsSig,
|
|
1233
|
+
this.structs
|
|
1234
|
+
)
|
|
1146
1235
|
} catch (error) {
|
|
1147
1236
|
throw new Error(`Failed to build bytecode for contract ${this.name}, error: ${error}`)
|
|
1148
1237
|
}
|
|
@@ -1172,7 +1261,7 @@ export class Contract extends Artifact {
|
|
|
1172
1261
|
methodIndex: number
|
|
1173
1262
|
): node.CallContract {
|
|
1174
1263
|
const functionSig = this.functions[`${methodIndex}`]
|
|
1175
|
-
const args =
|
|
1264
|
+
const args = toApiArgs(params.args ?? {}, functionSig, this.structs)
|
|
1176
1265
|
return {
|
|
1177
1266
|
...params,
|
|
1178
1267
|
group: groupIndex,
|
|
@@ -1190,7 +1279,7 @@ export class Contract extends Artifact {
|
|
|
1190
1279
|
): CallContractResult<unknown> {
|
|
1191
1280
|
const returnTypes = this.functions[`${methodIndex}`].returnTypes
|
|
1192
1281
|
const callResult = tryGetCallResult(result)
|
|
1193
|
-
const rawReturn = fromApiArray(callResult.returns, returnTypes)
|
|
1282
|
+
const rawReturn = fromApiArray(callResult.returns, returnTypes, this.structs)
|
|
1194
1283
|
const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn
|
|
1195
1284
|
|
|
1196
1285
|
const addressToCodeHash = new Map<string, string>()
|
|
@@ -1211,6 +1300,7 @@ export class Script extends Artifact {
|
|
|
1211
1300
|
readonly bytecodeTemplate: string
|
|
1212
1301
|
readonly bytecodeDebugPatch: string
|
|
1213
1302
|
readonly fieldsSig: FieldsSig
|
|
1303
|
+
readonly structs: Struct[]
|
|
1214
1304
|
|
|
1215
1305
|
constructor(
|
|
1216
1306
|
version: string,
|
|
@@ -1218,27 +1308,30 @@ export class Script extends Artifact {
|
|
|
1218
1308
|
bytecodeTemplate: string,
|
|
1219
1309
|
bytecodeDebugPatch: string,
|
|
1220
1310
|
fieldsSig: FieldsSig,
|
|
1221
|
-
functions: FunctionSig[]
|
|
1311
|
+
functions: FunctionSig[],
|
|
1312
|
+
structs: Struct[]
|
|
1222
1313
|
) {
|
|
1223
1314
|
super(version, name, functions)
|
|
1224
1315
|
this.bytecodeTemplate = bytecodeTemplate
|
|
1225
1316
|
this.bytecodeDebugPatch = bytecodeDebugPatch
|
|
1226
1317
|
this.fieldsSig = fieldsSig
|
|
1318
|
+
this.structs = structs
|
|
1227
1319
|
}
|
|
1228
1320
|
|
|
1229
|
-
static fromCompileResult(result: node.CompileScriptResult): Script {
|
|
1321
|
+
static fromCompileResult(result: node.CompileScriptResult, structs: Struct[] = []): Script {
|
|
1230
1322
|
return new Script(
|
|
1231
1323
|
result.version,
|
|
1232
1324
|
result.name,
|
|
1233
1325
|
result.bytecodeTemplate,
|
|
1234
1326
|
result.bytecodeDebugPatch,
|
|
1235
1327
|
result.fields,
|
|
1236
|
-
result.functions
|
|
1328
|
+
result.functions,
|
|
1329
|
+
structs
|
|
1237
1330
|
)
|
|
1238
1331
|
}
|
|
1239
1332
|
|
|
1240
1333
|
// TODO: safely parse json
|
|
1241
|
-
static fromJson(artifact: any, bytecodeDebugPatch = ''): Script {
|
|
1334
|
+
static fromJson(artifact: any, bytecodeDebugPatch = '', structs: Struct[] = []): Script {
|
|
1242
1335
|
if (
|
|
1243
1336
|
artifact.version == null ||
|
|
1244
1337
|
artifact.name == null ||
|
|
@@ -1254,14 +1347,15 @@ export class Script extends Artifact {
|
|
|
1254
1347
|
artifact.bytecodeTemplate,
|
|
1255
1348
|
bytecodeDebugPatch,
|
|
1256
1349
|
artifact.fieldsSig,
|
|
1257
|
-
artifact.functions
|
|
1350
|
+
artifact.functions,
|
|
1351
|
+
structs
|
|
1258
1352
|
)
|
|
1259
1353
|
}
|
|
1260
1354
|
|
|
1261
|
-
static async fromArtifactFile(path: string, bytecodeDebugPatch: string): Promise<Script> {
|
|
1355
|
+
static async fromArtifactFile(path: string, bytecodeDebugPatch: string, structs: Struct[] = []): Promise<Script> {
|
|
1262
1356
|
const content = await fsPromises.readFile(path)
|
|
1263
1357
|
const artifact = JSON.parse(content.toString())
|
|
1264
|
-
return this.fromJson(artifact, bytecodeDebugPatch)
|
|
1358
|
+
return this.fromJson(artifact, bytecodeDebugPatch, structs)
|
|
1265
1359
|
}
|
|
1266
1360
|
|
|
1267
1361
|
override toString(): string {
|
|
@@ -1294,34 +1388,86 @@ export class Script extends Artifact {
|
|
|
1294
1388
|
|
|
1295
1389
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
1296
1390
|
try {
|
|
1297
|
-
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig)
|
|
1391
|
+
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig, this.structs)
|
|
1298
1392
|
} catch (error) {
|
|
1299
1393
|
throw new Error(`Failed to build bytecode for script ${this.name}, error: ${error}`)
|
|
1300
1394
|
}
|
|
1301
1395
|
}
|
|
1302
1396
|
}
|
|
1303
1397
|
|
|
1304
|
-
function fromApiFields(
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
isMutable
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
|
|
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))
|
|
1321
1461
|
}
|
|
1322
1462
|
|
|
1323
|
-
function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig, systemEvent = false): Fields {
|
|
1324
|
-
|
|
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
|
+
}, {})
|
|
1325
1471
|
}
|
|
1326
1472
|
|
|
1327
1473
|
export interface Asset {
|
|
@@ -1359,50 +1505,33 @@ export interface ContractState<T extends Fields = Fields> {
|
|
|
1359
1505
|
asset: Asset
|
|
1360
1506
|
}
|
|
1361
1507
|
|
|
1362
|
-
function
|
|
1363
|
-
if (name in vals) {
|
|
1364
|
-
return vals[`${name}`]
|
|
1365
|
-
} else {
|
|
1366
|
-
throw Error(`No Val exists for ${name}`)
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
function extractFields(fields: NamedVals, fieldsSig: FieldsSig, mutable: boolean) {
|
|
1371
|
-
const fieldIndexes = fieldsSig.names
|
|
1372
|
-
.map((_, index) => index)
|
|
1373
|
-
.filter((index) => fieldsSig.isMutable[`${index}`] === mutable)
|
|
1374
|
-
const fieldNames = fieldIndexes.map((index) => fieldsSig.names[`${index}`])
|
|
1375
|
-
const fieldTypes = fieldIndexes.map((index) => fieldsSig.types[`${index}`])
|
|
1376
|
-
return toApiVals(fields, fieldNames, fieldTypes)
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
function toApiContractState(state: ContractState): node.ContractState {
|
|
1508
|
+
function toApiContractState(state: ContractState, structs: Struct[]): node.ContractState {
|
|
1380
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))
|
|
1381
1514
|
return {
|
|
1382
1515
|
address: state.address,
|
|
1383
1516
|
bytecode: state.bytecode,
|
|
1384
1517
|
codeHash: state.codeHash,
|
|
1385
1518
|
initialStateHash: state.initialStateHash,
|
|
1386
|
-
immFields
|
|
1387
|
-
mutFields
|
|
1519
|
+
immFields,
|
|
1520
|
+
mutFields,
|
|
1388
1521
|
asset: toApiAsset(state.asset)
|
|
1389
1522
|
}
|
|
1390
1523
|
}
|
|
1391
1524
|
|
|
1392
|
-
function toApiFields(fields: Fields, fieldsSig: FieldsSig): node.Val[] {
|
|
1393
|
-
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))
|
|
1394
1529
|
}
|
|
1395
1530
|
|
|
1396
|
-
function toApiArgs(args: Arguments, funcSig: FunctionSig): node.Val[] {
|
|
1397
|
-
return
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
export function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
|
|
1401
|
-
return names.map((name, index) => {
|
|
1402
|
-
const val = getVal(fields, name)
|
|
1403
|
-
const tpe = types[`${index}`]
|
|
1404
|
-
return toApiVal(val, tpe)
|
|
1405
|
-
})
|
|
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))
|
|
1406
1535
|
}
|
|
1407
1536
|
|
|
1408
1537
|
function toApiInputAsset(inputAsset: InputAsset): node.TestInputAsset {
|
|
@@ -1782,9 +1911,7 @@ export function decodeEvent<F extends Fields, M extends ContractEvent<F>>(
|
|
|
1782
1911
|
throw new Error('Invalid event index: ' + event.eventIndex + ', expected: ' + targetEventIndex)
|
|
1783
1912
|
}
|
|
1784
1913
|
const eventSig = contract.eventsSig[`${targetEventIndex}`]
|
|
1785
|
-
const
|
|
1786
|
-
const fieldTypes = eventSig.fieldTypes
|
|
1787
|
-
const fields = fromApiVals(event.fields, fieldNames, fieldTypes)
|
|
1914
|
+
const fields = fromApiEventFields(event.fields, eventSig)
|
|
1788
1915
|
return {
|
|
1789
1916
|
contractAddress: instance.address,
|
|
1790
1917
|
blockHash: event.blockHash,
|