@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
172 lines (171 loc) • 7.24 kB
TypeScript
/**
* Contract module - routines to interact with the æternity contract
*
* High level documentation of the contracts are available at
* https://github.com/aeternity/protocol/tree/master/contracts and
*/
import { Encoder as Calldata } from '@aeternity/aepp-calldata';
import { Tag, AensName } from '../tx/builder/constants.js';
import { BuildTxOptions } from '../tx/builder/index.js';
import { Encoded } from '../utils/encoder.js';
import { ContractCallObject as NodeContractCallObject, Event as NodeEvent } from '../apis/node/index.js';
import CompilerBase, { Aci } from './compiler/Base.js';
import Node from '../Node.js';
import { txDryRun } from '../chain.js';
import { sendTransaction, SendTransactionOptions } from '../send-transaction.js';
import { TxUnpacked } from '../tx/builder/schema.generated.js';
import { Optional } from '../utils/other.js';
interface Event extends NodeEvent {
address: Encoded.ContractAddress;
data: Encoded.ContractBytearray;
}
export interface ContractCallObject extends NodeContractCallObject {
returnValue: Encoded.ContractBytearray;
log: Event[];
}
interface DecodedEvent {
name: string;
args: unknown[];
contract: {
name: string;
address: Encoded.ContractAddress;
};
}
type TxData = Awaited<ReturnType<typeof sendTransaction>>;
interface SendAndProcessReturnType {
result?: ContractCallObject;
hash: TxData['hash'];
tx: TxUnpacked & {
tag: Tag.SignedTx | Tag.ContractCallTx | Tag.ContractCreateTx;
};
txData: TxData;
rawTx: Encoded.Transaction;
}
/**
* @category contract
*/
export interface ContractMethodsBase {
[key: string]: (...args: any[]) => any;
}
type MethodsToContractApi<M extends ContractMethodsBase> = {
[Name in keyof M]: M[Name] extends (...args: infer Args) => infer Ret ? (...args: [
...Args,
...([] | [
Name extends 'init' ? Parameters<Contract<M>['$deploy']>[1] : Parameters<Contract<M>['$call']>[2]
])
]) => Promise<Omit<Awaited<ReturnType<Contract<M>['$call']>>, 'decodedResult'> & {
decodedResult: Ret;
}> : never;
};
/**
* @category contract
*/
type ContractWithMethods<M extends ContractMethodsBase> = Contract<M> & MethodsToContractApi<M>;
type MethodNames<M extends ContractMethodsBase> = (keyof M & string) | 'init';
type MethodParameters<M extends ContractMethodsBase, Fn extends MethodNames<M>> = Fn extends 'init' ? M extends {
init: any;
} ? Parameters<M['init']> : [] : Parameters<M[Fn]>;
interface GetContractNameByEventOptions {
contractAddressToName?: {
[key: Encoded.ContractAddress]: string;
};
}
interface GetCallResultByHashReturnType<M extends ContractMethodsBase, Fn extends MethodNames<M>> {
decodedResult: ReturnType<M[Fn]>;
decodedEvents?: ReturnType<Contract<M>['$decodeEvents']>;
}
/**
* Generate contract ACI object with predefined js methods for contract usage - can be used for
* creating a reference to already deployed contracts
* @category contract
* @param options - Options object
* @returns JS Contract API
* @example
* ```js
* const contractIns = await Contract.initialize({ ...aeSdk.getContext(), sourceCode })
* await contractIns.$deploy([321]) or await contractIns.init(321)
* const callResult = await contractIns.$call('setState', [123])
* const staticCallResult = await contractIns.$call('setState', [123], { callStatic: true })
* ```
* Also you can call contract like: `await contractIns.setState(123, options)`
* Then sdk decide to make on-chain or static call (dry-run API) transaction based on function is
* stateful or not
*/
declare class Contract<M extends ContractMethodsBase> {
#private;
/**
* Compile contract
* @returns bytecode
*/
$compile(): Promise<Encoded.ContractBytearray>;
$getCallResultByTxHash<Fn extends MethodNames<M>>(hash: Encoded.TxHash, fnName: Fn, options?: Parameters<Contract<M>['$decodeEvents']>[1]): Promise<GetCallResultByHashReturnType<M, Fn> & {
result: ContractCallObject;
}>;
_estimateGas<Fn extends MethodNames<M>>(name: Fn, params: MethodParameters<M, Fn>, options?: Omit<Parameters<Contract<M>['$call']>[2], 'callStatic'>): Promise<number>;
/**
* Deploy contract
* @param params - Contract init function arguments array
* @param options - Options
* @returns deploy info
*/
$deploy(params: MethodParameters<M, 'init'>, options?: Parameters<Contract<M>['$call']>[2] & Partial<BuildTxOptions<Tag.ContractCreateTx, 'ownerId' | 'code' | 'callData'>>): Promise<Omit<SendAndProcessReturnType, 'hash'> & {
transaction?: Encoded.TxHash;
owner?: Encoded.AccountAddress;
address?: Encoded.ContractAddress;
decodedEvents?: ReturnType<Contract<M>['$decodeEvents']>;
}>;
/**
* Call contract function
* @param fn - Function name
* @param params - Array of function arguments
* @param options - Array of function arguments
* @returns CallResult
*/
$call<Fn extends MethodNames<M>>(fn: Fn, params: MethodParameters<M, Fn>, options?: Partial<BuildTxOptions<Tag.ContractCallTx, 'callerId' | 'contractId' | 'callData'>> & Parameters<Contract<M>['$decodeEvents']>[1] & Optional<SendTransactionOptions, 'onAccount' | 'onNode'> & Omit<Parameters<typeof txDryRun>[2], 'onNode'> & {
callStatic?: boolean;
}): Promise<SendAndProcessReturnType & Partial<GetCallResultByHashReturnType<M, Fn>>>;
/**
* Decode Events
* @param events - Array of encoded events (callRes.result.log)
* @param options - Options
* @returns DecodedEvents
*/
$decodeEvents(events: Event[], { omitUnknown, ...opt }?: {
omitUnknown?: boolean;
} & GetContractNameByEventOptions): DecodedEvent[];
static initialize<M extends ContractMethodsBase>({ onCompiler, onNode, bytecode, aci, address, sourceCodePath, sourceCode, fileSystem, validateBytecode, ...otherOptions }: Omit<ConstructorParameters<typeof Contract>[0], 'aci' | 'address'> & {
validateBytecode?: boolean;
aci?: Aci;
address?: Encoded.ContractAddress | AensName;
}): Promise<ContractWithMethods<M>>;
_aci: Aci;
_name: string;
_calldata: Calldata;
$options: Omit<ConstructorParameters<typeof Contract>[0], 'aci'>;
/**
* @param options - Options
*/
constructor({ aci, ...otherOptions }: {
onCompiler?: CompilerBase;
onNode: Node;
bytecode?: Encoded.ContractBytearray;
aci: Aci;
address?: Encoded.ContractAddress;
/**
* Supported only in Ceres
*/
name?: AensName;
sourceCodePath?: Parameters<CompilerBase['compile']>[0];
sourceCode?: Parameters<CompilerBase['compileBySourceCode']>[0];
fileSystem?: Parameters<CompilerBase['compileBySourceCode']>[1];
} & Parameters<Contract<M>['$deploy']>[1]);
}
interface ContractWithMethodsClass {
new <M extends ContractMethodsBase>(options: ConstructorParameters<typeof Contract>[0]): ContractWithMethods<M>;
initialize: (typeof Contract)['initialize'];
}
/**
* @category contract
*/
declare const ContractWithMethods: ContractWithMethodsClass;
export default ContractWithMethods;