A drop-in token swap for World App mini apps —
swap card + quote API, routed through Uniswap V2/V3 on World Chain.
The same swap that powers the nonnux mini apps (UFO PIZZA SLICE, PAU$, REI$ Slots, …), packaged so you can add it to your own World App mini app in a couple of lines. Built for Next.js (App Router) + Tailwind CSS.
npm install @nonnux/world-swap
Peers you almost certainly already have: react, react-dom, ethers@^6, @worldcoin/minikit-js. The package ships pre-bundled (minified ESM), so no extra bundler config is needed.
Create app/api/swap/quote/route.js:
// Batteries-included: nonnux token list + World Chain contracts
export { POST, GET } from '@nonnux/world-swap/server';
'use client';
import { SwapCard } from '@nonnux/world-swap';
import { Button } from '@/components/ui/Button'; // your own button
export default function SwapTab({ user }) {
return <SwapCard walletUser={user} Button={Button} />;
}
walletUser is your connected user ({ address }); pass null for the “connect wallet” state. Token icons load from /tokens/*.gif in your public/ folder (or point tokens[].icon at a URL).
World App rejects any contract/token your mini app hasn't whitelisted — skip this and swaps fail with invalid_contract. In the Developer Portal → your app → Configuration → Advanced, paste these.
Contract Entrypoints — 3 swap contracts + every tradeable token:
0x4479A14811274D0eEB8Eb8932fA5A49b51F37852,0x4Cf23b3C9BeB48b85bc8F01E3dAB674Ce94E180a,0x380a940524C4cC1829f654B7790B338f676C31b8,0x513530649BAC862c38b65e957E6EA38d3f86F3dc,0x10377A2e9CC81A8822885cd847e577F7F39B5574,0x2e5f6BB8C993e64B3bC1fC9473C8B2CDEd772D06,0xE67Fb81ca7d20eB90bA3a53220018a9A7f870de8,0x9d59Bb9d85Ae4622116Ad11055B5be4349b67dc2,0x3Cb880f7ac84950c369e700deE2778d023b0C52d,0xE977de70dd1F571Aa563E41525C28b4F1eDB69ba,0x03995cE5Ad612a2cC3E4DFBEEb0EeD7BC165749b,0x06B4C6830bb19BF07A88ff96758003074EaE9c52,0x2cFc85d8E48F8EAB294be644d9E25C3030863003,0x4200000000000000000000000000000000000006,0xab09A728E53d3d6BC438BE95eeD46Da0Bbe7FB38
Permit2 Tokens — every tradeable token (same list, minus the 3 contracts):
0x513530649BAC862c38b65e957E6EA38d3f86F3dc,0x10377A2e9CC81A8822885cd847e577F7F39B5574,0x2e5f6BB8C993e64B3bC1fC9473C8B2CDEd772D06,0xE67Fb81ca7d20eB90bA3a53220018a9A7f870de8,0x9d59Bb9d85Ae4622116Ad11055B5be4349b67dc2,0x3Cb880f7ac84950c369e700deE2778d023b0C52d,0xE977de70dd1F571Aa563E41525C28b4F1eDB69ba,0x03995cE5Ad612a2cC3E4DFBEEb0EeD7BC165749b,0x06B4C6830bb19BF07A88ff96758003074EaE9c52,0x2cFc85d8E48F8EAB294be644d9E25C3030863003,0x4200000000000000000000000000000000000006,0xab09A728E53d3d6BC438BE95eeD46Da0Bbe7FB38
First three entrypoints are the swap contracts (V2, V3, cross-version router); the rest are token contracts. Using a custom tokens list? Whitelist your own token addresses instead (the 3 contracts stay the same).
All optional, via props on <SwapCard> (or config on createSwapQuoteHandler()): tokens, contracts, rpcUrl, apiBasePath, explorerUrl, ImageComponent, storagePrefix, title, helpUrl, attribution.