Skip to main content
Execute smart contract calls on EVM chains using Solana assets as the funding source. These examples use the V3 calldata endpoints that support cross-chain contract execution.

Prerequisites

Install the required dependencies:
npm install @solana/web3.js bs58

Signing Utility for Contract Calls

For complete signing documentation covering all account types (EVM, Solana, EIP-7702), see the Signing Guide with detailed explanations and troubleshooting.
import { MessageV0, VersionedTransaction, PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';

/**
 * Signs a Solana chain operation with a private key
 * @param accountAddress - The address of the account to sign the chain operation
 * @param privateKey - The private key in base58 format  
 * @param chainOp - The chain operation object from quote response
 * @returns The signed chain operation with signature added
 */
export function signSolanaChainOperation(
  accountAddress: string,
  privateKey: string,
  chainOp: any,
): any {
  const msgBuffer = Buffer.from(chainOp.dataToSign, 'base64');

  const message = MessageV0.deserialize(msgBuffer);

  const transaction = new VersionedTransaction(message);

  const decodedKey = bs58.decode(privateKey);
  transaction.sign([
    {
      publicKey: new PublicKey(accountAddress),
      secretKey: Buffer.from(decodedKey),
    },
  ]);

  const signature = bs58.encode(Buffer.from(transaction.signatures[transaction.signatures.length - 1]));
  return {
    ...chainOp,
    signature,
  };
}

Example 1: USDC (Solana) → EVM Contract Call

Use USDC on Solana to fund and execute contract calls on Arbitrum:
First, prepare the contract call by specifying the target chain operations and token requirements:
curl -X POST 'https://be.onebalance.io/api/v3/quote/prepare-call-quote' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: 42bb629272001ee1163ca0dbbbc07bcbb0ef57a57baf16c4b1d4672db4562c11' \
  -d '{
    "accounts": [
      {
        "type": "solana",
        "accountAddress": "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6"
      },
      {
        "type": "kernel-v3.3-ecdsa",
        "accountAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        "signerAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        "deploymentType": "EIP7702"
      }
    ],
    "targetChain": "eip155:42161",
    "calls": [
      {
        "to": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "data": "0xa9059cbb0000000000000000000000004EbcFae0C3e747C95504CA7c79c46f725Cb4c7520000000000000000000000000000000000000000000000000000000000000001",
        "value": "0x0"
      }
    ],
    "tokensRequired": [
      {
        "assetType": "eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "amount": "10000"
      }
    ],
    "fromAssetId": "ob:usdc"
  }'
The fromAssetId: "ob:usdc" tells OneBalance to use USDC from your Solana account to fund the EVM contract call.

Example 2: SOL → EVM Contract Call

Use native SOL to fund contract calls on Arbitrum. This example shows more complex operations including Jupiter swaps:
curl -X POST 'https://be.onebalance.io/api/v3/quote/prepare-call-quote' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: 42bb629272001ee1163ca0dbbbc07bcbb0ef57a57baf16c4b1d4672db4562c11' \
  -d '{
    "accounts": [
      {
        "type": "solana",
        "accountAddress": "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6"
      },
      {
        "type": "kernel-v3.3-ecdsa",
        "accountAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        "signerAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        "deploymentType": "EIP7702"
      }
    ],
    "targetChain": "eip155:42161",
    "calls": [
      {
        "to": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "data": "0xa9059cbb0000000000000000000000004EbcFae0C3e747C95504CA7c79c46f725Cb4c7520000000000000000000000000000000000000000000000000000000000000001",
        "value": "0x0"
      }
    ],
    "tokensRequired": [
      {
        "assetType": "eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "amount": "10000"
      }
    ],
    "fromAssetId": "ob:sol"
  }'
When using fromAssetId: "ob:sol", OneBalance will swap SOL to USDC on Solana via Jupiter, then bridge to Arbitrum.

EIP-7702 Integration

OneBalance supports EIP-7702 delegated accounts that can be funded using Solana assets. This enables seamless cross-chain contract execution where Solana provides the funding and EIP-7702 provides the execution context.

Multi-Account Setup (Solana + EIP-7702)

When using Solana assets to fund EIP-7702 operations, you need both account types:
const multiAccountSetup = {
  accounts: [
    {
      type: "solana",
      accountAddress: "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6"
    },
    {
      type: "kernel-v3.3-ecdsa",
      accountAddress: "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
      signerAddress: "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
      deploymentType: "EIP7702" // This triggers delegation requirements
    }
  ]
};

Delegation Signature Requirements

EIP-7702 accounts require delegation signatures before execution:
Delegation Required: When using deploymentType: "EIP7702", you must sign the delegation object from the prepare-call-quote response before proceeding to call-quote.
1

Get Delegation Object

The prepare-call-quote response includes delegation data that must be signed:
const prepareResponse = await prepareCallQuote(multiAccountRequest);

// EIP-7702 delegation object is included in response
const delegationObject = prepareResponse.delegation;
console.log('Delegation to sign:', delegationObject);
2

Sign Delegation

Sign the delegation using your EIP-7702 signer:
// Sign the delegation object with your EIP-7702 signer
const delegationSignature = await evmSigner.signTypedData(delegationObject);

// Include the signature in your call-quote request
const callQuoteRequest = {
  ...prepareResponse,
  delegationSignature: delegationSignature
};
3

Execute Operation

The signed delegation enables atomic execution:
// The operation will:
// 1. Process delegation signature
// 2. Use Solana assets for funding
// 3. Execute contract calls via delegated account
// 4. All in a single atomic transaction
const result = await executeQuote(signedQuote);

Complete EIP-7702 Example

Here’s a complete example using SOL to fund an EIP-7702 contract call:
import { signSolanaChainOperation } from './signing-utils';

async function solanaToEIP7702ContractCall() {
  // 1. Prepare the call with both accounts
  const prepareRequest = {
    accounts: [
      {
        type: "solana",
        accountAddress: "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6"
      },
      {
        type: "kernel-v3.3-ecdsa",
        accountAddress: "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        signerAddress: "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
        deploymentType: "EIP7702"
      }
    ],
    targetChain: "eip155:42161",
    calls: [
      {
        to: "0xA0b86a33E6Af8661A8B9e0A4B9b10b8Abc7e1234", // Your contract
        data: "0x...", // Your contract call data
        value: "0x0"
      }
    ],
    tokensRequired: [
      {
        assetType: "eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        amount: "1000000" // 1 USDC
      }
    ],
    fromAssetId: "ob:sol" // Fund with SOL
  };

  // 2. Get preparation data including delegation
  const prepareResponse = await fetch('/api/v3/quote/prepare-call-quote', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(prepareRequest)
  });
  const prepareData = await prepareResponse.json();

  // 3. Sign the EIP-7702 delegation
  const delegationSignature = await evmSigner.signTypedData(prepareData.delegation);

  // 4. Get the call quote with delegation signature
  const callQuoteRequest = {
    ...prepareData,
    delegationSignature: delegationSignature
  };

  const callQuoteResponse = await fetch('/api/v3/quote/call-quote', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(callQuoteRequest)
  });
  const callQuote = await callQuoteResponse.json();

  // 5. Sign the Solana operation
  const solanaOp = callQuote.originChainsOperations.find(op => op.type === 'solana');
  const signedSolanaOp = signSolanaChainOperation(
    "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6",
    solanaPrivateKey,
    solanaOp
  );

  // 6. Execute the quote
  const executeRequest = {
    ...callQuote,
    originChainsOperations: [signedSolanaOp]
  };

  const result = await fetch('/api/v3/quote/execute-quote', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(executeRequest)
  });

  return await result.json();
}
EIP-7702 integration is supported on chains with EIP-7702 enabled. Check the supported networks for current availability.

Error Handling

Common issues with contract calls and their solutions:

Insufficient Balance for Contract Execution

// Always check aggregated balance before contract calls
const balanceResponse = await fetch(
  'https://be.onebalance.io/api/v3/balances/aggregated-balance?account=solana:YOUR_ACCOUNT',
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);
const balance = await balanceResponse.json();

const requiredAsset = balance.balanceByAggregatedAsset.find(b => b.aggregatedAssetId === 'ob:usdc');
if (parseInt(requiredAsset.balance) < requiredAmount) {
  throw new Error('Insufficient balance for contract call');
}

Missing EIP-7702 Delegation

// EIP-7702 accounts must include delegation signature
if (account.deploymentType === "EIP7702" && !callQuoteRequest.delegationSignature) {
  throw new Error('EIP-7702 requires delegation signature from prepare-call-quote');
}

Invalid Target Chain

// Verify target chain supports the contract
const supportedChains = ['eip155:1', 'eip155:42161', 'eip155:137'];
if (!supportedChains.includes(targetChain)) {
  throw new Error(`Contract not available on chain: ${targetChain}`);
}
For questions about Solana contract calls or integration support, use the Intercom chat widget in the bottom right corner, join our Discord, or reach out via support.
Last modified on October 24, 2025