diff --git a/.changeset/green-ghosts-hammer.md b/.changeset/green-ghosts-hammer.md new file mode 100644 index 0000000..2a5bf9a --- /dev/null +++ b/.changeset/green-ghosts-hammer.md @@ -0,0 +1,7 @@ +--- +"@delvtech/evm-client-ethers": minor +"@delvtech/evm-client-viem": minor +"@delvtech/evm-client": minor +--- + +Add a getBalance method to the Network interface for fetching native currency balances (e.g. ETH) diff --git a/packages/evm-client-ethers/src/network/createNetwork.ts b/packages/evm-client-ethers/src/network/createNetwork.ts index 0934f4a..d1ac465 100644 --- a/packages/evm-client-ethers/src/network/createNetwork.ts +++ b/packages/evm-client-ethers/src/network/createNetwork.ts @@ -3,6 +3,15 @@ import { Provider } from 'ethers'; export function createNetwork(provider: Provider): Network { return { + async getBalance(account, options = {}) { + const { blockHash, blockNumber, blockTag } = options; + + return provider.getBalance( + account, + blockHash || blockNumber || blockTag || 'latest', + ); + }, + async getBlock(options = {}) { const { blockHash, blockNumber, blockTag } = options; diff --git a/packages/evm-client-viem/src/network/createNetwork.ts b/packages/evm-client-viem/src/network/createNetwork.ts index 78e84e1..d2d7388 100644 --- a/packages/evm-client-viem/src/network/createNetwork.ts +++ b/packages/evm-client-viem/src/network/createNetwork.ts @@ -1,8 +1,32 @@ import { Network } from '@delvtech/evm-client'; -import { PublicClient, TransactionLegacy, rpcTransactionType } from 'viem'; +import { + GetBalanceParameters, + PublicClient, + TransactionLegacy, + rpcTransactionType, +} from 'viem'; export function createNetwork(publicClient: PublicClient): Network { return { + async getBalance(account, options) { + const { blockHash, blockNumber, blockTag } = options ?? {}; + + const parameters: Partial = { + address: account, + }; + + if (blockNumber) { + parameters.blockNumber = blockNumber; + } else if (blockTag) { + parameters.blockTag = blockHash; + } else if (blockHash) { + const block = await publicClient.getBlock({ blockHash }); + parameters.blockNumber = block.number; + } + + return publicClient.getBalance(parameters as GetBalanceParameters); + }, + async getBlock(args) { const block = await publicClient.getBlock(args); diff --git a/packages/evm-client/src/exports/network.ts b/packages/evm-client/src/exports/network.ts index 9bd3ad0..8065edc 100644 --- a/packages/evm-client/src/exports/network.ts +++ b/packages/evm-client/src/exports/network.ts @@ -1,9 +1,11 @@ export type { Block, BlockTag } from 'src/network/types/Block'; export type { Network, + NetworkGetBalanceArgs, NetworkGetBlockArgs, NetworkGetBlockOptions, NetworkGetTransactionArgs, + NetworkWaitForTransactionArgs, } from 'src/network/types/Network'; export type { MinedTransaction, diff --git a/packages/evm-client/src/network/stubs/NetworkStub.ts b/packages/evm-client/src/network/stubs/NetworkStub.ts index 034062d..0e988a2 100644 --- a/packages/evm-client/src/network/stubs/NetworkStub.ts +++ b/packages/evm-client/src/network/stubs/NetworkStub.ts @@ -2,6 +2,7 @@ import { SinonStub, stub } from 'sinon'; import { Block } from 'src/network/types/Block'; import { Network, + NetworkGetBalanceArgs, NetworkGetBlockArgs, NetworkGetTransactionArgs, NetworkWaitForTransactionArgs, @@ -13,6 +14,9 @@ import { Transaction, TransactionReceipt } from 'src/network/types/Transaction'; * testing. */ export class NetworkStub implements Network { + protected getBalanceStub: + | SinonStub<[NetworkGetBalanceArgs?], Promise> + | undefined; protected getBlockStub: | SinonStub<[NetworkGetBlockArgs?], Promise> | undefined; @@ -20,6 +24,26 @@ export class NetworkStub implements Network { | SinonStub<[NetworkGetTransactionArgs?], Promise> | undefined; + stubGetBalance({ + args, + value, + }: { + args?: NetworkGetBalanceArgs | undefined; + value: bigint; + }): void { + if (!this.getBalanceStub) { + this.getBalanceStub = stub(); + } + + // Account for dynamic args if provided + if (args) { + this.getBalanceStub.withArgs(args).resolves(value); + return; + } + + this.getBalanceStub.resolves(value); + } + stubGetBlock({ args, value, @@ -60,6 +84,15 @@ export class NetworkStub implements Network { this.getTransactionStub.resolves(value); } + getBalance(...args: NetworkGetBalanceArgs): Promise { + if (!this.getBalanceStub) { + throw new Error( + `The getBalance function must be stubbed first:\n\tcontract.stubGetBalance()`, + ); + } + return this.getBalanceStub(args); + } + getBlock(...args: NetworkGetBlockArgs): Promise { if (!this.getBlockStub) { throw new Error( diff --git a/packages/evm-client/src/network/types/Network.ts b/packages/evm-client/src/network/types/Network.ts index 1cec25f..ad8f9dd 100644 --- a/packages/evm-client/src/network/types/Network.ts +++ b/packages/evm-client/src/network/types/Network.ts @@ -7,6 +7,11 @@ import { Transaction, TransactionReceipt } from 'src/network/types/Transaction'; * An interface representing data the SDK needs to get from the network. */ export interface Network { + /** + * Get the balance of native currency for an account. + */ + getBalance(...args: NetworkGetBalanceArgs): Promise; + /** * Get a block from a block tag, number, or hash. If no argument is provided, * the latest block is returned. @@ -45,6 +50,11 @@ export type NetworkGetBlockOptions = blockTag?: BlockTag; }; +export type NetworkGetBalanceArgs = [ + address: `0x${string}`, + block?: NetworkGetBlockOptions, +]; + export type NetworkGetBlockArgs = [options?: NetworkGetBlockOptions]; export type NetworkGetTransactionArgs = [hash: `0x${string}`];