Documentation

Conduit Architecture

Conduits are the primary user-facing layer in Railnet. They wrap a single STEAM Vehicle with an ERC20 share token, providing familiar DeFi interactions (deposit, withdraw, transfer shares) while the underlying Vehicle handles protocol-specific complexity.

Think of it as:

  • Vehicle: The engine (executes protocol-specific logic like Aave supplies or ERC-7540 redeem requests)
  • Conduit: The dashboard (provides a familiar interface — ERC20 shares, fees, access control)

Users interact with Conduits; Conduits interact with Vehicles on their behalf.

The Share Token Model

A Conduit issues its own ERC20 shares (conduit shares) to represent ownership. Internally, the Conduit holds shares issued by the underlying Vehicle.

The conversion chain:

Conduit Shares ↔ Vehicle Shares ↔ Underlying Assets

As the underlying Vehicle earns yield, Vehicle share value increases → Conduit’s totalAssets() increases → each conduit share is worth more. Users never touch Vehicle shares directly.

Key Components

When building with Conduits, there are four main integration areas:

  1. Vault Operations: Deposit and withdraw through create() and process(). Conduit handles asset approval, Vehicle interaction, and share minting/burning.
  2. Yield Tracking: Monitor share price appreciation via totalAssets() and holdings(). Use convert() for pure asset-to-share conversion, estimate() for conversion including fees.
  3. Access Control: Optional AccountList module provides allowlist/blocklist for who can deposit and receive shares. A transferEnabled flag controls share transferability.
  4. Fee Management: Optional FeeManager integration supports management fees (time-based), performance fees (high water mark), deposit fees (entry), and redeem fees (exit).

Access control and fees are both optional modules chosen at deployment. They are covered in detail in Fees & Modules.

The Create → Process Lifecycle

Conduits simplify the STEAM lifecycle into two user-facing operations:

Create

When a user calls create(query, receiver):

  1. Validation: Conduit checks the receiver, ensures it’s enabled, verifies sender is allowed (via AccountList if configured).
  2. Asset Pull: Pulls assets from msg.sender — underlying tokens for deposits, conduit shares for redeems.
  3. Vehicle Interaction: Approves the Vehicle and calls vehicle.create().
  4. Fee Capture: Captures current fee configuration to ensure consistent fee application at settlement.
  5. Auto-Processing: If receiver == msg.sender, automatically attempts to process immediately.

Process

The process(query) function advances the query through STEAM:

  1. Fee Accrual: Accrues management and performance fees by minting shares to FeeManager.
  2. State Check: Checks current state in the Vehicle.
  3. PAUSED: Calls vehicle.resume() to continue.
  4. UNLOCKING: Calls vehicle.unlock(), mints conduit shares (deposits) or transfers assets (redeems), applies transactional fees.
  5. RECOVERING: Calls vehicle.recover() to refund assets or restore shares.

Deposit Flow

Step-by-step deposit:

User deposits 1,000 USDC into Conduit
    │
    ├─ 1. Conduit pulls 1,000 USDC from user
    │
    ├─ 2. Conduit approves Vehicle, calls vehicle.create(DEPOSIT)
    │
    ├─ 3a. Synchronous Vehicle (e.g., Aave):
    │      → Query reaches UNLOCKING immediately
    │      → Conduit calls vehicle.unlock()
    │      → Conduit mints shares to user (minus deposit fee if any)
    │      → Done in one transaction
    │
    └─ 3b. Asynchronous Vehicle (e.g., ERC7540):
           → Query enters PROCESSING
           → User (or Keeper) must call process() later
           → When ready: UNLOCKING → unlock → mint shares

Withdrawal Flow

Step-by-step redeem:

User redeems 1,000 conduit shares
    │
    ├─ 1. Conduit pulls 1,000 shares from user
    │
    ├─ 2. Conduit calls vehicle.create(REDEEM)
    │
    ├─ 3. Vehicle redeems underlying assets
    │
    ├─ 4. Conduit applies redeem fee (if any)
    │
    └─ 5. Conduit transfers base assets to user
           Conduit shares are burned

Conduit vs Direct Vehicle vs MultiVehicle

AspectDirect VehicleConduitMultiVehicle
Share TokenVehicle shares (internal)Conduit ERC20 sharesMultiVehicle ERC20 shares
Fee ManagementNoneFull suite (mgmt, perf, deposit, redeem)Full suite via FeeManager
Access ControlNoneAccountList (allowlist/blocklist)EAC role-based
Multi-ProtocolNoNo (wraps single vehicle)Yes (multiple sub-vehicles)
User ExperienceManual query managementSimple create/processAutomated queue-based
Best ForProtocol integrationsEnd-user productsInstitutional strategies

Key Interface Summary

MethodDescription
create(query, receiver, sourceSalt)Create deposit or redeem query, auto-processes if possible
process(query)Advance query through STEAM lifecycle; returns (queryId, newState)
holdings()Total Vehicle shares held by the Conduit
totalAssets()Total underlying assets managed
estimate(asset, mode, estimationType)Preview output including fees
convert(asset, sharesToAssets)Pure conversion without fees
ready()Whether the Conduit is open for deposits. Replaces isEnabled(); enable() opens it
isTransferable(from, to)Whether a share transfer between these accounts is allowed
forceRedeem(user, amount, output)Eject a blocked or sanctioned holder; needs CONDUIT_FORCE_REDEEM
getVehicle()The underlying Vehicle contract
asset()The underlying ERC20 asset address
queriesCount()Total queries created through this Conduit

Deployment

Conduits are deployed via ConduitFactory.spawn():

  1. Deploy Conduit proxy via Beacon pattern.
  2. Initialize with Vehicle, FeeManager, AccountList and the transferEnabled flag.
  3. Make initial deposit (anti-inflation protection).
  4. If sync vehicle: initial deposit settles immediately → Conduit enabled.
  5. If async vehicle: initial deposit stored as PendingDeposit → call finalizeConduitDeposit() after settlement.

Walk it end to end, with a live wallet, in Deploy a Conduit. For the modules referenced above — FeeManager, AccountList, OwnerRegistry, interceptions and the transferEnabled latch — see Fees & Modules.