Onchain Refund Infrastructure for online & in-store crypto payments

Unwind is an onchain refund and escrow infrastructure for stablecoin commerce which fits into merchants’ POS without breaking their payment workflows. Unwind focuses on adding a reversible flow to crypto payments which are ‘immutable’ & solving capital efficiency problems for merchants as they want to get early access to money with crypto which they otherwise can’t due to the T+2 settlement period with banks.
We have integrated unwind for merchants that use WPay, a point of sale integrated with WalletConnect Pay where merchants create a payment with the QR code, the customer pays USDC by scanning it, and settlement is tied to escrow on-chain. Funds are routed through a MerchantVault into RefundProtocol (Solidity escrow contract) that tracks each payment’s recipient, payer, refund destination, amounts, and optional WalletConnect Pay id hashes for deduplication and off-chain correlation to avoid cases like double spending and generation of refunds properly.
The contracts are live on Base mainnet and Arc testnet, and the protocol holds USDC under rules instead of a single custodian narrative where an arbiter configures per-recipient lockup rules according to Circle’s Refund Protocol logic. During the refund window, refundByRecipient (callable by the protocol owner, e.g. POS admin) or refundByArbiter can return funds to the customer’s refund address. Our frontend uses the flow of generating refunds by merchants since in traditional flows these refunds are generated by the businesses/merchants themselves. earlyWithdrawByArbiter lets the arbiter release liquidity early with an EIP-712 signature from the merchant and optional fees after lockup the merchant withdraw(). If funds are still reclaimable and the payment was not refunded, the payer can reclaim() after lockup plus a grace period.
Another feature which is interesting in our smart contract is the Arbiter-covered refunds can create merchant debt settled via settleDebt which works in a similar way where we do debt collateralized loan in future when we onboard smaller scale hotels & restaurants to allow for better capital efficiency.
When we started building Unwind, there were two main parts to build out. One was the merchant traditional POS blow, so not just any custom POS flow and second user flow which fits directly into the POS. After hours of battling with open-source PSP/POS systems, Square documentations, we finally landed onto WalletConnect’s POS app (WPay) in walletconnect-pay/pos-app. We integrated a server layer for chain actions and for merchant’s offchain data like paymentId to be brought at one place for a refund mechanism.
Our smart contracts are written in Foundry, Solidity ^0.8.24, and OpenZeppelin (specific contracts are Ownable, ReentrancyGuard, EIP-712). The funds from the user’s wallet are first received by MerchantVault, which then credits RefundProtocol escrow, where lockup and the refund window control refunds, merchant withdrawal, and payer reclaim. The motivation for using a vault instead of just routing the money directly to the smart contract is for the initiation of the escrow contract state. We started the project looking at integration with crypto debit/credit cards where we could add a virtual card in between to convert crypto to fiat and pay with. Alongside, refunds that could be routed back to user’s crypto cards when merchants initiate a refund through their POS. So, our initial scrapping of the idea, helped us find similarities here to create Just-in-time funding and follow the rules of Circle’s refund protocol between payer, recipient, and arbiter. Finally, we used a forge test for regression coverage and deployed with Forge scripts to Base mainnet and Arc testnet.
The POS we are using for the flow is an Expo / React Native with Expo Router and TypeScript. We designed the flow to feel like retail POS software on top of the merchant dashboard provided by Wallet Connect. For instance, entering amount entry to QR to polling until paid with clear success or failure receipt over Bluetooth/USB. We index the on-chain state server side and serve fresh blockchain data on component load.
The Integration has a few deliberate splits. The react native for all client side facing UI and a express server relaying the payments between the Vault and the Escrow contract, which then handles the refund process. React native talks to the WalletConnect Pay API directly to serve the payments information. Web can’t do that cleanly under browser CORS, so we added Vercel serverless proxies and parallel modules (payment.ts vs payment.web.ts, same for transactions). Shared HTTP logic lives in payment-core.ts so Metro doesn’t circle through .web re-exports. Escrow and refund calls go through EXPO_PUBLIC_SERVER_URL so signing and orchestration aren’t entirely on the device. On desktop web, a device frame and modal portal keep previews feeling like a handheld terminal instead of a full-page site. Together, that’s how we pieced Pay, Unwind, and merchant UX into one story: familiar checkout, enforceable refund rules on-chain, and practical deployment on Base and Arc.

