How equillar manage investment commissions
When creating the equillar smart-contract, one of the most important decisions was how to structure commissions. Instead of applying a single fixed percentage, we have implemented a dynamic commission system that rewards larger investments with lower rates. This approach incentivizes significant capital contributions while maintaining a fair and accessible base rate for smaller investors.
The Philosophy: Decreasing Commissions
The central idea of our system is simple: the more you invest, the lower the commission percentage you pay. This approach has several benefits:
- Accessibility: Small investors aren't penalized with disproportionate commissions
- Incentive: Encourages larger investments by offering better conditions
- Fairness: Balances operational costs with fair treatment for everyone
The Rate Denominator
To implement this dynamic system, we use a variable called the rate denominator. This is the key piece that makes commissions adjust automatically. Let's explore how it works
The calculate_rate_denominator function
Here's the actual contract code that calculates the rate denominator:
pub(self) const LOWER_AMOUNT_FOR_COMMISSION_REDUCTION: i128 = 100;
pub(self) const LOWER_DIVISOR: u32 = 10;
pub(self) const UPPER_DIVISOR: u32 = 60;
pub(self) const AMOUNT_PER_COMMISSION_REDUCTION: i128 = 400;
pub fn calculate_rate_denominator(amount: &i128, decimals: u32) -> u32 {
let scale_factor = 10_i128.pow(decimals);
let token_amount = amount / scale_factor;
if token_amount <= LOWER_AMOUNT_FOR_COMMISSION_REDUCTION {
return LOWER_DIVISOR;
}
let a = (token_amount - LOWER_AMOUNT_FOR_COMMISSION_REDUCTION)
/ AMOUNT_PER_COMMISSION_REDUCTION;
if a > UPPER_DIVISOR as i128 {
return UPPER_DIVISOR;
}
LOWER_DIVISOR + a as u32
}
Let's break down how calculate_rate_denominator works step by step:
Decimal Handling (Lines 1-4)
let scale_factor = 10_i128.pow(decimals);
let token_amount = amount / scale_factor;
First, the function converts the scaled amount (e.g., 3,600,000,000 for a token with 7 decimals such as USDC) to real token units (360). This is crucial because blockchain contracts receive amounts scaled by the token's decimals, but our logic needs to work with actual token quantities.
Base Tier Check (Lines 6-8)
if token_amount <= LOWER_AMOUNT_FOR_COMMISSION_REDUCTION {
return LOWER_DIVISOR;
}
If the investment is 100 tokens or less, we immediately return a rate denominator of 10. This is the "base" tier where all small investors are treated equally.
Tiered Calculation (Lines 10-11)
let a = (token_amount - LOWER_AMOUNT_FOR_COMMISSION_REDUCTION) / AMOUNT_PER_COMMISSION_REDUCTION;
For investments above 100 tokens, we calculate how many 400-token tiers the investment spans:
- First 100 tokens: Covered by base tier (rate denominator = 10)
- Tokens 101-500: Still rate denominator = 10 (excess < 400, so 0 additional tiers)
- Tokens 501-900: Rate denominator = 11 (excess ≥ 400, so +1 tier)
- Tokens 901-1,300: Rate denominator = 12 (excess ≥ 800, so +2 tiers)
- And so on...
This creates a tiered structure where every complete 400-token tier above the base reduces the commission percentage.
Maximum Cap (Lines 13-15)
if a > UPPER_DIVISOR as i128 {
return UPPER_DIVISOR;
}
We cap the rate denominator at 60 to prevent commissions from becoming unreasonably small. Even ultra-large investments (millions of tokens) will use a denominator of 60, which already provides significant commission reduction.
Final Calculation (Line 17)
LOWER_DIVISOR + a as u32
The final denominator is the base (10) plus the number of 400-token tiers exceeded.
Why This Design?
The tier-based approach (every 400 tokens) creates a balanced system:
- Gradual reduction: Commissions decrease smoothly, not in large jumps
- Fair for all ranges: Small, medium, and large investors all benefit
- Predictable: Easy to calculate and understand
- Bounded: The cap prevents extreme edge cases
Real-World Examples
| Investment | Formula | Calculation | Rate Denominator |
|---|---|---|---|
| 50 | N/A (≤100) | Base tier | 10 |
| 100 | N/A (=100) | Base tier | 10 |
| 300 | 10 + (300-100)/400 | 10 + 0 (200/400 = 0) | 10 |
| 500 | 10 + (500-100)/400 | 10 + 1 (400/400 = 1) | 11 |
| 900 | 10 + (900-100)/400 | 10 + 2 (800/400 = 2) | 12 |
| 1700 | 10 + (1700-100)/400 | 10 + 4 (1600/400 = 4) | 14 |
| 5000 | 10 + (5000-100)/400 | 10 + 12 (4900/400 = 12) | 22 |
| 25000 | 10 + (25000-100)/400 | 10 + 62 → capped | 60 |
As smart contracts do not work with floating-point numbers, division is always integer-based. This is why (for instance) the 300 amount case results in the base tier denominator.
Practical example
For a 1400 USDC investment:
- Unscale:
14000000000 / 10^7 = 1400USDC - Excess over base limit:
1400 - 100 = 1300USDC - 400-token tiers:
1300 / 400 = 3(integer based division) - Rate denominator:
10 + 3 = 13
Calculating the Final Commission
Once we have the rate denominator, the contract calculates the commission using this implementation:
let amount_to_commission = amount * (*i_rate as i128) / (rate_denominator as i128) / 100 / 100;
The two divisions by 100 are necessary because:
- First division: Converts the rate denominator to a percentage
- Second division: Converts the interest rate to a percentage (e.g., 850 → 8.5%) since it comes scaled as 10^2 to allow interests with decimals like (8.5%).
Complete Example: Project with 8.5% Yield
Imagine a project offering 8.5% yield (represented as 850 in the contract). Maria decides to invest 360 USDC tokens.
Step 1: Calculate the Rate Denominator
// Input: 3,600,000,000 (360 USDC tokens with 7 decimals)
let scale_factor = 10_i128.pow(7); // 10,000,000
let token_amount = 3_600_000_000 / 10_000_000; // 360 tokens
// Since 360 > 100:
let a = (360 - 100) / 400; // (260) / 400 = 0
let rate_denominator = 10 + 0; // 10
Step 2: Calculate the Commission
let i_rate = 850_u32; // 8.5%
let amount = 3_600_000_000_i128; // 360 scaled tokens
let amount_to_commission = (3_600_000_000 * 850) / 10 / 100 / 100;
// = 3_060_000_000_000 / 10 / 100 / 100
// = 306_000_000_000 / 100 / 100
// = 3_060_000_000 / 100
// = 30_600_000
// Unscaled: 30,600,000 / 10^7 = 3.06 tokens
Result
- Project yield: 8.5%
- Commission on investment: 0.85% (10 times lower than the yield)
- Absolute commission: 3.06 tokens
- Tokens available for yield generation: 356.94 tokens (after 0.85% commission)
Commission Comparison by Invested Amount
Let's see how commission varies for a project with 8.5% yield across different amounts:
| Investment | Rate Denominator | Commission (USDC) | % Commission |
|---|---|---|---|
| 50 | 10 | 0.43 | 0.85% |
| 360 | 10 | 3.06 | 0.85% |
| 1,000 | 12 | 7.08 | 0.71% |
| 2,000 | 14 | 12.14 | 0.61% |
| 5,000 | 22 | 19.32 | 0.39% |
| 10,000 | 34 | 25.00 | 0.25% |
| 50,000 | 60 (max) | 70.83 | 0.14% |
As you can see, the commission is inversely proportional to the amount invested, decreasing as the amount invested increases.
Conclusion
The dynamic commission system achieves a fair balance between sustainability and accessibility. By automatically adjusting rates based on investment size, we ensure that small investors have a fair entry point while rewarding larger commitments with better terms.
This approach, combined with transparent on-chain calculations and automatic token decimal handling, creates a commission structure that adapts to each investor's needs. The result is a system where everyone benefits: small investors keep more of their returns, large investors enjoy reduced costs, and the platform remains economically viable.
Top comments (0)