Documentation

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_SPAWN role on the Conduit Factory’s access control. This is not FACTORY_SPAWN — that role governs the vehicle factories, and holding it grants nothing here. Without CONDUIT_SPAWN the spawn reverts MissingRole(CONDUIT_SPAWN, <factory>, <you>) before touching any state.
  • An ExternalAccessControl contract. 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
2
Approve Deposit
3
Account List
4
Spawn Conduit
5
Finalize
6
Confirm onchain

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) — spawn records 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 AssetRegistry does not know returns an amount of zero, and deployment reverts with InvalidInitialDepositSize. 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:

ModeDepositTransfer
OPENanyone not block-listedanyone not block-listed
REGULARallow-listed onlyanyone not block-listed
STRICTallow-listed onlyboth 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, not CONDUIT_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), or grantScopedRole(role, conduitFactory, yourAddress) to scope it to this factory alone. The panel below names the missing role if you hit it.

transferEnabled is a one-way latch. You can turn transfers on later with enableTransfers(), but there is no way to turn them back off — disabling them would brick every downstream ERC20 integration. Starting with false is 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 returns true, 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

Query
Variables

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 _eq is 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.