@moonwall/types
Version:
Testing framework for the Moon family of projects
490 lines (489 loc) • 20.9 kB
TypeScript
import type { ApiPromise } from "@polkadot/api";
import type { ApiTypes } from "@polkadot/api/types";
import type { KeyringPair } from "@polkadot/keyring/types";
import type { Logger, LogFn } from "pino";
import type { Wallet, TransactionRequest } from "ethers";
import type { Abi, Account, createPublicClient, createWalletClient, Log, PublicActions, TransactionSerializable, Transport, WalletClient } from "viem";
import type { Chain } from "viem/chains";
import type { Web3 } from "web3";
import type { ForkConfig, FoundationType } from "./config";
import type { BlockCreation, BlockCreationResponse, ChopsticksBlockCreation } from "./context";
import type { ContractDeploymentOptions } from "./contracts";
import type { TransactionType } from "./eth";
import type { CallType } from "./foundations";
import type { DeepPartial, Prettify } from "./helpers";
import type { PolkadotClient } from "polkadot-api";
/**
* @name CustomTest
* @description The custom test type.
* @property id - A unique identifier for the test.
* @property title - The title of the test.
* @property test - A function to execute the test.
* @property modifier - An optional modifier to control test execution ("only" or "skip").
* @property minRtVersion - The minimum runtime version required for the test.
* @property chainType - The chain type required for the test.
* @property notChainType - The chain type excluded from the test.
* @property timeout - The test timeout value.
*/
export type CustomTest = (params: {
id: string;
title: string;
test: (vitestContext: any) => void;
modifier?: "only" | "skip";
minRtVersion?: number;
chainType?: "moonriver" | "moonbeam" | "moonbase";
notChainType?: "moonbeam" | "moonriver" | "moonbase";
timeout?: number;
}) => void;
export type FoundationMethod = "dev" | "chopsticks" | "zombie" | "read_only" | "fork";
export type ChainType = "moonbeam" | "moonriver" | "moonbase";
export type FoundationContextMap = {
[K in FoundationMethod]: K extends "dev" ? DevModeContext : K extends "chopsticks" ? ChopsticksContext : K extends "zombie" ? ZombieContext : K extends "read_only" ? ReadOnlyContext : GenericContext;
};
export type TestContextMap = {
[K in FoundationMethod]: ITestContext<FoundationContextMap[K]>;
};
export type TestCasesFn<T extends FoundationType> = (params: {
context: GenericContext & FoundationContextMap[T];
it: (params: ITestCase) => void;
log: LogFn;
logger: Logger;
}) => void;
export type TestCaseModifier = "only" | "skip";
export interface ITestCase {
id: string;
title: string;
test: (vitestContext: any) => void;
modifier?: TestCaseModifier;
minRtVersion?: number;
chainType?: "moonbeam" | "moonriver" | "moonbase";
notChainType?: "moonbeam" | "moonriver" | "moonbase";
timeout?: number;
}
export type TestSuiteConfig<T extends FoundationType = FoundationType> = {
id: string;
title: string;
foundationMethods: T;
description?: string;
testCases: TestCasesFn<T>;
};
export type FoundationHandler<T extends FoundationType> = (params: {
testCases: TestCasesFn<T>;
context: GenericContext;
testCase: (params: ITestCase) => void;
logger: Logger;
ctx?: any;
}) => void;
/**
* BETA: Represents overrides for launching a test environment.
* @property forkConfig - Optional configuration for forking a network.
*/
export type LaunchOverrides = {
forkConfig?: ForkConfig;
};
export type ITestSuiteType<T extends FoundationMethod> = {
id: string;
title: string;
testCases: (TestContext: TestContextMap[T]) => void;
foundationMethods: T;
options?: LaunchOverrides;
minRtVersion?: number;
chainType?: ChainType;
notChainType?: ChainType;
};
interface ITestContext<T extends GenericContext> {
context: T;
it: CustomTest;
log: LogFn;
logger: Logger;
}
/**
* @name DevTestContext
* @description The context for tests running in development mode.
* @property context - The context for the development mode.
* @property it - The CustomTest function for the test.
* @property log - The Logger instance for logging.
*/
export type DevTestContext = ITestContext<DevModeContext>;
/**
* @name ReadOnlyTestContext
* @description The context for tests running in read-only mode.
* @property context - The context for the read-only mode.
* @property it - The CustomTest function for the test.
* @property log - The Logger instance for logging.
*/
export type ReadOnlyTestContext = ITestContext<ReadOnlyContext>;
/**
* @name ChopsticksTestContext
* @description The context for tests running with chopsticks.
* @property context - The context for the chopsticks mode.
* @property it - The CustomTest function for the test.
* @property log - The Logger instance for logging.
*/
export type ChopsticksTestContext = ITestContext<ChopsticksContext>;
export type ZombieTestContext = ITestContext<ZombieContext>;
/**
* @name GenericTestContext
* @description The base test context for other contexts to extend, not to be used directly.
* @property context - The base context for other contexts to extend, not to be used directly.
* @property it - The CustomTest function for the test.
* @property log - The Logger instance for logging.
*/
export type GenericTestContext = ITestContext<GenericContext>;
/**
* @name UpgradePreferences
* @description The upgrade preferences object.
* @property runtimeName - The name of the runtime.
* @property runtimeTag - The tag of the runtime.
* @property from - The KeyringPair to be used for the upgrade.
* @property waitMigration - A flag to indicate whether to wait for migration.
* @property upgradeMethod - Specifies which upgrade method to use: "Governance", "WhiteListedCaller", "Sudo" (default).
* @property localPath - The local path for the runtime.
* @property logger - The debugger instance for logging.
*/
export interface UpgradePreferences {
runtimeName?: "moonbase" | "moonriver" | "moonbeam";
runtimeTag?: "local" | string;
from?: KeyringPair;
waitMigration?: boolean;
upgradeMethod?: "Governance" | "WhiteListedCaller" | "Sudo";
localPath?: string;
logger?: Logger | ((message: string) => void);
}
/**
* ViemClient - Combined type that contains both Wallet and Public viem client actions
*/
export type ViemClient = WalletClient<Transport, Chain, Account> & PublicActions;
export type ViemClientInterface = Prettify<ReturnType<typeof createWalletClient> & ReturnType<typeof createPublicClient>>;
/**
* GenericContext - Interface that encapsulates all the common methods and properties needed for all tests.
*/
export interface GenericContext {
api(type: "polkadotJs", name?: string): ApiPromise;
api(type: "ethers", name?: string): Wallet;
api(type: "web3", name?: string): Web3;
api(type: "viem", name?: string): ViemClient;
api(type: "papi", name?: string): PolkadotClient;
viem(name?: string): ViemClient;
polkadotJs(apiName?: string): ApiPromise;
ethers(name?: string): Wallet;
web3(name?: string): Web3;
papi(name?: string): PolkadotClient;
}
/**
* ReadOnlyContext - Interface that extends from GenericContext and includes the method for waiting a certain number of blocks.
*/
export interface ReadOnlyContext extends GenericContext {
waitBlock: (blocksToWaitFor?: number, chain?: string, mode?: "height" | "quantity") => Promise<void>;
}
/**
* ZombieContext - Interface that extends from GenericContext and includes methods for managing runtime upgrades and node operations within a blockchain network.
*/
export interface ZombieContext extends GenericContext {
/**
* Initiates the runtime upgrade process with the provided upgrade preferences.
*
* @param {UpgradePreferences} options The configuration options for the upgrade, including runtime details and migration settings.
* @returns {Promise<void>} A promise that resolves when the upgrade process has been initiated.
*/
upgradeRuntime: (options: UpgradePreferences) => Promise<void>;
/**
* ⚠️ WARNING: This doesn't seem to be working yet. ⚠️
*
* Checks if the specified node is running.
*
* @param {string} nodeName The name of the node to check.
* @returns {Promise<boolean>} A promise that resolves to a boolean indicating whether the node is up and running.
*/
isUp?: (nodeName: string) => Promise<boolean>;
/**
* Restarts the node with the given name.
*
* @param {string} nodeName The name of the node to restart.
* @returns {Promise<void>} A promise that resolves when the node restart has been completed.
*/
restartNode: (nodeName: string) => Promise<void>;
/**
* * ⚠️ WARNING: This doesn't seem to be working yet. ⚠️
*
* Pauses the node with the specified name.
*
* @param {string} nodeName The name of the node to pause.
* @returns {Promise<void>} A promise that resolves when the node has been successfully paused.
*/
pauseNode?: (nodeName: string) => Promise<void>;
/**
* ⚠️ WARNING: This doesn't seem to be working yet. ⚠️
*
* Resumes the operation of a paused node with the given name.
*
* @param {string} nodeName The name of the node to resume.
* @returns {Promise<void>} A promise that resolves when the node has resumed operations.
*/
resumeNode?: (nodeName: string) => Promise<void>;
/**
* Terminates the node with the provided name.
*
* @param {string} nodeName The name of the node to terminate.
* @returns {Promise<void>} A promise that resolves when the node has been successfully terminated.
*/
killNode: (nodeName: string) => Promise<void>;
/**
* Waits for a specified number of blocks before resolving. This can be based on block height or quantity, depending on the mode.
*
* @param {number} [blocksToWaitFor] The number of blocks to wait for before the promise resolves. If not provided, defaults to some predetermined quantity.
* @param {string} [chain] The name of the blockchain to monitor for block production.
* @param {"height" | "quantity"} [mode] The mode to determine the block wait criteria - by height or by quantity.
* @returns {Promise<void>} A promise that resolves after waiting for the specified number of blocks.
*/
waitBlock: (blocksToWaitFor?: number, chain?: string, mode?: "height" | "quantity") => Promise<void>;
}
/**
* ChopsticksContext - Interface that extends from GenericContext and includes methods for creating a block, setting storage, and upgrading runtime.
*/
export interface ChopsticksContext extends GenericContext {
/**
* Creates a block based on the given options.
*
* @param {ChopsticksBlockCreation} [options] Optional parameters for block creation.
* @returns {Promise<{ result: string }>} A Promise that resolves to an object containing the result string.
*/
createBlock: (options?: ChopsticksBlockCreation) => Promise<{
result: string;
}>;
/**
* Sets the storage based on the provided parameters.
*
* @param {Object} params The parameters required for setting storage.
* @param {string} [params.providerName] Optional name of the provider.
* @param {string} params.module The name of the module.
* @param {string} params.method The method to be called.
* @param {any} params.methodParams The parameters required for the method.
* @returns {Promise<void>} A Promise that resolves once the storage has been set.
*/
setStorage: (params: {
providerName?: string;
module: string;
method: string;
methodParams: any;
}) => Promise<void>;
/**
* Upgrades the runtime.
*
* @returns {Promise<void>} A Promise that resolves once the runtime has been upgraded.
*/
upgradeRuntime: (providerName?: string) => Promise<void>;
/**
* Getter that returns true if System.Account is AccountId20 (Ethereum Account length is 20 bytes).
*/
isEthereumChain: boolean;
/**
* Getter that returns an object with the default accounts already generated.
*/
keyring: {
alice: KeyringPair;
bob: KeyringPair;
charlie: KeyringPair;
dave: KeyringPair;
};
/**
* Property that returns true if System.Account is AccountId32 (Substrate Account length is 32 bytes).
*/
isSubstrateChain: boolean;
/**
* Default getter for a connected PolkadotJs ApiPromise instance
*/
pjsApi: ApiPromise;
/**
* Jump a specified number of ParachainStaking Rounds.
*
* @param {number} blocksToJump The number of ParachainStaking rounds to jump forward.
* @returns {Promise<void>} A Promise that resolves after the operation is fully complete.
*/
jumpRounds?: (options: {
rounds: number;
providerName?: string;
}) => Promise<void>;
}
/**
* DevModeContext - Interface that extends from GenericContext and includes a method for creating a block.
*/
export interface DevModeContext extends GenericContext {
/**
* Default getter for a connected PolkadotJs ApiPromise instance
*/
pjsApi: ApiPromise;
/**
* Getter that returns true if System.Account is AccountId20 (Ethereum Account length is 20 bytes).
*/
isEthereumChain: boolean;
/**
* Getter that returns true if chain has ParachainStaking pallet.
*/
isParachainStaking: boolean;
/**
* Getter that returns an object with the default accounts already generated.
*/
keyring: {
alice: KeyringPair;
bob: KeyringPair;
charlie: KeyringPair;
dave: KeyringPair;
};
/**
* Property that returns true if System.Account is AccountId32 (Substrate Account length is 32 bytes).
*/
isSubstrateChain: boolean;
/**
* Creates a block with given transactions and options.
*
* @template ApiType Type of API to be used.
* @template Calls Type of calls to be made, could be a single CallType or an array of CallType.
* @param {Calls} transactions An optional array of transactions.
* @param {BlockCreation} options Optional parameters for block creation.
* @returns {Promise<BlockCreationResponse<ApiType, Calls>>} A Promise that resolves to a BlockCreationResponse.
*/
createBlock<ApiType extends ApiTypes, Calls extends CallType<ApiType> | CallType<ApiType>[]>(transactions?: Calls, options?: BlockCreation): Promise<BlockCreationResponse<ApiType, Calls>>;
/**
* Creates a raw Ethereum transaction based on the given options.
*
* @template TOptions Type of option parameters to be used. Use libraryType to specify which web3 library to use
* (viem or ethers), otherwise will default to viem.
* @param {TOptions} options Options for creating a transaction.
* @returns {Promise<`0x${string}`>} A Promise that resolves to a raw transaction string prefixed with '0x'.
*/
createTxn?<TOptions extends (DeepPartial<ViemTransactionOptions> & {
libraryType?: "viem";
}) | (EthersTransactionOptions & {
libraryType: "ethers";
})>(options: TOptions): Promise<`0x${string}`>;
/**
* Execute a non-state changing transaction to a precompiled contract address (i.e. read).
*
* @param {PrecompileCallOptions} callOptions The options for the contract call.
* @returns {Promise<unknown>} A Promise that resolves to the return data from the contract call.
*/
readPrecompile?(callOptions: PrecompileCallOptions): Promise<unknown>;
/**
* Submit a state-changing transaction to a precompiled contract address.
*
* @param {PrecompileCallOptions} callOptions The options for the contract call.
* @returns {Promise<`0x${string}`>} The transaction hash that resolves after the write operation has been completed.
*/
writePrecompile?(callOptions: PrecompileCallOptions): Promise<`0x${string}`>;
/**
* Execute a non-state changing transaction to a deployed contract address (i.e. read).
*
* @param {ContractCallOptions} callOptions The options for the contract call.
* @returns {Promise<unknown>} A Promise that resolves to the return data from the contract call.
*/
readContract?(callOptions: ContractCallOptions): Promise<unknown>;
/**
* Submit a state-changing transaction to a deployed contract address.
*
* @param {ContractCallOptions} callOptions The options for the contract call.
* @returns {Promise<`0x${string}`>} The transaction hash that resolves after the write operation has been completed.
*/
writeContract?(callOptions: ContractCallOptions): Promise<`0x${string}`>;
/**
* Deploy a contract to the local dev network.
*
* @param {ContractDeploymentOptions} options The options necessary for the contract deployment.
* @returns {Promise<{contractAddress: `0x${string}` | null, status: "success" | "reverted", logs: Log<bigint, number>[], hash: `0x${string}`}>} A Promise that resolves to an object containing the contract address, the status of the deployment, logs, and the transaction hash of the deployment.
*/
deployContract?(contractName: string, options?: ContractDeploymentOptions): Promise<{
contractAddress: `0x${string}`;
logs: Log<bigint, number>[];
hash: `0x${string}`;
status: "success" | "reverted";
abi: Abi;
bytecode: `0x${string}`;
methods: any;
}>;
/**
* Jump a specified number of blocks.
*
* @param {number} blocksToJump The number of blocks to jump forward.
* @returns {Promise<void>} A Promise that resolves after the operation is fully complete.
*/
jumpBlocks?: (blocksToJump: number) => Promise<void>;
/**
* Jump a specified number of ParachainStaking Rounds.
*
* @param {number} blocksToJump The number of ParachainStaking rounds to jump forward.
* @returns {Promise<void>} A Promise that resolves after the operation is fully complete.
*/
jumpRounds?: (roundsToJump: number) => Promise<void>;
}
export type ViemTransactionOptions = TransactionSerializable & {
privateKey?: `0x${string}`;
skipEstimation?: boolean;
txnType?: TransactionType;
};
export type EthersTransactionOptions = TransactionRequest & {
txnType?: TransactionType;
privateKey?: `0x${string}`;
};
export type PrecompileCallOptions = Omit<ContractCallOptions, "contractName" | "contractAddress"> & {
/** The name of the Pre-compiled contract you want to interact with.
* Compiled contracts are a set of contract-like code that is
* embedded into the Moonbeam runtime.
*/
precompileName: string;
};
export interface ContractCallOptions {
/**
* The name of the compiled contract you want to interact with.
* Compiled contracts are solidity contracts already compiled by solc
* into JSON files accessible to this project. Refer to Moonwall help
* docs for more info.
*/
contractName: string;
/**
* The address of the deployed contract you want to interact with.
*/
contractAddress: `0x${string}`;
/**
* The name of the function in the contract that you want to call.
*/
functionName: string;
/**
* If set to true, only the raw transaction data will be returned,
* and the transaction will not be sent. This can be useful if you
* want to sign the transaction yourself or send it at a later time.
*/
rawTxOnly?: boolean;
/**
* If set to true, the function call will be executed as a "call" and
* will not create a transaction on the blockchain. This is useful
* for view functions that don't modify the blockchain's state.
*/
call?: boolean;
/**
* The private key used for signing the transaction. It should be a
* hexadecimal string with a "0x" prefix. If not provided, the
* transaciton will default to ALITH
*/
privateKey?: `0x${string}`;
/**
* The amount of gas to use for the transaction. This can either be a
* specific number (as a bigint) or the string "estimate", in which
* case the library will automatically estimate the gas needed.
*/
gas?: bigint | "estimate";
/**
* The native balance to send along with the transaction.
*/
value?: bigint;
/**
* The JavaScript library to use for interacting with the Ethereum network.
* "viem" or "ethers" are the currently supported options.
*/
web3Library?: "viem" | "ethers";
/**
* An array of arguments to pass to the function call. The types of these
* arguments depend on the function you're calling.
*/
args?: any[];
}
export {};