@alephium/web3 0.5.0-rc.0 → 0.5.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import { NamedVals, node, Number256, Token, Val } from '../api';
2
- import { SignDeployContractTxParams, SignDeployContractTxResult, SignExecuteScriptTxParams, SignerProvider } from '../signer';
3
- import { SubscribeOptions } from '../utils';
1
+ import { NamedVals, node, Number256, Token } from '../api';
2
+ import { SignDeployContractTxParams, SignDeployContractTxResult, SignExecuteScriptTxParams, SignerProvider, Address } from '../signer';
3
+ import { SubscribeOptions, Optional } from '../utils';
4
4
  import { EventSubscription } from './events';
5
5
  export declare type FieldsSig = node.FieldsSig;
6
6
  export declare type EventSig = node.EventSig;
@@ -127,12 +127,12 @@ export declare class Contract extends Artifact {
127
127
  static ContractDestroyedEventIndex: number;
128
128
  static ContractDestroyedEvent: EventSig;
129
129
  static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined, txId: string): ContractEvent;
130
- fromApiTestContractResult(methodIndex: number, result: node.TestContractResult, txId: string): TestContractResult;
130
+ fromApiTestContractResult(methodName: string, result: node.TestContractResult, txId: string): TestContractResult<unknown>;
131
131
  txParamsForDeployment<P extends Fields>(signer: SignerProvider, params: DeployContractParams<P>): Promise<SignDeployContractTxParams>;
132
132
  buildByteCodeToDeploy(initialFields: Fields): string;
133
133
  static fromApiEvents(events: node.ContractEventByTxId[], addressToCodeHash: Map<string, string>, txId: string): ContractEvent[];
134
134
  toApiCallContract<T extends Arguments>(params: CallContractParams<T>, groupIndex: number, contractAddress: string, methodIndex: number): node.CallContract;
135
- fromApiCallContractResult(result: node.CallContractResult, txId: string, methodIndex: number): CallContractResult;
135
+ fromApiCallContractResult(result: node.CallContractResult, txId: string, methodIndex: number): CallContractResult<unknown>;
136
136
  }
137
137
  export declare class Script extends Artifact {
138
138
  readonly bytecodeTemplate: string;
@@ -185,10 +185,10 @@ export interface ContractEvent<T extends Fields = Fields> {
185
185
  fields: T;
186
186
  }
187
187
  export declare type DebugMessage = node.DebugMessage;
188
- export interface TestContractResult {
188
+ export interface TestContractResult<R> {
189
189
  contractId: string;
190
190
  contractAddress: string;
191
- returns: Val[];
191
+ returns: R;
192
192
  gasUsed: number;
193
193
  contracts: ContractState[];
194
194
  txOutputs: Output[];
@@ -220,11 +220,12 @@ export interface DeployContractParams<P extends Fields = Fields> {
220
220
  export declare type DeployContractResult<T> = SignDeployContractTxResult & {
221
221
  instance: T;
222
222
  };
223
- export declare abstract class ContractFactory<T, P extends Fields = Fields> {
223
+ export declare abstract class ContractFactory<I, F extends Fields = Fields> {
224
224
  readonly contract: Contract;
225
225
  constructor(contract: Contract);
226
- deploy(signer: SignerProvider, deployParams: DeployContractParams<P>): Promise<DeployContractResult<T>>;
227
- abstract at(address: string): T;
226
+ abstract at(address: string): I;
227
+ deploy(signer: SignerProvider, deployParams: DeployContractParams<F>): Promise<DeployContractResult<I>>;
228
+ stateForTest(initFields: F, asset?: Asset, address?: string): ContractState<F>;
228
229
  }
229
230
  export interface ExecuteScriptParams<P extends Fields = Fields> {
230
231
  initialFields: P;
@@ -248,8 +249,8 @@ export interface CallContractParams<T extends Arguments = Arguments> {
248
249
  existingContracts?: string[];
249
250
  inputAssets?: node.TestInputAsset[];
250
251
  }
251
- export interface CallContractResult {
252
- returns: Val[];
252
+ export interface CallContractResult<R> {
253
+ returns: R;
253
254
  gasUsed: number;
254
255
  contracts: ContractState[];
255
256
  txInputs: string[];
@@ -264,5 +265,19 @@ export declare type ContractDestroyedEvent = ContractEvent<{
264
265
  }>;
265
266
  export declare function decodeContractCreatedEvent(event: node.ContractEvent): Omit<ContractCreatedEvent, 'contractAddress'>;
266
267
  export declare function decodeContractDestroyedEvent(event: node.ContractEvent): Omit<ContractDestroyedEvent, 'contractAddress'>;
267
- export declare function subscribeEventsFromContract<T extends Fields>(options: SubscribeOptions<ContractEvent<T>>, address: string, eventIndex: number, decodeFunc: (event: node.ContractEvent) => ContractEvent<T>, fromCount?: number): EventSubscription;
268
+ export declare function subscribeEventsFromContract<T extends Fields, M extends ContractEvent<T>>(options: SubscribeOptions<M>, address: string, eventIndex: number, decodeFunc: (event: node.ContractEvent) => M, fromCount?: number): EventSubscription;
269
+ export declare function testMethod<I, F extends Fields, A extends Arguments, R>(contract: ContractFactory<I, F>, methodName: string, params: Optional<TestContractParams<F, A>, 'testArgs' | 'initialFields'>): Promise<TestContractResult<R>>;
270
+ export declare abstract class ContractInstance {
271
+ readonly address: Address;
272
+ readonly contractId: string;
273
+ readonly groupIndex: number;
274
+ constructor(address: Address);
275
+ }
276
+ export declare function fetchContractState<F extends Fields, I extends ContractInstance>(contract: ContractFactory<I, F>, instance: ContractInstance): Promise<ContractState<F>>;
277
+ export declare function subscribeContractCreatedEvent(instance: ContractInstance, options: SubscribeOptions<ContractCreatedEvent>, fromCount?: number): EventSubscription;
278
+ export declare function subscribeContractDestroyedEvent(instance: ContractInstance, options: SubscribeOptions<ContractDestroyedEvent>, fromCount?: number): EventSubscription;
279
+ export declare function decodeEvent<F extends Fields, M extends ContractEvent<F>>(contract: Contract, instance: ContractInstance, event: node.ContractEvent, targetEventIndex: number): M;
280
+ export declare function subscribeContractEvent<F extends Fields, M extends ContractEvent<F>>(contract: Contract, instance: ContractInstance, options: SubscribeOptions<M>, eventName: string, fromCount?: number): EventSubscription;
281
+ export declare function subscribeAllEvents(contract: Contract, instance: ContractInstance, options: SubscribeOptions<ContractEvent<any>>, fromCount?: number): EventSubscription;
282
+ export declare function callMethod<I, F extends Fields, A extends Arguments, R>(contract: ContractFactory<I, F>, instance: ContractInstance, methodName: string, params: Optional<CallContractParams<A>, 'args'>): Promise<CallContractResult<R>>;
268
283
  export {};
@@ -43,7 +43,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43
43
  return (mod && mod.__esModule) ? mod : { "default": mod };
44
44
  };
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
- exports.subscribeEventsFromContract = exports.decodeContractDestroyedEvent = exports.decodeContractCreatedEvent = exports.ContractFactory = exports.randomTxId = exports.toApiVals = exports.Script = exports.Contract = exports.Artifact = exports.Project = exports.DEFAULT_COMPILER_OPTIONS = exports.DEFAULT_NODE_COMPILER_OPTIONS = void 0;
46
+ exports.callMethod = exports.subscribeAllEvents = exports.subscribeContractEvent = exports.decodeEvent = exports.subscribeContractDestroyedEvent = exports.subscribeContractCreatedEvent = exports.fetchContractState = exports.ContractInstance = exports.testMethod = exports.subscribeEventsFromContract = exports.decodeContractDestroyedEvent = exports.decodeContractCreatedEvent = exports.ContractFactory = exports.randomTxId = exports.toApiVals = exports.Script = exports.Contract = exports.Artifact = exports.Project = exports.DEFAULT_COMPILER_OPTIONS = exports.DEFAULT_NODE_COMPILER_OPTIONS = void 0;
47
47
  const buffer_1 = require("buffer/");
48
48
  const crypto_1 = require("crypto");
49
49
  const fs_1 = __importDefault(require("fs"));
@@ -54,6 +54,7 @@ const utils_1 = require("../utils");
54
54
  const global_1 = require("../global");
55
55
  const path = __importStar(require("path"));
56
56
  const events_1 = require("./events");
57
+ const constants_1 = require("../constants");
57
58
  var SourceKind;
58
59
  (function (SourceKind) {
59
60
  SourceKind[SourceKind["Contract"] = 0] = "Contract";
@@ -598,14 +599,18 @@ class Contract extends Artifact {
598
599
  fields: fromApiEventFields(event.fields, eventSig)
599
600
  };
600
601
  }
601
- fromApiTestContractResult(methodIndex, result, txId) {
602
+ fromApiTestContractResult(methodName, result, txId) {
603
+ const methodIndex = this.functions.findIndex((sig) => sig.name === methodName);
604
+ const returnTypes = this.functions[`${methodIndex}`].returnTypes;
605
+ const rawReturn = (0, api_1.fromApiArray)(result.returns, returnTypes);
606
+ const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn;
602
607
  const addressToCodeHash = new Map();
603
608
  addressToCodeHash.set(result.address, result.codeHash);
604
609
  result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash));
605
610
  return {
606
611
  contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(result.address)),
607
612
  contractAddress: result.address,
608
- returns: (0, api_1.fromApiArray)(result.returns, this.functions[`${methodIndex}`].returnTypes),
613
+ returns: returns,
609
614
  gasUsed: result.gasUsed,
610
615
  contracts: result.contracts.map((contract) => Contract.fromApiContractState(contract)),
611
616
  txOutputs: result.txOutputs.map(fromApiOutput),
@@ -653,10 +658,11 @@ class Contract extends Artifact {
653
658
  };
654
659
  }
655
660
  fromApiCallContractResult(result, txId, methodIndex) {
661
+ const returnTypes = this.functions[`${methodIndex}`].returnTypes;
662
+ const rawReturn = (0, api_1.fromApiArray)(result.returns, returnTypes);
663
+ const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn;
656
664
  const addressToCodeHash = new Map();
657
665
  result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash));
658
- const functionSig = this.functions[`${methodIndex}`];
659
- const returns = (0, api_1.fromApiArray)(result.returns, functionSig.returnTypes);
660
666
  return {
661
667
  returns: returns,
662
668
  gasUsed: result.gasUsed,
@@ -856,6 +862,14 @@ class ContractFactory {
856
862
  instance: this.at(result.contractAddress)
857
863
  };
858
864
  }
865
+ // This is used for testing contract functions
866
+ stateForTest(initFields, asset, address) {
867
+ const newAsset = {
868
+ alphAmount: asset?.alphAmount ?? constants_1.ONE_ALPH,
869
+ tokens: asset?.tokens
870
+ };
871
+ return this.contract.toState(initFields, newAsset, address);
872
+ }
859
873
  }
860
874
  exports.ContractFactory = ContractFactory;
861
875
  function decodeFields(event, eventSig, eventIndex) {
@@ -904,3 +918,120 @@ function subscribeEventsFromContract(options, address, eventIndex, decodeFunc, f
904
918
  return (0, events_1.subscribeToEvents)(opt, address, fromCount);
905
919
  }
906
920
  exports.subscribeEventsFromContract = subscribeEventsFromContract;
921
+ async function testMethod(contract, methodName, params) {
922
+ const txId = params?.txId ?? randomTxId();
923
+ const apiParams = contract.contract.toApiTestContractParams(methodName, {
924
+ ...params,
925
+ txId: txId,
926
+ initialFields: params.initialFields === undefined ? {} : params.initialFields,
927
+ testArgs: params.testArgs === undefined ? {} : params.testArgs
928
+ });
929
+ const apiResult = await (0, global_1.getCurrentNodeProvider)().contracts.postContractsTestContract(apiParams);
930
+ const testResult = contract.contract.fromApiTestContractResult(methodName, apiResult, txId);
931
+ contract.contract.printDebugMessages(methodName, testResult.debugMessages);
932
+ return testResult;
933
+ }
934
+ exports.testMethod = testMethod;
935
+ class ContractInstance {
936
+ constructor(address) {
937
+ this.address = address;
938
+ this.contractId = (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(address));
939
+ this.groupIndex = (0, utils_1.groupOfAddress)(address);
940
+ }
941
+ }
942
+ exports.ContractInstance = ContractInstance;
943
+ async function fetchContractState(contract, instance) {
944
+ const contractState = await (0, global_1.getCurrentNodeProvider)().contracts.getContractsAddressState(instance.address, {
945
+ group: instance.groupIndex
946
+ });
947
+ const state = contract.contract.fromApiContractState(contractState);
948
+ return {
949
+ ...state,
950
+ fields: state.fields
951
+ };
952
+ }
953
+ exports.fetchContractState = fetchContractState;
954
+ function subscribeContractCreatedEvent(instance, options, fromCount) {
955
+ return subscribeEventsFromContract(options, instance.address, Contract.ContractCreatedEventIndex, (event) => {
956
+ return {
957
+ ...decodeContractCreatedEvent(event),
958
+ contractAddress: instance.address
959
+ };
960
+ }, fromCount);
961
+ }
962
+ exports.subscribeContractCreatedEvent = subscribeContractCreatedEvent;
963
+ function subscribeContractDestroyedEvent(instance, options, fromCount) {
964
+ return subscribeEventsFromContract(options, instance.address, Contract.ContractDestroyedEventIndex, (event) => {
965
+ return {
966
+ ...decodeContractDestroyedEvent(event),
967
+ contractAddress: instance.address
968
+ };
969
+ }, fromCount);
970
+ }
971
+ exports.subscribeContractDestroyedEvent = subscribeContractDestroyedEvent;
972
+ function decodeEvent(contract, instance, event, targetEventIndex) {
973
+ if (event.eventIndex !== targetEventIndex &&
974
+ !(targetEventIndex >= 0 && targetEventIndex < contract.eventsSig.length)) {
975
+ throw new Error('Invalid event index: ' + event.eventIndex + ', expected: ' + targetEventIndex);
976
+ }
977
+ const eventSig = contract.eventsSig[`${targetEventIndex}`];
978
+ const fieldNames = eventSig.fieldNames;
979
+ const fieldTypes = eventSig.fieldTypes;
980
+ const fields = (0, api_1.fromApiVals)(event.fields, fieldNames, fieldTypes);
981
+ return {
982
+ contractAddress: instance.address,
983
+ blockHash: event.blockHash,
984
+ txId: event.txId,
985
+ eventIndex: event.eventIndex,
986
+ name: eventSig.name,
987
+ fields: fields
988
+ };
989
+ }
990
+ exports.decodeEvent = decodeEvent;
991
+ function subscribeContractEvent(contract, instance, options, eventName, fromCount) {
992
+ const eventIndex = contract.eventsSig.findIndex((sig) => sig.name === eventName);
993
+ return subscribeEventsFromContract(options, instance.address, eventIndex, (event) => decodeEvent(contract, instance, event, eventIndex), fromCount);
994
+ }
995
+ exports.subscribeContractEvent = subscribeContractEvent;
996
+ function subscribeAllEvents(contract, instance, options, fromCount) {
997
+ const messageCallback = (event) => {
998
+ switch (event.eventIndex) {
999
+ case Contract.ContractCreatedEventIndex: {
1000
+ return options.messageCallback({
1001
+ ...decodeContractCreatedEvent(event),
1002
+ contractAddress: instance.address
1003
+ });
1004
+ }
1005
+ case Contract.ContractDestroyedEventIndex: {
1006
+ return options.messageCallback({
1007
+ ...decodeContractDestroyedEvent(event),
1008
+ contractAddress: instance.address
1009
+ });
1010
+ }
1011
+ default:
1012
+ return options.messageCallback({
1013
+ ...decodeEvent(contract, instance, event, event.eventIndex),
1014
+ contractAddress: instance.address
1015
+ });
1016
+ }
1017
+ };
1018
+ const errorCallback = (err, subscription) => {
1019
+ return options.errorCallback(err, subscription);
1020
+ };
1021
+ const opt = {
1022
+ pollingInterval: options.pollingInterval,
1023
+ messageCallback: messageCallback,
1024
+ errorCallback: errorCallback
1025
+ };
1026
+ return (0, events_1.subscribeToEvents)(opt, instance.address, fromCount);
1027
+ }
1028
+ exports.subscribeAllEvents = subscribeAllEvents;
1029
+ async function callMethod(contract, instance, methodName, params) {
1030
+ const methodIndex = contract.contract.getMethodIndex(methodName);
1031
+ const txId = params?.txId ?? randomTxId();
1032
+ const callParams = contract.contract.toApiCallContract({ ...params, txId: txId, args: params.args === undefined ? {} : params.args }, instance.groupIndex, instance.address, methodIndex);
1033
+ const result = await (0, global_1.getCurrentNodeProvider)().contracts.postContractsCallContract(callParams);
1034
+ const callResult = contract.contract.fromApiCallContractResult(result, txId, methodIndex);
1035
+ return callResult;
1036
+ }
1037
+ exports.callMethod = callMethod;
@@ -29,4 +29,5 @@ export declare type Eq<X, Y> = _Eq<{
29
29
  [P in keyof Y]: Y[P];
30
30
  }>;
31
31
  export declare function assertType<T extends true>(): void;
32
+ export declare type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
32
33
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alephium/web3",
3
- "version": "0.5.0-rc.0",
3
+ "version": "0.5.0-rc.1",
4
4
  "description": "A JS/TS library to interact with the Alephium platform",
5
5
  "license": "GPL",
6
6
  "main": "dist/src/index.js",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "author": "Alephium dev <dev@alephium.org>",
29
29
  "config": {
30
- "alephium_version": "1.7.0-rc1",
30
+ "alephium_version": "1.7.0",
31
31
  "explorer_backend_version": "1.12.0"
32
32
  },
33
33
  "scripts": {
@@ -40,13 +40,25 @@ import {
40
40
  SignDeployContractTxParams,
41
41
  SignDeployContractTxResult,
42
42
  SignExecuteScriptTxParams,
43
- SignerProvider
43
+ SignerProvider,
44
+ Address
44
45
  } from '../signer'
45
46
  import * as ralph from './ralph'
46
- import { bs58, binToHex, contractIdFromAddress, SubscribeOptions, Subscription, assertType, Eq } from '../utils'
47
+ import {
48
+ bs58,
49
+ binToHex,
50
+ contractIdFromAddress,
51
+ SubscribeOptions,
52
+ Subscription,
53
+ assertType,
54
+ Eq,
55
+ Optional,
56
+ groupOfAddress
57
+ } from '../utils'
47
58
  import { getCurrentNodeProvider } from '../global'
48
59
  import * as path from 'path'
49
60
  import { EventSubscription, subscribeToEvents } from './events'
61
+ import { ONE_ALPH } from '../constants'
50
62
 
51
63
  export type FieldsSig = node.FieldsSig
52
64
  export type EventSig = node.EventSig
@@ -871,14 +883,23 @@ export class Contract extends Artifact {
871
883
  }
872
884
  }
873
885
 
874
- fromApiTestContractResult(methodIndex: number, result: node.TestContractResult, txId: string): TestContractResult {
886
+ fromApiTestContractResult(
887
+ methodName: string,
888
+ result: node.TestContractResult,
889
+ txId: string
890
+ ): TestContractResult<unknown> {
891
+ const methodIndex = this.functions.findIndex((sig) => sig.name === methodName)
892
+ const returnTypes = this.functions[`${methodIndex}`].returnTypes
893
+ const rawReturn = fromApiArray(result.returns, returnTypes)
894
+ const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn
895
+
875
896
  const addressToCodeHash = new Map<string, string>()
876
897
  addressToCodeHash.set(result.address, result.codeHash)
877
898
  result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash))
878
899
  return {
879
900
  contractId: binToHex(contractIdFromAddress(result.address)),
880
901
  contractAddress: result.address,
881
- returns: fromApiArray(result.returns, this.functions[`${methodIndex}`].returnTypes),
902
+ returns: returns,
882
903
  gasUsed: result.gasUsed,
883
904
  contracts: result.contracts.map((contract) => Contract.fromApiContractState(contract)),
884
905
  txOutputs: result.txOutputs.map(fromApiOutput),
@@ -941,11 +962,17 @@ export class Contract extends Artifact {
941
962
  }
942
963
  }
943
964
 
944
- fromApiCallContractResult(result: node.CallContractResult, txId: string, methodIndex: number): CallContractResult {
965
+ fromApiCallContractResult(
966
+ result: node.CallContractResult,
967
+ txId: string,
968
+ methodIndex: number
969
+ ): CallContractResult<unknown> {
970
+ const returnTypes = this.functions[`${methodIndex}`].returnTypes
971
+ const rawReturn = fromApiArray(result.returns, returnTypes)
972
+ const returns = rawReturn.length === 0 ? null : rawReturn.length === 1 ? rawReturn[0] : rawReturn
973
+
945
974
  const addressToCodeHash = new Map<string, string>()
946
975
  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
976
  return {
950
977
  returns: returns,
951
978
  gasUsed: result.gasUsed,
@@ -1180,10 +1207,10 @@ export interface ContractEvent<T extends Fields = Fields> {
1180
1207
 
1181
1208
  export type DebugMessage = node.DebugMessage
1182
1209
 
1183
- export interface TestContractResult {
1210
+ export interface TestContractResult<R> {
1184
1211
  contractId: string
1185
1212
  contractAddress: string
1186
- returns: Val[]
1213
+ returns: R
1187
1214
  gasUsed: number
1188
1215
  contracts: ContractState[]
1189
1216
  txOutputs: Output[]
@@ -1250,13 +1277,16 @@ assertType<
1250
1277
  >
1251
1278
  export type DeployContractResult<T> = SignDeployContractTxResult & { instance: T }
1252
1279
 
1253
- export abstract class ContractFactory<T, P extends Fields = Fields> {
1280
+ export abstract class ContractFactory<I, F extends Fields = Fields> {
1254
1281
  readonly contract: Contract
1282
+
1255
1283
  constructor(contract: Contract) {
1256
1284
  this.contract = contract
1257
1285
  }
1258
1286
 
1259
- async deploy(signer: SignerProvider, deployParams: DeployContractParams<P>): Promise<DeployContractResult<T>> {
1287
+ abstract at(address: string): I
1288
+
1289
+ async deploy(signer: SignerProvider, deployParams: DeployContractParams<F>): Promise<DeployContractResult<I>> {
1260
1290
  const signerParams = await this.contract.txParamsForDeployment(signer, deployParams)
1261
1291
  const result = await signer.signAndSubmitDeployContractTx(signerParams)
1262
1292
  return {
@@ -1265,7 +1295,14 @@ export abstract class ContractFactory<T, P extends Fields = Fields> {
1265
1295
  }
1266
1296
  }
1267
1297
 
1268
- abstract at(address: string): T
1298
+ // This is used for testing contract functions
1299
+ stateForTest(initFields: F, asset?: Asset, address?: string): ContractState<F> {
1300
+ const newAsset = {
1301
+ alphAmount: asset?.alphAmount ?? ONE_ALPH,
1302
+ tokens: asset?.tokens
1303
+ }
1304
+ return this.contract.toState(initFields, newAsset, address)
1305
+ }
1269
1306
  }
1270
1307
 
1271
1308
  export interface ExecuteScriptParams<P extends Fields = Fields> {
@@ -1293,8 +1330,8 @@ export interface CallContractParams<T extends Arguments = Arguments> {
1293
1330
  inputAssets?: node.TestInputAsset[]
1294
1331
  }
1295
1332
 
1296
- export interface CallContractResult {
1297
- returns: Val[]
1333
+ export interface CallContractResult<R> {
1334
+ returns: R
1298
1335
  gasUsed: number
1299
1336
  contracts: ContractState[]
1300
1337
  txInputs: string[]
@@ -1336,11 +1373,11 @@ export function decodeContractDestroyedEvent(
1336
1373
  }
1337
1374
  }
1338
1375
 
1339
- export function subscribeEventsFromContract<T extends Fields>(
1340
- options: SubscribeOptions<ContractEvent<T>>,
1376
+ export function subscribeEventsFromContract<T extends Fields, M extends ContractEvent<T>>(
1377
+ options: SubscribeOptions<M>,
1341
1378
  address: string,
1342
1379
  eventIndex: number,
1343
- decodeFunc: (event: node.ContractEvent) => ContractEvent<T>,
1380
+ decodeFunc: (event: node.ContractEvent) => M,
1344
1381
  fromCount?: number
1345
1382
  ): EventSubscription {
1346
1383
  const messageCallback = (event: node.ContractEvent): Promise<void> => {
@@ -1351,7 +1388,7 @@ export function subscribeEventsFromContract<T extends Fields>(
1351
1388
  }
1352
1389
 
1353
1390
  const errorCallback = (err: any, subscription: Subscription<node.ContractEvent>): Promise<void> => {
1354
- return options.errorCallback(err, subscription as unknown as Subscription<ContractEvent<T>>)
1391
+ return options.errorCallback(err, subscription as unknown as Subscription<M>)
1355
1392
  }
1356
1393
  const opt: SubscribeOptions<node.ContractEvent> = {
1357
1394
  pollingInterval: options.pollingInterval,
@@ -1360,3 +1397,187 @@ export function subscribeEventsFromContract<T extends Fields>(
1360
1397
  }
1361
1398
  return subscribeToEvents(opt, address, fromCount)
1362
1399
  }
1400
+
1401
+ export async function testMethod<I, F extends Fields, A extends Arguments, R>(
1402
+ contract: ContractFactory<I, F>,
1403
+ methodName: string,
1404
+ params: Optional<TestContractParams<F, A>, 'testArgs' | 'initialFields'>
1405
+ ): Promise<TestContractResult<R>> {
1406
+ const txId = params?.txId ?? randomTxId()
1407
+ const apiParams = contract.contract.toApiTestContractParams(methodName, {
1408
+ ...params,
1409
+ txId: txId,
1410
+ initialFields: params.initialFields === undefined ? {} : params.initialFields,
1411
+ testArgs: params.testArgs === undefined ? {} : params.testArgs
1412
+ })
1413
+ const apiResult = await getCurrentNodeProvider().contracts.postContractsTestContract(apiParams)
1414
+ const testResult = contract.contract.fromApiTestContractResult(methodName, apiResult, txId)
1415
+ contract.contract.printDebugMessages(methodName, testResult.debugMessages)
1416
+ return testResult as TestContractResult<R>
1417
+ }
1418
+
1419
+ export abstract class ContractInstance {
1420
+ readonly address: Address
1421
+ readonly contractId: string
1422
+ readonly groupIndex: number
1423
+
1424
+ constructor(address: Address) {
1425
+ this.address = address
1426
+ this.contractId = binToHex(contractIdFromAddress(address))
1427
+ this.groupIndex = groupOfAddress(address)
1428
+ }
1429
+ }
1430
+
1431
+ export async function fetchContractState<F extends Fields, I extends ContractInstance>(
1432
+ contract: ContractFactory<I, F>,
1433
+ instance: ContractInstance
1434
+ ): Promise<ContractState<F>> {
1435
+ const contractState = await getCurrentNodeProvider().contracts.getContractsAddressState(instance.address, {
1436
+ group: instance.groupIndex
1437
+ })
1438
+ const state = contract.contract.fromApiContractState(contractState)
1439
+ return {
1440
+ ...state,
1441
+ fields: state.fields as F
1442
+ }
1443
+ }
1444
+
1445
+ export function subscribeContractCreatedEvent(
1446
+ instance: ContractInstance,
1447
+ options: SubscribeOptions<ContractCreatedEvent>,
1448
+ fromCount?: number
1449
+ ): EventSubscription {
1450
+ return subscribeEventsFromContract(
1451
+ options,
1452
+ instance.address,
1453
+ Contract.ContractCreatedEventIndex,
1454
+ (event) => {
1455
+ return {
1456
+ ...decodeContractCreatedEvent(event),
1457
+ contractAddress: instance.address
1458
+ }
1459
+ },
1460
+ fromCount
1461
+ )
1462
+ }
1463
+
1464
+ export function subscribeContractDestroyedEvent(
1465
+ instance: ContractInstance,
1466
+ options: SubscribeOptions<ContractDestroyedEvent>,
1467
+ fromCount?: number
1468
+ ): EventSubscription {
1469
+ return subscribeEventsFromContract(
1470
+ options,
1471
+ instance.address,
1472
+ Contract.ContractDestroyedEventIndex,
1473
+ (event) => {
1474
+ return {
1475
+ ...decodeContractDestroyedEvent(event),
1476
+ contractAddress: instance.address
1477
+ }
1478
+ },
1479
+ fromCount
1480
+ )
1481
+ }
1482
+
1483
+ export function decodeEvent<F extends Fields, M extends ContractEvent<F>>(
1484
+ contract: Contract,
1485
+ instance: ContractInstance,
1486
+ event: node.ContractEvent,
1487
+ targetEventIndex: number
1488
+ ): M {
1489
+ if (
1490
+ event.eventIndex !== targetEventIndex &&
1491
+ !(targetEventIndex >= 0 && targetEventIndex < contract.eventsSig.length)
1492
+ ) {
1493
+ throw new Error('Invalid event index: ' + event.eventIndex + ', expected: ' + targetEventIndex)
1494
+ }
1495
+ const eventSig = contract.eventsSig[`${targetEventIndex}`]
1496
+ const fieldNames = eventSig.fieldNames
1497
+ const fieldTypes = eventSig.fieldTypes
1498
+ const fields = fromApiVals(event.fields, fieldNames, fieldTypes)
1499
+ return {
1500
+ contractAddress: instance.address,
1501
+ blockHash: event.blockHash,
1502
+ txId: event.txId,
1503
+ eventIndex: event.eventIndex,
1504
+ name: eventSig.name,
1505
+ fields: fields
1506
+ } as M
1507
+ }
1508
+
1509
+ export function subscribeContractEvent<F extends Fields, M extends ContractEvent<F>>(
1510
+ contract: Contract,
1511
+ instance: ContractInstance,
1512
+ options: SubscribeOptions<M>,
1513
+ eventName: string,
1514
+ fromCount?: number
1515
+ ): EventSubscription {
1516
+ const eventIndex = contract.eventsSig.findIndex((sig) => sig.name === eventName)
1517
+ return subscribeEventsFromContract<F, M>(
1518
+ options,
1519
+ instance.address,
1520
+ eventIndex,
1521
+ (event) => decodeEvent(contract, instance, event, eventIndex),
1522
+ fromCount
1523
+ )
1524
+ }
1525
+
1526
+ export function subscribeAllEvents(
1527
+ contract: Contract,
1528
+ instance: ContractInstance,
1529
+ options: SubscribeOptions<ContractEvent<any>>,
1530
+ fromCount?: number
1531
+ ): EventSubscription {
1532
+ const messageCallback = (event: node.ContractEvent): Promise<void> => {
1533
+ switch (event.eventIndex) {
1534
+ case Contract.ContractCreatedEventIndex: {
1535
+ return options.messageCallback({
1536
+ ...decodeContractCreatedEvent(event),
1537
+ contractAddress: instance.address
1538
+ })
1539
+ }
1540
+
1541
+ case Contract.ContractDestroyedEventIndex: {
1542
+ return options.messageCallback({
1543
+ ...decodeContractDestroyedEvent(event),
1544
+ contractAddress: instance.address
1545
+ })
1546
+ }
1547
+
1548
+ default:
1549
+ return options.messageCallback({
1550
+ ...decodeEvent(contract, instance, event, event.eventIndex),
1551
+ contractAddress: instance.address
1552
+ })
1553
+ }
1554
+ }
1555
+ const errorCallback = (err: any, subscription: Subscription<node.ContractEvent>): Promise<void> => {
1556
+ return options.errorCallback(err, subscription as unknown as Subscription<ContractEvent<any>>)
1557
+ }
1558
+ const opt: SubscribeOptions<node.ContractEvent> = {
1559
+ pollingInterval: options.pollingInterval,
1560
+ messageCallback: messageCallback,
1561
+ errorCallback: errorCallback
1562
+ }
1563
+ return subscribeToEvents(opt, instance.address, fromCount)
1564
+ }
1565
+
1566
+ export async function callMethod<I, F extends Fields, A extends Arguments, R>(
1567
+ contract: ContractFactory<I, F>,
1568
+ instance: ContractInstance,
1569
+ methodName: string,
1570
+ params: Optional<CallContractParams<A>, 'args'>
1571
+ ): Promise<CallContractResult<R>> {
1572
+ const methodIndex = contract.contract.getMethodIndex(methodName)
1573
+ const txId = params?.txId ?? randomTxId()
1574
+ const callParams = contract.contract.toApiCallContract(
1575
+ { ...params, txId: txId, args: params.args === undefined ? {} : params.args },
1576
+ instance.groupIndex,
1577
+ instance.address,
1578
+ methodIndex
1579
+ )
1580
+ const result = await getCurrentNodeProvider().contracts.postContractsCallContract(callParams)
1581
+ const callResult = contract.contract.fromApiCallContractResult(result, txId, methodIndex)
1582
+ return callResult as CallContractResult<R>
1583
+ }
@@ -219,3 +219,4 @@ type _Eq<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1
219
219
  export type Eq<X, Y> = _Eq<{ [P in keyof X]: X[P] }, { [P in keyof Y]: Y[P] }>
220
220
  // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
221
221
  export function assertType<T extends true>(): void {}
222
+ export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>