Integrations
World ID, 1inch, Privy, ENS
Four partner integrations, each doing one job: World ID gates the operator, 1inch quotes swaps for the operator's EVM wallet, Privy signs clients in with a passkey, and ENS names addresses. For each one, here is what it does, the exact env vars, where the code is, and the limit we state rather than hide.
World ID
What it does. Proves the operator is one human before margin can leave the treasury. The browser runs IDKit v4 (IDKitRequestWidget with the ProofOfHuman preset, allow_legacy_proofs=false) against a server-signed request context; the raw result is verified server-side at POST https://developer.worldcoin.org/api/v4/verify/{rp_id}; then verifyOperator is relayed to the agency with the deployer key so the RP-scoped nullifier is burned on-chain. A second proof from the same human returns 409 NULLIFIER_ALREADY_USED. The full sequence is on The operator.
NEXT_PUBLIC_WORLD_ID_APP_ID | The app_... id from the Developer Portal. Public; shipped to the browser for IDKit. Without it /api/operator/verify answers 503 and the gate falls back to a labelled simulation. |
|---|---|
NEXT_PUBLIC_WORLD_ID_ACTION | Action identifier created under the app's Actions tab. aetheris-operator; case-sensitive. |
WORLD_ID_RP_ID | Relying-party id (rp_...). Used to sign the request context and as the path of the v4 verify endpoint. |
WORLD_ID_RP_SIGNING_KEY | Relying-party signing key, hex. Server-only; app/api/worldid/rp-context/route.ts signs a nonce with it before the widget opens. |
WORLD_ID_API_BASE | Verifier origin; defaults to https://developer.worldcoin.org in lib/worldid.ts. |
WORLD_ID_ROUTER_ADDRESS | Constructor argument for the agency. Left unset on Hedera, which puts the contract in explicit bypass mode. |
WORLD_ID_GROUP_ID | Credential group id passed to the router; 1 is Orb. |
Where in the code
components/worldid-gate.tsx- the widget, the request-context fetch, the relay call and the result card.app/api/worldid/rp-context/route.ts- signs the IDKit v4rp_context(300 s TTL).lib/worldid.ts-verifyWorldIdV4,isIdKitResultV4,extractV4Nullifier; the legacy v3verifyWorldIdProofis kept for older proofs.app/api/operator/verify/route.ts- verify, checknullifierHashUsed, relayverifyOperator, map reverts to 409 / 400 / 502.app/api/verify-worldid/route.ts- verification only, no relay; accepts a v4 result or a legacy{proof, signal}.lib/operator-registry.ts,lib/worldid-status.ts- the on-chain reads and the cached readiness probe behind the dashboard badge.contracts/AetherisAgency.sol-verifyOperator,nullifierHashUsed,isVerifiedOperator,worldIdVerificationBypassed,setWorldId.
1inch
What it does. Gives the operator swap quotes and unsigned swap calldata from the 1inch Swap API v6.0 through two server-side proxy routes, so ONEINCH_API_KEY never reaches the browser. POST /api/swap/quote takes {chainId, src, dst, amount} and returns a normalised quote (dstAmount, estimatedGas, protocols); POST /api/swap/build adds from and optional slippage (0 to 50, default 1) and returns {to, data, value, gas?}. The build route never signs or broadcasts. Both validate addresses and base-unit amounts, reject same-token pairs, and answer 400 for a chain outside the supported list.
Ethereum 1 Arbitrum 42161 Base 8453 Optimism 10 Polygon 137
ONEINCH_API_KEY | Bearer token for api.1inch.dev. Server-only; lib/oneinch.ts calls assertServerOnly before every request. |
|---|---|
NEXT_PUBLIC_ONEINCH_BASE_URL | API origin; defaults to https://api.1inch.dev. |
Where in the code
lib/oneinch.ts-getQuote,buildSwapTx,getTokenBalances; bounded retry with backoff on 429 and 5xx, 1inch's own error text re-thrown on 4xx.app/api/swap/quote/route.ts,app/api/swap/build/route.ts- the proxies.components/treasury-panel.tsx- the "Rebalance via 1inch v6.0" form at/dashboard#swap.contracts/AetherisTreasury.sol-rebalance(...), an owner-only accounting entry for a swap executed off-chain; the app UI does not call it.
Privy
What it does. Signs users in and gives them a wallet that can sign on Hedera. lib/privy.ts configures login methods email, google, passkey and wallet; embedded Ethereum wallets are created on login for users without one (createOnLogin: "users-without-wallets") with Privy's wallet UIs kept on; the default chain is Hedera testnet (296) and the supported chains are Hedera plus the five 1inch venues from lib/chains.ts. The role context reads the connected wallet, switches it to 296 and hands its EIP-1193 provider to lib/write.ts for approve, createJob and refundJob. See The client.
NEXT_PUBLIC_PRIVY_APP_ID | Privy app id from the dashboard. Public by design. components/providers.tsx mounts PrivyProvider only when it looks like a real id (18 or more alphanumeric characters). |
|---|---|
PRIVY_APP_SECRET | Privy server secret, reserved for server-side token verification. lib/privy.ts documents it and never references it; no route in this repository reads it today. |
Where in the code
lib/privy.ts-privyConfig,privyLoginMethods,isPrivyConfigured.lib/chains.ts-hederaTestnet(id 296, HBAR, Hashio relay, HashScan) andaetherisChains.components/providers.tsx- mountsPrivyProviderconditionally; exportsPRIVY_ENABLED.components/connect-button.tsx- "Sign in with passkey", the wallet menu, and the labelled demo session when Privy is absent.components/app/role-context.tsx-usePrivy/useWalletsbridge, chain switch, provider hand-off.
ENS
What it does. Turns addresses into names and back. lib/ens.ts builds one viem public client on Ethereum mainnet with a fallback transport: NEXT_PUBLIC_ENS_RPC_URL first, then publicnode, drpc, ankr and cloudflare, each with an 8 s timeout and one retry. It exposes resolveEnsName, lookupEnsAddress, getEnsAvatar, getEnsTextRecord and getEnsIdentity, every one returning null on failure so a dead RPC can never break a render. GET /api/ens?name=... or ?address=... keeps the client on the server and returns {address, name, avatar, source}, where source is live when anything resolved and unconfigured otherwise, cached for five minutes.
In the UI: the wallet menu reverse-resolves the connected address ("Resolved via ENS" or "No reverse ENS record"); the agency page accepts /agency/<name> as well as an address; the Mission Control header shows the agency's ENS name from the subgraph when it has one; and verifyOperator stores an ensName alongside the verification, defaulting to aetheris.eth in the relay.
NEXT_PUBLIC_ENS_RPC_URL | Ethereum mainnet RPC tried first; defaults to https://ethereum-rpc.publicnode.com. |
|---|---|
AETHERIS_ENS_NAME | The name the agency publishes as its identity at deploy time (aetheris.eth). |
Where in the code
lib/ens.ts- the mainnet client and resolvers.app/api/ens/route.ts- the HTTP route, backed byresolveEnsProfileincomponents/aetheris-server.ts.components/use-ens.ts,components/connect-button.tsx,app/(app)/agency/[id]/page.tsx- the consumers.
