Solana
Solana (SOL)
Solana can be accessed with the following coin types:
| Environment | Coin Type | Faucet |
|---|---|---|
| Solana Production | sol | |
| Solana Testnet | tsol | https://solfaucet.com/ |
Note: Solana Devnet is the primary pre-Mainnet chain for testing by developers and users, whereas Solana Testnet is almost exclusively for validators testing validator client upgrades. For more details on Solana clusters, see their documentation, Solana Clusters.
Explorer
https://explorer.solana.com/
Generating wallets
bitgo
.coin('tsol')
.wallets()
.generateWallet({
label: 'My Test Wallet',
passphrase: 'secretpassphrase1a5df8380e0e30',
})
.then(function (wallet) {
// print the new wallet
console.dir(wallet);
});LABEL="My Test Wallet"
PASSPHRASE="secretpassphrase1a5df8380e0e30"
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d "{ \"label\": \"$LABEL\", \"passphrase\": \"$PASSPHRASE\" }" \
http://$BITGO_EXPRESS_HOST/api/v2/tsol/wallet/generateYou can create wallets with a single line of code using the BitGo SDK.
Creating addresses
bitgo
.coin('tsol')
.wallets()
.getWallet({ id: '636d0c90b221c80007c69365ca8a3508' })
.then(function (wallet) {
return wallet.createAddress();
})
.then(function (newAddress) {
// print new address details
console.dir(newAddress);
});WALLET=636d0c90b221c80007c69365ca8a3508
curl -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
https://app.bitgo-test.com/api/v2/tsol/wallet/$WALLET/addressBalances
Solana (SOL) is the native asset of the Solana blockchain. The base unit of Solana is a Lamport (1/1000000000) of 1 SOL coin:
- 1 Lamport is (
10-9) or 0.000000001 SOL. - 1 Solana is (
109) or 1000000000 Lamport.
BitGo supports balance values in string and number format, but we recommend strings to ensure values do not exceed the
programmable number limit: balanceString, confirmedBalanceString, and spendableBalanceString.
Solana accounts pay a fee to store data on the blockchain, which Solana calls "rent". To prevent accounts from paying rent, Solana wallets retain a minimum balance of 0.002447136 SOL to make them rent exempt. The minimum balance must stay on your wallet and cannot be spent.
Fee rate
The default fee is 0.00001 SOL for all Hot/Custody/Cold wallet transactions.
Consolidation
In order to consolidate assets into your root address through the SDK, you can use the following:
async function consolidate(walletId) {
await bitgo.authenticateWithAccessToken({ accessToken });
const unlock = await bitgo.unlock({ otp: '000000', duration: 3600 });
if (!unlock) {
console.log('We did not unlock.');
throw new Error();
}
const walletInstance = await bitgo.coin(coin).wallets().get({ id: walletId });
const consolidationTxs = await walletInstance.sendAccountConsolidations({
walletPassphrase: walletPassphrase,
});
}Note: SOL consolidations support up to 25 addresses per transaction.
For consolidations, the coin value is always sol or tsol irrespective of whether you are trying to consolidate native SOL or Solana tokens.
Note: The addresses array should only contain the owner addresses and not the Associated Token Account (ATA) addresses of the tokens.
Associated Token Account (ATA)
Solana supports token assets in a unique account called an Associated Token Account (ATA). An ATA is a Token Account whose address derives from the wallet public key, the token mint, and the token program. The respective address that holds the token owns each ATA. Each token asset requires a separate ATA.
When is an ATA Created
First-Time Token Transfer: ATAs are automatically created when transferring tokens to a SOL address for the first time. The sender, or the one initiating the transfer to an address without an ATA, covers the minimum rent fee in SOL (0.00203928 SOL) required to maintain the ATA.
When to Enable ATAs
ATAs must be enabled manually for root addresses. If it’s a HOT wallet, the ATA can be enabled by navigating to the settings page, selecting "Enable Tokens," and then choosing the token and root address. Alternatively, ATA can also be enabled by initiating a token transfer to the root address.
For SMC/custodial wallets, there is no UI option to enable ATAs. Therefore, the only way to enable an ATA on the root address is by sending a small token transfer, which triggers the creation of the ATA.
Impact on SOL Balance
The SOL required to cover rent for the ATA creation will be deducted from the balance of the address that initiates the creation.
Post-First-Time Transfer
After you create an ATA for a token on an address, subsequent token transfers directly deposit into the ATA, eliminating any further SOL deductions for rent.
Differentiating Between SOL and ATA Transactions
SOL Transfers: Normal SOL transfers do not involve ATAs and can be differentiated by checking if the transaction contains any "Create Account" instructions. Token Transfers with ATA: Token deposits that involve ATA creation will have additional instructions in the transaction explorer (such as "Create Account") and can be identified as such.
Closing ATAs
You can close empty ATAs to recover the rent lamports locked in those accounts. Closing an ATA uses the SPL CloseAccount instruction. BitGo credits recovered rent to the wallet root address (not configurable).
On-chain and explorer behavior
- Closing deallocates the token account; it no longer appears as an active token account with a balance.
- Historical transactions (creation, transfers, and the close itself) remain on the blockchain and are still visible on explorers when you look up the ATA address.
- Closing does not erase on-chain history.
Prerequisites
| Requirement | Description |
|---|---|
| Zero token balance | Each ATA must have 0 SPL token balance. Transfer or consolidate tokens first if the balance is non-zero. |
| Wallet ownership | Each ATA must belong to the wallet (a BitGo address record for that wallet). |
| Single owner per request | All ATAs in one request must share the same on-chain owner (authority). If the wallet root owns some ATAs and a derived receive address owns others, create separate transaction requests. |
| MPC wallet | Use the Transaction Request API (POST /api/v2/wallet/{walletId}/txrequests). Multisignature wallets use the standard build/sign flow instead. |
Limits
- Up to 27 distinct ATA addresses per transaction (Solana transaction size limit).
- BitGo deduplicates duplicate ATA addresses in
recipients(first occurrence wins). - One transaction and one signing flow for the full batch (when prerequisites are met).
Intent: closeAssociatedTokenAccount
closeAssociatedTokenAccount| Field | Required | Description |
|---|---|---|
intentType | Yes | Must be "closeAssociatedTokenAccount". |
recipients | Yes | Non-empty array; one entry per ATA to close. |
memo | Yes | Optional memo string; if omitted, the platform normalizes to "". |
Each recipients[] entry:
| Field | Required | Description |
|---|---|---|
address.address | Yes | The ATA address to close (not the owner wallet address). |
amount.value | Yes | Must be exactly "0". |
amount.symbol | Yes | Coin symbol, e.g. "sol" or "tsol". |
tokenName | No | Must not be included. |
tokenData | No | Must not be included. |
Recipients identify accounts by ATA address only. The API does not require all ATAs in a batch to use the same token mint; BitGo validates each ATA individually.
Create a close-ATA transaction request
const walletId = '636d0c90b221c80007c69365ca8a3508';
const ataAddress1 = 'ATA_ADDRESS_1';
const ataAddress2 = 'ATA_ADDRESS_2';
bitgo
.post(bitgo.url('/wallet/' + walletId + '/txrequests'))
.send({
apiVersion: 'lite',
intent: {
intentType: 'closeAssociatedTokenAccount',
memo: '',
recipients: [
{
address: { address: ataAddress1 },
amount: { value: '0', symbol: 'tsol' },
},
{
address: { address: ataAddress2 },
amount: { value: '0', symbol: 'tsol' },
},
],
},
})
.then(function (txRequest) {
console.dir(txRequest);
// Sign and send using your standard MPC transaction-request flow.
});WALLET=636d0c90b221c80007c69365ca8a3508
ATA_1=ATA_ADDRESS_1
ATA_2=ATA_ADDRESS_2
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"apiVersion": "lite",
"intent": {
"intentType": "closeAssociatedTokenAccount",
"memo": "",
"recipients": [
{
"address": { "address": "'"$ATA_1"'" },
"amount": { "value": "0", "symbol": "tsol" }
},
{
"address": { "address": "'"$ATA_2"'" },
"amount": { "value": "0", "symbol": "tsol" }
}
]
}
}' \
https://app.bitgo-test.com/api/v2/wallet/$WALLET/txrequestsAfter you create the transaction request, sign and send it using your standard MPC transaction-request workflow (same as other Solana transaction-request intents).
Updated 9 days ago