
Lease on Solana is getting cheaper, and which means you and your customers at the moment are sitting on extra lamports that may be reclaimed.
Should you handle a pockets or different utility service (e.g., token account closing), chances are you’ll wish to enable your customers to reclaim extra lease on their token accounts and token mints. Should you function a program, chances are you’ll wish to enable customers to reclaim extra lease on PDAs that your program owns. Let’s stroll by means of learn how to do each.
Reclaiming from Token Accounts and Mints
The Token Program was lately reimplemented utilizing Pinocchio (known as P-token). When P-token went reside on mainnet, a number of new directions had been added to this system, together with one which was constructed precisely for this: WithdrawExcessLamports.
It recovers SOL sitting above the rent-exempt minimal from a token account, mint, or multisig account — with out touching token balances and with out closing the account. The account stays open and useful; solely the excess lamports transfer.
The on-chain logic is easy. Conceptually, the processor computes the supply account’s rent-exempt ground, and strikes all the things above it to the vacation spot:
// Simplified from the Token Program's withdraw_excess_lamports processor.
// The supply retains precisely its rent-exempt minimal; the remainder strikes out.
let rent_exempt_reserve = Lease::get()?.minimum_balance(source_account_info.data_len());
let extra = source_account_info
.lamports()
.checked_sub(rent_exempt_reserve)
.ok_or(TokenError::Overflow)?;
// Credit score the vacation spot, debit the supply.
*destination_account_info.borrow_mut_lamports_unchecked() += extra;
*source_account_info.borrow_mut_lamports_unchecked() = rent_exempt_reserve;
The withdrawal have to be signed by the account’s authority:
- For a token account, that is the account proprietor.
- For a mint, that is the mint authority
- For a mint whose authority has been revoked, authorization can as a substitute come from the mint account itself signing — i.e. the transaction is signed with the mint’s personal key.
Shopper-side (TypeScript)
WithdrawExcessLamports is uncovered by means of the @solana-program/token shopper. The form of the decision is:
import { getWithdrawExcessLamportsInstruction } from "@solana-program/token";
// Transfer all lamports above the rent-exempt ground out of `sourceAccount`
// (a token account or mint) into `vacation spot`, approved by `authority`.
const instruction = getWithdrawExcessLamportsInstruction({
supply: sourceAddress, // the token account or mint holding extra SOL
vacation spot: destinationAddress, // the place the reclaimed lamports land
authority: authoritySigner // proprietor / mint authority / the mint itself
});
// Drop `instruction` right into a transaction message and ship as typical.
That is all the movement for something the Token Program owns. The Token 2022 program has the identical instruction accessible through the @solana-program/token-2022.
Reclaiming from your personal program’s PDAs
The Token Program can solely assist with accounts it owns. To your personal program-owned accounts (e.g., DeFi place PDAs, config accounts, escrow vaults), your program is the proprietor, so you will have to write down the reclaim logic as an instruction in your program. The excellent news is it is the identical concept that they token program makes use of, following the realloc sample you already use when resizing an account.
Two issues decide an account’s lease ground: its information dimension and the present lamports_per_byte. You reclaim by (1) shrinking the account to the scale it really wants, then (2) shifting any lamports above the brand new rent-exempt minimal out to a vacation spot.
Shrinking / reclaiming: you pull lamports out
For a program-owned account, you possibly can’t use a System Program switch to maneuver lamports out (System solely strikes lamports out of accounts it owns). As a substitute, as a result of your program owns the account, you mutate the lamport balances instantly (just like the token program’s WithdrawExcessLamports instruction). Debit the account and credit score the vacation spot in the identical instruction; the runtime enforces that the 2 sides steadiness.
use solana_program::{lease::Lease, sysvar::Sysvar};
pub fn reclaim_excess(
target_account: &AccountInfo, // owned by THIS program
vacation spot: &AccountInfo, // e.g. the consumer's pockets
authority: &AccountInfo, // authority
) -> ProgramResult {
// 1. Validate Authority & PDA
// Program-specific logic for validating your PDA & authority
// 2. Compute the rent-exempt ground on the CURRENT lamports_per_byte.
// Studying from the Lease sysvar means you choose up the decreased charge
// mechanically — by no means hardcode the fixed.
let rent_exempt_reserve = Lease::get()?.minimum_balance(target_account.data_len());
// 3. Every thing above the ground is reclaimable.
let extra = target_account
.lamports()
.saturating_sub(rent_exempt_reserve);
if extra == 0 {
return Okay(());
}
// 4. Direct lamport motion — authorized as a result of this program owns target_account.
**vacation spot.try_borrow_mut_lamports()? += extra;
**target_account.try_borrow_mut_lamports()? -= extra;
Okay(())
}
The total guidelines for a secure reclaim instruction:
- Confirm possession — the goal account have to be owned by your program, or the direct lamport mutation will fail.
- Confirm the authority signer — determine who’s allowed to reclaim (the place proprietor, an admin, and many others.) and verify they signed.
- Learn the ground from the Lease sysvar — that is what makes your program mechanically right throughout every section of the lease discount rollout.
- Transfer solely the surplus — depart the rent-exempt reserve in place so the account stays alive.
- Steadiness the transaction — the sum of lamports throughout accounts have to be conserved; credit score the vacation spot by precisely what you debit.
This works identically whether or not your program is written in Anchor, native Rust, or Pinocchio — the framework solely modifications the encircling boilerplate (account validation, (de)serialization), not the core lamport arithmetic.
Full code samples
For full, runnable packages and shoppers:
Be certain new accounts are sized correctly
One factor to look out for in your present codebases is lease constants. Since lease is altering (and prone to change once more sooner or later), finest observe is to at all times fetch the present lease exempt quantity reasonably than hard-coding lease quantities:
// Program Requests
// https://docs.rs/solana-rent/newest/solana_rent/index.html
let lamports_required = (Lease::get()?).try_minimum_balance(account_span)?;
// Shopper Requests
// https://solana.com/docs/rpc/http/getminimumbalanceforrentexemption
// Package Instance:
let minBalForRentExemption = await rpc
.getMinimumBalanceForRentExemption(dataLength)
.ship();
Wanting forward
Immediately marks the primary section of a 5-phased lease discount roll-out. Observe the complete rollout at https://solana.com/upgrades/reduced-rent.
The core groups engaged on Solana are transport quick, so count on extra modifications like these that enhance the builder and consumer expertise. To remain up with the newest, subscribe to https://x.com/solana_devs and take a look at https://solana.com/upgrades.
