A Solana program that enables cross-chain swaps from EVM chains to Solana using Across Protocol for bridging and Jupiter for DEX aggregation.
SuperSwap-Sol is a trustless, on-chain solution for executing cross-chain swaps between EVM chains and Solana. The program:
- Receives bridged USDC from Across Protocol
- Parses the embedded swap instructions
- Executes swaps via Jupiter aggregator
- Delivers tokens to the end user
- Automatically refunds USDC if swaps fail
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ EVM Chain │────────▶│ Across │────────▶│ Solana │
│ (Base) │ │ Protocol │ │ SuperSwap │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Jupiter │
│ Swap │
└─────────────┘
│
▼
┌─────────────┐
│ User │
└─────────────┘
- ✅ Trustless cross-chain swaps (EVM → Solana)
- ✅ Integration with Across Protocol for bridging
- ✅ Integration with Jupiter for optimal swap routing
- ✅ Automatic refunds on swap failure
- ✅ Configurable fees
- ✅ Emergency pause mechanism
- ✅ Admin controls for configuration updates
- ✅ Comprehensive error handling
superswap-sol/
├── programs/
│ └── superswap-sol/
│ ├── src/
│ │ ├── lib.rs # Program entry point
│ │ ├── error.rs # Custom error definitions
│ │ ├── state.rs # Account structures
│ │ ├── instructions/ # Instruction handlers
│ │ │ ├── mod.rs
│ │ │ ├── initialize.rs # Program initialization
│ │ │ ├── update_config.rs # Config management
│ │ │ ├── process_bridge_and_swap.rs # Main swap logic
│ │ │ ├── execute_jupiter_swap.rs # Jupiter integration
│ │ │ ├── recover_funds.rs # Emergency recovery
│ │ │ └── pause.rs # Pause/unpause
│ │ └── utils/ # Helper utilities
│ │ ├── mod.rs
│ │ ├── jupiter.rs # Jupiter helpers
│ │ └── refund.rs # Refund logic
│ ├── Cargo.toml
│ └── Xargo.toml
├── tests/
│ └── superswap-sol.ts # Integration tests
├── Anchor.toml # Anchor configuration
├── Cargo.toml # Workspace configuration
├── package.json # Node.js dependencies
└── tsconfig.json # TypeScript configuration
Before you begin, ensure you have the following installed:
-
Rust (1.75.0 or later)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env
-
Solana CLI (1.18.22 or later)
sh -c "$(curl -sSfL https://release.solana.com/v1.18.22/install)" -
Anchor CLI (0.30.1)
cargo install --git https://github.com/coral-xyz/anchor avm --locked --force avm install 0.30.1 avm use 0.30.1
-
Node.js (18.x or later) and Yarn
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs npm install -g yarn
-
Clone the repository:
cd /home/ck/Documents/superswap-sol -
Install dependencies:
yarn install
-
Build the program:
anchor build
-
Generate TypeScript types:
anchor build
Generate a keypair for local development:
solana-keygen new --outfile ~/.config/solana/id.jsonFor local development:
solana config set --url localhostFor devnet:
solana config set --url devnetFor mainnet:
solana config set --url mainnet-betasolana airdrop 2For local testing, start a local Solana validator:
solana-test-validatorIn a separate terminal, monitor logs:
solana logsanchor buildThis generates:
- Program binary:
target/deploy/superswap_sol.so - IDL:
target/idl/superswap_sol.json - TypeScript types:
target/types/superswap_sol.ts
For local testing:
anchor deployFor devnet:
anchor deploy --provider.cluster devnetRun the full test suite:
anchor testRun tests without restarting validator:
anchor test --skip-local-validatorAfter deployment, initialize the program with configuration:
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { SuperswapSol } from "../target/types/superswap_sol";
const program = anchor.workspace.SuperswapSol as Program<SuperswapSol>;
const provider = anchor.AnchorProvider.env();
// Derive config PDA
const [configPda] = PublicKey.findProgramAddressSync(
[Buffer.from("config")],
program.programId
);
// Initialize
await program.methods
.initialize({
acrossHandler: acrossHandlerPublicKey,
jupiterProgram: new PublicKey("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"),
usdcMint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
feeRecipient: feeRecipientPublicKey,
feeBps: 30, // 0.3%
})
.accounts({
config: configPda,
admin: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc();Test individual instructions in isolation:
anchor test tests/initialize.spec.ts
anchor test tests/config.spec.tsTest the full swap flow:
anchor test tests/superswap-sol.tsTo test with real Jupiter swaps on devnet:
- Update
Anchor.tomlto use devnet - Get devnet USDC from faucet
- Use Jupiter API to generate swap instructions
- Test the full flow
Example:
// Generate Jupiter swap instructions
const quoteResponse = await fetch(
`https://quote-api.jup.ag/v6/quote?inputMint=${usdcMint}&outputMint=${destinationMint}&amount=${amount}`
).then(res => res.json());
const swapResponse = await fetch('https://quote-api.jup.ag/v6/swap', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
quoteResponse,
userPublicKey: userPublicKey.toString(),
}),
}).then(res => res.json());
// Use swapResponse.swapTransaction for jupiter_swap_dataWhen bridging USDC via Across, include swap parameters in the message:
interface AcrossMessage {
orderId: number; // Unique order identifier
recipient: string; // Solana address (base58)
minOutputAmount: number; // Minimum tokens expected
destinationMint: string; // Token mint address (base58)
deadline: number; // Unix timestamp
jupiterSwapData: Buffer; // Serialized Jupiter instruction
}-
Get Jupiter Quote:
const quote = await fetch( `https://quote-api.jup.ag/v6/quote?inputMint=${USDC_MINT}&outputMint=${destinationMint}&amount=${amount}&slippageBps=50` ).then(r => r.json());
-
Generate Swap Transaction:
const swap = await fetch('https://quote-api.jup.ag/v6/swap-instructions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ quoteResponse: quote, userPublicKey: superswapProgramAddress, }), }).then(r => r.json());
-
Encode Message for Across:
const message = { orderId: Date.now(), recipient: userSolanaAddress, minOutputAmount: quote.otherAmountThreshold, destinationMint: destinationTokenMint, deadline: Math.floor(Date.now() / 1000) + 1800, // 30 minutes jupiterSwapData: Buffer.from(swap.swapInstruction, 'base64'), }; const encodedMessage = borsh.serialize(MessageSchema, message);
-
Bridge via Across:
// Use Across SDK to bridge with message await acrossClient.bridge({ fromChain: 'base', toChain: 'solana', token: USDC_ADDRESS, amount: amount, recipient: SUPERSWAP_PROGRAM_ADDRESS, message: encodedMessage, });
The program executes Jupiter swaps via CPI (Cross-Program Invocation):
- Receives serialized Jupiter instruction in
jupiter_swap_data - Validates the instruction format
- Builds account list from instruction
- Executes CPI to Jupiter program
- Validates output meets minimum requirements
- Transfers output tokens to user
Use Jupiter V6 for optimal routing:
// Get quote
const quote = await jupiterApi.quoteGet({
inputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
outputMint: destinationMint,
amount: amount,
slippageBps: 50,
});
// Get swap instructions
const swapInstructions = await jupiterApi.swapInstructionsPost({
swapRequest: {
quoteResponse: quote,
userPublicKey: programAddress,
},
});The program includes comprehensive error handling:
If a Jupiter swap fails:
- Program catches the error
- Marks order as
Failed - Automatically refunds USDC to user
- Emits failure event
// Automatic refund on swap failure
if swap_result.is_err() {
msg!("Swap failed, initiating refund");
refund_usdc(
&config,
&mut swap_order,
&program_usdc_account,
&recipient_usdc_account,
&token_program,
)?;
}| Error | Description | Action |
|---|---|---|
ProgramPaused |
Program is paused | Wait for unpause |
SlippageExceeded |
Output below minimum | Increase slippage or retry |
DeadlineExceeded |
Transaction too slow | Increase deadline |
InvalidSwapCalldata |
Malformed Jupiter data | Regenerate swap data |
- Only Across handler can trigger swaps
- Only admin can update configuration
- PDA-based authority for token transfers
- Minimum output enforced
- Deadline checks prevent stale transactions
- Fee calculations checked for overflow
- Automatic refunds on failure
- User always receives either tokens or USDC
- No funds can be stuck
- Admin can pause program
- Admin can recover stuck funds
- Configuration updates require admin signature
- Build program:
anchor build - Update program ID in
Anchor.tomlandlib.rs - Deploy:
anchor deploy --provider.cluster devnet - Initialize program with test configuration
- Test with small amounts
- Verify refund logic
- Complete security audit
- Test thoroughly on devnet
- Prepare admin keypair (use hardware wallet)
- Set up fee recipient
- Deploy program
- Initialize with production config:
- Across handler: Verified Across program address
- Jupiter program:
JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 - USDC mint:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v - Fee: 0.3% (30 bps) or as decided
- Test with small real transaction
- Monitor logs for 24 hours
- Gradually increase limits
Monitor program execution:
solana logs | grep "superswap"Query program state:
// Get config
const config = await program.account.config.fetch(configPda);
// Get swap order
const swapOrder = await program.account.swapOrder.fetch(swapOrderPda);
// Check order status
console.log("Status:", swapOrder.status);- Total volume processed
- Success rate of swaps
- Average swap time
- Fee revenue
- Failed transactions (refunds)
Error: "anchor-lang version mismatch"
cargo clean
anchor buildError: "program ID mismatch" Update the program ID in:
Anchor.tomlprograms/superswap-sol/src/lib.rs(declare_id!)
Error: "insufficient funds"
solana airdrop 2Error: "account not found" Ensure validator is running and program is deployed:
solana program show <PROGRAM_ID>Error: "ProgramPaused" Program is paused by admin. Check with:
const config = await program.account.config.fetch(configPda);
console.log("Is paused:", config.isPaused);Error: "SlippageExceeded" Jupiter swap output below minimum. Increase slippage tolerance or update price.
To enable Solana → EVM swaps:
- Add instruction to initiate SVM → EVM bridge
- Swap tokens to USDC on Solana via Jupiter
- Bridge USDC to EVM chain via Across
- Include calldata for EVM DEX swap (e.g., Uniswap)
Enable complex routing:
- Swap through multiple intermediate tokens
- Use multiple DEXs for better pricing
- Split large orders across venues
Add limit order functionality:
- Users set desired price
- Execute when price is met
- Cancel/modify pending orders
Initializes the program configuration.
Parameters:
across_handler: Pubkey- Across handler authorityjupiter_program: Pubkey- Jupiter program IDusdc_mint: Pubkey- USDC token mintfee_recipient: Pubkey- Fee collection addressfee_bps: u16- Fee in basis points (0-1000)
Processes bridged USDC and executes swap.
Parameters:
order_id: u64- Unique order identifierrecipient: Pubkey- Token recipientusdc_amount: u64- Amount of USDC bridgedmin_output_amount: u64- Minimum tokens expecteddestination_mint: Pubkey- Destination token mintdeadline: i64- Expiration timestampjupiter_swap_data: Vec<u8>- Serialized Jupiter instruction
Updates program configuration (admin only).
Pauses/unpauses program (admin only).
Recovers stuck funds (admin only, emergency use).
Global program configuration.
Represents an individual swap order.
Status:
Pending- Order being processedCompleted- Swap successfulRefunded- Swap failed, USDC refundedFailed- Order failed with error
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
MIT License - see LICENSE file for details.
For issues and questions:
- GitHub Issues: SuperSwap Issues
- Discord: SuperSwap Community
- Documentation: docs.superswap.io