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

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": "ds:usdc"
  }'
The fromAssetId: "ds: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": "ds:sol"
  }'
When using fromAssetId: "ds: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: "ds: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 === 'ds: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.