Skip to main content
A Conduit wraps an existing Vehicle and issues its own ERC20 shares. This lets multiple Multi-Vehicles access the same yield source while the Conduit manages position aggregation, deposits, and redeems through the STEAM lifecycle.
Platforms also deploy Conduits as distribution channels for existing strategies. See Deploy a Conduit as a platform for the platform-focused guide.

When to use a Conduit

Use a Conduit when:
  • Multiple Multi-Vehicles need access to the same underlying yield source
  • You want a single shared position instead of separate per-Multi-Vehicle positions
  • You need ERC20 transferable shares representing a pro-rata claim on the underlying Vehicle
If only one Multi-Vehicle will ever use a yield source, a regular Vehicle is simpler.

Prerequisites

  • A deployed STEAM Vehicle (e.g., an ERC4626Vehicle)
  • A deployed CoreFactory and FreezablePausableBeacon for the Conduit implementation
  • Familiarity with the STEAM standard

Deploy a Conduit

1

Deploy the ConduitFactory

The ConduitFactory is responsible for spawning new Conduit instances.
ConduitFactory factory = new ConduitFactory(
    coreFactory,
    conduitBeacon,
    accessControl
);
2

Configure spawn parameters

Define the Conduit’s configuration including the underlying Vehicle, transfer mode, and initial deposit size.
ConduitFactory.SpawnParams memory params = ConduitFactory.SpawnParams({
    name: "My Conduit",
    symbol: "mCON",
    vehicle: IVehicle(VEHICLE_ADDRESS),
    feeManager: IFeeManager(address(0)),       // No fees for now
    accountList: IAccountList(address(0)),       // No access control
    ownerRegistry: IOwnerRegistry(address(0)),   // No external registry
    accessControl: accessControl,
    transferMode: ConduitStructs.TransferMode.ALLOW_TRANSFER,
    initialDepositSize: 1e18,
    initialExpectedSupply: 1e18,
    depositAsset: IERC20(underlyingAsset),
    querySalt: bytes32(0),
    deploymentSalt: keccak256("my-conduit-salt")
});
3

Spawn the Conduit

Approve the factory to spend the initial deposit, then spawn.
// Approve the factory to spend the initial deposit
IERC20(underlyingAsset).approve(address(factory), 1e18);

// Spawn the Conduit
Conduit conduit = Conduit(
    address(factory.spawn(params, keccak256("deployment-salt")))
);
The initial deposit protects against inflation attacks by bootstrapping the share supply. The initial shares are burned automatically.

Make a deposit

After deployment, deposit into the Conduit. The Conduit handles pulling assets and creating the STEAM query in the underlying Vehicle.
// Approve the Conduit to spend your tokens
IERC20(underlyingAsset).approve(address(conduit), 100e18);

// Define the deposit query
Query memory depositQuery = Query({
    owner: address(conduit),
    receiver: address(conduit),
    mode: Mode.DEPOSIT,
    input: new Asset[](1),
    output: new Asset[](0),
    salt: bytes32(uint256(1)),
    data: ""
});
depositQuery.input[0] = Asset({
    asset: address(underlyingAsset),
    value: 100e18
});

// Create and auto-process the deposit
conduit.create(depositQuery, msg.sender);
After the deposit settles, check your shares:
uint256 shares = conduit.balanceOf(msg.sender);
uint256 assets = conduit.totalAssets();

Redeem from a Conduit

Provide Conduit shares as input, and the Conduit handles the interaction with the underlying Vehicle.
// Approve the Conduit to burn your shares
conduit.approve(address(conduit), shares);

// Define the redeem query
Query memory redeemQuery = Query({
    owner: address(conduit),
    receiver: address(conduit),
    mode: Mode.REDEEM,
    input: new Asset[](1),
    output: new Asset[](0),
    salt: bytes32(uint256(2)),
    data: ""
});
redeemQuery.input[0] = Asset({
    asset: address(conduit),
    value: shares
});

// Create and auto-process the redeem
conduit.create(redeemQuery, msg.sender);

Next steps

Configure fees

Add fee structures to your Conduit.

Learn about Conduits

Understand Conduit architecture in depth.