Deploy a Conduit
This guide walks you through wrapping an existing Vehicle in a Conduit — the ERC20 layer your users actually hold.
You will learn how to:
- Find the Vehicles available to wrap on Railnet
- Approve the initial deposit the factory pulls on your behalf
- Optionally gate who may hold your shares with an Account List
- Spawn your Conduit from the Conduit Factory
- Finalize the deposit when the underlying Vehicle settles asynchronously
- Read your Conduit’s onchain data using Railnet GraphQL
For the concepts behind all of this, read Conduit Architecture and Fees & Modules.
Pre-requisites:
- A wallet with funds: enough of the target Vehicle’s asset (e.g. USDC) to cover the initial deposit the factory requires, and some ETH for gas
- The
CONDUIT_SPAWNrole on the Conduit Factory’s access control. This is notFACTORY_SPAWN— that role governs the vehicle factories, and holding it grants nothing here. WithoutCONDUIT_SPAWNthe spawn revertsMissingRole(CONDUIT_SPAWN, <factory>, <you>)before touching any state. - An
ExternalAccessControlcontract. If you followed the Multi-Vehicle guide, the one you deployed there is already in your address book and the form below will pick it up.
Steps:
1. Pick a Vehicle to wrap
A Conduit wraps exactly one Vehicle, and that choice is fixed at deployment. The table below lists what the indexer knows about, newest first.
There is no type restriction here on purpose. A MultiVehicle is itself a Vehicle, and a Conduit over a MultiVehicle — one ERC20 for users, many protocols underneath — is the common production shape.
What does matter is how the Vehicle settles, because it decides whether step 5 applies to you:
- Synchronous (ERC-4626, Aave V3, Morpho Blue) — the initial deposit settles
inside
spawn, and your Conduit comes back already open. - Asynchronous (ERC-7540, Lagoon, MultiVehicle) —
spawnrecords a pending deposit and the Conduit stays closed until you finalize it.
2. Approve the initial deposit
The factory makes an initial deposit into the Conduit on your behalf, to protect
against inflation attacks, and pulls it from your wallet during spawn. So you
must first approve the Conduit Factory to spend that amount.
You do not choose the amount, and you do not choose the asset. The asset is the Vehicle’s asset, and the amount is read per asset from the on-chain AssetRegistry (getInitialDepositAmount). Two consequences:
- Approve at least that amount. Approving less makes deployment revert with
InsufficientAllowance. - The asset must be registered. An asset the
AssetRegistrydoes not know returns an amount of zero, and deployment reverts withInvalidInitialDepositSize. You cannot wrap a Vehicle whose asset is unregistered.
3. Deploy an Account List — optional
Skip this step if anyone should be able to hold your Conduit’s shares. A Conduit
with 0x0000... for its account list is a valid, working Conduit, and that is the
right shape for a public product. Nothing later in this guide depends on it.
Deploy one if you need to gate who may deposit, hold or transfer — a permissioned
vehicle, a jurisdiction restriction, a sanctions obligation. Do it now, because
the account list is a spawn parameter and cannot be swapped afterwards. Only the
lists themselves stay editable. One AccountList can also back several Conduits, so
reuse an address here if you already have one.
The mode decides how far the allow-list reaches:
| Mode | Deposit | Transfer |
|---|---|---|
OPEN | anyone not block-listed | anyone not block-listed |
REGULAR | allow-listed only | anyone not block-listed |
STRICT | allow-listed only | both sides allow-listed |
Redeem is gated by sanctions alone in every mode. Blocking somebody stops them
entering, never leaving — a blocked, non-sanctioned holder can always exit with
their funds. To remove a holder rather than wait for them, use forceRedeem, which
burns their shares and returns the underlying to that holder; it needs CONDUIT_FORCE_REDEEM and only works on an already blocked or sanctioned target.
This spawn is gated on
FACTORY_SPAWN, notCONDUIT_SPAWN— a different role, checked by a different factory. Holding one grants nothing on the other. The panel names the missing role if you hit it.
List management lives on the AccountList’s own access control, under
ACCOUNT_LIST_MANAGER— a third access-control surface, separate from the Conduit’s and the Vehicle’s. Point it at an EAC whose admin you control, or you will not be able to edit the lists later.
4. Spawn the Conduit
Now deploy the Conduit itself. Every module address below is optional — a Conduit
with 0x0000... for all three is valid — but none of them can be swapped later, so
decide before you spawn. An Account List deployed in step 3 is filled in for you. See Fees & Modules for what each one buys you.
The spawn is gated on
CONDUIT_SPAWN. It is not public by default, so an admin has to grant it on the factory’s External Access Control before you can deploy —grantRole(0x786b35649a4a9a34706607080cadb43353bb4f0aafc29641aaf041cde2516814, yourAddress), orgrantScopedRole(role, conduitFactory, yourAddress)to scope it to this factory alone. The panel below names the missing role if you hit it.
transferEnabledis a one-way latch. You can turn transfers on later withenableTransfers(), but there is no way to turn them back off — disabling them would brick every downstream ERC20 integration. Starting withfalseis the conservative choice if you are unsure.
5. Finalize the initial deposit
Skip this if you wrapped a synchronous Vehicle. Its initial deposit settled inside
spawn,ready()already returnstrue, and there is nothing to finalize. The panel below tells you which case you are in.
On an asynchronous Vehicle, spawn recorded a PendingDeposit and emitted PendingConduitDeposit. The Conduit stays closed — only its deployer can touch it
— until the seed query reaches SETTLED and someone calls finalizeConduitDeposit on the factory.
That call drives the query forward with process() and, once settled, burns the
seed shares, verifies initialExpectedSupply, enables the Conduit, and clears the
pending record. Calling it too early is harmless: it leaves the pending record in
place, so just re-call it after each state advance.
6. Fetch your deployed Conduit
Once deployed and indexed, query the Railnet Subgraph to verify your Conduit’s configuration and the Vehicle it wraps.
Fetch Conduit Details
enabled is the indexer’s view of ready() — if it is still false after a
synchronous deployment, the indexer has simply not caught up yet.
Addresses are matched lowercase. The indexer stores them that way and
_eqis case-sensitive, so a checksummed address — which is what your wallet, the explorer and the panel above all hand you — matches nothing. The runner above lowercases address variables for you; if you query the endpoint directly, lowercase them yourself.
Next steps
- Open your Conduit in the explorer at
/conduit/<address>to see its queries, fees and holders. - Move funds in and out and read a position with the SDK: Deposit & Withdraw.
- Add fees or an allow-list: Fees & Modules.