SPL Token Transfer & Approval on Neon EVM: A Comprehensive Guide to Cross-Chain Token Operations


Introduction
The blockchain landscape has shifted to a multi-chain paradigm, where Solana offers lightning-fast transactions and low costs, while Ethereum excels with its rich DeFi ecosystem. Neon EVM enables developers to harness the strengths of both networks. SPL tokens, Solana's native token standard, are now accessible to Ethereum-compatible applications via Neon EVM, opening doors to innovative cross-chain DeFi, gaming, and financial solutions.
This guide, put together from my research and personal knowledge acquired through testing and implementations, walks you through building SPL token transfer and approval functionality on Neon EVM.
The Cross-Chain Challenge
The Problem Space
Blockchain silos force users to pick between:
Solana: High performance, low fees, but a limited DeFi ecosystem.
Ethereum: Extensive DeFi, yet plagued by high gas costs and congestion.
Traditional cross-chain bridges introduce:
Security risks: Centralized points of failure.
Complexity: Multi-step transactions.
Cost: Additional bridge fees.
Liquidity fragmentation: Assets locked in bridge contracts.
Neon EVM's Solution
Neon EVM tackles these issues with:
Native Solana Integration: Direct access to Solana programs.
Ethereum Compatibility: Leverage EVM tools and interfaces.
Unified Experience: Develop for both ecosystems with one codebase.
Simplified Operations: Streamlined cross-chain workflows.
Neon EVM Architecture Overview
Core Components
Neon EVM translates Ethereum transactions into Solana program calls, featuring:
1. Neon Proxy
Purpose: Routes transactions across chains.
Functionality: Manages scheduling, execution, gas estimation.
Key Features: Nonce management and transaction routing.
2. Solana Native SDK
Purpose: Offers JavaScript/TypeScript interfaces for Solana.
Components:
NeonProxyRpcApi
,ScheduledTransaction
, and balance account management.
3. Composability Libraries
Purpose: Modular libraries for Solana program interactions.
Structure: Separate modules for SPL tokens, system programs, etc.
Transaction Flow: Using Solana Native SDK
User action via JavaScript/TypeScript.
Solana wallet signing.
Scheduled transaction creation.
Solana transaction execution.
Neon EVM execution.
State synchronization.
SPL Token Integration
ERC20ForSPL: ERC 20 Interface Contract for SPL Tokens
ERC20ForSPL contracts link SPL tokens to ERC20 interfaces, offering:
Dual Interface Support: Compatible with both standards.
Cross-Chain State Management: Syncs token states.
Event Emission: Standard ERC20 events.
Contract Structure
contract ERC20ForSPL {
bytes32 public tokenMint; // Solana token mint address
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferSolana(bytes32 to, uint64 amount) external returns (bool);
function approveSolana(bytes32 spender, uint64 amount) external returns (bool);
}
Associated Token Accounts (ATAs)
SPL tokens use ATAs for balance management:
Deterministic Addresses: Derived from owner and token mint.
Single Token Type: One token per ATA.
Ownership Model: Tied to the owner's Solana account.
ATA Creation
const ataAddress = await getAssociatedTokenAddress(
tokenMint, // SPL token mint
ownerPublicKey, // Owner's Solana public key
true // Allow off-curve owner
);
Implementation Deep Dive
Project Structure
transfer-approve-spl/
├── composability/ # Cross-chain libraries
│ ├── CallSPLTokenProgram.sol
│ ├── CallAssociatedTokenProgram.sol
│ └── libraries/
├── token/ # ERC20ForSPL contracts
├── precompiles/ # Neon EVM precompile interfaces
├── utils/ # Utility libraries
├── token-approval-solana-signer-sdk.js
└── token-transfer-solana-signer-sdk.js
Core Dependencies
{
"@neonevm/solana-sign": "^0.2.1",
"@solana/spl-token": "^0.4.13",
"@solana/web3.js": "^1.98.2",
"ethers": "^6.12.1"
}
Initialization
const connection = new web3.Connection('https://api.devnet.solana.com', 'confirmed');
const proxyApi = new NeonProxyRpcApi('https://devnet.neonevm.org/sol');
const solanaPrivateKey = bs58.decode(process.env.PRIVATE_KEY_SOLANA);
const keypair = web3.Keypair.fromSecretKey(solanaPrivateKey);
const {chainId, solanaUser} = await proxyApi.init(keypair);
if (await connection.getBalance(solanaUser.publicKey) == 0) {
console.error('Add SOLs to', solanaUser.publicKey.toBase58());
process.exit();
}
Token Approval Logic
Understanding SPL Approvals
Unlike ERC20, SPL approvals use a delegate model:
ERC20: State stored in contract.
SPL: State stored in token account.
Implementation
Approval Flow
const currentApproval = await USDC.allowance(solanaUser.neonWallet, solanaUser.neonWallet);
const transactionData = {
from: solanaUser.neonWallet,
to: USDC_ADDRESS,
data: USDC.interface.encodeFunctionData("approve", [
solanaUser.neonWallet,
Math.floor(Date.now() / 1000)
])
};
const transactionGas = await proxyApi.estimateScheduledTransactionGas({
solanaPayer: solanaUser.publicKey,
transactions: [transactionData]
});
Key Insights
Self-Approval: Same address for owner and spender.
Time-Based: Uses timestamps for approval windows.
Cross-Chain State: Maintained on Neon EVM, initiated from Solana.
Security Tips
Use time-limited approvals.
Approve only necessary amounts.
Regularly review and revoke approvals.
Token Transfer Logic
Cross-Chain Architecture
Solana Layer: ATA management, balance validation, delegation setup.
Neon EVM Layer: Contract execution, state updates, event emission.
Implementation
ATA Management
const solanaUserUSDC_ATA = await getAssociatedTokenAddress(
new web3.PublicKey(ethers.encodeBase58(usdcTokenMint)),
solanaUser.publicKey,
true
);
try {
ataInfo = await getAccount(connection, solanaUserUSDC_ATA);
} catch (e) {
if (e instanceof TokenAccountNotFoundError) {
const ataIx = createAssociatedTokenAccountInstruction(
keypair.publicKey,
solanaUserUSDC_ATA,
keypair.publicKey,
new web3.PublicKey(ethers.encodeBase58(usdcTokenMint))
);
}
}
Delegation Setup
if (ataInfo.delegate == null || ataInfo.delegate.toBase58() != usdcContractPDA.toBase58()) {
scheduledTransaction.instructions.unshift(
createApproveInstruction(
solanaUserUSDC_ATA,
usdcContractPDA,
solanaUser.publicKey,
'18446744073709551615' // max uint64
)
);
}
Transfer Execution
const transactionData = {
from: solanaUser.neonWallet,
to: USDC_ADDRESS,
data: USDC.interface.encodeFunctionData("transfer", [
receiver.address,
1 * 10 ** 6 // 1 USDC
])
};
const { scheduledTransaction } = await proxyApi.createScheduledTransaction({
transactionGas,
transactionData,
nonce
});
Security Measures
Validate balances and amounts.
Verify delegates and recipients.
Scheduled Transaction Mechanism
Lifecycle
Initialization with Solana wallet.
Gas estimation.
Transaction creation.
Balance account setup.
Signing and execution.
Implementation
const nonce = Number(await proxyApi.getTransactionCount(solanaUser.neonWallet));
const { scheduledTransaction } = await proxyApi.createScheduledTransaction({
transactionGas,
transactionData,
nonce
});
const account = await connection.getAccountInfo(solanaUser.balanceAddress);
if (account === null) {
scheduledTransaction.instructions.unshift(
createBalanceAccountInstruction(
neonEvmProgram,
solanaUser.publicKey,
solanaUser.neonWallet,
chainId
)
);
}
const { blockhash } = await connection.getLatestBlockhash();
scheduledTransaction.recentBlockhash = blockhash;
scheduledTransaction.sign({ publicKey: solanaUser.publicKey, secretKey: solanaUser.keypair.secretKey });
const signature = await connection.sendRawTransaction(scheduledTransaction.serialize());
Nonce Management
Unique per account.
Sequential ordering.
Cross-chain managed.
Nonce Code
const nonce = Number(await proxyApi.getTransactionCount(solanaUser.neonWallet));
const scheduledTransactionInstance = new ScheduledTransaction({
nonce: toBeHex(nonce),
payer: solanaUser.neonWallet,
target: contractAddress,
callData: transactionData,
maxFeePerGas: toBeHex(0x77359400),
chainId: toBeHex(NeonChainId.testnetSol)
});
Security Considerations
Authentication
Secure Solana keypair storage.
Proper Neon EVM address derivation.
Authorization
PDA-based delegation.
Time-limited, amount-capped approvals.
Challenges
State Sync: Handle race conditions and consistency.
Attacks: Prevent replay and front-running with nonces.
Best Practices
modifier nonReentrant() {
require(!locked, "Reentrant call");
locked = true;
_;
locked = false;
}
- Regular audits and monitoring.
Performance Optimization
Gas Strategies
Batch Operations
const instructions = [
createBalanceAccountInstruction(...),
createApproveInstruction(...),
createTransferInstruction(...)
];
scheduledTransaction.instructions.push(...instructions);
Caching
- Cache account info, balances, and transaction status.
Network Optimization
Use connection pooling and fallback RPCs.
Adjust priority fees dynamically.
Real-World Applications
DeFi
- Cross-chain DEX and yield farming.
Gaming
- Portable NFTs and cross-chain tournaments.
Enterprise
- Supply chain tracking and cross-chain payments.
Best Practices
Code Organization
class TokenManager {
constructor(provider, signer) {
this.provider = provider;
this.signer = signer;
}
async approve(token, spender, amount) { /* ... */ }
async transfer(token, to, amount) { /* ... */ }
}
Testing
describe('Token Transfer', () => {
it('should transfer tokens', async () => {
const transfer = await tokenManager.transfer(usdcToken, recipient, amount);
expect(transfer.status).toBe('success');
});
});
Monitoring
class TransactionMonitor {
async monitorTransaction(txHash, chain) {
const status = await this.getTransactionStatus(txHash, chain);
if (status === 'failed') await this.sendAlert(`Failed: ${txHash}`);
return status;
}
}
Conclusion
SPL token transfer and approval on Neon EVM revolutionize cross-chain interoperability. With a robust architecture, enhanced security, and optimization techniques, developers can build powerful applications spanning Solana and Ethereum.
Future Directions
Enhanced composability and security.
Better developer tools and standards.
Final Thoughts
This technology paves the way for a unified blockchain ecosystem, driving innovation in DeFi, gaming, and enterprise use cases.
References
Subscribe to my newsletter
Read articles from Goodness Mbakara directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Goodness Mbakara
Goodness Mbakara
Python | Django | Backend | Software | Rest API Developer