Wallets

Sign Transactions on Solana

Learn how to build transactions and sign them with our server-side SDK.

This tutorial walks you through creating a developer-controlled wallet to sign transactions on Solana.

Before you begin:

When creating a developer-controlled wallet, pass SOL-DEVNET or SOL in the blockchains field. This wallet can be used to sign transactions.

The following example code shows how to create a wallet using the Circle Developer SDK.

const response = await circleDeveloperSdk.createWallets({
  accountType: 'EOA',
  blockchains: ['SOLANA-DEVNET'],
  count: 2,
  walletSetId: '<wallet-set-id>',
})

For Solana, you can sign a raw transaction using the API or SDK.

The following example code shows how to prepare a raw transaction for swapping tokens on Jupiter. Note that this code is purely for example purposes only.

// Get quote for swapping SOL to USDC with input 0.01 SOL and 0.5% slippage
const quoteResponse = await (
  await fetch(
    'https://quote-api.jup.ag/v6/quote?inputMint=So11111111111111111111111111111111111111112&outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&amount=10000000&slippageBps=50',
  )
).json()
// Get serialized transactions for the swap
const { swapTransaction } = await (
  await fetch('https://quote-api.jup.ag/v6/swap', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      // quoteResponse from /quote API
      quoteResponse,
      // User public key to be used for the swap
      userPublicKey: 'FILL-YOUR-WALLET-ADDRESS',
      // Auto wrap and unwrap SOL. Default is true
      wrapAndUnwrapSol: true,
    }),
  })
).json()

The following example code shows how to sign the raw transaction.

const response = await circleDeveloperSdk.signTransaction({
  walletId: 'FILL-YOUR-SOL-WALLET-ID',
  rawTransaction: swapTransaction,
})

The following example code shows how you can encode a raw transaction to a Base64 encoded string in JavaScript.

const web3 = require('@solana/web3.js')
const {
  initiateDeveloperControlledWalletsClient,
} = require('@circle-fin/developer-controlled-wallets')
const circleDeveloperSdk = initiateDeveloperControlledWalletsClient({
  baseUrl: 'https://api.circle.com',
  apiKey: 'YOUR-API-KEY',
  entitySecret: 'YOUR-ENTITY-SECRET', // Make sure to enter the entity secret from the step above.
})

async function transferNativeToken() {
  const connection = new web3.Connection(
    web3.clusterApiUrl('devnet'),
    'confirmed',
  )

  // Amount to send (in SOL)
  const amount = 0.1

  // Convert SOL to lamports
  const lamports = web3.LAMPORTS_PER_SOL * amount

  const fromPubKey = new web3.PublicKey('YOUR-WALLET-ADDRESS')
  const toPubKey = new web3.PublicKey('DESTINATION-WALLET-ADDRESS')

  // Create a transfer instruction
  const instruction = web3.SystemProgram.transfer({
    fromPubkey: fromPubKey,
    toPubkey: toPubKey,
    lamports: lamports,
  })

  // Get the latest blockhash
  const { blockhash } = await connection.getLatestBlockhash()

  // Create the transaction
  const transaction = new web3.Transaction().add(instruction)

  // Set the recent blockhash and the paying account
  transaction.recentBlockhash = blockhash
  transaction.feePayer = fromPubKey

  // Serialize the transaction
  const rawTransaction = transaction.serialize({
    requireAllSignatures: false,
    verifySignatures: false,
  })

  //   // sign the transaction
  const response = await circleDeveloperSdk.signTransaction({
    walletId: 'YOUR-WALLET-ADDRESS-WALLET-ID',
    memo: 'TEST-SIGN-RAW-TX',
    rawTransaction: rawTransaction.toString('base64'),
  })

  const rawTransactionBuf = Buffer.from(
    response.data.signedTransaction,
    'base64',
  )
  const txid = await connection.sendRawTransaction(rawTransactionBuf, {
    skipPreflight: false,
    maxRetries: 2,
  })
  console.log(`txid:${txid}`)

  await connection.confirmTransaction(txid)
  console.log(`https://solscan.io/tx/${txid}`)
}

transferNativeToken()
Did this page help you?
© 2023-2025 Circle Technology Services, LLC. All rights reserved.