Skip to content

MockSmartAgentKitClient

The @smartagentkit/testing package provides an in-memory mock of the full SDK client for testing without RPC, bundler, or deployed contracts.

Constructor

typescript
new MockSmartAgentKitClient(options?: MockClientOptions)
OptionTypeDefaultDescription
verbosebooleanfalseLog all operations to console
initialBalancebigint10n * 10n**18nStarting ETH balance (10 ETH)
tokenBalancesRecord<string, bigint>{}Starting token balances keyed by address
typescript
import { MockSmartAgentKitClient } from "@smartagentkit/testing";

const mockClient = new MockSmartAgentKitClient({
  verbose: true,
  initialBalance: parseEther("100"),
  tokenBalances: {
    "0xUSDC...": 1_000_000n * 10n ** 6n, // 1M USDC
  },
});

ISmartAgentKitClient Methods

MockSmartAgentKitClient implements all methods from the ISmartAgentKitClient interface. See SmartAgentKitClient for full method signatures.

Key Differences from the Real Client

BehaviorReal ClientMock Client
RPC connectionRequiredNot needed
BundlerRequiredNot needed
Deployed contractsRequiredNot needed
Policy enforcementOn-chain hooksIn-memory simulation
Transaction hashesReal on-chain hashesDeterministic mock values
Session storageIn-memory (same)In-memory (same)
BalancesRead from chainTracked in-memory

Supported Features

  • Wallet creation with all presets (defi-trader, treasury-agent, payment-agent, minimal)
  • execute() and executeBatch() with in-memory policy checks
  • Spending limit enforcement with rolling windows
  • Allowlist/blocklist enforcement
  • Pause/unpause state tracking
  • Session creation, listing, and revocation
  • Balance tracking (ETH and ERC-20 tokens)

Mock-Specific Methods

getLog

typescript
getLog(): MockLogEntry[]

Returns the full operation log. Useful for asserting that specific operations occurred during a test.

typescript
interface MockLogEntry {
  operation: string;
  timestamp: number;
  params: Record<string, unknown>;
  result: Record<string, unknown>;
}
typescript
const log = mockClient.getLog();
const executions = log.filter((e) => e.operation === "execute");
expect(executions).toHaveLength(3);

setState

typescript
setState(walletAddress: Address, updates: Partial<MockWalletState>): void

Override wallet state for test setup. Useful for setting up specific scenarios without executing transactions.

typescript
interface MockWalletState {
  paused: boolean;
  ethBalance: bigint;
  tokenBalances: Record<string, bigint>;
  // ... other internal state
}
typescript
// Set up a paused wallet for testing
mockClient.setState(wallet.address, { paused: true });

// Set up a wallet with low balance
mockClient.setState(wallet.address, {
  ethBalance: parseEther("0.001"),
});

getWalletState

typescript
getWalletState(walletAddress: Address): MockWalletState

Read the current mock wallet state. Useful for asserting state changes after operations.

typescript
const state = mockClient.getWalletState(wallet.address);
expect(state.ethBalance).toBeLessThan(parseEther("10"));
expect(state.paused).toBe(false);

Example: Unit Testing with Vitest

typescript
import { describe, it, expect, beforeEach } from "vitest";
import { MockSmartAgentKitClient } from "@smartagentkit/testing";
import { parseEther } from "viem";

describe("My Agent", () => {
  let client: MockSmartAgentKitClient;
  let wallet: AgentWallet;

  beforeEach(async () => {
    client = new MockSmartAgentKitClient({
      initialBalance: parseEther("10"),
    });
    wallet = await client.createWallet({
      owner: "0x1234...",
      preset: "defi-trader",
    });
  });

  it("should respect spending limits", async () => {
    // This should succeed (within 1 ETH daily limit)
    await client.execute(wallet, {
      target: "0xDex...",
      value: parseEther("0.5"),
    });

    // This should fail (would exceed 1 ETH daily limit)
    await expect(
      client.execute(wallet, {
        target: "0xDex...",
        value: parseEther("0.8"),
      })
    ).rejects.toThrow("Spending limit exceeded");
  });

  it("should block when paused", async () => {
    await client.pause(wallet.address, "0xOwnerKey...");

    await expect(
      client.execute(wallet, {
        target: "0x...",
        value: parseEther("0.01"),
      })
    ).rejects.toThrow("paused");
  });
});

Released under the MIT License.