Skip to main content

Module Reference

Complete API documentation for all functions and hooks used in the Compose SDK.

React Hooks

useSmartAccount

Hook to create and access a smart account. Returns a React Query result with the smart account data.

import { useSmartAccount } from '@ssv-labs/compose-sdk/react';

function useSmartAccount({
chainId,
multiChainIds
}: {
chainId: number;
multiChainIds?: number[];
}): UseQueryResult<SmartAccountResult>;

Parameters

  • chainId (number): Chain ID for the primary chain
  • multiChainIds? (number[]): Optional array of chain IDs for multi-chain support. When provided, the smart account will be configured to work across all specified chains with the same address.

Returns

UseQueryResult<SmartAccountResult>: React Query result object with:

  • data: SmartAccountResult | undefined - Smart account object containing:
    • account: Smart account instance with address property and createUserOp() method
    • publicClient: Public client for the chain
  • isLoading: boolean - True while the account is being created
  • isError: boolean - True if an error occurred
  • error: Error | null - Error object if creation failed

Important Notes

  • The hook returns a React Query result object, not { data, isLoading }
  • Always access properties via smartAccountQuery.data, smartAccountQuery.isLoading, etc.
  • The multiChainIds parameter is required for cross-chain functionality
  • Access the address via smartAccountQuery.data?.account?.address
  • The smart account address will be the same across all chains when using multiChainIds

Example

import { useSmartAccount } from '@ssv-labs/compose-sdk/react';
import { rollupA, rollupB } from '@ssv-labs/compose-sdk';
import { useAccount } from 'wagmi';

function MyComponent() {
const { isConnected } = useAccount();

// Hook returns a query object
const smartAccountQuery = useSmartAccount({
chainId: rollupA.id,
multiChainIds: [rollupA.id, rollupB.id]
});

if (!isConnected) return <div>Please connect your wallet</div>;
if (smartAccountQuery.isLoading) return <div>Creating smart account...</div>;

// Access account via query.data?.account
const smartAccount = smartAccountQuery.data?.account;
const publicClient = smartAccountQuery.data?.publicClient;

return (
<div>
<p>Address: {smartAccount?.address}</p>
</div>
);
}

Core Functions

composePreparedUserOps

Composes multiple prepared user operations for atomic cross-chain execution. User operations must be prepared using prepareUserOperation from viem/account-abstraction before composing.

import { composePreparedUserOps } from '@ssv-labs/compose-sdk';
import { prepareUserOperation } from 'viem/account-abstraction';

function composePreparedUserOps(
operations: PreparedUserOpInput[]
): Promise<ComposedUserOps>;

Parameters

  • operations (PreparedUserOpInput[]): Array of objects, each containing:
    • account: Smart account instance (from useSmartAccount().data?.account)
    • publicClient: Public client for the chain (from useSmartAccount().data?.publicClient)
    • userOp: Prepared user operation (from prepareUserOperation)

Returns

Promise<ComposedUserOps>: Object with:

  • send(): () => Promise<SendResult> - Function that sends the transactions and returns:
    • wait(): () => Promise<TransactionReceipt[]> - Function that waits for all transaction receipts
  • builds: TransactionBuild[] - Array of transaction builds with .hash property
  • explorerUrls: string[] - Array of explorer URLs for each transaction

Example - Single Chain

import { composePreparedUserOps } from '@ssv-labs/compose-sdk';
import { prepareUserOperation } from 'viem/account-abstraction';
import { encodeFunctionData, erc20Abi } from 'viem';

// Step 1: Create user operation with multiple calls
const { userOp } = await smartAccount.createUserOp([
{
to: tokenAddress,
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'approve',
args: [spenderAddress, amount]
})
},
{
to: tokenAddress,
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
args: [recipientAddress, amount]
})
}
]);

// Step 2: Prepare the user operation
const preparedUserOp = await prepareUserOperation(publicClient, userOp);

// Step 3: Compose and send
const { send, explorerUrls } = await composePreparedUserOps([{
account: smartAccount,
publicClient: publicClient,
userOp: preparedUserOp,
}]);

// Step 4: Send and wait for receipts
const { wait } = await send();
const receipts = await wait();

Example - Multiple Chains

// Create user operations for both chains
const { userOp: userOpA } = await smartAccountA.createUserOp([/* calls */]);
const { userOp: userOpB } = await smartAccountB.createUserOp([/* calls */]);

// Prepare user operations
const preparedUserOpA = await prepareUserOperation(publicClientA, userOpA);
const preparedUserOpB = await prepareUserOperation(publicClientB, userOpB);

// Compose operations from both chains
const { send, builds, explorerUrls } = await composePreparedUserOps([
{
account: smartAccountA,
publicClient: publicClientA,
userOp: preparedUserOpA,
},
{
account: smartAccountB,
publicClient: publicClientB,
userOp: preparedUserOpB,
},
]);

// Send to sequencer and wait for receipts
const { wait } = await send();
const [receiptA, receiptB] = await wait();

// Get transaction hashes
const hashes = builds.map(b => b.hash);

Smart Account Methods

account.createUserOp

Creates a user operation from an array of calls. This method is available on the smart account instance returned by useSmartAccount().data?.account.

account.createUserOp(calls: Call[]): Promise<{ userOp: UserOperation }>;

Parameters

  • calls (Call[]): Array of call objects, each containing:
    • to: Address - Target contract address
    • value: bigint - ETH value to send (in wei)
    • data: Hex - Encoded function call data (use encodeFunctionData from viem)

Returns

Promise<{ userOp: UserOperation }>: Object containing:

  • userOp: UserOperation - The user operation data (must be prepared before composing)

Example

import { encodeFunctionData, erc20Abi } from 'viem';

// Create user operation with multiple calls
const { userOp } = await smartAccount.createUserOp([
{
to: '0x...', // Token address
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'approve',
args: ['0x...', 10000000000000000000n]
})
},
{
to: '0x...', // Another token
value: 0n,
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', 5000000000000000000n]
})
}
]);

// Then prepare the user operation before composing
import { prepareUserOperation } from 'viem/account-abstraction';
const preparedUserOp = await prepareUserOperation(publicClient, userOp);

Chain Exports

The SDK exports predefined chain configurations for Compose rollups:

import { rollupA, rollupB } from '@ssv-labs/compose-sdk';

// Use in useSmartAccount
const smartAccountQuery = useSmartAccount({
chainId: rollupA.id,
multiChainIds: [rollupA.id, rollupB.id]
});

Available Chains

  • rollupA: Chain ID 11113
  • rollupB: Chain ID 22224

Helper Functions

Encoding Function Calls

Use encodeFunctionData from viem to encode function calls for user operations:

import { encodeFunctionData, erc20Abi } from 'viem';

// Encode an approval
const approveData = encodeFunctionData({
abi: erc20Abi,
functionName: 'approve',
args: ['0x...', 10000000000000000000n]
});

// Encode a transfer
const transferData = encodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
args: ['0x...', 5000000000000000000n]
});

Preparing User Operations

Use prepareUserOperation from viem/account-abstraction to prepare user operations before composing:

import { prepareUserOperation } from 'viem/account-abstraction';

// After creating a user operation
const { userOp } = await smartAccount.createUserOp([/* calls */]);

// Prepare it before composing
const preparedUserOp = await prepareUserOperation(publicClient, userOp);