Reference dapp showing how to use @epoch-protocol/epoch-intents-sdk to move value between an EVM chain (Sepolia) and Miden testnet via Epoch intents.
Two flows:
- Cross-chain — EVM → Miden. Pay USDC on Sepolia, receive the target asset (P2IDE note) on Miden.
- Withdraw — Miden → EVM. Burn a Miden note, receive the corresponding asset on Sepolia.
- React 19 + Vite + TypeScript + Tailwind v4
- EVM: wagmi + RainbowKit + viem
- Miden:
@miden-sdk/miden-sdk,@miden-sdk/miden-wallet-adapter-react - Intents:
@epoch-protocol/epoch-intents-sdkagainst the Epoch testnet allocator
- Copy env file:
cp .env.example .env
.env:VITE_ALLOCATOR_URL=https://testnet-dev.epochprotocol.xyz - Install + start:
pnpm i pnpm run dev
- Open
http://localhost:5173.
- EVM: any RainbowKit-supported wallet (MetaMask etc.) on Sepolia. Pays gas + provides USDC for cross-chain deposits.
- Miden: Miden wallet adapter. Required for Withdraw and for creating P2IDE notes in Cross-chain.
- Miden testnet tokens: claim from official Miden faucet in Miden Wallet.
- Sepolia USDC: ping Epoch team with your Ethereum address; team will send Sepolia USDC.
- Sepolia ETH: any public Sepolia faucet for gas.
| Path | Purpose |
|---|---|
src/services/epoch-bridge.ts |
Epoch SDK wrapper (intent build / submit / poll) |
src/hooks/useEpochIntent.ts |
EVM→Miden intent submission flow |
src/hooks/useWithdrawIntent.ts |
Miden→EVM withdraw flow |
src/hooks/useMidenWalletAdapter.ts |
Miden wallet connect/state |
src/hooks/useMidenTransfer.ts |
P2IDE note creation on Miden |
src/hooks/useIntentFlowStatus.ts |
Intent lifecycle polling |
src/constants/chains.ts |
Sepolia + Miden virtual chain id (999999999) |
src/config/wagmi.ts |
wagmi/RainbowKit config |
MIDEN_DESTINATION_CHAIN_ID = 999999999is the virtual chain id used astokenOut.chainIdwhen Miden is the intent output. Do not set this to a real EVM chain id.- Allocator URL is configurable via
VITE_ALLOCATOR_URL. Default points at Epoch testnet-dev. - Build:
pnpm build(tsc -b && vite build). Lint:pnpm lint.