Prerequisites
Install the required dependencies:Copy
Ask AI
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.
Copy
Ask AI
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:- Step 1: Prepare Call Quote
- Step 2: Get Call Quote
- Step 3: Execute Quote
First, prepare the contract call by specifying the target chain operations and token requirements:
Copy
Ask AI
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.Use the prepared data to get a signed quote for execution:
Copy
Ask AI
curl -X POST 'https://be.onebalance.io/api/v3/quote/call-quote' \
-H 'Content-Type: application/json' \
-H 'x-api-key: 42bb629272001ee1163ca0dbbbc07bcbb0ef57a57baf16c4b1d4672db4562c11' \
-d '{
"fromAggregatedAssetId": "ob:usdc",
"accounts": [
{
"type": "solana",
"accountAddress": "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6"
},
{
"type": "kernel-v3.3-ecdsa",
"accountAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
"signerAddress": "0xDb69A4Ded06AaD92C69c42232b691CFD8bF347e8",
"deploymentType": "EIP7702"
}
],
"tamperProofSignature": "0x6316c2fe49d51af45b7bb7bb311395595fe29b7bd9de2e219cba0942fda2461c1c3f19108d6f391cd02c7cdc7d218ff0945d32ba784be1357b3c954ff7ae254e1c",
"chainOperation": {
"userOp": {
"sender": "0xdb69a4ded06aad92c69c42232b691cfd8bf347e8",
"nonce": "913479994650515257524606220465835134743662536739504622017003723935449089",
"callData": "0xe9ae5c53010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000004ebcfae0c3e747c95504ca7c79c46f725cb4c752000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
"callGasLimit": "2831389",
"verificationGasLimit": "46313",
"preVerificationGas": "0",
"maxFeePerGas": "0",
"maxPriorityFeePerGas": "0",
"paymaster": "0xa784e6482bd5edbfe5991b18cbd545ebd46e1cc4",
"paymasterVerificationGasLimit": "13011",
"paymasterPostOpGasLimit": "0",
"paymasterData": "0x",
"signature": "0x8ca6ea251b08d488919a3c8708c6c9cdc782190d57151a1e83c0b4627aa819fa6f668b46d894e8f68291338bdf05111bf98ad8dbc6f7d4b2aa484a2749a26ebc1b"
},
"typedDataToSign": {
"domain": {
"name": "RoleBasedECDSAValidator",
"version": "1.4.3",
"chainId": 42161,
"verifyingContract": "0xA24bD06230f3F54e5bf266AE7A41750eE3b789FA"
},
"types": {
"Approve": [
{
"name": "callDataAndNonceHash",
"type": "bytes32"
}
]
},
"primaryType": "Approve",
"message": {
"callDataAndNonceHash": "0x68752061ab5e1f42561b192a3ea5e70c4005b62a7ea4698b14a35ab0004f6687"
}
},
"assetType": "eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"amount": "10000"
}
}
}'
You must use the exact
tamperProofSignature and chainOperation data from the prepare step response.Sign the Solana operation and execute the cross-chain contract call:
Copy
Ask AI
import { MessageV0, VersionedTransaction, PublicKey } from '@solana/web3.js';
import bs58 from 'bs58';
// Sign the Solana operation from the quote
function signSolanaChainOperation(
accountAddress: string,
privateKey: string,
chainOp: 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 };
}
// Sign and execute
const solanaOp = callQuote.originChainsOperations[0];
const signedSolanaOp = signSolanaChainOperation(
"EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6",
"your-private-key",
solanaOp
);
const executeRequest = {
...callQuote,
originChainsOperations: [signedSolanaOp],
tamperProofSignature: "0xb83221a24cf7df0ece73a97b9888ea2091bcc5478aa142ec77b5fe3ebe83f92b2ef121ace109ea79f3b032bb6186c8af3fdc0e9c3dd5e968bf05cabe9adcab421c"
};
// Execute the quote
const executeResponse = await fetch('https://be.onebalance.io/api/v3/quote/execute-quote', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': '42bb629272001ee1163ca0dbbbc07bcbb0ef57a57baf16c4b1d4672db4562c11'
},
body: JSON.stringify(executeRequest)
});
const result = await executeResponse.json();
console.log('Contract call executed:', result);
Successfully executed a USDC transfer contract call on Arbitrum using USDC from your Solana account as funding.
Example 2: SOL → EVM Contract Call
Use native SOL to fund contract calls on Arbitrum. This example shows more complex operations including Jupiter swaps:- Step 1: Prepare with SOL
- Complex Operation Response
- Final Execution
Copy
Ask AI
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.The response includes Jupiter swap instructions and address lookup tables:
Copy
Ask AI
{
"originChainsOperations": [
{
"type": "solana",
"instructions": [
{
"keys": [
{
"pubkey": "EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "ATw6BVTaLgdDAJ9Deki3Zs1bvruoNfs99TWi7L3XhtFD",
"isSigner": false,
"isWritable": true
}
],
"programId": "11111111111111111111111111111111",
"data": "02000000561b160000000000"
},
{
"programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"data": "d033ef977b2bed5c010000001a640001c4d3030000000000d80d150000000000f40100"
}
],
"addressLookupTableAddresses": [
"D6XNrxMsDoABJVVY5YyHxJuAB6WGzYCXpZeKyNtqu2v4"
],
"assetType": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501",
"amount": "1448790"
}
]
}
SOL operations often use address lookup tables for efficiency. OneBalance handles this automatically.
Copy
Ask AI
// The signing process is identical, but notice the complex swap operation
const signedOperation = signSolanaChainOperation(
"EB8Hi4LoqUVCGUPJ2y9MsHbEsJQJvmpQRUWrLpjEZxC6",
"your-solana-private-key",
solanaOperation
);
// Execute with the complex operation including Jupiter swaps
const result = await executeQuote(signedOperation);
// Result shows:
// - SOL swapped to USDC on Solana via Jupiter
// - USDC bridged to Arbitrum
// - Contract call executed on Arbitrum
// - All in a single atomic operation
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:Copy
Ask AI
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:Copy
Ask AI
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:
Copy
Ask AI
// 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:
Copy
Ask AI
// 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:- Full Flow
- Benefits
Copy
Ask AI
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();
}
Atomic Cross-Chain Execution:
- SOL swapped to USDC on Solana
- USDC bridged to target EVM chain
- EIP-7702 delegation processed
- Contract call executed
- All happens in coordinated atomic operations
- Use cheaper Solana transaction fees
- Leverage SOL liquidity for EVM operations
- Batch multiple operations together
- Single API call for complex operations
- No manual bridging or swapping required
- Built-in slippage protection
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
Copy
Ask AI
// 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
Copy
Ask AI
// 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
Copy
Ask AI
// 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}`);
}