Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

account.sendCalls()

Send multiple calls as a bundled user operation without waiting for receipt.

Type: instance async

Signature

async sendCalls(
  calls: TransactionCall[],
  options?: SendCallsOptions
): Promise<BundledTransactionResult>

Parameters

calls

Type: TransactionCall[]

Array of transaction calls to execute.

interface TransactionCall {
  /** Target contract address */
  to: Address;
  /** Value to send in wei (bigint or hex string) */
  value?: bigint | string;
  /** Call data */
  data?: Hex;
}

options (optional)

Type: SendCallsOptions

Optional settings for call execution.

interface SendCallsOptions {
  /** Permission ID to use for executing the calls through the permission manager */
  permissionId?: Hex;
}

Returns

Promise<BundledTransactionResult> - The user operation ID and chain ID.

interface BundledTransactionResult {
  /** User operation hash */
  id: Hex;
  /** Chain ID where the operation was submitted */
  chainId: number;
}

Behavior

  1. Bundles all calls into a single user operation
  2. Sends the user operation to the bundler
  3. Returns immediately with the user operation ID
  4. Does not wait for transaction inclusion

For waiting until the transaction is mined, use sendTransaction().

Example

Getting an Account Instance

Before calling instance methods, create an account using one of the factory methods:

import { Account } from '@jaw.id/core';
 
// Option 1: Restore existing session or login with passkey
const account = await Account.get({ chainId: 1, apiKey: 'your-api-key' });
 
// Option 2: Create a new account with passkey
const account = await Account.create(
  { chainId: 1, apiKey: 'your-api-key' },
  { username: 'alice' }
);
 
// Option 3: Import from cloud backup
const account = await Account.import({ chainId: 1, apiKey: 'your-api-key' });
 
// Option 4: From a local account (server-side / embedded wallets)
const account = await Account.fromLocalAccount(
  { chainId: 1, apiKey: 'your-api-key' },
  localAccount
);

Batch Multiple Calls

import { encodeFunctionData } from 'viem';
 
// Multiple token transfers in one operation
const transfers = recipients.map(({ address, amount }) => ({
  to: USDC_ADDRESS,
  data: encodeFunctionData({
    abi: erc20Abi,
    functionName: 'transfer',
    args: [address, amount],
  }),
}));
 
const { id } = await account.sendCalls(transfers);
console.log('Batch transfer submitted:', id);

Execute with Permission (Delegated Execution)

When a permission has been granted via account.grantPermissions(), you can execute calls using that permission. This allows delegated execution within the permission's constraints.

import { encodeFunctionData } from 'viem';
 
// First, get the permission ID from a previous grantPermissions call
const permissionId = '0x1234...'; // The permission ID returned from grantPermissions
 
const transferData = encodeFunctionData({
  abi: erc20Abi,
  functionName: 'transfer',
  args: ['0x5678...', 1000000n],
});
 
// Execute the transfer using the permission
const { id } = await account.sendCalls(
  [{ to: USDC_ADDRESS, data: transferData }],
  { permissionId }
);
 
console.log('Batch transfer submitted with permission:', id);

When using the permissionId option:

  • The calls are executed through the JustaPermissionManager contract
  • The permission's call and spend limits are enforced
  • The spender must have been granted appropriate permissions for the calls being made

sendTransaction vs sendCalls

sendTransaction()sendCalls()
ReturnsTransaction hashUser operation ID
WaitsYes, until minedNo, returns immediately
Use caseNeed confirmationFire and forget

Related