@tevm/test-matchers
Version:
Vite test matchers for Tevm or EVM-related testing in TypeScript.
750 lines (735 loc) • 29.2 kB
TypeScript
import { CallResult, GetAccountResult } from '@tevm/actions';
import { Abi, AbiParameter, AbiParameterToPrimitiveType, Address, Log, Hex, TransactionReceipt, Client, ContractFunctionName, ContractErrorName, ContractEventName, IsAddressOptions } from 'viem';
export { IsAddressOptions } from 'viem';
import { TevmNode } from '@tevm/node';
import { Assertion } from 'vitest';
import { AbiParameter as AbiParameter$1, ExtractAbiFunction, AbiParametersToPrimitiveTypes, ExtractAbiError, AbiEventParameter, ExtractAbiEvent } from 'abitype';
interface ContainsContractAbi<TAbi extends Abi = Abi> {
abi: TAbi;
address?: `0x${string}`;
}
interface ContainsContractAddressAndOptionalAbi<TAbi extends Abi = Abi> {
abi?: TAbi;
address: `0x${string}`;
}
interface ContainsTransactionLogs {
logs: Log[];
}
interface ContainsAddress {
address: Address;
}
type ContainsTransactionAny = Hex | CallResult | TransactionReceipt;
type AbiInputsToNamedArgs<TInputs extends readonly AbiParameter[]> = {
[K in TInputs[number] as K extends {
name: infer TName extends string;
} ? TName : never]: K extends {
name: string;
} ? AbiParameterToPrimitiveType<K> : never;
};
/**
* Balance change specification for the toChangeBalances matcher
*/
interface BalanceChange {
account: Address | ContainsAddress;
amount: bigint | number | string;
}
interface BalanceMatchers {
/**
* Asserts that a transaction changes an account's ETH balance by the expected amount.
*
* @param client - The client or node to use for balance queries
* @param account - The account address or object with address
* @param expectedChange - The expected balance change in wei (negative for decrease)
*
* @example
* ```typescript
* // Account gains 100 wei
* await expect(txHash).toChangeBalance(client, '0x123...', 100n)
*
* // Account loses 50 wei
* await expect(txHash).toChangeBalance(client, account, -50n)
*
* // Works with transaction promises
* await expect(client.sendTransaction(tx))
* .toChangeBalance(client, sender, -1000n)
* ```
*
* @see {@link toChangeBalances} to test multiple accounts
* @see {@link toChangeTokenBalance} to test ERC20 token balances
*/
toChangeBalance(client: Client | TevmNode, account: Address | ContainsAddress, expectedChange: bigint | number | string): Promise<void>;
/**
* Asserts that a transaction changes multiple accounts' ETH balances by the expected amounts.
*
* When using .not, it will pass if at least one balance change differs from expected.
*
* @param client - The client or node to use for balance queries
* @param balanceChanges - Array of expected balance changes
*
* @example
* ```typescript
* // Test a simple transfer
* await expect(txHash).toChangeBalances(client, [
* { account: sender, amount: -100n }, // sender loses 100 wei
* { account: recipient, amount: 100n }, // recipient gains 100 wei
* ])
*
* // Test contract deployment (deployer pays gas)
* await expect(deployTx).toChangeBalances(client, [
* { account: deployer, amount: -gasUsed },
* { account: contractAddress, amount: 0n },
* ])
* ```
*
* @see {@link toChangeBalance} to test a single account
* @see {@link toChangeTokenBalances} to test multiple ERC20 balances
*/
toChangeBalances(client: Client | TevmNode, balanceChanges: BalanceChange[]): Promise<void>;
/**
* Asserts that a transaction changes an account's ERC20 token balance by the expected amount.
*
* @param client - The client or node to use for balance queries
* @param tokenContract - The ERC20 token contract address or object with address
* @param account - The account address or object with address
* @param expectedChange - The expected token balance change (negative for decrease)
*
* @example
* ```typescript
* // Account gains 100 tokens
* await expect(txHash).toChangeTokenBalance(
* client,
* '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
* '0x123...',
* 100n
* )
*
* // Using contract object
* await expect(txHash).toChangeTokenBalance(
* client,
* tokenContract,
* account,
* -50_000000n // 50 USDC (6 decimals)
* )
* ```
*
* @see {@link toChangeTokenBalances} to test multiple accounts
* @see {@link toChangeBalance} to test ETH balances
*/
toChangeTokenBalance(client: Client | TevmNode, tokenContract: Address | ContainsAddress, account: Address | ContainsAddress, expectedChange: bigint | number | string): Promise<void>;
/**
* Asserts that a transaction changes multiple accounts' ERC20 token balances by the expected amounts.
*
* When using .not, it will pass if at least one token balance change differs from expected.
*
* @param client - The client or node to use for balance queries
* @param tokenContract - The ERC20 token contract address or object with address
* @param balanceChanges - Array of expected token balance changes
*
* @example
* ```typescript
* // Test a token transfer
* await expect(txHash).toChangeTokenBalances(
* client,
* '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
* [
* { account: sender, amount: -1000000n }, // -1 USDC
* { account: recipient, amount: 1000000n }, // +1 USDC
* ]
* )
*
* // Test token minting
* await expect(mintTx).toChangeTokenBalances(client, tokenContract, [
* { account: mintRecipient, amount: 1000n },
* { account: treasury, amount: 50n }, // 5% mint fee
* ])
* ```
*
* @see {@link toChangeTokenBalance} to test a single account
* @see {@link toChangeBalances} to test multiple ETH balances
*/
toChangeTokenBalances(client: Client | TevmNode, tokenContract: Address | ContainsAddress, balanceChanges: BalanceChange[]): Promise<void>;
}
type ChainableAssertion<T = unknown> = Promise<Assertion<T>> & Assertion<T>;
interface ContractMatchers {
/**
* Asserts that a transaction called a specific contract function.
* Can be used with contract objects, function signatures, or selectors.
*
* @param client - Client for transaction execution
* @param contract - Contract object with ABI and address
* @param functionName - Name of the function in the ABI
*
* @example
* ```typescript
* // Using contract object
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
*
* // Chain with argument assertions
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
* .withFunctionArgs(to, 100n)
*
* // Chain with argument assertions by name (partial matching)
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
* .withFunctionNamedArgs({ to, value: 100n })
* ```
*
* @see {@link withFunctionArgs} to test function arguments positionally
* @see {@link withFunctionNamedArgs} to test function arguments by name
*/
toCallContractFunction<TAbi extends Abi, TFunctionName extends ContractFunctionName<TAbi>>(client: Client | TevmNode, contract: ContainsContractAddressAndOptionalAbi<TAbi>, functionName: TFunctionName): Promise<ContractAssertionWithContract<TAbi, TFunctionName>> & ContractAssertionWithContract<TAbi, TFunctionName>;
/**
* Asserts that a transaction called a function matching the signature.
*
* @param client - Client for transaction execution
* @param functionSignature - Function signature string (e.g., "transfer(address,uint256)")
*
* @example
* ```typescript
* await expect(txHash).toCallContractFunction(client, contract, 'transfer(address,uint256)')
* await expect(txHash).toCallContractFunction(client, { address: '0x123...' }, 'transfer(address,uint256)')
* ```
*/
toCallContractFunction(client: Client | TevmNode, contract: ContainsContractAddressAndOptionalAbi, functionSignature: string): ChainableAssertion;
/**
* Asserts that a transaction called a function matching the selector.
*
* @param client - Client for transaction execution
* @param functionSelector - Function selector (4-byte hex)
*
* @example
* ```typescript
* await expect(txHash).toCallContractFunction(client, contract, '0xa9059cbb') // transfer function selector
* await expect(txHash).toCallContractFunction(client, { address: '0x123...' }, '0xa9059cbb') // transfer function selector
* ```
*/
toCallContractFunction(client: Client | TevmNode, contract: ContainsContractAddressAndOptionalAbi, functionSelector: Hex): ChainableAssertion;
}
interface ContractAssertionWithContract<TAbi extends Abi, TFunctionName extends ContractFunctionName<TAbi>> {
/**
* Chains with toCallContractFunction to assert function arguments in positional order.
* Arguments must match exactly in the order they appear in the function.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Expected arguments in order
*
* @example
* ```typescript
* // transfer function: transfer(address to, uint256 value)
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
* .withFunctionArgs(
* '0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed', // to
* 1000n // value
* )
* ```
*
* @see {@link withFunctionNamedArgs} for partial matching by name
*/
withFunctionArgs<TInputs extends readonly AbiParameter$1[] = ExtractAbiFunction<TAbi, TFunctionName> extends {
inputs: infer U extends readonly AbiParameter$1[];
} ? U : readonly AbiParameter$1[]>(...expectedArgs: AbiParametersToPrimitiveTypes<TInputs>): ChainableAssertion;
/**
* Chains with toCallContractFunction to assert function arguments by name.
* Supports partial matching - only specified arguments are checked.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Object with expected named arguments (partial)
*
* @example
* ```typescript
* // Check only specific arguments
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
* .withFunctionNamedArgs({
* to: recipient,
* value: 1000n
* })
*
* // Empty object matches any call to this function
* await expect(txHash)
* .toCallContractFunction(client, tokenContract, 'transfer')
* .withFunctionNamedArgs({})
* ```
*
* @see {@link withFunctionArgs} for positional argument matching
*/
withFunctionNamedArgs<TInputs extends readonly AbiParameter$1[] = ExtractAbiFunction<TAbi, TFunctionName> extends {
inputs: infer U extends readonly AbiParameter$1[];
} ? U : readonly AbiParameter$1[]>(expectedArgs: Partial<AbiInputsToNamedArgs<TInputs>>): ChainableAssertion;
}
interface ErrorMatchers {
/**
* Asserts that a transaction reverted for any reason.
* This includes string reverts, custom errors, and panics.
*
* @param client - Optional client for transaction execution
*
* @example
* ```typescript
* // Test any revert
* await expect(writeContract(client, contract.write.failingFunction()))
* .toBeReverted(client)
*
* // Works with .not for successful transactions
* await expect(writeContract(client, contract.write.successfulFunction()))
* .not.toBeReverted(client)
* ```
*
* @see {@link toBeRevertedWithString} for specific revert messages
* @see {@link toBeRevertedWithError} for custom errors
*/
toBeReverted(client?: Client): Promise<void>;
/**
* Asserts that a transaction reverted with a specific revert string.
* Use this for `revert("message")` style reverts.
*
* @param client - Client for transaction execution
* @param revertString - Expected exact revert message
*
* @example
* ```typescript
* // Contract: require(amount > 0, "Amount must be positive")
* await expect(writeContract(client, contract.write.transfer(to, 0n)))
* .toBeRevertedWithString(client, 'Amount must be positive')
*
* // Note: Message must match exactly
* await expect(transaction)
* .not.toBeRevertedWithString(client, 'Different message')
* ```
*
* @see {@link toBeRevertedWithError} for custom errors
*/
toBeRevertedWithString(client: Client, revertString: string): Promise<void>;
/**
* Asserts that a transaction reverted with a specific custom error.
* Use this for custom error types, not `revert()` strings.
*
* @param client - Client for transaction execution
* @param contract - Contract object with ABI containing the error
* @param errorName - Name of the custom error in the ABI
*
* @example
* ```typescript
* // error InsufficientBalance(uint256 available, uint256 required);
* await expect(writeContract(client, contract.write.transfer(to, 1000n)))
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
*
* // Chain with argument assertions
* await expect(writeContract(client, contract.write.transfer(to, 1000n)))
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
* .withErrorArgs(50n, 1000n)
*
* // Chain with argument assertions by name (partial matching)
* await expect(writeContract(client, contract.write.transfer(to, 1000n)))
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
* .withErrorNamedArgs({ required: 1000n })
* ```
*
* @see {@link withErrorArgs} to test error arguments
* @see {@link withErrorNamedArgs} to test error arguments by name
* @see {@link toBeRevertedWithString} for revert strings
*/
toBeRevertedWithError<TAbi extends Abi, TErrorName extends ContractErrorName<TAbi>>(client: Client, contract: ContainsContractAbi<TAbi>, errorName: TErrorName): Promise<ErrorAssertionWithContract<TAbi, TErrorName>> & ErrorAssertionWithContract<TAbi, TErrorName>;
/**
* Asserts that a transaction reverted with an error matching the signature.
*
* @param client - Client for transaction execution
* @param errorName - Error signature string (e.g., "InsufficientBalance(uint256,uint256)")
*
* @example
* ```typescript
* await expect(transaction)
* .toBeRevertedWithError(client, 'InsufficientBalance(uint256,uint256)')
* .withErrorArgs(50n, 1000n)
* ```
*/
toBeRevertedWithError(client: Client, errorName: string): ChainableAssertion;
/**
* Asserts that a transaction reverted with an error matching the selector.
*
* @param client - Client for transaction execution
* @param errorSelector - Error selector (4-byte hex)
*
* @example
* ```typescript
* await expect(transaction)
* .toBeRevertedWithError(client, '0x356680b7') // InsufficientBalance selector
* ```
*/
toBeRevertedWithError(client: Client, errorSelector: Hex): ChainableAssertion;
}
interface ErrorAssertionWithContract<TAbi extends Abi, TErrorName extends ContractErrorName<TAbi>> {
/**
* Chains with toBeRevertedWithError to assert error arguments in positional order.
* Arguments must match exactly in the order they appear in the error.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Expected arguments in order
*
* @example
* ```typescript
* // error InsufficientBalance(uint256 available, uint256 required);
* await expect(transaction)
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
* .withErrorArgs(
* 50n, // available
* 1000n // required
* )
* ```
*
* @see {@link withErrorNamedArgs} for partial matching by name
*/
withErrorArgs<TInputs extends readonly AbiParameter[] = ExtractAbiError<TAbi, TErrorName> extends {
inputs: infer U extends readonly AbiParameter[];
} ? U : readonly AbiParameter[]>(...expectedArgs: AbiParametersToPrimitiveTypes<TInputs>): ChainableAssertion;
/**
* Chains with toBeRevertedWithError to assert error arguments by name.
* Supports partial matching - only specified arguments are checked.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Object with expected named arguments (partial)
*
* @example
* ```typescript
* // Check only specific arguments
* await expect(transaction)
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
* .withErrorNamedArgs({ required: 1000n })
*
* // Check all arguments
* await expect(transaction)
* .toBeRevertedWithError(client, contract, 'InsufficientBalance')
* .withErrorNamedArgs({
* available: 50n,
* required: 1000n
* })
* ```
*
* @see {@link withErrorArgs} for positional argument matching
*/
withErrorNamedArgs<TInputs extends readonly AbiParameter[] = ExtractAbiError<TAbi, TErrorName> extends {
inputs: infer U extends readonly AbiParameter[];
} ? U : readonly AbiParameter[]>(expectedArgs: Partial<AbiInputsToNamedArgs<TInputs>>): ChainableAssertion;
}
interface EmitMatchers {
/**
* Asserts that a transaction emitted a specific event.
* Can be used with contract objects, event signatures, or selectors.
*
* @param contract - Contract object with ABI and address
* @param eventName - Name of the event in the ABI
*
* @example
* ```typescript
* // Using contract object
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
*
* // Chain with argument assertions
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
* .withEventArgs(from, to, 100n)
*
* // Chain with argument assertions by name (partial matching)
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
* .withEventNamedArgs({ to })
* ```
*
* @see {@link withEventArgs} to test event arguments positionally
* @see {@link withEventNamedArgs} to test event arguments by name
*/
toEmit<TAbi extends Abi, TEventName extends ContractEventName<TAbi>>(contract: ContainsContractAbi<TAbi>, eventName: TEventName): Promise<EmitAssertionWithContract<TAbi, TEventName>> & EmitAssertionWithContract<TAbi, TEventName>;
/**
* Asserts that a transaction emitted an event matching the signature.
*
* @param eventSignature - Event signature string (e.g., "Transfer(address,address,uint256)")
*
* @example
* ```typescript
* await expect(txHash)
* .toEmit('Transfer(address,address,uint256)')
* .withEventArgs(from, to, amount)
* ```
*/
toEmit(eventSignature: string): ChainableAssertion;
/**
* Asserts that a transaction emitted an event matching the selector.
*
* @param eventSelector - Event selector (4-byte hex)
*
* @example
* ```typescript
* await expect(txHash)
* .toEmit('0xddf252ad...') // Transfer event selector
* ```
*/
toEmit(eventSelector: Hex): ChainableAssertion;
}
interface EmitAssertionWithContract<TAbi extends Abi, TEventName extends ContractEventName<TAbi>> {
/**
* Chains with toEmit to assert event arguments in positional order.
* Arguments must match exactly in the order they appear in the event.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Expected arguments in order
*
* @example
* ```typescript
* // Transfer event: Transfer(address from, address to, uint256 value)
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
* .withEventArgs(
* '0x742d35Cc6274c36e1019e41D77d0A4aa7D7dE01e', // from
* '0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed', // to
* 1000n // value
* )
* ```
*
* @see {@link withEventNamedArgs} for partial matching by name
*/
withEventArgs<TInputs extends readonly AbiEventParameter[] = ExtractAbiEvent<TAbi, TEventName> extends {
inputs: infer U extends readonly AbiEventParameter[];
} ? U : readonly AbiEventParameter[]>(...expectedArgs: AbiParametersToPrimitiveTypes<TInputs>): ChainableAssertion;
/**
* Chains with toEmit to assert event arguments by name.
* Supports partial matching - only specified arguments are checked.
*
* **Limitation**: Cannot use .not before this method.
*
* @param expectedArgs - Object with expected named arguments (partial)
*
* @example
* ```typescript
* // Check only specific arguments
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
* .withEventNamedArgs({
* to: recipient,
* value: 1000n
* })
*
* // Empty object matches any event of this type
* await expect(txHash)
* .toEmit(tokenContract, 'Transfer')
* .withEventNamedArgs({})
* ```
*
* @see {@link withEventArgs} for positional argument matching
*/
withEventNamedArgs<TInputs extends readonly AbiEventParameter[] = ExtractAbiEvent<TAbi, TEventName> extends {
inputs: infer U extends readonly AbiEventParameter[];
} ? U : readonly AbiEventParameter[]>(expectedArgs: Partial<AbiInputsToNamedArgs<TInputs>>): ChainableAssertion;
}
type ExpectedState = Partial<Omit<GetAccountResult, 'address' | 'errors'>>;
interface StorageEntry {
slot: Hex;
value: Hex;
}
type ExpectedStorage = StorageEntry | StorageEntry[];
interface StateMatchers {
/**
* Asserts that an address contains deployed contract code (is initialized).
* Fails if the address is an EOA or has no code.
*
* @param client - The client or node to use for state queries
*
* @example
* ```typescript
* // Check if address has deployed code
* await expect('0x742d35Cc5dB4c8E9f8D4Dc1Ef70c4c7c8E5b7A6b')
* .toBeInitializedAccount(client)
*
* // Check EOA (should fail)
* await expect('0x0000000000000000000000000000000000000000')
* .not.toBeInitializedAccount(client)
* ```
*
* @see {@link toHaveState} to check specific state properties
*/
toBeInitializedAccount(client: Client | TevmNode): Promise<void>;
/**
* Asserts that an account has specific state properties.
* Can check balance, nonce, code, and storage in a single assertion.
*
* @param client - The client or node to use for state queries
* @param expectedState - The expected state properties (partial match)
*
* @example
* ```typescript
* // Check multiple state properties
* await expect('0x742d35Cc5dB4c8E9f8D4Dc1Ef70c4c7c8E5b7A6b')
* .toHaveState(client, {
* balance: 1000n,
* nonce: 5n,
* code: '0x6080604052...', // contract bytecode
* storage: {
* '0x0': '0x1',
* '0x1': '0x2'
* }
* })
*
* // Check only balance
* await expect(address).toHaveState(client, { balance: 0n })
* ```
*
* @see {@link toHaveStorageAt} to check only storage
* @see {@link toBeInitializedAccount} to check if contract exists
*/
toHaveState(client: Client | TevmNode, expectedState: ExpectedState): Promise<void>;
/**
* Asserts that a contract has specific storage values at given slots.
*
* @param client - The client or node to use for state queries
* @param expectedStorage - Single storage entry or array of entries
*
* @example
* ```typescript
* // Check single storage slot
* await expect(contractAddress)
* .toHaveStorageAt(client, {
* slot: '0x0',
* value: '0x1'
* })
*
* // Check multiple storage slots
* await expect(contractAddress)
* .toHaveStorageAt(client, [
* { slot: '0x0', value: '0x1' }, // owner
* { slot: '0x1', value: '0x64' }, // totalSupply = 100
* { slot: '0x2', value: '0x0' }, // paused = false
* ])
* ```
*
* @see {@link toHaveState} to check multiple state properties
*/
toHaveStorageAt(client: Client | TevmNode, expectedStorage: ExpectedStorage): Promise<void>;
}
type IsHexOptions = {
/**
* Whether to check for strict hex format or only for 0x prefix
* @default true
*/
strict?: boolean;
/**
* Optional expected size in bytes
*/
size?: number;
};
type EqualHexOptions = {
/**
* Whether to compare hex strings exactly as written or normalize them first.
* When false (default), leading zeros are trimmed before byte comparison (e.g., "0x00123" equals "0x123").
* When true, hex strings must match exactly including leading zeros.
* @default false
*/
exact?: boolean;
};
interface UtilsMatchers {
/**
* Asserts that a value is a valid Ethereum address.
* By default, requires EIP-55 checksum validation.
*
* @param opts - Options for address validation
* @param opts.strict - If true (default), enforces EIP-55 checksum. If false, accepts any case.
*
* @example
* ```typescript
* // Validates checksummed address (default)
* expect('0x742d35Cc5dB4c8E9f8D4Dc1Ef70c4c7c8E5b7A6b').toBeAddress()
*
* // Accept any case
* expect('0x742d35cc5db4c8e9f8d4dc1ef70c4c7c8e5b7a6b').toBeAddress({ strict: false })
*
* // Works with .not
* expect('not-an-address').not.toBeAddress()
* ```
*
* @see {@link toEqualAddress} for case-insensitive address comparison
*/
toBeAddress(opts?: IsAddressOptions): void;
/**
* Asserts that a value is a valid hex string.
* Optionally validates the exact byte size.
*
* @param opts - Options for hex validation
* @param opts.strict - If true (default), validates hex characters. If false, only checks for 0x prefix.
* @param opts.size - Expected size in bytes (e.g., 32 for a transaction hash)
*
* @example
* ```typescript
* // Basic hex validation
* expect('0x1234abcd').toBeHex()
*
* // Validate transaction hash (32 bytes)
* expect(txHash).toBeHex({ size: 32 })
*
* // Validate function selector (4 bytes)
* expect('0xa9059cbb').toBeHex({ size: 4 })
* ```
*
* @see {@link toEqualHex} for hex string comparison
*/
toBeHex(opts?: IsHexOptions): void;
/**
* Asserts that two Ethereum addresses are equal (case-insensitive).
* Uses viem's isAddressEqual for comparison.
*
* @param expected - The expected address
*
* @example
* ```typescript
* // Same address, different cases
* expect('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC')
* .toEqualAddress('0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac')
*
* // Works with .not
* expect(address1).not.toEqualAddress(address2)
* ```
*
* @see {@link toBeAddress} for address validation
*/
toEqualAddress(expected: unknown): void;
/**
* Asserts that two hex strings are equal.
* By default, normalizes hex strings by trimming leading zeros.
*
* @param expected - The expected hex string
* @param opts - Options for comparison
* @param opts.exact - If true, performs exact string comparison. If false (default), normalizes before comparing.
*
* @example
* ```typescript
* // Normalized comparison (default)
* expect('0x000123').toEqualHex('0x123')
* expect('0x0').toEqualHex('0x00')
*
* // Exact comparison
* expect('0x000123').toEqualHex('0x000123', { exact: true })
*
* // Case insensitive
* expect('0xabcd').toEqualHex('0xABCD')
*
* // Chain with .not
* expect('0x000123').not.toEqualHex('0x123')
* ```
*
* @see {@link toBeHex} for hex validation
*/
toEqualHex(expected: unknown, opts?: EqualHexOptions): void;
}
declare module 'vitest' {
interface Assertion<T = any> extends UtilsMatchers, EmitMatchers, ErrorMatchers, StateMatchers, BalanceMatchers, ContractMatchers {
}
interface AsymmetricMatchersContaining extends UtilsMatchers, EmitMatchers, ErrorMatchers, StateMatchers, BalanceMatchers, ContractMatchers {
}
}
export type { BalanceChange, ContainsAddress, ContainsContractAbi, ContainsContractAddressAndOptionalAbi, ContainsTransactionAny, ContainsTransactionLogs, EqualHexOptions, IsHexOptions };