EntryTokenRegistry and DexAdapter
EntryTokenRegistry is the allowlist + deterministic routing table for multi-token entry.
It enables:
- Furnace.enterWithToken(tokenIn, amountIn, …): tokenIn -> CLAIM (direct or via WETH)
- MineCore.takeoverWithToken(tokenIn, amountIn, minEthOut): tokenIn -> WETH -> unwrap -> ETH
Key constraints (v1.0.0):
- no user-supplied routes
- allowlist only
- every hop is validated against allowlisted pools via router.poolFor(…)
Policy split: two registries
v1.0.0 expects two registry instances:
- FurnaceEntryTokenRegistry
- tokens allowed for onboarding into the Furnace
- MineCoreEntryTokenRegistry
- tokens allowed for takeovers (recommended to start empty or extremely conservative)
Do not wire the same registry into both surfaces.
WETH special-case (required)
WETH is always supported without allowlisting:
- token configs forbid tokenIn == wrappedNative
- core entrypoints special-case tokenIn == WETH:
- MineCore.takeoverWithToken(WETH, amountIn, minEthOut): unwrap 1:1, enforce ethOut >= minEthOut
- Furnace.enterWithToken(WETH, amountIn,…): unwrap 1:1, then treat as ETH input
RouterConfig
Registry stores global router config:
- router (v1.0.0 expects DexAdapter)
- factory (must equal router.defaultFactory())
- wrappedNative (must equal router.weth())
- claimToken (must match the immutable ClaimToken)
Important invariant:
- wrappedNative and claimToken are immutable after first set.
Canonical WETH/CLAIM hop
The registry stores the pinned WETH/CLAIM pool:
- used for Furnace ETH entry (ETH -> CLAIM)
- used for token routes that go tokenIn -> WETH -> CLAIM
Per-token TokenConfig
Each allowlisted token has:
- enabled (gate inside this registry instance)
- tokenIn -> WETH hop (always required)
- optional tokenIn -> CLAIM direct hop (Furnace-only)
Route resolution:
- resolveTakeoverRoute(tokenIn) -> [tokenIn -> WETH]
- resolveFurnaceRoute(tokenIn) ->
- [tokenIn -> CLAIM] if directToClaimEnabled
- else [tokenIn -> WETH, WETH -> CLAIM]
Guardian: disable-only
EntryTokenRegistry has a guardian role for incident response:
- owner can enable and disable
- guardian can disable only
This is how the protocol can rapidly remove a problematic token or pool route.
DexAdapter
DexAdapter is the Aerodrome v2 router wrapper.
Why it exists:
- keeps the immutable core from hard-binding to a specific DEX router forever
- pins the minimal swap ABI surface used by MineCore and Furnace
Operational model:
- routing changes ship by redeploying DexAdapter and timelock-updating EntryTokenRegistry.router
- core contracts freeze their registry address pointers, not the registry’s internal routing table
Quoters (recommended)
Token-entry calls require user slippage guards:
- Furnace:
minVeOut - MineCore takeoverWithToken:
minEthOut
Do not attempt to recreate routing offchain by hand.
Use canonical quote surfaces:
- Furnace provides built-in view quotes:
quoteEnterWithEthquoteEnterWithClaimquoteEnterWithToken
- MineCore token takeovers use a separate view contract:
MineCoreQuoter.quoteTakeoverWithToken(tokenIn, amountIn) -> (ethOut, takeoverPrice)MineCoreQuoter.resolveTakeoverRoute(tokenIn) -> RegistryRoute[]
Why MineCoreQuoter exists:
- keeps MineCore bytecode smaller (DEX quote + validation lives here)
- mirrors MineCore’s swap validation:
- routes are registry-resolved (no user-supplied routes)
- allowlisted pool must match
router.poolFor(...) - tokenIn == wrapped native is special-cased (unwrap 1:1)
Agent / UI recipe (token takeovers):
- quote
ethOutfor your chosenamountIn - choose
slippageBps - compute
minEthOut = ethOut * (10_000 - slippageBps) / 10_000 - call
MineCore.takeoverWithToken(tokenIn, amountIn, minEthOut)
Agent SDK helpers
The TypeScript Agent SDK provides a canonical way to consume these routes and quotes:
- Spot swap quoting via the protocol’s DexAdapter:
quoteDexAmountsOut({ amountIn, routes })
- Route resolution (allowlisted):
resolveMineCoreTakeoverRoute({ tokenIn })(token -> WETH)resolveFurnaceEntryRoute({ tokenIn })(token -> CLAIM direct or via WETH)
- Common spot price helpers:
quoteEthToClaim({ ethIn })quoteClaimToEth({ claimIn })quoteEntryTokenToEth({ tokenIn, amountIn })quoteEntryTokenToClaim({ tokenIn, amountIn })
For a “bot-ready” aggregated snapshot (CLAIM spot + all enabled entry tokens), use:
getLivePrices({ subgraphUrl, ... })- Optional caching / throttling for polling loops:
getLivePrices({ subgraphUrl, cache: createLivePricesCache(), ... }) - CLI:
npm -C agents/sdk run example:prices - CLI with caching:
PRICES_CACHE=1 ... npm -C agents/sdk run example:prices