This page covers the smart contract implementation details. See Glossary.
The 4 fee types
Railnet supports four distinct fee types, each calculated and applied at different points in the vehicle lifecycle.Performance fee (on earnings)
A fee charged on gains above the high water mark. You only collect when the strategy makes money.If the strategy loses value, no performance fees are collected until the share price recovers past the previous high water mark.
Management fee (time-based)
An annualized fee prorated by the time elapsed since the last fee-cache update (onUpdate). Charged regardless of performance.
Deposit fee (entry fee)
A fee charged when users deposit assets. Deducted from shares received during the unlock phase.Redeem fee (exit fee)
A fee charged when users redeem shares. Deducted from assets received during the unlock phase.When fees are applied
Fee recipients and distribution
Fees can be distributed to multiple recipients with configured percentage splits:Example configurations
- Hedge fund model
- Index fund model
- Active management
- Long-term capital
Configuration
Prerequisites
You need the following roles on your External Access Control, scoped to the Fee Manager contract:Set fee percentages
Configure the four fee rates. Values must not exceed the maximum limits set during Fee Manager deployment.Fee configuration IDs
Every acceptedsetFees call derives a configId — keccak256(abi.encode(fees)) — stores the Fees struct under it, and makes it the current configuration. feeManager.fees() returns (configId, Fees) for the current one, and feeManager.fees(configId) returns any past one. Passing bytes32(0) to the config-scoped functions resolves to the current configuration; an unknown id reverts with NonExistingConfigId.
This versioning is what keeps asynchronous queries consistent:
- Transactional fees. The vehicle pins the active
configIdwhen a query is created and reads it back onunlock, so a fee change mid-flight never applies retroactively to an in-flight query. Read it withvehicle.feesConfigId(query)— orconduit.feesConfigId(query)for a Conduit, which pins its own Fee Manager’s id atcreatetime. - Ongoing fees.
onUpdatesnapshots the currentconfigIdinto the vehicle’sCacheasapplicableConfigId, alongside the high water mark and timestamp. The nextonOperationsuses that snapshot, so a new rate only starts accruing after the vehicle’s next update.
Fee calculation formulas
Management fee formula
Management fee formula
The management fee is annualized and prorated by time elapsed:Where
timeDelta is the seconds elapsed since the last update and 31536000 is the number of seconds in a year (365 days).Performance fee formula
Performance fee formula
The performance fee is applied to earnings above the high water mark:The high water mark (
lastTotalAssets) is refreshed when the vehicle calls onUpdate at the end of an operation, so you only pay performance fees on new gains.Deposit and redeem fee formulas
Deposit and redeem fee formulas
Transactional fees are deducted from the gross amount:For reverse calculations (determining gross amount from a desired net amount):
Configure fee recipients
Fee recipients define how collected fees are split among addresses. The sum of all recipient shares must equal 10,000 bps (100%).Collect accumulated fees
Performance and management fees accumulate as vehicle shares held by the Fee Manager. The Fee Manager never redeems those shares itself: a vehicle is an ERC20 share token, so you dispatch the shares to the recipients and each recipient redeems on its own schedule.1
Monitor accumulated fees
Check the FeeManager’s share balance in the vehicle to see how much has been collected.
2
Dispatch the vehicle shares
Because the vehicle is itself an ERC20 share token, dispatch it like any other asset. Recipients receive vehicle shares, split by their
shareBps.Requires: FEE_MANAGER_DISPATCH_ERC20 role.3
Dispatch collected assets
Transactional deposit and redeem fees reach the Fee Manager denominated in the payout asset rather than in shares. Dispatch each ERC20 balance the same way.Requires:
FEE_MANAGER_DISPATCH_ERC20 role.dispatchERC20 reverts with ZeroValue when the Fee Manager holds none of the requested asset, so check the balance before dispatching.