First-ever trustless P2P cross-chain swap: users securely trade tokens without DEXes/bridges

A trustless P2P swap platform where two users can securely exchange tokens across chains without DEXes or bridges.
Meet Mohit and Jack - two crypto enthusiasts with a simple problem.
Mohit has 1000 USDC sitting on Base chain, but he really wants some Tempo tokens that are only available on the Tempo chain. He's been waiting for weeks, checking every DEX and bridge, but there's just no way to get Tempo tokens.
Meanwhile, Jack has plenty of Tempo tokens on Tempo chain, but he needs USDC on Base for his next DeFi play. He's also been searching everywhere - no bridges, no DEXes, nothing.
The frustrating reality:
They're literally perfect trading partners, but the infrastructure doesn't exist for them to help each other out. This is the P2P swap gap - millions of users with complementary needs, but no trustless way to connect them.
A trustless P2P swap platform where two users can securely exchange tokens across chains without DEXes or bridges.
Smart Contracts (Solidity)
EscrowFactory - Main factory contract that deploys escrow instancesEscrowSrc - Source chain escrow contract that locks asker's tokensEscrowDst - Destination chain escrow contract that locks fullfiller's tokensBaseEscrow - Abstract base contract with common escrow functionalityBackend Services (Node.js/TypeScript)
Frontend Application (Next.js/React)
graph TD
A[User A Creates Swap] --> B[Secret Generated]
B --> C[Source Escrow Deployed]
C --> D[Tokens Locked with Hashlock]
D --> E[User B Fulfills Swap]
E --> F[Destination Escrow Deployed]
F --> G[Relayer Sets Fulfiller]
G --> H[User A Claims with Secret]
H --> I[Secret Revealed]
I --> J[Both Escrows Withdrawn]
J --> K[Swap Completed]
SrcWithdrawal: Only asker can withdraw with secret (0-24h)SrcPublicWithdrawal: Anyone with access token can withdraw (24-48h)SrcCancellation: Only asker can cancel (24-48h)SrcPublicCancellation: Anyone with access token can cancel (48-72h)DstWithdrawal: Only asker can withdraw with secret (0-24h)DstPublicWithdrawal: Anyone with access token can withdraw (24-48h)DstCancellation: Only fullfiller can cancel (24-48h)Available on:
Live now: peerswap.vercel.app
git clone <repository-url>
cd peerswap
# Backend
cd backend
npm install
# Frontend
cd ../miniapp/peerswap
npm install
# Smart contracts
cd ../../peerswap-contracts
forge install
# Backend
cp backend/.env.example backend/.env
# Configure your environment variables
# Frontend
cp miniapp/peerswap/.env.example miniapp/peerswap/.env.local
# Configure your environment variables
cd backend
npm run dev
cd miniapp/peerswap
npm run dev
cd peerswap-contracts
forge script script/Deploy.s.sol --rpc-url <RPC_URL> --private-key <PRIVATE_KEY> --broadcast
# Smart contracts
cd peerswap-contracts
forge test
# Backend
cd backend
npm test
# Frontend
cd miniapp/peerswap
npm test
POST /swaps - Create a new swapGET /swaps - List all swapsGET /swap-status/:hashlock - Check swap statusPOST /claim - Submit secret for claimingGET /health - Health checkPOST /check-deployments - Check all swap deploymentsGET /check-relayer - Check relayer addressesRELAYER_PRIVATE_KEY - Private key for relayer operationsPORT - Server port (default: 8787)RPC_URL_SEPOLIA - Sepolia RPC endpointRPC_URL_BASE_SEPOLIA - Base Sepolia RPC endpointNEXT_PUBLIC_BACKEND_URL - Backend API URLNEXT_PUBLIC_FACTORY_ADDRESS_SEPOLIA - Sepolia factory addressNEXT_PUBLIC_FACTORY_ADDRESS_BASE_SEPOLIA - Base Sepolia factory addressBuilt with ❤️ for the decentralized future
So I was thinking about this problem where people have tokens on different chains but can't easily trade them. Like, you have USDC on Base but want some random token that only exists on Tempo chain. There's no bridge, no DEX has the pair, and centralized exchanges are a pain.
I wanted to build something where two people could trade directly - no middleman, no bridges, just pure P2P. The key insight was using hashlocked escrows with timelocks. It's like a cryptographic handshake where both parties have to commit before either can back out.
Smart Contracts (Solidity) I went with a factory pattern using OpenZeppelin's clone system. This was crucial because deploying new escrows for each swap would be expensive. The clone pattern lets me deploy cheaply while keeping each escrow as a separate contract. I used CREATE2 for deterministic addresses - this was important for the relayer to know where escrows would be deployed.
The contracts are pretty complex with multiple timelock stages. I spent a lot of time getting the security right - there are different permissions at different time periods, and I had to handle edge cases like stuck funds.
Backend (Node.js/TypeScript) I built an Express API that acts as a relayer. The key thing here is that the relayer coordinates but never holds funds - it's just facilitating the cross-chain communication. I used in-memory storage for speed, and built an event-driven system that listens to blockchain events in real-time.
Frontend (Next.js/React) I integrated with Farcaster as a mini app because I wanted social discovery. People can find trading partners through their social network, which builds trust. I used Wagmi for wallet integration and built a smooth UX for cross-chain transactions.
Multi-Stage Timelock System This was probably the most complex part. I created different permission levels at different time periods:
The access token system was my solution to the "what if someone disappears" problem. It lets the community help complete stuck swaps.
Cross-Chain Secret Revelation Getting the secret to work across chains while maintaining atomicity was tricky. I had to make sure that revealing the secret on one chain would unlock funds on both chains, but only if both escrows were properly set up.
Emergency Recovery I built a 72-hour rescue mechanism. If someone disappears or something goes wrong, the community can rescue funds after a long enough period. This was important for user confidence.
Farcaster Integration This was huge for user experience. Instead of just posting "I want to trade X for Y" on random forums, people can do it through their social network. It builds trust because you're trading with people you know or have mutual connections with.
Worldcoin Integration I added Worldcoin for identity verification. This prevents spam and multiple accounts from the same person. It also helps with compliance - regulators like knowing who's doing what.
Self SDK Integration I integrated Self SDK for enhanced user experience and identity management. This provides additional layers of user verification and helps create a more trusted environment for P2P trading. The SDK's identity features complement the Worldcoin verification, creating a robust user authentication system.
Fluence Virtual Server I used Fluence's virtual server infrastructure for decentralized backend services. This was crucial for maintaining the decentralized nature of the platform - instead of relying on centralized servers, the relayer services run on Fluence's decentralized network. This ensures that even the coordination layer remains decentralized and resilient.
Gas Fee Protection I made sure that whoever calls the withdrawal function gets their gas fees back. This prevents users from being penalized for completing swaps.
Event-Driven Architecture Instead of polling the blockchain constantly, I built an event-driven system that responds immediately when things happen. This makes the UX much smoother.
Clone Pattern for Gas Efficiency Using OpenZeppelin's clone pattern was crucial for keeping costs down. Each swap needs its own escrow, but deploying full contracts would be expensive.
Decentralized Infrastructure The combination of Fluence's virtual servers and Self SDK creates a truly decentralized experience. Users don't have to trust any centralized entity - not even for the coordination services.
The combination of social integration (Farcaster), identity verification (Worldcoin + Self SDK), decentralized infrastructure (Fluence), and trustless P2P mechanics creates something that's both secure and user-friendly. The timelock system handles edge cases while maintaining the trustless nature.
The relayer coordination without custody was key - it enables cross-chain functionality while keeping the system decentralized. The relayer just facilitates communication, it never touches the funds.
I ended up with a system where two people can trade tokens across chains without trusting each other or any centralized entity. The social integration makes it easy to find trading partners, and the security mechanisms handle all the edge cases.
It's live at peerswap.vercel.app and works on Ethereum Sepolia and Base Sepolia. The whole thing took about 48 hours of intense coding, but the result is something that actually solves a real problem in a trustless way.
Source Chain Stages:
SrcWithdrawal (0-24h): Only asker with secretSrcPublicWithdrawal (24-48h): Anyone with access tokenSrcCancellation (24-48h): Only asker can cancelSrcPublicCancellation (48-72h): Public cancellationDestination Chain Stages:
DstWithdrawal (0-24h): Only asker with secretDstPublicWithdrawal (24-48h): Public withdrawalDstCancellation (24-48h): Only fulfiller can cancelThe relayer coordinates cross-chain operations but never controls funds - this is particularly clever because it maintains decentralization while enabling cross-chain functionality.
The complex timelock system with different permissions at different stages is quite sophisticated - it handles edge cases like stuck funds while maintaining security.
Using OpenZeppelin's clone pattern for escrow deployment is gas-efficient and allows for predictable addresses.
Real-time blockchain event processing without polling - this is efficient and responsive.

