SolRescue is a self-hosted token rescue service for compromised Solana wallets.
It uses native fee-payer delegation, meaning the compromised wallet never receives SOL, preventing sweep bots from triggering.
When a Solana wallet is compromised, rescuing tokens normally fails:
- You send SOL to pay transaction fees
- A sweep bot instantly steals the SOL
- The token transfer never executes
SolRescue solves this by:
- The server pays all transaction fees
- The compromised wallet only signs the token transfer
Since no SOL enters the compromised wallet, sweep bots have nothing to steal.
Client Server Solana Network
│ │ │
│ 1. POST /api/tokens │ │
│─────────────────────────>│ │
│ │ Query token accounts │
│ │─────────────────────────────>│
│ │<─────────────────────────────│
│ Return balances │ │
│<─────────────────────────│ │
│ │ │
│ 2. POST /api/simulate │ │
│─────────────────────────>│ │
│ │ Check ATAs, calculate fees │
│ │─────────────────────────────>│
│ Return preview │ │
│<─────────────────────────│ │
│ │ │
│ 3. Generate proof │ │
│ (sign message) │ │
│ │ │
│ 4. POST /api/execute │ │
│ (key + proof + params) │ │
│─────────────────────────>│ │
│ │ Verify ownership proof │
│ │ Build transaction: │
│ │ - Fee payer: server wallet │
│ │ - Signer: compromised key │
│ │ │
│ │ Send atomic transaction │
│ │─────────────────────────────>│
│ │ │
│ │ Confirm transaction │
│ │<─────────────────────────────│
│ Return signature │ │
│<─────────────────────────│ │
SolRescue supports both:
- Classic SPL Token
- Token-2022
Detect mint program
│
├── TOKEN_PROGRAM_ID (classic)
│ └── Standard ATA creation
│
└── TOKEN_2022_PROGRAM_ID
│
├── Check PermanentDelegate
│
├── If present:
│ └── Two-transaction flow
│
└── Otherwise:
└── Standard single transaction
Token-2022 mints with PermanentDelegate require special handling.
Fee payer: Server wallet
Instructions:
- Transfer SOL → Destination wallet
- Transfer SOL → Fee collection wallet
- Transfer SOL → Compromised wallet (exact ATA rent amount)
- Create destination ATA (payer = compromised)
- Create fee collection ATA (payer = compromised)
Fee payer: Server wallet
Instructions:
- Transfer tokens → Destination (95%)
- Transfer tokens → Fee collection (5%)
Net cost to compromised wallet: 0 SOL
The server covers all expenses.
Before executing a rescue, the client must:
- Sign a known message
- Using the compromised wallet private key
Verification uses:
nacl.sign.detached.verify
This proves the caller controls the wallet.
Keys are handled with strict rules:
- HTTPS only (TLS required)
- Used in memory only
- Never logged
- Never stored
- Cleared from memory immediately
| Endpoint | Limit |
|---|---|
| General API | 30 requests / 15 minutes |
| Rescue execution | 5 rescues / hour |
Prevents automated abuse.
Using:
- Helmet
- CSP
- HSTS
- X-Frame-Options
Additional protections:
- JSON body limited to 10KB
- CORS restricted in production
Logging is handled with:
- Winston
Features:
- Request IDs
- IP logging
- Transaction signatures
- Automatic rotation
Private keys never appear in logs.
git clone https://github.com/yourusername/solrescue.git
cd solrescue
npm installcp .env.production.example .env
Edit .env.
NODE_ENV=production
RPC_URL=https://mainnet.helius-rpc.com/?api-key=YOUR_KEY
FEE_PAYER_PRIVATE_KEY=<server_wallet_base58>
FEE_COLLECTION_ADDRESS=<fee_wallet>
SERVICE_FEE_PERCENT=5
MIN_RESCUE_AMOUNT=1000
ALLOWED_ORIGIN=https://your-domain.com
PROOF_MESSAGE=I authorize Solana Rescue to recover my tokens
| Variable | Description |
|---|---|
| NODE_ENV | Environment mode |
| RPC_URL | Solana RPC endpoint |
| FEE_PAYER_PRIVATE_KEY | Wallet paying transaction fees |
| FEE_COLLECTION_ADDRESS | Fee wallet |
| SERVICE_FEE_PERCENT | Service fee percentage |
| MIN_RESCUE_AMOUNT | Minimum rescue amount |
| ALLOWED_ORIGIN | Allowed CORS domain |
| PROOF_MESSAGE | Message users sign |
- Push repository to GitHub
- Import repository into Vercel
- Add environment variables
- Deploy
Use:
- PM2
- Nginx
- SSL via Let's Encrypt
Example:
pm2 start server.js --name solrescue
Returns server status.
{
"status": "ok",
"feePayerBalanceSOL": 0.0432,
"serviceFeePercent": 5
}Returns the message users must sign.
{
"message": "I authorize Solana Rescue to recover my tokens"
}Fetch token balances.
{
"walletAddress": "7xKX..."
}Execute token rescue.
{
"compromisedWalletPrivateKey": "base58_private_key_here",
"ownershipProof": "base58_signature_here",
"tokenMint": "...",
"tokenAccount": "...",
"destinationAddress": "..."
}{
"success": true,
"signature": "...",
"total": "15000000",
"userReceived": "14250000",
"serviceFee": "750000"
}Example:
import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";
import nacl from "tweetnacl";
const response = await fetch("/api/proof-message");
const { message } = await response.json();
const keypair = Keypair.fromSecretKey(bs58.decode(privateKey));
const messageBytes = new TextEncoder().encode(message);
const signature = nacl.sign.detached(messageBytes, keypair.secretKey);
const ownershipProof = bs58.encode(signature);solrescue/
├── server.js
├── src/
│ ├── rescue.js
│ └── logger.js
├── public/
│ └── index.html
├── logs/
│ ├── rescue.log
│ └── error.log
├── .env.production.example
├── vercel.json
├── DEPLOYMENT.md
├── PRODUCTION.md
└── package.json
| Layer | Technology |
|---|---|
| Backend | Node.js + Express |
| Blockchain | Solana Web3 SDK |
| Token handling | SPL Token |
| Security | Helmet + Rate Limit |
| Logging | Winston |
| Frontend | Vanilla JavaScript |
Private keys are transmitted to the server.
Deploy only behind TLS.
Monitor:
/api/health
Ensure the server wallet always has SOL balance.
For high-value rescues, combine with:
- Jito Labs bundles
This reduces MEV risk.
MIT