ReferenceCurveFactory_v1 creates a market’s contracts and initializes them in one transaction (createReferenceCurveWithRecovery).
The launch route (LaunchMarket.s.sol and LaunchMarketProduction.s.sol) takes one market configuration file to a sealed market. It creates the market, grants its roles, hands the admin role to the market’s admin execution core and seals it. A check runs before each broadcast and after each mined step. An off-chain readback (bin/lib/handoff-assert.ts) checks the final state.
Before any market
The protocol contracts exist before the first market. The deployment script creates them throughDeterministicFactory_v1, a CREATE2 factory that only its allowedDeployer can use.
ReferenceCurveFactory_v1 creates a market only for an allowed deployer, or for any caller while open deployment is on. A production plan refuses a factory with open deployment. Authority covers who changes the factory’s deployers and Safe pair.
Configuration inputs
A market configuration file sets these inputs. The launch plan (LaunchMarketPlan_v1) reads and validates them before any broadcast.
The reserve manager accepts two configuration forms. The first holds the unbacked-draw flag and ceiling. The second also turns on the endowed option and names the expected endowment controller and endowment admin. The launch route at this commit encodes the first form.
The plan validation reverts on any of these:
- A bps value above 10,000.
- A segment with a zero price, zero supply per step or zero steps.
- A ceiling above 0 while unbacked draws are not allowed.
- A zero value for rounds per transaction, fee multiplier, decay duration or the early access global cap.
- A zero elevation threshold, an empty, zero or duplicate elevation keeper, or an elevation keeper equal to the deploy signer.
- A rebalance keeper, operator or handoff holder that is unset, equal to another of the three, or equal to the deploy signer.
- On a production plan: a chain ID not in
productionChainIds, a fixture file, an empty metadata URI, no admin execution core, a handoff holder other than the core, or a missing proposer, executor or canceller.
Steps
The route runs in separate invocations. Each later invocation reads the mined state of the earlier ones.- Preflight. Every check in the preflight table below runs before any broadcast. Any failure stops the route with nothing sent.
- Create (
runCreate). The deploy signer callscreateReferenceCurveWithRecovery. Inside that one transaction the factory:- checks each module’s metadata title, and requires the guardian’s recovery Safe to be the factory’s emergency Safe;
- creates the curve proxy and records it under the next market ID;
- deploys the issuance token through
CurveBoundTokenDeployer_v1, bound to the curve, with the approval Safe as owner and as rebind authority; - writes the token address into the curve’s configuration, and reverts if that word was not zero;
- creates the authorizer, fee treasury, reserve manager, staking manager, credit facility and elevation treasury proxies through
ModuleFactory_v1; - deploys the market’s
MarketFreezeGuardian_v1with the factory’s Safe pair, the recovery Safe and the recovery delay; - initializes the curve, then the authorizer, fee treasury, reserve manager and the three optional modules, each with the same curve, authorizer, fee treasury, reserve manager and guardian;
- runs the creation checks in the table below.
- Bind (
runConfigure). The route reads the market ID, curve and block from the minedReferenceCurveCreatedlog. It requires the ID to resolve to that curve on the factory, and the deploy signer to be the onlyDEFAULT_ADMIN_ROLEholder. - Strategy. A production plan has no staking strategy. A testnet plan can create one.
- Early access. The deploy signer calls
attachPresaleWithTreasury. The factory creates a second splitter for early access fees and aPresale_v1that uses it. The caller must holdDEFAULT_ADMIN_ROLEon the market. A second attach for the same market reverts. - Guardian check. The route requires the guardian to serve this curve, hold the governance Safe pair and the reviewed recovery settings, and be the guardian of every module.
- Roles. The route creates
REBALANCER,OPERATORandECONOMIC_ADMINand grants their selectors. It grantsPUBLIC_ROLEthese functions:sell, creditrepay, and stakingstake,harvestYieldandwithdrawFunds. - Module permissions. The route creates
PRESALE_MODULE,CREDIT_FACILITY_MODULEandSTAKING_MODULE, each held by its module contract alone. It grants each module the calls it makes to the curve, the credit facility and the reserve manager. It pairs the presale with the credit facility on the authorizer (setPresaleCreditFacilityPair). - Elevation. The route creates
ELEVATION_MODULE, held by the elevation treasury, andELEVATION_KEEPER, held by the elevation keepers. It points both splitters at the elevation treasury, as a share or as the elevation fee address, by the configured mode. - Module factory allowance. The deploy signer drops any
ModuleFactory_v1allowance it holds. - Spot tolerance. The deploy signer, still
DEFAULT_ADMIN_ROLE, callssetSpotToleranceBpswith the configured value. - Admission (
runAdmission). The core admitsacceptDefaultAdminandsealDefaultAdminon the market’s authorizer, each by a scheduled self-call. - Offer (
runProposal). The deploy signer callsproposeDefaultAdmin(core, expiresAt). - Acceptance (
runAcceptance). The core schedules and then executesacceptDefaultAdmin(nonce). - Retirement (
runBootstrapRetirement). The deploy signer renouncesDEFAULT_ADMIN_ROLE. The handover locks. - Factory allowance (
runFactoryAllowanceRemoval). The deploy signer renounces itsReferenceCurveFactory_v1deployer allowance. - Seal (
runSeal). The core schedules and then executessealDefaultAdmin. - Final readback (
readSeal,runPublish). The route requiresisProductionActiveand reruns the handoff checks. It then writes the market artifact.
_handOverAdmin, which grants the role to the handoff holder and renounces the deploy signer, then by the factory allowance renounce.
Checks
State at the end of the launch route
After the launch route
The launch scripts at this commit end at the seal. Opening the market is a set of later calls. Each call by the core needs an admitted selector and waits the core’s minimum delay.
Curve
buy checks the buy switch for every caller. Early access purchases go through the curve’s buy, so they also need buying open.
Edge cases
- Restarted phases. Each production phase rebuilds the market from mined logs and reruns the complete configuration check. A phase that finds its operation waiting or done sends nothing.
- Expired offer. If the offer cannot cover the core’s delay and window, the deploy signer cancels it and proposes a new one.
- Interleaved creation. The creation phase checks that the latest market ID resolves to its curve in simulation only. The configuration phase binds to the mined log, and the on-chain readbacks detect another creation between the two.
- Seal order.
sealDefaultAdminreverts unless the core is the only holder, the handover is locked and the core’s code hash is unchanged. - Funding before the seal.
enableBuy,buy,buyForandsetPresaleStateare refused for every caller until the seal.
Code
Source:
house-markets/contracts at 0ebbc89a (branch integration/v12-post-qa).