DEV Community

Ayush Kumar
Ayush Kumar

Posted on AI-assisted

Building Beanstick: Autonomous Fiat-to-Crypto Settlement on Solana with Anchor PDAs & zkTLS

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)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

The protocol coordinates three independent layers:

  1. 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.
  2. Anchor Escrow Program: Manages non-custodial token vaults via PDAs and enforces a strict finite-state machine (INITIATED β†’ LOCKED β†’ ATTESTED β†’ RELEASED / REFUNDED).
  3. 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>,
}
Enter fullscreen mode Exit fullscreen mode

When an LP locks liquidity:

  1. The program transfers tokens (native SOL, SPL USDC, or PYUSD) into escrow_vault.
  2. A deadline timestamp is set. If the buyer never sends fiat, the LP can call refund_escrow after expiration.
  3. When the bank transaction is verified off-chain, the attestor invokes submit_zktls_attestation.
  4. 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,
)?;
Enter fullscreen mode Exit fullscreen mode

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:

  1. When a buyer completes a payment (via UPI, Venmo, or SEPA), the bank sends a TLS-encrypted HTTP response.
  2. An MPC attestor participates in key-splitting with the TLS session, verifying the authenticator MAC and response payload.
  3. 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.
  4. 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


πŸ’‘ What We Learned

  • Anchor 0.30.1 Interface Accounts: Using InterfaceAccount<'info, TokenAccount> and TokenInterface allows 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!

Top comments (0)

⌂ 捒网址