> ## Documentation Index
> Fetch the complete documentation index at: https://docs.onebalance.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Contract Call Patterns

> Explore advanced cross-chain contract call patterns in OneBalance, including multi-step flows and production optimizations.

Implement sophisticated contract call patterns for production applications. Learn advanced techniques for complex workflows and robust error handling.

## Transaction Batching

### Aggregate, Swap, and Stake Pattern

This pattern combines multiple DeFi operations into a single transaction, using aggregated funds to open leveraged positions across protocols.

```typescript cross-chain-leverage.ts theme={null}
async function openLeveragedPosition(
  marginAmount: bigint,
  leverage: number,
  marginAsset: string,
  isLong: boolean
) {
  const calls = [];
  
  // 1. Swap aggregated USDC to margin asset if needed
  if (marginAsset !== USDC_ADDRESS) {
    calls.push({
      to: DEX_ROUTER,
      data: encodeFunctionData({
        abi: parseAbi(['function swap(address,address,uint256,uint256,address)']),
        functionName: 'swap',
        args: [USDC_ADDRESS, marginAsset, marginAmount, minOut, account.accountAddress]
      }),
      value: '0'
    });
  }
  
  // 2. Deposit margin to perpetual protocol
  calls.push({
    to: PERP_CONTRACT,
    data: encodeFunctionData({
      abi: parseAbi(['function depositMargin(address,uint256)']),
      functionName: 'depositMargin',
      args: [marginAsset, marginAmount]
    }),
    value: '0'
  });
  
  // 3. Open leveraged position
  calls.push({
    to: PERP_CONTRACT,
    data: encodeFunctionData({
      abi: parseAbi(['function openPosition(uint256,bool)']),
      functionName: 'openPosition',
      args: [marginAmount * BigInt(leverage), isLong]
    }),
    value: '0'
  });

  return await executeCall({
    targetChain: 'eip155:42161', // Arbitrum
    calls,
    tokensRequired: [{
      assetType: `eip155:42161/erc20:${marginAsset}`,
      amount: marginAmount.toString()
    }],
    allowanceRequirements: [
      {
        assetType: `eip155:42161/erc20:${USDC_ADDRESS}`,
        amount: marginAmount.toString(),
        spender: DEX_ROUTER
      },
      {
        assetType: `eip155:42161/erc20:${marginAsset}`,
        amount: marginAmount.toString(),
        spender: PERP_CONTRACT
      }
    ],
    fromAggregatedAssetId: 'ob:usdc' // Pull from any chain
  });
}
```

### Cross-Chain Swap and Stake

Use USDC from multiple chains to swap and stake in a single operation. This pattern optimizes for users who want to participate in staking protocols using their distributed token holdings.

```typescript cross-chain-staking.ts theme={null}
const crossChainStake = async (stakeAmount: bigint) => {
  const WETH = '0x4200000000000000000000000000000000000006';
  const STAKING_CONTRACT = '0x796f1793599D7b6acA6A87516546DdF8E5F3aA9d';
  const UNISWAP_ROUTER = '0x2626664c2603336E57B271c5C0b26F421741e481';
  
  // 1. Swap USDC to WETH on Base
  const swapData = encodeFunctionData({
    abi: parseAbi([
      'function exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160)) returns (uint256)'
    ]),
    functionName: 'exactInputSingle',
    args: [{
      tokenIn: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
      tokenOut: WETH,
      fee: 3000,
      recipient: account.accountAddress,
      deadline: Math.floor(Date.now() / 1000) + 1800,
      amountIn: stakeAmount,
      amountOutMinimum: 0n,
      sqrtPriceLimitX96: 0n
    }]
  });

  // 2. Stake WETH (approval handled by allowanceRequirements)
  const stakeData = encodeFunctionData({
    abi: parseAbi(['function stake(uint256 amount)']),
    functionName: 'stake',
    args: [stakeAmount] // Will use actual WETH received from swap
  });

  return await executeCall({
    targetChain: 'eip155:8453', // Base
    calls: [
      {
        to: UNISWAP_ROUTER,
        data: swapData,
        value: '0'
      },
      {
        to: STAKING_CONTRACT,
        data: stakeData,
        value: '0'
      }
    ],
    tokensRequired: [{
      assetType: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      amount: stakeAmount.toString()
    }],
    allowanceRequirements: [
      {
        assetType: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
        amount: stakeAmount.toString(),
        spender: UNISWAP_ROUTER
      },
      {
        assetType: `eip155:8453/erc20:${WETH}`,
        amount: stakeAmount.toString(), // Approximate amount for approval
        spender: STAKING_CONTRACT
      }
    ],
    fromAggregatedAssetId: 'ob:usdc'
  });
};
```

## Batch Operations

### Multi-Recipient Payment System

Process multiple payments efficiently by grouping them by token type and using multicall patterns to reduce gas costs.

```typescript batch-payments.ts theme={null}
interface Payment {
  recipient: string;
  amount: bigint;
  token: string;
}

async function batchPayout(payments: Payment[]) {
  const calls = [];
  const tokensRequired = [];
  
  // Group payments by token to optimize gas usage
  const paymentsByToken = payments.reduce((acc, payment) => {
    if (!acc[payment.token]) acc[payment.token] = [];
    acc[payment.token].push(payment);
    return acc;
  }, {} as Record<string, Payment[]>);
  
  for (const [token, tokenPayments] of Object.entries(paymentsByToken)) {
    // Use multicall for same-token transfers
    const multicallData = encodeFunctionData({
      abi: parseAbi(['function multicall(bytes[] calldata data)']),
      functionName: 'multicall',
      args: [
        tokenPayments.map(p => 
          encodeFunctionData({
            abi: parseAbi(['function transfer(address,uint256)']),
            functionName: 'transfer',
            args: [p.recipient, p.amount]
          })
        )
      ]
    });
    
    calls.push({
      to: token,
      data: multicallData,
      value: '0'
    });
    
    const totalAmount = tokenPayments.reduce(
      (sum, p) => sum + p.amount, 
      0n
    );
    
    tokensRequired.push({
      assetType: `eip155:8453/erc20:${token}`,
      amount: totalAmount.toString()
    });
  }
  
  return await executeCall({
    targetChain: 'eip155:8453',
    calls,
    tokensRequired,
    fromAggregatedAssetId: 'ob:usdc'
  });
}
```

## Gas Optimization Patterns

### Conditional Execution Pattern

Skip unnecessary operations by checking on-chain state before execution, reducing gas costs for operations that may not be needed.

```typescript conditional-execution.ts theme={null}
async function optimizedDeFiOperation(amount: bigint) {
  const calls = [];
  const AAVE_POOL = '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5';
  const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
  
  // Check if we need to withdraw from lending protocol first
  const currentDeposit = await checkAaveDeposit(account.accountAddress);
  
  if (currentDeposit > 0n) {
    calls.push({
      to: AAVE_POOL,
      data: encodeFunctionData({
        abi: parseAbi(['function withdraw(address,uint256,address)']),
        functionName: 'withdraw',
        args: [USDC_ADDRESS, currentDeposit, account.accountAddress]
      }),
      value: '0'
    });
  }
  
  // Main operation (e.g., swap, stake, etc.)
  calls.push({
    to: TARGET_CONTRACT,
    data: mainOperationData,
    value: '0'
  });
  
  // Only re-deposit excess if amount justifies gas cost
  const minDepositAmount = parseUnits('100', 6); // $100 minimum
  if (amount > minDepositAmount) {
    calls.push({
      to: AAVE_POOL,
      data: encodeFunctionData({
        abi: parseAbi(['function supply(address,uint256,address,uint16)']),
        functionName: 'supply',
        args: [USDC_ADDRESS, amount, account.accountAddress, 0]
      }),
      value: '0'
    });
  }
  
  return await executeCall({
    targetChain: 'eip155:8453',
    calls,
    tokensRequired: [{
      assetType: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      amount: amount.toString()
    }],
    allowanceRequirements: [{
      assetType: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
      amount: amount.toString(),
      spender: AAVE_POOL
    }]
  });
}
```

## Error Recovery Patterns

### Safe Execution with Fallbacks

Implement fallback mechanisms for DEX operations when primary routes fail due to liquidity or slippage issues.

```typescript error-recovery.ts theme={null}
interface CallData {
  to: string;
  data: string;
  value: string;
}

async function safeExecuteWithFallback(
  primaryOperation: CallData[],
  fallbackOperation: CallData[]
) {
  try {
    // Attempt primary operation first
    return await executeCall({
      targetChain: 'eip155:8453',
      calls: primaryOperation,
      tokensRequired: calculateTokensRequired(primaryOperation)
    });
  } catch (error: any) {
    // Handle specific errors with fallback strategies
    if (error.message.includes('INSUFFICIENT_LIQUIDITY') || 
        error.message.includes('EXCESSIVE_SLIPPAGE')) {
      console.log('Primary route failed, attempting fallback...');
      
      return await executeCall({
        targetChain: 'eip155:8453',
        calls: fallbackOperation,
        tokensRequired: calculateTokensRequired(fallbackOperation)
      });
    }
    
    // Re-throw unexpected errors
    throw error;
  }
}

function calculateTokensRequired(calls: CallData[]) {
  // Implementation to analyze calls and determine token requirements
  return [];
}
```

## State Management Patterns

### Transaction Lifecycle Tracking

Track and monitor complex transactions with automatic retry and status monitoring capabilities.

```typescript transaction-tracker.ts theme={null}
interface OperationStatus {
  status: 'PENDING' | 'COMPLETED' | 'FAILED' | 'IN_PROGRESS' | 'REFUNDED';
}

interface OperationDetails {
  hash: string;
  chainId: number;
  explorerUrl: string;
}

interface OriginAssetUsed {
  aggregatedAssetId: string;
  amount: string;
  assetType: string[];
  fiatValue: Array<{
    assetType: string;
    fiatValue: string;
  }>;
}

interface DestinationAssetUsed {
  aggregatedAssetId: string;
  amount: string;
  assetType: string;
  fiatValue: string;
  minimumAmount?: string;
  minimumFiatValue?: string;
}

interface Transaction {
  quoteId: string;
  status: OperationStatus;
  user: string;
  recipientAccountId: string;
  originChainOperations: OperationDetails[];
  destinationChainOperations: OperationDetails[];
  type: string;
  originToken: OriginAssetUsed;
  destinationToken: DestinationAssetUsed;
  timestamp: string;
}

interface LocalTransactionState {
  id: string;
  request: any;
  localStatus: 'preparing' | 'executing' | 'monitoring' | 'completed' | 'failed';
  preparedAt: number;
  transaction?: Transaction;
  error?: any;
}

class TransactionTracker {
  private pending = new Map<string, LocalTransactionState>();
  
  async executeAndTrack(request: any): Promise<Transaction> {
    const txId = this.generateId();
    
    // Store initial transaction state
    this.pending.set(txId, {
      id: txId,
      request,
      localStatus: 'preparing',
      preparedAt: Date.now()
    });
    
    try {
      // Step 1: Prepare and sign
      const quote = await this.prepareAndSign(request);
      this.updateLocalStatus(txId, 'executing');
      
      // Step 2: Execute
      const result = await this.executeQuote(quote);
      this.updateLocalStatus(txId, 'monitoring');
      
      // Step 3: Monitor with exponential backoff
      const finalResult = await this.monitorWithBackoff(quote.id);
      
      this.updateLocalStatus(txId, 'completed', finalResult);
      return finalResult;
      
    } catch (error) {
      this.updateLocalStatus(txId, 'failed', undefined, error);
      throw error;
    } finally {
      // Cleanup after 24 hours
      setTimeout(() => this.pending.delete(txId), 86400000);
    }
  }
  
  private async monitorWithBackoff(quoteId: string): Promise<Transaction> {
    const delays = [1000, 2000, 5000, 10000, 15000]; // Progressive delays
    const maxAttempts = 30;
    
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
      const status = await getQuoteStatus(quoteId);
      
      if (['COMPLETED', 'FAILED', 'REFUNDED'].includes(status.status.status)) {
        return status;
      }
      
      const delay = delays[Math.min(attempt, delays.length - 1)];
      await new Promise(resolve => setTimeout(resolve, delay));
    }
    
    throw new Error('Transaction monitoring timeout');
  }
  
  private generateId(): string {
    return `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  private updateLocalStatus(
    id: string, 
    localStatus: LocalTransactionState['localStatus'], 
    transaction?: Transaction,
    error?: any
  ) {
    const tx = this.pending.get(id);
    if (tx) {
      tx.localStatus = localStatus;
      if (transaction) tx.transaction = transaction;
      if (error) tx.error = error;
    }
  }
  
  // Get current transaction status
  getTransactionStatus(id: string): LocalTransactionState | undefined {
    return this.pending.get(id);
  }
  
  // Get all pending transactions
  getPendingTransactions(): LocalTransactionState[] {
    return Array.from(this.pending.values());
  }
}
```

## Integration Patterns

### Wallet-Agnostic Implementation

Create universal interfaces that work with any wallet provider, making your integration flexible across different wallet ecosystems.

```typescript wallet-integration.ts theme={null}
interface WalletAdapter {
  signTypedData(data: any): Promise<string>;
  getAddress(): Promise<string>;
  isConnected(): Promise<boolean>;
}

class UniversalOneBalance {
  constructor(
    private apiKey: string,
    private wallet: WalletAdapter
  ) {}
  
  async executeCall(params: any) {
    // Ensure wallet is connected
    const isConnected = await this.wallet.isConnected();
    if (!isConnected) {
      throw new Error('Wallet not connected');
    }
    
    // Prepare operation
    const account = await this.getAccount();
    const preparedQuote = await this.prepare({
      ...params,
      account
    });
    
    // Sign with wallet adapter
    const signature = await this.wallet.signTypedData(
      preparedQuote.chainOperation.typedDataToSign
    );
    
    preparedQuote.chainOperation.userOp.signature = signature;
    
    // Execute operation
    return await this.execute(preparedQuote);
  }
  
  private async getAccount() {
    const address = await this.wallet.getAddress();
    return {
      sessionAddress: address,
      adminAddress: address, // Simplified for basic account
      accountAddress: await this.predictAccountAddress(address)
    };
  }
}

// MetaMask adapter example
const metamaskAdapter: WalletAdapter = {
  signTypedData: (data) => window.ethereum.request({
    method: 'eth_signTypedData_v4',
    params: [address, JSON.stringify(data)]
  }),
  getAddress: async () => {
    const accounts = await window.ethereum.request({ 
      method: 'eth_accounts' 
    });
    return accounts[0];
  },
  isConnected: async () => {
    const accounts = await window.ethereum.request({ 
      method: 'eth_accounts' 
    });
    return accounts.length > 0;
  }
};

// Usage
const oneBalance = new UniversalOneBalance(apiKey, metamaskAdapter);
```

## Performance Optimization Tips

<CardGroup cols={2}>
  <Card title="Batch Operations" icon="layers">
    Group similar operations to reduce transaction overhead and gas costs
  </Card>

  <Card title="Use Multicall" icon="zap">
    Combine multiple calls to the same contract in a single transaction
  </Card>

  <Card title="Cache Quotes" icon="database">
    Store prepared quotes for retry scenarios (valid for \~30 seconds)
  </Card>

  <Card title="Async Monitoring" icon="activity">
    Don't block UI while monitoring transaction status - use background polling
  </Card>
</CardGroup>

### Implementation Best Practices

<Steps>
  <Step title="Plan Your Operations">
    Design your call sequence to minimize gas usage and maximize success probability
  </Step>

  <Step title="Handle Edge Cases">
    Implement fallbacks for common failure scenarios like insufficient liquidity
  </Step>

  <Step title="Monitor Actively">
    Track transaction status and provide users with real-time updates
  </Step>

  <Step title="Test Thoroughly">
    Validate complex patterns with small amounts before production deployment
  </Step>
</Steps>

<Tip>
  **Advanced Features**: For even more sophisticated patterns, consider combining these techniques with OneBalance's resource locks and time-based permissions for enhanced security and user experience.
</Tip>
