The Server SDK is currently experimental and not ready for production use.
Signing and Sending Transactions
This guide covers how to sign and send transactions using the Phantom Server SDK across different blockchain networks.
Overview
The SDK provides a simple, unified interface that handles both signing AND sending transactions:
const signedResult = await sdk.signAndSendTransaction({
walletId, // The wallet to sign with
transaction, // Web3.js transaction object, or evm ones
networkId // Target network
});
// The SDK automatically submits the transaction to the blockchain!
// You get back the signed transaction to extract the signature
The signAndSendTransaction method does two things automatically:
- Signs the transaction with the wallet’s private key
- Submits the signed transaction to the blockchain network
You don’t need to manually submit the transaction - the SDK handles this for you!
Basic Solana Transfer
Here’s a complete example of sending SOL from one address to another:
import { ServerSDK, NetworkId } from '@phantom/server-sdk';
import {
Connection,
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL
} from '@solana/web3.js';
import bs58 from 'bs58';
async function sendSOL(
sdk: ServerSDK,
walletId: string,
fromAddress: string,
toAddress: string,
amountSOL: number
) {
// Connect to Solana network
const connection = new Connection('https://api.mainnet-beta.solana.com');
// Create transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: new PublicKey(fromAddress),
toPubkey: new PublicKey(toAddress),
lamports: amountSOL * LAMPORTS_PER_SOL
})
);
// Get recent blockhash
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(fromAddress);
// Sign and send - SDK handles both!
const signedResult = await sdk.signAndSendTransaction({
walletId,
transaction,
networkId: NetworkId.SOLANA_MAINNET
});
console.log('✅ Transaction signed and sent!');
// Extract signature from the returned signed transaction
const signedTx = Transaction.from(
Buffer.from(signedResult.rawTransaction, 'base64url')
);
let signature: string;
if (signedTx.signature) {
signature = bs58.encode(signedTx.signature);
} else if (signedTx.signatures?.[0]?.signature) {
signature = bs58.encode(signedTx.signatures[0].signature);
} else {
throw new Error('Failed to extract signature');
}
console.log(`Transaction signature: ${signature}`);
// Wait for confirmation
const confirmation = await connection.confirmTransaction(signature);
return {
signature,
confirmed: !confirmation.value.err
};
}
Complete Example with Priority Fees
Based on the SDK demo, here’s how to send a transaction with priority fees:
import { ComputeBudgetProgram } from '@solana/web3.js';
async function sendWithPriorityFee(
sdk: ServerSDK,
walletId: string,
fromAddress: string,
toAddress: string,
amountSOL: number
) {
const connection = new Connection('https://api.devnet.solana.com');
const transaction = new Transaction();
// Add priority fee instruction first
const priorityFee = 1000; // micro-lamports per compute unit
transaction.add(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
})
);
// Add transfer instruction
transaction.add(
SystemProgram.transfer({
fromPubkey: new PublicKey(fromAddress),
toPubkey: new PublicKey(toAddress),
lamports: Math.floor(amountSOL * LAMPORTS_PER_SOL)
})
);
// Prepare transaction
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(fromAddress);
// Sign and send (SDK does both!)
const signedResult = await sdk.signAndSendTransaction({
walletId,
transaction,
networkId: NetworkId.SOLANA_DEVNET
});
// Extract signature
const signedTx = Transaction.from(
Buffer.from(signedResult.rawTransaction, 'base64url')
);
const signature = bs58.encode(signedTx.signatures[0].signature);
console.log(`Transaction sent with signature: ${signature}`);
// Wait for confirmation
const startTime = Date.now();
let confirmed = false;
let attempts = 0;
while (!confirmed && attempts < 30) {
const status = await connection.getSignatureStatus(signature);
if (status?.value) {
if (status.value.err) {
throw new Error(`Transaction failed: ${JSON.stringify(status.value.err)}`);
}
if (status.value.confirmationStatus === 'confirmed' ||
status.value.confirmationStatus === 'finalized') {
confirmed = true;
const elapsed = (Date.now() - startTime) / 1000;
console.log(`✅ Confirmed in ${elapsed.toFixed(1)} seconds`);
}
}
if (!confirmed) {
attempts++;
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return { signature, confirmed };
}
Key Points to Remember
- The SDK handles both signing AND sending - You don’t need to manually submit transactions
- Always use fresh blockhashes - Get a new blockhash right before creating the transaction
- Extract signatures from the result - The SDK returns the signed transaction, not the signature directly
- Handle confirmations separately - The SDK sends the transaction but doesn’t wait for confirmation
- Use proper error handling - Network issues and blockchain errors can occur
Next Steps
Disclaimers
The Server SDK is a beta version, and Phantom will not be liable for any losses or damages suffered by you or your end users.
Any suggestions, enhancement requests, recommendations, or other feedback provided by you regarding the Server SDK will be the exclusive property of Phantom. By using this beta version and providing feedback, you agree to assign any rights in that feedback to Phantom.