This guide will walk you through the process of sending transactions from your wallet using the Crossmint transactions API with custodial signers. Custodial signers enable secure transaction signing without managing private keys directly.
Note: This guide currently only works for wallets set up with a custodial admin signer. We will soon update it
to cover all types of signers.
You can send various types of transactions using the Create Transaction API. Here’s how to do it for different chains:
For EVM-based chains like Ethereum, Polygon, Base, etc., you can send transactions as follows:
const walletLocator ='0x...';// Address of your wallet from the quickstart guideconst apiKey ='sk_staging...';const contractAddress ='0x...';asyncfunctionsendTransaction(){const response =awaitfetch(`https://staging.crossmint.com/api/2022-06-09/wallets/${walletLocator}/transactions`,{ method:'POST', headers:{'Content-Type':'application/json','X-API-KEY': apiKey,}, body:JSON.stringify({ params:{ calls:[{ to: contractAddress, value:'0',// Value in wei (0 for contract calls with no ETH transfer) data:'0x1234abcd...',// The encoded function call data}], chain:'base-sepolia',// Specify your target chain},}),});const data =await response.json();console.log(data);return data;}
When interacting with smart contracts, you need to encode your function calls as data. Here’s how to do it:
import{ encodeFunctionData }from'viem';// Example: Encoding a "transfer" function call for an ERC-20 tokenconst recipientAddress ='0x...';// Address of the recipientconst tokenAmount =1000000n;// 1 token with 6 decimals// Encode the function callconst data =encodeFunctionData({ abi:[{ name:'transfer', type:'function', inputs:[{ name:'to', type:'address'},{ name:'amount', type:'uint256'}], outputs:[{ name:'', type:'bool'}], stateMutability:'nonpayable'}], args:[recipientAddress, tokenAmount]});console.log(data);// Example output: 0xa9059cbb000000000000000000000000recipientAddressWithout0x00000000000000000000000000000000000000000000000000000000000003e8
For EVM-based chains like Ethereum, Polygon, Base, etc., you can send transactions as follows:
const walletLocator ='0x...';// Address of your wallet from the quickstart guideconst apiKey ='sk_staging...';const contractAddress ='0x...';asyncfunctionsendTransaction(){const response =awaitfetch(`https://staging.crossmint.com/api/2022-06-09/wallets/${walletLocator}/transactions`,{ method:'POST', headers:{'Content-Type':'application/json','X-API-KEY': apiKey,}, body:JSON.stringify({ params:{ calls:[{ to: contractAddress, value:'0',// Value in wei (0 for contract calls with no ETH transfer) data:'0x1234abcd...',// The encoded function call data}], chain:'base-sepolia',// Specify your target chain},}),});const data =await response.json();console.log(data);return data;}
When interacting with smart contracts, you need to encode your function calls as data. Here’s how to do it:
import{ encodeFunctionData }from'viem';// Example: Encoding a "transfer" function call for an ERC-20 tokenconst recipientAddress ='0x...';// Address of the recipientconst tokenAmount =1000000n;// 1 token with 6 decimals// Encode the function callconst data =encodeFunctionData({ abi:[{ name:'transfer', type:'function', inputs:[{ name:'to', type:'address'},{ name:'amount', type:'uint256'}], outputs:[{ name:'', type:'bool'}], stateMutability:'nonpayable'}], args:[recipientAddress, tokenAmount]});console.log(data);// Example output: 0xa9059cbb000000000000000000000000recipientAddressWithout0x00000000000000000000000000000000000000000000000000000000000003e8
For Solana, you’ll need to prepare the transaction first, then send it to the API:
1
Prepare Transaction
Create a transaction with placeholders that Crossmint will replace:
import{ PublicKey, TransactionMessage, VersionedTransaction, SystemProgram,LAMPORTS_PER_SOL}from"@solana/web3.js";import base58 from"bs58";// Your wallet address from the quickstart guideconst fromPublicKey =newPublicKey("your_wallet_address");// Recipient addressconst toPublicKey =newPublicKey("recipient_address");// Create a transaction (example: sending 0.01 SOL)const message =newTransactionMessage({ instructions:[ SystemProgram.transfer({ fromPubkey: fromPublicKey, toPubkey: toPublicKey, lamports:0.01*LAMPORTS_PER_SOL,}),// Add more instructions as needed],// Use placeholder values - Crossmint will replace these recentBlockhash:"11111111111111111111111111111111", payerKey:newPublicKey("11111111111111111111111111111112"),}).compileToV0Message();const transaction =newVersionedTransaction(message);// Serialize and encode the transactionconst serializedTransaction = transaction.serialize();const serializedTransactionBase58 = base58.encode(serializedTransaction);console.log("Base58 Encoded Transaction:", serializedTransactionBase58);
The transaction will be properly configured on Crossmint’s servers with the correct blockhash and payer before execution.
Crossmint will also handle signing the transaction with your wallet’s custodial signer.
2
Send Transaction
Now send the transaction to the Crossmint API:
const walletLocator ='your_wallet_address';// Your Solana wallet address from the quickstart guideconst apiKey ='sk_staging...';asyncfunctionsendTransaction(serializedTransactionBase58:string){const response =awaitfetch(`https://staging.crossmint.com/api/2022-06-09/wallets/${walletLocator}/transactions`,{ method:'POST', headers:{'Content-Type':'application/json','X-API-KEY': apiKey,}, body:JSON.stringify({ params:{ transaction: serializedTransactionBase58}}),});const data =await response.json();console.log(data);return data;}// Call the function with your base58-encoded transactionsendTransaction("your_base58_encoded_transaction").catch(console.error);
For more complex Solana transactions, such as token transfers or interactions with programs, you’d add the appropriate instructions to the transaction message before serializing it.