Fees (Fee)
What is Fee
Fee (commission) — is a percentage of the transfer amount that is retained by the bridge when transferring tokens between networks.
Why is fee needed?
Commission (fee) is charged by the bridge during cross-chain token transfers to cover operational costs and ensure economic sustainability of the protocol.
Important
Fee is charged only on the EVM network side. On the TVM side, no fee is applied.
Who receives the fee?
- Fee accumulates on the MultiVault contract
- Recipient:
governanceaddress (contract administrator) - Fee withdrawal:
skim()function transfers accumulated fees to the governance address
Types of Fees
Deposit Fee
Fee is charged when depositing tokens from EVM to TVM network.
User sends 1000 USDT → Fee 10 USDT (1%) → 990 USDT goes to TVMWhen applied:
- When calling
deposit()on the MultiVault contract - When calling
depositByNativeToken()for native tokens (ETH, BNB, etc.)
Withdraw Fee
Fee is charged when withdrawing tokens from TVM to EVM network.
User withdraws 1000 USDT from TVM → Fee 10 USDT (1%) → Receives 990 USDT in EVMWhen applied:
- When calling
saveWithdrawNative()/saveWithdrawAlien()on the MultiVault contract - After event confirmation by relays
Fee Collection Scheme
┌─────────────────────────────────────────────────────────────────┐
│ EVM → TVM (Deposit) │
├─────────────────────────────────────────────────────────────────┤
│ User sends 1000 tokens │
│ ↓ │
│ MultiVault.deposit() │
│ ↓ │
│ Calculate fee: 1000 × depositFee / 10000 │
│ ↓ │
│ Fee (e.g. 10) stays on MultiVault │
│ ↓ │
│ 990 tokens transferred to TVM │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ TVM → EVM (Withdraw) │
├─────────────────────────────────────────────────────────────────┤
│ User initiates withdraw of 1000 tokens in TVM │
│ ↓ │
│ Event created, relays confirm │
│ ↓ │
│ User calls saveWithdraw*() on MultiVault │
│ ↓ │
│ Calculate fee: 1000 × withdrawFee / 10000 │
│ ↓ │
│ Fee (e.g. 10) stays on MultiVault │
│ ↓ │
│ User receives 990 tokens │
└─────────────────────────────────────────────────────────────────┘Default and Token-specific Fee
Two Configuration Levels
Fees are configured at two levels:
| Level | Description | When Used |
|---|---|---|
| Default Fee | Global default values | When activating a new token |
| Token-specific Fee | Individual token settings | After token activation |
Default Fee
Global fee settings, separated by token type:
| Parameter | Description |
|---|---|
defaultNativeDepositFee | Default deposit fee for Native tokens (originally issued in TVM) |
defaultNativeWithdrawFee | Default withdraw fee for Native tokens |
defaultAlienDepositFee | Default deposit fee for Alien tokens (originally issued in EVM) |
defaultAlienWithdrawFee | Default withdraw fee for Alien tokens |
Token-specific Fee
Individual settings for each token:
| Parameter | Description |
|---|---|
tokens_[token].depositFee | Deposit fee for specific token |
tokens_[token].withdrawFee | Withdraw fee for specific token |
How Fee is Applied
┌─────────────────────────────────────────────────────────────────┐
│ Fee Application Scheme During Token Activation │
├─────────────────────────────────────────────────────────────────┤
│ │
│ First use of token │
│ ↓ │
│ _activateToken() is called │
│ ↓ │
│ Token type determined (Native or Alien relative to TVM) │
│ ↓ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Native token │ │ Alien token │ │
│ │ (from TVM) │ │ (from EVM) │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ ↓ ↓ │
│ defaultNativeDepositFee defaultAlienDepositFee │
│ defaultNativeWithdrawFee defaultAlienWithdrawFee │
│ ↓ ↓ │
│ └───────────┬───────────┘ │
│ ↓ │
│ Copied to tokens_[token].depositFee / withdrawFee │
│ ↓ │
│ All subsequent operations use token-specific fee │
│ │
└─────────────────────────────────────────────────────────────────┘Important
After token activation, changing default fee DOES NOT affect this token. To change the fee for an already activated token, you must explicitly call setTokenDepositFee() / setTokenWithdrawFee().
Fee Configuration
Setting default fee (for new tokens):
setDefaultNativeDepositFee(100); // 1% for Native tokens (from TVM) deposit
setDefaultNativeWithdrawFee(50); // 0.5% for Native tokens withdraw
setDefaultAlienDepositFee(100); // 1% for Alien tokens (from EVM) deposit
setDefaultAlienWithdrawFee(50); // 0.5% for Alien tokens withdrawSetting token-specific fee (for existing tokens):
setTokenDepositFee(tokenAddress, 200); // 2% deposit for specific token
setTokenWithdrawFee(tokenAddress, 100); // 1% withdraw for specific tokenData Structure
Constants
| Constant | Value | Description |
|---|---|---|
MAX_BPS | 10,000 | 100% in basis points (1 BPS = 0.01%) |
FEE_LIMIT | 5,000 | Maximum allowed fee = 50% |
Token Structure
Stores token information, including fees. Each token has individual fee settings.
| Attribute | Type | Description |
|---|---|---|
activation | uint | Block number of token activation |
blacklisted | bool | Token blacklist flag |
depositFee | uint | Deposit fee (in BPS) |
withdrawFee | uint | Withdrawal fee (in BPS) |
isNative | bool | true = Native token (from TVM), false = Alien token (from EVM) |
custom | address | Custom token address |
Storage Variables
| Variable | Type | Description |
|---|---|---|
tokens_ | mapping(address => Token) | Mapping token address → configuration |
defaultNativeDepositFee | uint | Default fee for Native token (from TVM) deposit |
defaultNativeWithdrawFee | uint | Default fee for Native token withdrawal |
defaultAlienDepositFee | uint | Default fee for Alien token (from EVM) deposit |
defaultAlienWithdrawFee | uint | Default fee for Alien token withdrawal |
Fee Enum
| Value | Description |
|---|---|
Deposit | Deposit fee |
Withdraw | Withdrawal fee |
Fee Calculation
Formula
fee = amount × feeRate / MAX_BPSWhere:
amount— transfer amountfeeRate— fee rate in BPS (basis points)MAX_BPS= 10,000 (100%)
Calculation Function
| Function | Description |
|---|---|
_calculateMovementFee() | Calculates fee based on operation type (Deposit/Withdraw) and token rate |
Calculation Examples
| Amount | Fee Rate (BPS) | Fee Rate (%) | Fee |
|---|---|---|---|
| 1,000,000 | 10 | 0.1% | 1,000 |
| 1,000,000 | 100 | 1% | 10,000 |
| 1,000,000 | 500 | 5% | 50,000 |
| 1,000,000 | 5,000 | 50% | 500,000 (maximum) |
Fee Management
Default Fee Setting Functions
| Function | Parameters | Description |
|---|---|---|
setDefaultNativeDepositFee() | fee: uint | Sets default deposit fee for Native tokens (from TVM) |
setDefaultNativeWithdrawFee() | fee: uint | Sets default withdraw fee for Native tokens |
setDefaultAlienDepositFee() | fee: uint | Sets default deposit fee for Alien tokens (from EVM) |
setDefaultAlienWithdrawFee() | fee: uint | Sets default withdraw fee for Alien tokens |
Token Fee Setting Functions
| Function | Parameters | Description |
|---|---|---|
setTokenDepositFee() | token: address, fee: uint | Sets deposit fee for specific token |
setTokenWithdrawFee() | token: address, fee: uint | Sets withdraw fee for specific token |
Fee Withdrawal
| Function | Parameters | Description |
|---|---|---|
skim() | token: address | Transfers accumulated token fees to governance address |
The function calculates accumulated fee as the difference between contract balance and locked liquidity (liquidity[token]).
Access Rights
| Action | Required Role | Contract |
|---|---|---|
| Set default fee | governance | MultiVaultFacetFees |
| Set token fee | governance | MultiVaultFacetFees |
| Withdraw fees (skim) | governance | MultiVaultFacetFees |
Events
| Event | Parameters | Description |
|---|---|---|
UpdateDefaultNativeDepositFee | fee | Change in default deposit fee for Native tokens |
UpdateDefaultNativeWithdrawFee | fee | Change in default withdraw fee for Native tokens |
UpdateDefaultAlienDepositFee | fee | Change in default deposit fee for Alien tokens |
UpdateDefaultAlienWithdrawFee | fee | Change in default withdraw fee for Alien tokens |
UpdateTokenDepositFee | token, fee | Change in deposit fee for token |
UpdateTokenWithdrawFee | token, fee | Change in withdraw fee for token |
SkimFee | token, skim_to_everscale, amount | Withdrawal of accumulated fees |
Limits
| Parameter | Value | Description |
|---|---|---|
| MAX_BPS | 10,000 | 100% in basis points |
| FEE_LIMIT | 5,000 | Maximum fee = 50% |
Attempting to set fee > FEE_LIMIT will result in transaction rejection.
Fee in Different Flows
EVM → TVM (deposit)
- User calls
deposit()on MultiVault depositFeeis calculated via_calculateMovementFee()- Fee is deducted from transfer amount
- Fee remains on MultiVault contract (accumulates)
- Amount minus fee is transferred to TVM network
TVM → EVM (withdraw)
- User initiates withdraw in TVM network (no fee charged)
- Event contract is created with transfer information
- Relay nodes confirm the event
- User calls
saveWithdraw*()on MultiVault in EVM withdrawFeeis calculated via_calculateMovementFee()- Fee is deducted, user receives amount minus fee
API Reference
POST /payload/build
Returns fee information in response:
| Field | Type | Description |
|---|---|---|
feeAmount | string | Calculated fee in token's smallest units |
tokenAmount | string | Token amount after fee deduction |
Risks and Edge Cases
| Risk/Error | Cause | Protection/Solution |
|---|---|---|
| Fee > Amount | Fee exceeds transfer amount | Transaction reverts (underflow) |
| Fee = 50%+ | Attempt to set fee above limit | Check fee <= FEE_LIMIT |
| Zero governance | Fee recipient not set | governance set during initialization |
| Token not activated | Fee not set for token | Token activates automatically on first use |
| Default fee change | Doesn't affect existing tokens | Must explicitly call setTokenFee for each token |
Error Codes
| Error Code | Description |
|---|---|
"Fee: limit exceeded" | Attempt to set fee > FEE_LIMIT (5000 BPS = 50%) |
"Fees: no fees to skim" | Calling skim() when accumulated fee = 0 |
"Actors: only governance" | Calling setDefaultFee not from governance address |
"Actors: only governance or management" | Calling skim() not from governance/management |