How fees are configured, collected, and distributed in Railnet
This page covers the smart contract implementation details. See Glossary.
The FeeManager is an optional contract that you can attach to a Multi-Vehicle or Conduit at deployment time. It automates fee calculation and collection across the vehicle lifecycle. Once set during initialization, the FeeManager cannot be changed or removed, ensuring predictability for users.You can share a single FeeManager across multiple Multi-Vehicle contracts to maintain consistent fee behavior and centralize configuration changes.
Fee values must not exceed the maxFees ceiling defined at deployment. Attempting to set fees above the maximum will cause the transaction to revert. You can query the current maximums with feeManager.maxFees().
Fee recipients define how collected fees are split among addresses. The sum of all recipient shares must equal 10,000 bps (100%).
FeeManager.FeeRecipient[] memory recipients = new FeeManager.FeeRecipient[](2);// 70% to the operatorrecipients[0] = FeeManager.FeeRecipient({ target: operatorAddress, shareBps: 7000});// 30% to the DAO treasuryrecipients[1] = FeeManager.FeeRecipient({ target: daoTreasuryAddress, shareBps: 3000});feeManager.setFeeRecipients(recipients);
Updating recipients causes old recipients to lose access to any uncollected fees. Always call dispatchERC20 to distribute pending fees before changing recipients.
Performance and management fees accumulate as vehicle shares held by the Fee Manager. To convert these shares into underlying assets, trigger a redemption.
1
Monitor accumulated fees
Check the FeeManager’s share balance in the vehicle to see how much has been collected.
The Fee Manager holds vehicle shares from accumulated performance and management fees. Redeem them to convert shares into the underlying asset.Requires:FEE_MANAGER_REDEEM_VEHICLE_SHARES role.
bytes32 querySalt = keccak256(abi.encodePacked(block.timestamp, "fees"));(Query memory query, State state) = feeManager.redeemVehicleShares( multiVehicle, querySalt);// Progress query until settled
3
Distribute to recipients
Once redeemed, dispatch base assets to configured recipients.Requires:FEE_MANAGER_DISPATCH_ERC20 role.
feeManager.dispatchERC20(IERC20(baseAsset));// Distributes entire balance according to recipient shares
Query the Fee Manager’s current state at any time.
// Get current fee configuration(bytes32 configId, FeeManager.Fees memory currentFees) = feeManager.fees();// Get maximum fee limitsFeeManager.Fees memory maxFees = feeManager.maxFees();// Get current recipientsFeeManager.FeeRecipient[] memory recipients = feeManager.feeRecipients();// Get fee cache for a specific vehicle (high water mark, last update, etc.)FeeManager.Cache memory vehicleCache = feeManager.cache(address(vehicle));
The FeeManager address (set during Multi-Vehicle construction)
The maxFees ceiling (set during FeeManager deployment)
Plan carefully: Choose maxFees conservatively. You can always charge less than the maximum, but you can never increase fees beyond it. For example, set maxFees.performanceFeeBps = 3000 (30%) even if you start at 2000 (20%) to allow future flexibility.