Open the app · Website · Demo video · Pitch video · X @weirstudio
Direct debit for digital dollars, live on Monad Mainnet. Built for Monad Metropolis, Track 02: Consumer Products & Payments, by arhamkhan.
Say yes once to a subscription, a meter that bills by the second, a weekly payment to family abroad, or an API your agent pays by the request. Your money stays in your own account, earning, until the moment each charge is due. Either side can stop it in one tap.
Tip
Try it free. Open the app and switch to Testnet in the header: the faucet gives you test dollars, and a passkey is all you need. No wallet, no seed phrase, no gas token.
Weir in 30 seconds
weir-launch-github.mp4
Full quality, to watch or download: weirpay.vercel.app/videos
| Technical demo, live on Monad Mainnet | Pitch |
|---|---|
![]() |
![]() |
| Every flow running for real, with each transaction opened on Monadscan | What Weir is, the problem it solves, who it is for, and who is building it |
Watch it · In 30 seconds · How a payment works · Live on Monad · Proven on Mainnet · Who it is for · The mandate · Pay per request · Architecture · Built on Monad · Safety · Run it locally · Credits
Stablecoin subscriptions today either lock your whole budget in escrow, ask for an unlimited approval, or make you pay by hand every month. Banks solved this long ago with the direct debit mandate: a standing yes, capped and cancellable, while the money stays with its owner. Weir is that mandate, enforced by a contract with no owner, no fee and no upgrade path.
| You get | How |
|---|---|
| A yes with limits written in | Every mandate caps each charge, the lifetime total and the date it ends |
| Money that keeps earning | A mandate can draw from savings in a Morpho vault, so dollars earn until each charge |
| No wallet app, no gas token | A passkey (Face ID or a fingerprint) signs; a relayer pays the gas |
| A stop button that always works | One tap pauses or cancels on chain, with nobody's permission |
| Billing by the second | Monad's sub-second blocks make per-second streams practical |
| Paying APIs by the request | Over x402: approve an API once, then each request is a signature, settled on chain in batches |
Weir runs on Monad Mainnet with real USDC and AUSD, and on Monad Testnet with test dollars for trying it for free. The app and the website switch between the two.
| Service | Where |
|---|---|
| App | app-weirpay.vercel.app |
| Website | weirpay.vercel.app |
| API, Mainnet | api-mainnet-production-fc07.up.railway.app/health |
| API, Testnet | api-testnet-production-9789.up.railway.app/health |
| Live stats (Envio HyperIndex) | api-mainnet-production-fc07.up.railway.app/v1/stats |
| Envio HyperIndex GraphQL (both networks) | https://indexer.dev.hyperindex.xyz/896b0e4/v1/graphql, the current hosted deployment (example queries) |
| X | @weirstudio |
A keeper charges what is due on each network every few seconds, and the Envio HyperIndex project indexes both, all hosted on Railway.
| Mainnet (143) | Testnet (10143) | |
|---|---|---|
| MandateHub | 0x184c…EcA0 |
0x08ca…0Bc1 |
| MandateCharger | 0xC555…CFf03 |
0xB433…9E03 |
| SavingsRouter | 0x9eE6…0295 |
0x41dC…A46E |
| MandateMeter | 0x4674…8862 |
0x75a6…7a36 |
| Dollars | USDC, AUSD | tAUSD (open faucet), USDC |
| Savings | Morpho USDC and AUSD vaults | a test vault paying a simulated 5% |
Every contract is source-verified, an exact match on both of Monad's explorers, MonadVision and Monadscan, and on Sourcify: see the verification report.
Full addresses, blocks and transactions are in deployments.json, checked against the chain by script/VerifyDeployment.s.sol.
On 3 October 2026, pnpm live:mainnet ran the whole product on Monad Mainnet with one real dollar of USDC, through the real API and keeper.
The payer never held MON, and every check passed on chain.
| Step | Transaction |
|---|---|
| Save $0.50 into the Morpho USDC vault, relayed on a permit | 0x7e95902e… |
| Set up a mandate from savings, with its backup, in one transaction | 0xdaeada33… |
| The keeper charges two mandates in one batch, one paid by the Morpho vault straight to the merchant | 0x1b6eb28c… |
Savings emptied, so the next charge falls back to the balance (ChargedFromBalance) |
0xd59cf14f… |
| A stream paused by the session key alone, settling the seconds used | 0xf708907b… |
| Cancelled by the payer's signature | 0xc6e05aa7… |
People who pay every month and do not think of themselves as crypto users. None of them sees a seed phrase, a gas token or a wallet extension; they see a checkout, a passkey prompt, and a list of payments they can stop.
- Families supporting someone abroad. Each relative sets up what they can give, monthly or just once, in Agora's dollar; it arrives in seconds, shown in the recipient's own currency.
- People in high-inflation countries who keep their money in dollars. School fees, rent and phone bills come out on schedule, while the dollars sit earning in savings until each one is due, and no bill can ever take more than its limit.
- Heavy AI-tool users and their agents. Pay by the second, only while a tool is in use, instead of a stack of monthly plans; an agent can subscribe and stop on its own with
mm weir.
- Subscribe at a checkout. A business shares a link; you approve with your passkey in two signatures and no transaction.
- Manage your payments. See everything running, pause or stop any of it, move money into savings, add money from other chains, get a reminder the day before a charge, and keep a private note on each payment that only your passkey can read.
- Support family across borders. One person shares a link with their country on it; each relative gives every month or sends once, in seconds, and sees what it is worth there ("$50 ≈ Rs 13,875").
- Run a business. Create plans, prove the wallet you get paid to, watch revenue arrive, and send your earnings on from your Privy wallet with no gas.
- Install it. Weir adds to a phone's home screen and opens like an app.
- Pay for an API by the request. Approve it once with a passkey and limits you choose; each request after that is paid with no prompt and no gas.
- Let an agent pay.
mm weirlets a MetaMask Agent Wallet subscribe, pay APIs per request over x402, and manage its payments by signing alone.
A mandate is a standing authorization from one payer to one merchant with three limits: per charge, lifetime total, and an expiry. No code path can raise a limit, change who gets paid, or freeze the money, and the contract never holds a cent.
Two kinds of charge. A periodic mandate takes a fixed amount once per period; a charge that lands late skips missed periods rather than billing them. A stream charges a rate per second for exactly the time elapsed, and paused time is never billed.
Earn until charged. A mandate can draw from the payer's shares in an ERC-4626 vault. Each charge withdraws exactly what is due, straight to the merchant, and checks the merchant received exactly that. If the vault cannot pay (short of liquidity, say), the charge comes from the payer's balance instead, under the same limits.
One passkey, many keys. Through Mera, one passkey derives an owner key that signs a mandate's terms, and a session key kept on the device that can only pause, resume and cancel. Neither ever sends a transaction; the relayer does. The same passkey, asked at a second PRF salt of Weir's own, gives a key that does no account work at all: it seals the payer's private notes, which Weir's API stores as ciphertext it cannot read or tie to anyone.
Anyone can charge.
charge(id) is permissionless: Weir's keeper, a Chainlink CRE workflow, the merchant or the payer.
A charge the payer cannot fund moves nothing; the mandate is marked past due and retried.
An API can charge per request with Weir, over x402 V2, the HTTP 402 payment standard.
An unpaid request gets a 402 Payment Required offering the weir-meter scheme: who is paid, in what, and one request's price.
- Approve once. The payer signs a permit and the meter's terms: at most so much a day and so much in all, until a date, paying this API only.
Weir's relayer opens it on
MandateMeterin one transaction. - Pay each request with a signature. The client signs a usage receipt for the new running total,
previous + price, with its session key: no prompt, no transaction, no gas. Weir's API, the facilitator, checks the signature, the exact total, both caps and the payer's funds before the API does any work, and records it. - Settle in batches. Anyone may call
settlewith the latest receipt; Weir's settler does once the total is worth a transaction. The meter pays the merchant what the receipt adds, never past a cap, straight from the payer's balance. - Stop any time. The session key cancels in one signature; receipts signed before the stop are still honoured, and nothing after it.
import { createMeterFetch, createPaywall, weirMeter } from "@weir/x402";
// An API: charge a tenth of a cent a request, paid to your wallet in USDC on Monad Mainnet.
const paywall = createPaywall({ ...weirMeter(143), payTo, asset: USDC, price: 1_000n });
export default { fetch: (request: Request) => paywall(request, handler) };
// A client: pay any weir-meter API it has a meter with, up to a cent a request.
const pay = createMeterFetch({ signer: sessionKey, maxPrice: 10_000n });
const answer = await pay("https://api.example/quote");Each API has a demo: GET /demo/fx?to=PKR on either network's API answers today's dollar rate for $0.001.
On Testnet it is free to try; on Mainnet it is open to the first 100 people, and pauses itself before the relayer's gas runs low.
In the app, Pay per request approves it and calls it; an agent does the same with mm weir approve and mm weir fetch.
After the first request a client pays up front, so a paid request is one round trip, and the facilitator answers it in about 25 ms.
Proven on Mainnet.
On 18 October 2026, pnpm live:x402 --network mainnet --calls 20 paid the demo with real USDC.
| Step | Transaction |
|---|---|
| Approve: permit and meter terms, one relayed transaction | 0x5cba66dd… |
| 20 paid requests, signed by the session key | none: no transaction per request |
| The 21st refused at the daily cap | none: refused before the API ran |
| Settle the $0.02 running total | 0x13f75883… |
| Stop, signed by the session key | 0x120028d9… |
- Contracts (
src/):MandateHubholds every mandate and moves money only from payer to merchant;MandateChargercharges many at once and takes Chainlink CRE reports;SavingsRoutermoves a payer's dollars in and out of savings on a permit;MandateMeterholds pay-per-request approvals and settles their signed running totals. No owner, no fee, no upgrade. - API (
apps/api): relays signed installs and actions so the payer never pays gas, serves plans, merchants and family support, keeps an index of every mandate, meter and charge, caught up with HyperSync, and is the x402 facilitator that verifies each paid request and settles them in batches. - Keeper (
apps/keeper) and CRE workflow (apps/cre-keeper): two independent ways to charge what is due; anyone else may charge too. - Indexer (
apps/envio-indexer): Envio HyperIndex aggregates both networks into revenue, MRR, daily volume and metered usage for the dashboard and the website. - App (
apps/web) and website (apps/landing): the product, on Mainnet or Testnet, and the site that explains it.
Solidity 0.8.25 with Foundry; TypeScript throughout; viem; React 19 with Vite and React Router; Next.js for the website; Hono and Postgres for the API; x402 V2 (@x402/core); Mera passkeys; Privy; Aurora Intents; Chainlink CRE; Envio HyperIndex and HyperSync; web-push.
| Monad capability | What Weir does with it |
|---|---|
| Sub-second finality | Checkout confirms before a person looks away; billing by the second is economic |
eth_sendRawTransactionSync |
An install is one round trip, under a second end to end |
| Cheap, parallel execution | One transaction charges a batch of mandates |
| USDC and AUSD with EIP-2612 permits | Installs are signatures, never a transaction from the payer |
| Morpho vaults on Monad | Savings earn until each charge |
| Mera passkeys | One passkey: an owner key and a session key, and a second PRF namespace that encrypts private notes |
| Chainlink CRE | A workflow charges due mandates by signed report through MandateCharger |
| Chainlink Data Feeds | Fiat rates on Monad (EUR, GBP, CAD, CHF, JPY) for showing what a payment is worth where it lands |
| Agora's AUSD | Family support pays in AUSD by default, and a one-off "send now" settles in the same transaction |
| Envio HyperIndex and HyperSync | HyperIndex aggregates every network's mandates, charges, MRR and daily revenue, and serves the business dashboard's Revenue section and the home page's live figures; HyperSync catches the API's own index up |
| Privy | Business sign-in, an embedded wallet as the payout address, payout wallets the business has proven it holds, and gas-free payouts the Privy wallet signs |
| Aurora Intents | Dollars from any chain straight into a payer's account as USDC on Monad |
| MetaMask Agent Wallet | mm weir for agents: subscribe, and pay APIs per request |
| x402 | APIs charge per request in Weir's weir-meter scheme; a request costs one signature and no transaction, and the totals settle on Monad in batches |
Every property below is asserted by unit tests, fuzz tests and stateful invariants over 16,384 generated calls each, and the suites were checked by planting bugs and confirming each is caught.
- Money only moves from a mandate's payer to its recorded merchant, and the contract never holds any.
- No charge exceeds the per-charge cap, and the total never exceeds the lifetime cap.
- Nothing is collected after expiry, while a stream is paused, or after cancellation.
- A stream never collects more than its rate times the time it actually ran.
- A charge the payer cannot fund moves nothing.
- A meter never pays more than the running total its payer or manager signed, nor past its daily or lifetime cap, and a receipt signed after a stop or after expiry pays nothing.
- A call that runs out of gas reverts whole; it is never mistaken for a refusal, so it can never trigger a fallback or skip a settlement.
- Terms never change after creation, and a signature works once, before its deadline, for exactly what it signed.
You need Foundry, Node 20.19 or newer (22 for the indexer and mm), pnpm 10, and Postgres 14.
git submodule update --init --recursive
pnpm install --frozen-lockfile
pnpm --filter @weir/shared build # the app and the website read it built
forge test && pnpm testCopy .env.example to .env (Testnet) and, for Mainnet, to .env.mainnet.
Then run each network's API and keeper, and the app:
pnpm api # Testnet API on :8790
pnpm keeper # Testnet keeper
pnpm api:mainnet # Mainnet API on :8792
pnpm keeper:mainnet # Mainnet keeper
pnpm --filter @weir/web dev # the app on :5173, with the network switch
pnpm landing # the website on :3000Add ?devkey=1 to the app's address in development to use a local stand-in for the passkey.
| Command | What it proves |
|---|---|
pnpm smoke |
The whole flow on Testnet with a fresh payer that never holds gas |
WEIR_FORK_E2E=1 pnpm exec vitest run apps/api/src/mainnet.fork.test.ts |
The whole flow on a local fork of Mainnet against real USDC and the real Morpho vault; add WEIR_FORK_RECORDED=1 to test the deployed contracts |
pnpm live:mainnet |
The whole flow on Mainnet with about a dollar of real USDC, through the real API and keeper, every step checked on chain into .state/mainnet-live/report.json |
pnpm live:x402 --network testnet --calls 100 |
Pay per request against the deployed API, as an agent: approve, paid requests with a session key, refusal at the cap, settlement on chain, stop; --network mainnet with LIVE_PAYER_KEY_FILE spends real USDC |
| Path | What it is |
|---|---|
src/ |
MandateHub, MandateCharger, SavingsRouter, MandateMeter, and the Testnet stand-ins |
test/ |
Unit, fuzz and invariant suites |
packages/shared |
Networks, assets, typed data, dollar arithmetic, ABIs, the deployment record |
apps/api |
Relayer, plans and merchants, family support, reminders, private notes, webhooks, the index |
apps/keeper |
Finds due mandates and charges them in batches with tight gas |
apps/cre-keeper |
The Chainlink CRE workflow (README) |
apps/envio-indexer |
The Envio HyperIndex project (README) |
apps/web |
The app: checkout, payments, family support, the business dashboard |
apps/landing |
The website, with a live mandate count read from the chain |
packages/x402 |
@weir/x402: the weir-meter scheme, a paywall for any Fetch-API server, and a paying fetch (README) |
packages/agent-wallet-plugin |
mm weir (README) |
tools/readme-art |
Draws this README's banner and diagrams from the app's own design tokens and typeface (assets/readme) |
Deploying
MONAD_CHAIN_ID in the env file selects the network, and the deploy script refuses any other chain.
forge clean
set -a && source .env && set +a # or .env.mainnet
forge script script/Deploy.s.sol:Deploy --rpc-url "$MONAD_RPC_URL" --private-key "$DEPLOYER_PRIVATE_KEY" --broadcast
node --env-file=.env scripts/record-deployment.mjs
forge script script/VerifyDeployment.s.sol:VerifyDeployment --rpc-url "$MONAD_RPC_URL"
pnpm --filter @weir/shared buildThe meter deploys on its own, after the hub, accepting the hub's assets: forge script script/DeployMandateMeter.s.sol:DeployMandateMeter the same way, then node --env-file=.env scripts/record-deployment.mjs DeployMandateMeter.
Then point the CRE configs and the indexer at the new record (pnpm sync in apps/envio-indexer).
Hosting
Railway: the API and the keeper once per network, the indexer, and Postgres.
One image (Dockerfile, railway.json, .railwayignore) runs the API or the keeper; WEIR_SERVICE picks which.
| Service | Image | Settings |
|---|---|---|
| api-mainnet, api-testnet | Dockerfile, WEIR_SERVICE=api |
that network's API values from .env.mainnet or .env, DATABASE_URL (its own database), ENVIO_DATABASE_URL, API_ALLOWED_ORIGINS set to the app and the website, PUBLIC_API_URL (its own public address, which x402 offers name as the facilitator), and for the paid demo DEMO_PAY_TO, DEMO_PRICE, and on Mainnet DEMO_MAX_PAYERS and DEMO_GAS_RESERVE, which cap the people it takes and keep it from spending gas real payments need; METER_SETTLE_MIN and METER_SETTLE_AFTER_SECONDS tune settlement batches |
| keeper-mainnet, keeper-testnet | Dockerfile, WEIR_SERVICE=keeper |
that network's keeper values |
| envio | apps/envio-indexer/Dockerfile (railway up apps/envio-indexer --path-as-root) |
ENVIO_API_TOKEN, ENVIO_PG_* for its own database |
| Postgres | Railway's | one database per API and one for the indexer |
Database credentials are Railway references (${{Postgres.PGPASSWORD}}), never copied. Each API migrates on start; PORT is 8080 and /health is the health check.
Vercel: the app and the website, one project each.
| Project | Root directory | Settings |
|---|---|---|
| app | apps/web |
VITE_API_URL_MAINNET, VITE_API_URL_TESTNET, VITE_PRIVY_APP_ID, VITE_AURORA_API_KEY, VITE_WALLETCONNECT_PROJECT_ID, VITE_DEMO_PLAN_ID, VITE_DEMO_PLAN_ID_MAINNET, VITE_SITE_URL |
| website | apps/landing |
NEXT_PUBLIC_APP_URL |
Then add the app's domain to Privy's allowed domains and to each API's API_ALLOWED_ORIGINS.
Built by arhamkhan for Monad Metropolis. Follow along on X at @weirstudio.
AI tools. Development used AI coding assistants, mainly Claude Code, for writing and reviewing code, tests and documentation, under the author's direction.
External code.
Weir builds on open-source work, each under its own license:
OpenZeppelin Contracts (MIT, a submodule at v5.7.0: SafeERC20, EIP712, ECDSA, SignatureChecker, ReentrancyGuardTransient),
forge-std (MIT/Apache-2.0),
viem (MIT),
Mera passkeys,
@scure/bip32 and bip39 (MIT),
Privy React and server SDKs,
Aurora Intents swap widget,
Chainlink CRE SDK,
Envio HyperIndex and the HyperSync client,
React, React Router, Vite, Next.js, Hono, postgres, web-push, GSAP, Framer Motion, Lucide and the Geist typeface (OFL).
Savings are held in Morpho Vault V2 vaults on Monad, which Weir calls but does not include.
MIT.






