Building Beanstick: Autonomous Fiat-to-Crypto Settlement on Solana with Anchor PDAs & zkTLS
Moving value between traditional banking (Web2) and decentralized finance (Web3) has long been one of crypto's biggest bottlenecks. Traditional centralized onramps impose 3% to 8% fees, hold customer funds for days, and require users to trust custodial intermediaries.
For the MLH Solana Hackathon 2026, we built Beanstick (BeanSol): an autonomous, non-custodial fiat-to-crypto settlement network designed specifically around Solana's high-speed architecture, sub-second finality, and negligible fees.
Here is an architectural walkthrough of how we engineered Beanstick using Rust, Anchor 0.30.1, autonomous AI LP agents, and zkTLS proofs.
⚡ Why Solana?
On EVM chains, high gas spikes and multi-block confirmation delays make real-time payment settlement impractical. A user at a point-of-sale or online checkout cannot wait 15 minutes for block finality.
Solana solves this natively:
- ~400ms Block Times: Escrows lock and release in sub-second timeframes, matching the UX of modern fiat rails like UPI or Venmo.
- Predictable Micro-Fees: Transactions cost less than $0.001, allowing micro-swaps without fee penalties.
- Composable Program Derived Addresses (PDAs): Enable deterministic, program-owned escrow vaults with zero human intermediaries.
🧠 The Architecture: How It Works End-to-End
┌──────────────────┐ ┌───────────────────────┐ ┌────────────────────┐ │ Buyer (User) │ ───────> │ Autonomous AI Swarm │ <──────> │ Neo4j AuraDB Graph│ │ "100 USD to SOL" │ │ (Reverse Auction) │ │ (Reputation & Trust│ └────────┬─────────┘ └───────────┬───────────┘ └────────────────────┘ │ │ │ ▼ lock_escrow() │ ┌───────────────────────┐ │ │ Solana Anchor Program │ │ │ [PDA Token Vault] │ │ └──────────┬────────────┘ ▼ Fiat Transfer │ ┌──────────────────┐ │ │ Web2 Bank / UPI │ │ └────────┬─────────┘ │ ▼ TLS Response │ ┌──────────────────┐ │ │ zkTLS Attestor │ ─────────────────────┘ │ (MPC ZK-SNARK) │ submit_zktls_attestation() ──> release_escrow() (PDA Vault -> Buyer) └──────────────────┘ The protocol coordinates three independent layers:
- Agentic Swarm Protocol: Independent Liquidity Provider (LP) AI agents hold dedicated Solana keypairs, monitor order intents, and compete in sub-millisecond automated reverse auctions to offer the lowest spread.
- Anchor Escrow Program: Manages non-custodial token vaults via PDAs and enforces a strict finite-state machine (
INITIATED→LOCKED→ATTESTED→RELEASED/REFUNDED). - zkTLS Cryptographic Verification: Attestor agents use Multi-Party Computation (MPC) to verify bank receipts without ever seeing or storing user banking credentials, submitting zero-knowledge proofs on-chain.
🛠️ Solana Anchor Implementation: PDA Escrows & Vaults
In our Anchor program (programs/beanstick), token vaults are strictly controlled by Program Derived Addresses. As Prasiddh Naik noted in his dive on Solana PDAs and Kode-n-Rolla discussed on Anchor escrow programs, deriving deterministic seeds is key to avoiding state collisions.
Here is how our escrow account and token vault are canonically derived:
#[derive(Accounts)] #[instruction(order_id: u64)] pub struct LockEscrow<'info> { #[account(mut)] pub lp_authority: Signer<'info>, #[account( init, payer = lp_authority, space = 8 + Escrow::INIT_SPACE, seeds = [b"escrow", order_id.to_le_bytes().as_ref()], bump )] pub escrow: Account<'info, Escrow>, #[account( init, payer = lp_authority, seeds = [b"escrow-vault", escrow.key().as_ref()], bump, token::mint = token_mint, token::authority = escrow_vault, )] pub escrow_vault: InterfaceAccount<'info, TokenAccount>, #[account(mut)] pub lp_token_account: InterfaceAccount<'info, TokenAccount>, pub token_mint: InterfaceAccount<'info, Mint>, pub token_program: Interface<'info, TokenInterface>, pub system_program: Program<'info, System>, } When an LP locks liquidity:
- The program transfers tokens (native SOL, SPL USDC, or PYUSD) into
escrow_vault. - A deadline timestamp is set. If the buyer never sends fiat, the LP can call
refund_escrowafter expiration. - When the bank transaction is verified off-chain, the attestor invokes
submit_zktls_attestation. - The program signs the release using the PDA seeds:
let order_bytes = escrow.order_id.to_le_bytes(); let signer_seeds: &[&[&[u8]]] = &[&[ b"escrow-vault", escrow_key.as_ref(), &[escrow.vault_bump], ]]; token_interface::transfer_checked( CpiContext::new_with_signer( token_program.to_account_info(), TransferChecked { from: escrow_vault.to_account_info(), to: buyer_token_account.to_account_info(), authority: escrow_vault.to_account_info(), mint: token_mint.to_account_info(), }, signer_seeds, ), escrow.amount, token_mint.decimals, )?; The buyer receives their tokens in ~400ms—pure on-chain settlement with zero counterparty risk.
🛡️ zkTLS: Bridging Web2 Banking to Web3
The hardest challenge in fiat onramping is proving that a bank transfer actually happened without centralized bank API keys.
Beanstick uses zkTLS:
- When a buyer completes a payment (via UPI, Venmo, or SEPA), the bank sends a TLS-encrypted HTTP response.
- An MPC attestor participates in key-splitting with the TLS session, verifying the authenticator MAC and response payload.
- The attestor produces a concise ZK-SNARK proving:
- The transaction status is
SUCCESS. - The recipient matches the winning LP agent's bank account.
- The reference ID matches the
order_id.
- The transaction status is
- The on-chain Anchor program verifies the proof hash and triggers instant vault disbursement.
No passwords, session cookies, or bank accounts are ever broadcast or stored on-chain.
🚀 Live Demo & Links
- 🌐 Live Web Application: https://beanstick.vercel.app/
- 💻 GitHub Repository: https://github.com/ayushkumar2601/sol_bean
- 📽️ Video Walkthrough: https://youtu.be/K4bAbqF7MX4
- 📄 Technical Documentation: Architecture Docs
💡 What We Learned
- Anchor 0.30.1 Interface Accounts: Using
InterfaceAccount<'info, TokenAccount>andTokenInterfaceallows seamless compatibility across both standard SPL tokens and Token-2022 extensions. - Compute Budget Optimization: On Solana, explicitly requesting compute units and priority fees (
setComputeUnitPrice) ensures instant inclusion even during high-traffic network periods. - Agent Coordination on Solana: Giving autonomous AI agents their own Solana keypairs unlocks a completely new design space for decentralized market-making.
If you are exploring Solana, Anchor PDAs, or zkTLS, check out the repo and let us know what you think in the comments!