Reclaim SOL
Complete flow from wallet scan to confirmed burn. This recipe shows the full happy path with error handling.
Full example
import { BurnerClient, SessionScope } from '@burnandclaim/sdk'
import type {
WalletItem,
ItemSelection,
BuiltTransaction,
SubmissionResult,
} from '@burnandclaim/sdk'
import { VersionedTransaction } from '@solana/web3.js'
/**
* Server-side: create a session token with all required scopes.
*/
async function createSession(walletAddress: string): Promise<string> {
const server = new BurnerClient({
apiKey: process.env.BURNER_API_KEY,
})
const session = await server.createSession({
walletAddress,
scopes: [
SessionScope.WalletRead,
SessionScope.TransactionsBuild,
SessionScope.TransactionsSubmit,
],
ttlSeconds: 600,
})
return session.token
}
/**
* Client-side: scan, build, sign, and submit.
*/
async function reclaimSol(
sessionToken: string,
walletAddress: string,
signAllTransactions: (txs: VersionedTransaction[]) => Promise<VersionedTransaction[]>
) {
const client = new BurnerClient({ sessionToken })
// 1. Scan the wallet
const { items, counts } = await client.getWalletAssets(walletAddress)
if (items.length === 0) {
return { reclaimed: 0, burned: 0 }
}
// 2. Select all closeable/burnable items
const selections: ItemSelection[] = items
.filter((item) => item.actions.length > 0)
.map((item) => ({
type: item.type,
address: item.address,
action: item.actions[0], // prefer the first action
}))
// 3. Build unsigned transactions
const { transactions, totals } = await client.buildTransactions(
walletAddress,
{ items: selections }
)
console.log(`Building ${transactions.length} transactions for ${totals.itemCount} items`)
console.log(`Estimated reclaim: ${(totals.netRebate / 1e9).toFixed(6)} SOL`)
// 4. Deserialize and sign
const unsigned = transactions.map((tx) =>
VersionedTransaction.deserialize(
Buffer.from(tx.transactionBase64, 'base64')
)
)
const signed = await signAllTransactions(unsigned)
// 5. Submit
const { results } = await client.submitTransactions(walletAddress, {
signed: signed.map((tx, i) => ({
transactionBase64: Buffer.from(tx.serialize()).toString('base64'),
submissionTicket: transactions[i].submissionTicket,
})),
})
// 6. Report
let successCount = 0
let failCount = 0
for (const result of results) {
switch (result.status) {
case 'submitted':
successCount++
console.log(`OK: https://solscan.io/tx/${result.signature}`)
break
case 'duplicate':
successCount++ // already submitted, count as success
break
case 'failed':
failCount++
console.error(`FAIL: ${result.error?.code} - ${result.error?.message}`)
break
}
}
return {
reclaimed: totals.netRebate / 1e9,
burned: successCount,
failed: failCount,
}
}Filtering by item type
You may want to let users choose which types of items to burn. Filter the selections before building:
// Only close empty accounts (safest -- no tokens are destroyed)
const emptyAccountsOnly = items
.filter((item) => item.type === 'empty_account')
.map((item) => ({
type: item.type,
address: item.address,
action: 'close' as const,
}))Handling expired blockhashes
If the user takes too long to sign, the blockhash may expire. Catch the TICKET_EXPIRED or RPC_ERROR and rebuild:
const { results } = await client.submitTransactions(walletAddress, { signed })
const expired = results.filter(
(r) => r.status === 'failed' && r.error?.code === 'TICKET_EXPIRED'
)
if (expired.length > 0) {
// Rebuild only the failed items
const failedSelections = expired.flatMap((r) => r.includes)
const rebuilt = await client.buildTransactions(walletAddress, {
items: failedSelections,
})
// Sign and submit again...
}Displaying rebate estimates
The totals object from buildTransactions has everything you need for a confirmation dialog:
function formatConfirmation(totals: {
itemCount: number
grossRebate: number
netRebate: number
donationAmount: number
fees: number
}) {
return {
items: totals.itemCount,
grossSol: (totals.grossRebate / 1e9).toFixed(6),
netSol: (totals.netRebate / 1e9).toFixed(6),
feeSol: (totals.fees / 1e9).toFixed(6),
donationSol: (totals.donationAmount / 1e9).toFixed(6),
}
}
// e.g. { items: 15, grossSol: "0.030589", netSol: "0.029060", feeSol: "0.001529", donationSol: "0.000000" }Last updated on