@alephium/web3 0.3.0-rc.8 → 0.5.0-rc.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 +5 -3
- package/dist/src/api/api-alephium.js +1 -1
- package/dist/src/api/types.d.ts +1 -0
- package/dist/src/api/types.js +9 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.js +2 -1
- package/dist/src/contract/contract.d.ts +72 -46
- package/dist/src/contract/contract.js +165 -76
- package/dist/src/contract/ralph.js +12 -3
- package/dist/src/signer/tx-builder.js +2 -2
- package/dist/src/signer/types.d.ts +2 -4
- package/dist/src/utils/utils.js +3 -1
- package/package.json +3 -3
- package/src/api/api-alephium.ts +5 -3
- package/src/api/types.ts +8 -0
- package/src/constants.ts +1 -0
- package/src/contract/contract.ts +249 -141
- package/src/contract/ralph.ts +13 -3
- package/src/signer/tx-builder.ts +2 -2
- package/src/signer/types.ts +14 -6
- package/src/utils/utils.ts +3 -1
package/src/contract/contract.ts
CHANGED
|
@@ -33,26 +33,27 @@ import {
|
|
|
33
33
|
Token,
|
|
34
34
|
Val,
|
|
35
35
|
fromApiTokens,
|
|
36
|
-
fromApiVals
|
|
36
|
+
fromApiVals,
|
|
37
|
+
typeLength
|
|
37
38
|
} from '../api'
|
|
38
39
|
import {
|
|
39
40
|
SignDeployContractTxParams,
|
|
41
|
+
SignDeployContractTxResult,
|
|
40
42
|
SignExecuteScriptTxParams,
|
|
41
|
-
SignerProvider
|
|
42
|
-
SignExecuteScriptTxResult,
|
|
43
|
-
SignDeployContractTxResult
|
|
43
|
+
SignerProvider
|
|
44
44
|
} from '../signer'
|
|
45
45
|
import * as ralph from './ralph'
|
|
46
|
-
import { bs58, binToHex, contractIdFromAddress, assertType, Eq } from '../utils'
|
|
46
|
+
import { bs58, binToHex, contractIdFromAddress, SubscribeOptions, Subscription, assertType, Eq } from '../utils'
|
|
47
47
|
import { getCurrentNodeProvider } from '../global'
|
|
48
|
-
import { web3 } from '..'
|
|
49
48
|
import * as path from 'path'
|
|
49
|
+
import { EventSubscription, subscribeToEvents } from './events'
|
|
50
50
|
|
|
51
51
|
export type FieldsSig = node.FieldsSig
|
|
52
52
|
export type EventSig = node.EventSig
|
|
53
53
|
export type FunctionSig = node.FunctionSig
|
|
54
54
|
export type Fields = NamedVals
|
|
55
55
|
export type Arguments = NamedVals
|
|
56
|
+
export type HexString = string
|
|
56
57
|
|
|
57
58
|
enum SourceKind {
|
|
58
59
|
Contract = 0,
|
|
@@ -354,7 +355,7 @@ export class Project {
|
|
|
354
355
|
return script.artifact
|
|
355
356
|
}
|
|
356
357
|
|
|
357
|
-
private async saveArtifactsToFile(): Promise<void> {
|
|
358
|
+
private async saveArtifactsToFile(projectRootDir: string): Promise<void> {
|
|
358
359
|
const artifactsRootDir = this.artifactsRootDir
|
|
359
360
|
const saveToFile = async function (compiled: Compiled<Artifact>): Promise<void> {
|
|
360
361
|
const artifactPath = compiled.sourceInfo.getArtifactPath(artifactsRootDir)
|
|
@@ -366,7 +367,7 @@ export class Project {
|
|
|
366
367
|
}
|
|
367
368
|
this.contracts.forEach((contract) => saveToFile(contract))
|
|
368
369
|
this.scripts.forEach((script) => saveToFile(script))
|
|
369
|
-
await this.projectArtifact.saveToFile(
|
|
370
|
+
await this.projectArtifact.saveToFile(projectRootDir)
|
|
370
371
|
}
|
|
371
372
|
|
|
372
373
|
contractByCodeHash(codeHash: string): Contract {
|
|
@@ -382,6 +383,7 @@ export class Project {
|
|
|
382
383
|
private static async compile(
|
|
383
384
|
provider: NodeProvider,
|
|
384
385
|
sourceInfos: SourceInfo[],
|
|
386
|
+
projectRootDir: string,
|
|
385
387
|
contractsRootDir: string,
|
|
386
388
|
artifactsRootDir: string,
|
|
387
389
|
errorOnWarnings: boolean,
|
|
@@ -414,7 +416,7 @@ export class Project {
|
|
|
414
416
|
errorOnWarnings,
|
|
415
417
|
projectArtifact
|
|
416
418
|
)
|
|
417
|
-
await project.saveArtifactsToFile()
|
|
419
|
+
await project.saveArtifactsToFile(projectRootDir)
|
|
418
420
|
return project
|
|
419
421
|
}
|
|
420
422
|
|
|
@@ -422,6 +424,7 @@ export class Project {
|
|
|
422
424
|
provider: NodeProvider,
|
|
423
425
|
sourceInfos: SourceInfo[],
|
|
424
426
|
projectArtifact: ProjectArtifact,
|
|
427
|
+
projectRootDir: string,
|
|
425
428
|
contractsRootDir: string,
|
|
426
429
|
artifactsRootDir: string,
|
|
427
430
|
errorOnWarnings: boolean,
|
|
@@ -460,6 +463,7 @@ export class Project {
|
|
|
460
463
|
return Project.compile(
|
|
461
464
|
provider,
|
|
462
465
|
sourceInfos,
|
|
466
|
+
projectRootDir,
|
|
463
467
|
contractsRootDir,
|
|
464
468
|
artifactsRootDir,
|
|
465
469
|
errorOnWarnings,
|
|
@@ -590,12 +594,13 @@ export class Project {
|
|
|
590
594
|
const provider = getCurrentNodeProvider()
|
|
591
595
|
const sourceFiles = await Project.loadSourceFiles(projectRootDir, contractsRootDir)
|
|
592
596
|
const { errorOnWarnings, ...nodeCompilerOptions } = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial }
|
|
593
|
-
const projectArtifact = await ProjectArtifact.from(
|
|
597
|
+
const projectArtifact = await ProjectArtifact.from(projectRootDir)
|
|
594
598
|
if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
|
|
595
599
|
console.log(`Compiling contracts in folder "${contractsRootDir}"`)
|
|
596
600
|
Project.currentProject = await Project.compile(
|
|
597
601
|
provider,
|
|
598
602
|
sourceFiles,
|
|
603
|
+
projectRootDir,
|
|
599
604
|
contractsRootDir,
|
|
600
605
|
artifactsRootDir,
|
|
601
606
|
errorOnWarnings,
|
|
@@ -607,6 +612,7 @@ export class Project {
|
|
|
607
612
|
provider,
|
|
608
613
|
sourceFiles,
|
|
609
614
|
projectArtifact,
|
|
615
|
+
projectRootDir,
|
|
610
616
|
contractsRootDir,
|
|
611
617
|
artifactsRootDir,
|
|
612
618
|
errorOnWarnings,
|
|
@@ -722,13 +728,6 @@ export class Contract extends Artifact {
|
|
|
722
728
|
return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug)
|
|
723
729
|
}
|
|
724
730
|
|
|
725
|
-
async fetchState(address: string, group: number): Promise<ContractState> {
|
|
726
|
-
const state = await web3.getCurrentNodeProvider().contracts.getContractsAddressState(address, {
|
|
727
|
-
group: group
|
|
728
|
-
})
|
|
729
|
-
return this.fromApiContractState(state)
|
|
730
|
-
}
|
|
731
|
-
|
|
732
731
|
override toString(): string {
|
|
733
732
|
const object = {
|
|
734
733
|
version: this.version,
|
|
@@ -742,7 +741,7 @@ export class Contract extends Artifact {
|
|
|
742
741
|
return JSON.stringify(object, null, 2)
|
|
743
742
|
}
|
|
744
743
|
|
|
745
|
-
toState(fields:
|
|
744
|
+
toState<T extends Fields>(fields: T, asset: Asset, address?: string): ContractState<T> {
|
|
746
745
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress()
|
|
747
746
|
return {
|
|
748
747
|
address: addressDef,
|
|
@@ -763,53 +762,13 @@ export class Contract extends Artifact {
|
|
|
763
762
|
return bs58.encode(bytes)
|
|
764
763
|
}
|
|
765
764
|
|
|
766
|
-
|
|
765
|
+
printDebugMessages(funcName: string, messages: DebugMessage[]) {
|
|
767
766
|
if (messages.length != 0) {
|
|
768
767
|
console.log(`Testing ${this.name}.${funcName}:`)
|
|
769
768
|
messages.forEach((m) => console.log(`Debug - ${m.contractAddress} - ${m.message}`))
|
|
770
769
|
}
|
|
771
770
|
}
|
|
772
771
|
|
|
773
|
-
private async _test(
|
|
774
|
-
funcName: string,
|
|
775
|
-
params: TestContractParams,
|
|
776
|
-
expectPublic: boolean,
|
|
777
|
-
accessType: string,
|
|
778
|
-
printDebugMessages: boolean
|
|
779
|
-
): Promise<TestContractResult> {
|
|
780
|
-
const apiParams: node.TestContract = this.toTestContract(funcName, params)
|
|
781
|
-
const apiResult = await web3.getCurrentNodeProvider().contracts.postContractsTestContract(apiParams)
|
|
782
|
-
|
|
783
|
-
const methodIndex =
|
|
784
|
-
typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName)
|
|
785
|
-
const isPublic = this.functions[`${methodIndex}`].isPublic
|
|
786
|
-
if (printDebugMessages) {
|
|
787
|
-
this._printDebugMessages(funcName, apiResult.debugMessages)
|
|
788
|
-
}
|
|
789
|
-
if (isPublic === expectPublic) {
|
|
790
|
-
const result = await this.fromTestContractResult(methodIndex, apiResult)
|
|
791
|
-
return result
|
|
792
|
-
} else {
|
|
793
|
-
throw new Error(`The test method ${funcName} is not ${accessType}`)
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
async testPublicMethod(
|
|
798
|
-
funcName: string,
|
|
799
|
-
params: TestContractParams,
|
|
800
|
-
printDebugMessages = true
|
|
801
|
-
): Promise<TestContractResult> {
|
|
802
|
-
return this._test(funcName, params, true, 'public', printDebugMessages)
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
async testPrivateMethod(
|
|
806
|
-
funcName: string,
|
|
807
|
-
params: TestContractParams,
|
|
808
|
-
printDebugMessages = true
|
|
809
|
-
): Promise<TestContractResult> {
|
|
810
|
-
return this._test(funcName, params, false, 'private', printDebugMessages)
|
|
811
|
-
}
|
|
812
|
-
|
|
813
772
|
toApiFields(fields?: Fields): node.Val[] {
|
|
814
773
|
if (typeof fields === 'undefined') {
|
|
815
774
|
return []
|
|
@@ -839,12 +798,17 @@ export class Contract extends Artifact {
|
|
|
839
798
|
return typeof states != 'undefined' ? states.map((state) => toApiContractState(state)) : undefined
|
|
840
799
|
}
|
|
841
800
|
|
|
842
|
-
|
|
801
|
+
toApiTestContractParams(funcName: string, params: TestContractParams): node.TestContract {
|
|
802
|
+
const immFields =
|
|
803
|
+
params.initialFields === undefined ? [] : extractFields(params.initialFields, this.fieldsSig, false)
|
|
804
|
+
const mutFields =
|
|
805
|
+
params.initialFields === undefined ? [] : extractFields(params.initialFields, this.fieldsSig, true)
|
|
843
806
|
return {
|
|
844
807
|
group: params.group,
|
|
845
808
|
address: params.address,
|
|
846
809
|
bytecode: this.bytecodeDebug,
|
|
847
|
-
|
|
810
|
+
initialImmFields: immFields,
|
|
811
|
+
initialMutFields: mutFields,
|
|
848
812
|
initialAsset: typeof params.initialAsset !== 'undefined' ? toApiAsset(params.initialAsset) : undefined,
|
|
849
813
|
methodIndex: this.getMethodIndex(funcName),
|
|
850
814
|
args: this.toApiArgs(funcName, params.testArgs),
|
|
@@ -853,14 +817,14 @@ export class Contract extends Artifact {
|
|
|
853
817
|
}
|
|
854
818
|
}
|
|
855
819
|
|
|
856
|
-
fromApiContractState(state: node.ContractState): ContractState {
|
|
820
|
+
fromApiContractState(state: node.ContractState): ContractState<Fields> {
|
|
857
821
|
return {
|
|
858
822
|
address: state.address,
|
|
859
823
|
contractId: binToHex(contractIdFromAddress(state.address)),
|
|
860
824
|
bytecode: state.bytecode,
|
|
861
825
|
initialStateHash: state.initialStateHash,
|
|
862
826
|
codeHash: state.codeHash,
|
|
863
|
-
fields: fromApiFields(state.
|
|
827
|
+
fields: fromApiFields(state.immFields, state.mutFields, this.fieldsSig),
|
|
864
828
|
fieldsSig: this.fieldsSig,
|
|
865
829
|
asset: fromApiAsset(state.asset)
|
|
866
830
|
}
|
|
@@ -871,24 +835,26 @@ export class Contract extends Artifact {
|
|
|
871
835
|
return contract.fromApiContractState(state)
|
|
872
836
|
}
|
|
873
837
|
|
|
838
|
+
static ContractCreatedEventIndex = -1
|
|
874
839
|
static ContractCreatedEvent: EventSig = {
|
|
875
840
|
name: 'ContractCreated',
|
|
876
841
|
fieldNames: ['address'],
|
|
877
842
|
fieldTypes: ['Address']
|
|
878
843
|
}
|
|
879
844
|
|
|
845
|
+
static ContractDestroyedEventIndex = -2
|
|
880
846
|
static ContractDestroyedEvent: EventSig = {
|
|
881
847
|
name: 'ContractDestroyed',
|
|
882
848
|
fieldNames: ['address'],
|
|
883
849
|
fieldTypes: ['Address']
|
|
884
850
|
}
|
|
885
851
|
|
|
886
|
-
static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined):
|
|
852
|
+
static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined, txId: string): ContractEvent {
|
|
887
853
|
let eventSig: EventSig
|
|
888
854
|
|
|
889
|
-
if (event.eventIndex ==
|
|
855
|
+
if (event.eventIndex == Contract.ContractCreatedEventIndex) {
|
|
890
856
|
eventSig = this.ContractCreatedEvent
|
|
891
|
-
} else if (event.eventIndex ==
|
|
857
|
+
} else if (event.eventIndex == Contract.ContractDestroyedEventIndex) {
|
|
892
858
|
eventSig = this.ContractDestroyedEvent
|
|
893
859
|
} else {
|
|
894
860
|
const contract = Project.currentProject.contractByCodeHash(codeHash!)
|
|
@@ -896,14 +862,16 @@ export class Contract extends Artifact {
|
|
|
896
862
|
}
|
|
897
863
|
|
|
898
864
|
return {
|
|
865
|
+
txId: txId,
|
|
899
866
|
blockHash: event.blockHash,
|
|
900
867
|
contractAddress: event.contractAddress,
|
|
901
868
|
name: eventSig.name,
|
|
869
|
+
eventIndex: event.eventIndex,
|
|
902
870
|
fields: fromApiEventFields(event.fields, eventSig)
|
|
903
871
|
}
|
|
904
872
|
}
|
|
905
873
|
|
|
906
|
-
|
|
874
|
+
fromApiTestContractResult(methodIndex: number, result: node.TestContractResult, txId: string): TestContractResult {
|
|
907
875
|
const addressToCodeHash = new Map<string, string>()
|
|
908
876
|
addressToCodeHash.set(result.address, result.codeHash)
|
|
909
877
|
result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash))
|
|
@@ -914,47 +882,79 @@ export class Contract extends Artifact {
|
|
|
914
882
|
gasUsed: result.gasUsed,
|
|
915
883
|
contracts: result.contracts.map((contract) => Contract.fromApiContractState(contract)),
|
|
916
884
|
txOutputs: result.txOutputs.map(fromApiOutput),
|
|
917
|
-
events: result.events
|
|
918
|
-
const contractAddress = event.contractAddress
|
|
919
|
-
const codeHash = addressToCodeHash.get(contractAddress)
|
|
920
|
-
if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
|
|
921
|
-
return Contract.fromApiEvent(event, codeHash)
|
|
922
|
-
} else {
|
|
923
|
-
throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
|
|
924
|
-
}
|
|
925
|
-
}),
|
|
885
|
+
events: Contract.fromApiEvents(result.events, addressToCodeHash, txId),
|
|
926
886
|
debugMessages: result.debugMessages
|
|
927
887
|
}
|
|
928
888
|
}
|
|
929
889
|
|
|
930
|
-
async txParamsForDeployment(
|
|
890
|
+
async txParamsForDeployment<P extends Fields>(
|
|
931
891
|
signer: SignerProvider,
|
|
932
|
-
params:
|
|
892
|
+
params: DeployContractParams<P>
|
|
933
893
|
): Promise<SignDeployContractTxParams> {
|
|
934
|
-
const bytecode = this.buildByteCodeToDeploy(params.initialFields
|
|
894
|
+
const bytecode = this.buildByteCodeToDeploy(params.initialFields ?? {})
|
|
935
895
|
const signerParams: SignDeployContractTxParams = {
|
|
936
896
|
signerAddress: await signer.getSelectedAddress(),
|
|
937
897
|
bytecode: bytecode,
|
|
938
|
-
initialAttoAlphAmount: params
|
|
939
|
-
issueTokenAmount: params
|
|
940
|
-
initialTokenAmounts: params
|
|
941
|
-
gasAmount: params
|
|
942
|
-
gasPrice: params
|
|
898
|
+
initialAttoAlphAmount: params?.initialAttoAlphAmount,
|
|
899
|
+
issueTokenAmount: params?.issueTokenAmount,
|
|
900
|
+
initialTokenAmounts: params?.initialTokenAmounts,
|
|
901
|
+
gasAmount: params?.gasAmount,
|
|
902
|
+
gasPrice: params?.gasPrice
|
|
943
903
|
}
|
|
944
904
|
return signerParams
|
|
945
905
|
}
|
|
946
906
|
|
|
947
|
-
async deploy(
|
|
948
|
-
signer: SignerProvider,
|
|
949
|
-
params: Omit<BuildDeployContractTx, 'signerAddress'>
|
|
950
|
-
): Promise<SignDeployContractTxResult> {
|
|
951
|
-
const signerParams = await this.txParamsForDeployment(signer, params)
|
|
952
|
-
return signer.signAndSubmitDeployContractTx(signerParams)
|
|
953
|
-
}
|
|
954
|
-
|
|
955
907
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
956
908
|
return ralph.buildContractByteCode(this.bytecode, initialFields, this.fieldsSig)
|
|
957
909
|
}
|
|
910
|
+
|
|
911
|
+
static fromApiEvents(
|
|
912
|
+
events: node.ContractEventByTxId[],
|
|
913
|
+
addressToCodeHash: Map<string, string>,
|
|
914
|
+
txId: string
|
|
915
|
+
): ContractEvent[] {
|
|
916
|
+
return events.map((event) => {
|
|
917
|
+
const contractAddress = event.contractAddress
|
|
918
|
+
const codeHash = addressToCodeHash.get(contractAddress)
|
|
919
|
+
if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
|
|
920
|
+
return Contract.fromApiEvent(event, codeHash, txId)
|
|
921
|
+
} else {
|
|
922
|
+
throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
|
|
923
|
+
}
|
|
924
|
+
})
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
toApiCallContract<T extends Arguments>(
|
|
928
|
+
params: CallContractParams<T>,
|
|
929
|
+
groupIndex: number,
|
|
930
|
+
contractAddress: string,
|
|
931
|
+
methodIndex: number
|
|
932
|
+
): node.CallContract {
|
|
933
|
+
const functionSig = this.functions[`${methodIndex}`]
|
|
934
|
+
const args = toApiVals(params.args ?? {}, functionSig.paramNames, functionSig.paramTypes)
|
|
935
|
+
return {
|
|
936
|
+
...params,
|
|
937
|
+
group: groupIndex,
|
|
938
|
+
address: contractAddress,
|
|
939
|
+
methodIndex: methodIndex,
|
|
940
|
+
args: args
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
fromApiCallContractResult(result: node.CallContractResult, txId: string, methodIndex: number): CallContractResult {
|
|
945
|
+
const addressToCodeHash = new Map<string, string>()
|
|
946
|
+
result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash))
|
|
947
|
+
const functionSig = this.functions[`${methodIndex}`]
|
|
948
|
+
const returns = fromApiArray(result.returns, functionSig.returnTypes)
|
|
949
|
+
return {
|
|
950
|
+
returns: returns,
|
|
951
|
+
gasUsed: result.gasUsed,
|
|
952
|
+
contracts: result.contracts.map((state) => Contract.fromApiContractState(state)),
|
|
953
|
+
txInputs: result.txInputs,
|
|
954
|
+
txOutputs: result.txOutputs.map((output) => fromApiOutput(output)),
|
|
955
|
+
events: Contract.fromApiEvents(result.events, addressToCodeHash, txId)
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
958
|
}
|
|
959
959
|
|
|
960
960
|
export class Script extends Artifact {
|
|
@@ -1025,13 +1025,13 @@ export class Script extends Artifact {
|
|
|
1025
1025
|
return JSON.stringify(object, null, 2)
|
|
1026
1026
|
}
|
|
1027
1027
|
|
|
1028
|
-
async txParamsForExecution(
|
|
1028
|
+
async txParamsForExecution<P extends Fields>(
|
|
1029
1029
|
signer: SignerProvider,
|
|
1030
|
-
params:
|
|
1030
|
+
params: ExecuteScriptParams<P>
|
|
1031
1031
|
): Promise<SignExecuteScriptTxParams> {
|
|
1032
1032
|
const signerParams: SignExecuteScriptTxParams = {
|
|
1033
1033
|
signerAddress: await signer.getSelectedAddress(),
|
|
1034
|
-
bytecode: this.buildByteCodeToDeploy(params.initialFields
|
|
1034
|
+
bytecode: this.buildByteCodeToDeploy(params.initialFields ?? {}),
|
|
1035
1035
|
attoAlphAmount: params.attoAlphAmount,
|
|
1036
1036
|
tokens: params.tokens,
|
|
1037
1037
|
gasAmount: params.gasAmount,
|
|
@@ -1040,20 +1040,27 @@ export class Script extends Artifact {
|
|
|
1040
1040
|
return signerParams
|
|
1041
1041
|
}
|
|
1042
1042
|
|
|
1043
|
-
async execute(
|
|
1044
|
-
signer: SignerProvider,
|
|
1045
|
-
params: Omit<BuildExecuteScriptTx, 'signerAddress'>
|
|
1046
|
-
): Promise<SignExecuteScriptTxResult> {
|
|
1047
|
-
const signerParams = await this.txParamsForExecution(signer, params)
|
|
1048
|
-
return await signer.signAndSubmitExecuteScriptTx(signerParams)
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
1043
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
1052
1044
|
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig)
|
|
1053
1045
|
}
|
|
1054
1046
|
}
|
|
1055
1047
|
|
|
1056
|
-
function fromApiFields(
|
|
1048
|
+
function fromApiFields(immFields: node.Val[], mutFields: node.Val[], fieldsSig: node.FieldsSig): Fields {
|
|
1049
|
+
const vals: node.Val[] = []
|
|
1050
|
+
let immIndex = 0
|
|
1051
|
+
let mutIndex = 0
|
|
1052
|
+
const isMutable = fieldsSig.types.flatMap((tpe, index) =>
|
|
1053
|
+
Array(typeLength(tpe)).fill(fieldsSig.isMutable[`${index}`])
|
|
1054
|
+
)
|
|
1055
|
+
isMutable.forEach((mutable) => {
|
|
1056
|
+
if (mutable) {
|
|
1057
|
+
vals.push(mutFields[`${mutIndex}`])
|
|
1058
|
+
mutIndex += 1
|
|
1059
|
+
} else {
|
|
1060
|
+
vals.push(immFields[`${immIndex}`])
|
|
1061
|
+
immIndex += 1
|
|
1062
|
+
}
|
|
1063
|
+
})
|
|
1057
1064
|
return fromApiVals(vals, fieldsSig.names, fieldsSig.types)
|
|
1058
1065
|
}
|
|
1059
1066
|
|
|
@@ -1085,13 +1092,13 @@ export interface InputAsset {
|
|
|
1085
1092
|
asset: Asset
|
|
1086
1093
|
}
|
|
1087
1094
|
|
|
1088
|
-
export interface ContractState {
|
|
1095
|
+
export interface ContractState<T extends Fields = Fields> {
|
|
1089
1096
|
address: string
|
|
1090
1097
|
contractId: string
|
|
1091
1098
|
bytecode: string
|
|
1092
1099
|
initialStateHash?: string
|
|
1093
1100
|
codeHash: string
|
|
1094
|
-
fields:
|
|
1101
|
+
fields: T
|
|
1095
1102
|
fieldsSig: FieldsSig
|
|
1096
1103
|
asset: Asset
|
|
1097
1104
|
}
|
|
@@ -1104,13 +1111,24 @@ function getVal(vals: NamedVals, name: string): Val {
|
|
|
1104
1111
|
}
|
|
1105
1112
|
}
|
|
1106
1113
|
|
|
1114
|
+
function extractFields(fields: NamedVals, fieldsSig: FieldsSig, mutable: boolean) {
|
|
1115
|
+
const fieldIndexes = fieldsSig.names
|
|
1116
|
+
.map((_, index) => index)
|
|
1117
|
+
.filter((index) => fieldsSig.isMutable[`${index}`] === mutable)
|
|
1118
|
+
const fieldNames = fieldIndexes.map((index) => fieldsSig.names[`${index}`])
|
|
1119
|
+
const fieldTypes = fieldIndexes.map((index) => fieldsSig.types[`${index}`])
|
|
1120
|
+
return toApiVals(fields, fieldNames, fieldTypes)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1107
1123
|
function toApiContractState(state: ContractState): node.ContractState {
|
|
1124
|
+
const stateFields = state.fields ?? {}
|
|
1108
1125
|
return {
|
|
1109
1126
|
address: state.address,
|
|
1110
1127
|
bytecode: state.bytecode,
|
|
1111
1128
|
codeHash: state.codeHash,
|
|
1112
1129
|
initialStateHash: state.initialStateHash,
|
|
1113
|
-
|
|
1130
|
+
immFields: extractFields(stateFields, state.fieldsSig, false),
|
|
1131
|
+
mutFields: extractFields(stateFields, state.fieldsSig, true),
|
|
1114
1132
|
asset: toApiAsset(state.asset)
|
|
1115
1133
|
}
|
|
1116
1134
|
}
|
|
@@ -1123,7 +1141,7 @@ function toApiArgs(args: Arguments, funcSig: FunctionSig): node.Val[] {
|
|
|
1123
1141
|
return toApiVals(args, funcSig.paramNames, funcSig.paramTypes)
|
|
1124
1142
|
}
|
|
1125
1143
|
|
|
1126
|
-
function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
|
|
1144
|
+
export function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
|
|
1127
1145
|
return names.map((name, index) => {
|
|
1128
1146
|
const val = getVal(fields, name)
|
|
1129
1147
|
const tpe = types[`${index}`]
|
|
@@ -1139,29 +1157,25 @@ function toApiInputAssets(inputAssets?: InputAsset[]): node.TestInputAsset[] | u
|
|
|
1139
1157
|
return typeof inputAssets !== 'undefined' ? inputAssets.map(toApiInputAsset) : undefined
|
|
1140
1158
|
}
|
|
1141
1159
|
|
|
1142
|
-
export interface TestContractParams {
|
|
1160
|
+
export interface TestContractParams<F extends Fields = Fields, A extends Arguments = Arguments> {
|
|
1143
1161
|
group?: number // default 0
|
|
1144
1162
|
address?: string
|
|
1145
|
-
|
|
1163
|
+
blockHash?: string
|
|
1164
|
+
txId?: string
|
|
1165
|
+
initialFields: F
|
|
1146
1166
|
initialAsset?: Asset // default 1 ALPH
|
|
1147
|
-
|
|
1148
|
-
testArgs?: Arguments // default no arguments
|
|
1167
|
+
testArgs: A
|
|
1149
1168
|
existingContracts?: ContractState[] // default no existing contracts
|
|
1150
1169
|
inputAssets?: InputAsset[] // default no input asserts
|
|
1151
1170
|
}
|
|
1152
1171
|
|
|
1153
|
-
export interface ContractEvent {
|
|
1154
|
-
blockHash: string
|
|
1172
|
+
export interface ContractEvent<T extends Fields = Fields> {
|
|
1155
1173
|
txId: string
|
|
1156
|
-
name: string
|
|
1157
|
-
fields: Fields
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
export interface ContractEventByTxId {
|
|
1161
1174
|
blockHash: string
|
|
1162
1175
|
contractAddress: string
|
|
1176
|
+
eventIndex: number
|
|
1163
1177
|
name: string
|
|
1164
|
-
fields:
|
|
1178
|
+
fields: T
|
|
1165
1179
|
}
|
|
1166
1180
|
|
|
1167
1181
|
export type DebugMessage = node.DebugMessage
|
|
@@ -1173,7 +1187,7 @@ export interface TestContractResult {
|
|
|
1173
1187
|
gasUsed: number
|
|
1174
1188
|
contracts: ContractState[]
|
|
1175
1189
|
txOutputs: Output[]
|
|
1176
|
-
events:
|
|
1190
|
+
events: ContractEvent[]
|
|
1177
1191
|
debugMessages: DebugMessage[]
|
|
1178
1192
|
}
|
|
1179
1193
|
export declare type Output = AssetOutput | ContractOutput
|
|
@@ -1214,41 +1228,135 @@ function fromApiOutput(output: node.Output): Output {
|
|
|
1214
1228
|
}
|
|
1215
1229
|
}
|
|
1216
1230
|
|
|
1217
|
-
export
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
txId: string
|
|
1222
|
-
contractAddress: string
|
|
1223
|
-
contractId: string
|
|
1231
|
+
export function randomTxId(): string {
|
|
1232
|
+
const bytes = new Uint8Array(32)
|
|
1233
|
+
crypto.getRandomValues(bytes)
|
|
1234
|
+
return binToHex(bytes)
|
|
1224
1235
|
}
|
|
1225
1236
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
export interface BuildDeployContractTx {
|
|
1229
|
-
signerAddress: string
|
|
1230
|
-
initialFields?: Fields
|
|
1237
|
+
export interface DeployContractParams<P extends Fields = Fields> {
|
|
1238
|
+
initialFields: P
|
|
1231
1239
|
initialAttoAlphAmount?: Number256
|
|
1232
1240
|
initialTokenAmounts?: Token[]
|
|
1233
1241
|
issueTokenAmount?: Number256
|
|
1234
1242
|
gasAmount?: number
|
|
1235
1243
|
gasPrice?: Number256
|
|
1236
1244
|
}
|
|
1237
|
-
assertType<
|
|
1245
|
+
assertType<
|
|
1246
|
+
Eq<
|
|
1247
|
+
Omit<DeployContractParams<undefined>, 'initialFields'>,
|
|
1248
|
+
Omit<SignDeployContractTxParams, 'signerAddress' | 'bytecode'>
|
|
1249
|
+
>
|
|
1250
|
+
>
|
|
1251
|
+
export type DeployContractResult<T> = SignDeployContractTxResult & { instance: T }
|
|
1252
|
+
|
|
1253
|
+
export abstract class ContractFactory<T, P extends Fields = Fields> {
|
|
1254
|
+
readonly contract: Contract
|
|
1255
|
+
constructor(contract: Contract) {
|
|
1256
|
+
this.contract = contract
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
async deploy(signer: SignerProvider, deployParams: DeployContractParams<P>): Promise<DeployContractResult<T>> {
|
|
1260
|
+
const signerParams = await this.contract.txParamsForDeployment(signer, deployParams)
|
|
1261
|
+
const result = await signer.signAndSubmitDeployContractTx(signerParams)
|
|
1262
|
+
return {
|
|
1263
|
+
...result,
|
|
1264
|
+
instance: this.at(result.contractAddress)
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1238
1267
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1268
|
+
abstract at(address: string): T
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
export interface ExecuteScriptParams<P extends Fields = Fields> {
|
|
1272
|
+
initialFields: P
|
|
1242
1273
|
attoAlphAmount?: Number256
|
|
1243
1274
|
tokens?: Token[]
|
|
1244
1275
|
gasAmount?: number
|
|
1245
1276
|
gasPrice?: Number256
|
|
1246
1277
|
}
|
|
1247
|
-
assertType<Eq<keyof BuildExecuteScriptTx, keyof BuildTxParams<SignExecuteScriptTxParams>>>()
|
|
1248
1278
|
|
|
1249
|
-
export interface
|
|
1250
|
-
|
|
1251
|
-
toGroup: number
|
|
1279
|
+
export interface ExecuteScriptResult {
|
|
1280
|
+
groupIndex: number
|
|
1252
1281
|
unsignedTx: string
|
|
1253
1282
|
txId: string
|
|
1283
|
+
signature: string
|
|
1284
|
+
gasAmount: number
|
|
1285
|
+
gasPrice: Number256
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
export interface CallContractParams<T extends Arguments = Arguments> {
|
|
1289
|
+
args: T
|
|
1290
|
+
worldStateBlockHash?: string
|
|
1291
|
+
txId?: string
|
|
1292
|
+
existingContracts?: string[]
|
|
1293
|
+
inputAssets?: node.TestInputAsset[]
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
export interface CallContractResult {
|
|
1297
|
+
returns: Val[]
|
|
1298
|
+
gasUsed: number
|
|
1299
|
+
contracts: ContractState[]
|
|
1300
|
+
txInputs: string[]
|
|
1301
|
+
txOutputs: Output[]
|
|
1302
|
+
events: ContractEvent[]
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
export type ContractCreatedEvent = ContractEvent<{ address: HexString }>
|
|
1306
|
+
export type ContractDestroyedEvent = ContractEvent<{ address: HexString }>
|
|
1307
|
+
|
|
1308
|
+
function decodeFields(event: node.ContractEvent, eventSig: EventSig, eventIndex: number): Fields {
|
|
1309
|
+
if (event.eventIndex !== eventIndex) {
|
|
1310
|
+
throw new Error(`Invalid event index: ${event.eventIndex}, expected: ${eventIndex}`)
|
|
1311
|
+
}
|
|
1312
|
+
return fromApiVals(event.fields, eventSig.fieldNames, eventSig.fieldTypes)
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
export function decodeContractCreatedEvent(event: node.ContractEvent): Omit<ContractCreatedEvent, 'contractAddress'> {
|
|
1316
|
+
const fields = decodeFields(event, Contract.ContractCreatedEvent, Contract.ContractCreatedEventIndex)
|
|
1317
|
+
return {
|
|
1318
|
+
blockHash: event.blockHash,
|
|
1319
|
+
txId: event.txId,
|
|
1320
|
+
eventIndex: event.eventIndex,
|
|
1321
|
+
name: Contract.ContractCreatedEvent.name,
|
|
1322
|
+
fields: { address: fields['address'] as HexString }
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
export function decodeContractDestroyedEvent(
|
|
1327
|
+
event: node.ContractEvent
|
|
1328
|
+
): Omit<ContractDestroyedEvent, 'contractAddress'> {
|
|
1329
|
+
const fields = decodeFields(event, Contract.ContractDestroyedEvent, Contract.ContractDestroyedEventIndex)
|
|
1330
|
+
return {
|
|
1331
|
+
blockHash: event.blockHash,
|
|
1332
|
+
txId: event.txId,
|
|
1333
|
+
eventIndex: event.eventIndex,
|
|
1334
|
+
name: Contract.ContractDestroyedEvent.name,
|
|
1335
|
+
fields: { address: fields['address'] as HexString }
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
export function subscribeEventsFromContract<T extends Fields>(
|
|
1340
|
+
options: SubscribeOptions<ContractEvent<T>>,
|
|
1341
|
+
address: string,
|
|
1342
|
+
eventIndex: number,
|
|
1343
|
+
decodeFunc: (event: node.ContractEvent) => ContractEvent<T>,
|
|
1344
|
+
fromCount?: number
|
|
1345
|
+
): EventSubscription {
|
|
1346
|
+
const messageCallback = (event: node.ContractEvent): Promise<void> => {
|
|
1347
|
+
if (event.eventIndex !== eventIndex) {
|
|
1348
|
+
return Promise.resolve()
|
|
1349
|
+
}
|
|
1350
|
+
return options.messageCallback(decodeFunc(event))
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
const errorCallback = (err: any, subscription: Subscription<node.ContractEvent>): Promise<void> => {
|
|
1354
|
+
return options.errorCallback(err, subscription as unknown as Subscription<ContractEvent<T>>)
|
|
1355
|
+
}
|
|
1356
|
+
const opt: SubscribeOptions<node.ContractEvent> = {
|
|
1357
|
+
pollingInterval: options.pollingInterval,
|
|
1358
|
+
messageCallback: messageCallback,
|
|
1359
|
+
errorCallback: errorCallback
|
|
1360
|
+
}
|
|
1361
|
+
return subscribeToEvents(opt, address, fromCount)
|
|
1254
1362
|
}
|