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

wallet_sendCalls

Broadcast bundle of calls to the network.

Authentication Required: Yes

Request

await jaw.provider.request({
  method: 'wallet_sendCalls',
  params: [{
    calls: [
      {
        to: '0xContractA...',
        value: '0x0',
        data: '0x...',
      },
      {
        to: '0xContractB...',
        value: '0x0',
        data: '0x...',
      },
    ],
  }],
});

Parameters

NameTypeRequiredDescription
callsarrayYesArray of call objects
calls[].to0x${string}YesRecipient address
calls[].value0x${string}NoValue in wei (hex), default "0x0"
calls[].data0x${string}NoCall data (hex), default "0x"
chainId0x${string}NoTarget chain ID (defaults to connected chain)
capabilitiesobjectNoAdditional capabilities (see below)

Capabilities

NameTypeDescription
capabilities.permissionsobjectPermission capability for delegated execution
capabilities.permissions.id0x${string}ID of the permission to use for execution

Response

Returns a batch call identifier.

Example

{
  "id": "0x123abc..."
}

Behavior

  • All calls succeed atomically or all fail together
  • Uses currently connected chain if chainId not specified
  • Returns batch ID immediately for status tracking
  • Background task monitors completion
  • Gas is sponsored by paymaster if configured
  • Users offered native ERC-20 paymaster option for gas fees (no configuration needed)

Errors

CodeDescription
4001User rejected the request
4100Unauthorized (not authenticated)
-32602Invalid params

Example

Transfer Multiple ERC-20 Tokens

import { encodeFunctionData } from 'viem';
 
const transferAbi = [{
  name: 'transfer',
  type: 'function',
  inputs: [
    { name: 'to', type: 'address' },
    { name: 'amount', type: 'uint256' },
  ],
}];
 
const account = '0x1234...';
const recipient = '0x5678...';
 
// Encode both transfers
const usdcTransfer = encodeFunctionData({
  abi: transferAbi,
  functionName: 'transfer',
  args: [recipient, 1000000n],
});
 
const uniTransfer = encodeFunctionData({
  abi: transferAbi,
  functionName: 'transfer',
  args: [recipient, 1000000000000000000n],
});
 
// Send both transfers atomically
const result = await jaw.provider.request({
  method: 'wallet_sendCalls',
  params: [{
    calls: [
      {
        to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
        data: usdcTransfer,
      },
      {
        to: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
        data: uniTransfer,
      },
    ],
  }],
});
 
console.log('Batch ID:', result.id);

Check Status

// Get status of the batch
const status = await jaw.provider.request({
  method: 'wallet_getCallsStatus',
  params: [result.id],
});
 
console.log('Status:', status.status);

Execute with Permission (Delegated Execution)

When a permission has been granted via wallet_grantPermissions, you can execute calls using that permission. This allows the spender to execute transactions on behalf of the account within the permission's constraints.

import { encodeFunctionData } from 'viem';
 
// First, get the permission ID from a previous wallet_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 result = await jaw.provider.request({
  method: 'wallet_sendCalls',
  params: [{
    calls: [
      {
        to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
        data: transferData,
      },
    ],
    capabilities: {
      permissions: {
        id: permissionId,
      },
    },
  }],
});
 
console.log('Batch ID:', result.id);

When using the permissions capability:

  • 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

Related Methods