Skip to content

Commit 9e7d02f

Browse files
authored
Merge pull request #129 from Great-2025/feature/multi-fee-tier-structure
feat: Scaffold multi-fee tier structure for factory pool creation
2 parents a655748 + b964ab8 commit 9e7d02f

3 files changed

Lines changed: 74 additions & 7 deletions

File tree

README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,49 @@
88

99
## 🏗 Architecture
1010

11-
The system consists of two decoupled smart contracts:
11+
The system consists of multiple smart contracts:
1212

1313
1. **`invoice_nft`**: A standard-compliant NFT representing a verified invoice. It holds metadata (IPFS hash, face value, currency, due date).
1414
2. **`lending_pool`**: An escrow vault where liquidity providers deposit stablecoins (USDC). It accepts `invoice_nft` as collateral to automate loan origination and repayment.
15+
3. **`factory`**: Factory contract for deploying liquidity pools with specific fee tiers.
16+
4. **`amm_pool`**: Automated Market Maker pool contract with configurable fee tiers.
17+
18+
## 💰 Fee Tiers
19+
20+
The Factory contract supports creating pools with different fee tiers to optimize for various token pair characteristics:
21+
22+
| Fee Tier | Basis Points | Percentage | Use Case |
23+
| :--- | :--- | :--- | :--- |
24+
| **Stable** | 5 | 0.05% | Stablecoin pairs (USDC/USDT, DAI/USDC) |
25+
| **Standard** | 30 | 0.30% | Standard token pairs (ETH/USDC, BTC/USDC) |
26+
| **Volatile** | 100 | 1.00% | Highly volatile exotic pairs |
27+
28+
### Creating a Pool with Specific Fee Tier
29+
30+
```rust
31+
// Create a stablecoin pool with 0.05% fee
32+
let pool_address = factory.create_pool(
33+
token_a,
34+
token_b,
35+
5 // 5 basis points = 0.05%
36+
);
37+
38+
// Create a standard pool with 0.30% fee
39+
let pool_address = factory.create_pool(
40+
token_a,
41+
token_b,
42+
30 // 30 basis points = 0.30%
43+
);
44+
45+
// Create a volatile pool with 1.00% fee
46+
let pool_address = factory.create_pool(
47+
token_a,
48+
token_b,
49+
100 // 100 basis points = 1.00%
50+
);
51+
```
52+
53+
**Important:** Only fee tiers of 5, 30, or 100 basis points are supported. Any other value will cause the transaction to fail.
1554

1655
## 💾 Storage Architecture
1756

contracts/amm_pool/src/lib.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct PoolState {
1313
pub token_b_decimals: u32,
1414
pub reserve_a: i128,
1515
pub reserve_b: i128,
16+
pub fee_tier: u32, // Fee tier in basis points (5, 30, or 100)
1617
pub is_deprecated: bool,
1718
pub _status: u32, // 0 = unlocked, 1 = locked (reentrancy protection)
1819
}
@@ -28,11 +29,12 @@ pub struct AmmPool;
2829

2930
#[contractimpl]
3031
impl AmmPool {
31-
/// Initialize the AMM pool with two tokens and admin.
32+
/// Initialize the AMM pool with two tokens, admin, and fee tier.
3233
/// 1. Queries the Stellar network to fetch exact decimal precision via Soroban token interface.
3334
/// 2. Validates that both values are positive integers <= 18.
34-
/// 3. Aborts initialization if either token's decimals cannot be determined or are invalid.
35-
pub fn init(env: Env, admin: Address, token_a: Address, token_b: Address) {
35+
/// 3. Validates fee tier is one of the supported values (5, 30, or 100 basis points).
36+
/// 4. Aborts initialization if validation fails.
37+
pub fn init(env: Env, admin: Address, token_a: Address, token_b: Address, fee_tier: u32) {
3638
if env.storage().instance().has(&DataKey::State) {
3739
panic!("Already initialized");
3840
}
@@ -50,13 +52,19 @@ impl AmmPool {
5052
panic!("Invalid decimals for token_b");
5153
}
5254

55+
// Validate fee tier
56+
if fee_tier != 5 && fee_tier != 30 && fee_tier != 100 {
57+
panic!("Invalid fee tier. Only 5, 30, or 100 basis points are supported");
58+
}
59+
5360
let state = PoolState {
5461
token_a,
5562
token_b,
5663
token_a_decimals: decimals_a,
5764
token_b_decimals: decimals_b,
5865
reserve_a: 0,
5966
reserve_b: 0,
67+
fee_tier,
6068
is_deprecated: false,
6169
_status: 0, // Start unlocked
6270
};

lib.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub struct Pool {
1010
pub address: Address,
1111
pub token_a: Address,
1212
pub token_b: Address,
13+
pub fee_tier: u32, // Fee tier in basis points (5, 30, or 100)
1314
pub paused: bool,
1415
}
1516

@@ -64,24 +65,33 @@ impl FactoryContract {
6465
pools.get(sorted_tokens).map(|p| p.address)
6566
}
6667

67-
/// Deploys a new liquidity pool for the given token pair.
68+
/// Deploys a new liquidity pool for the given token pair with a specific fee tier.
6869
///
6970
/// # Arguments
7071
/// * `env` - The Soroban environment.
7172
/// * `token_a` - The first token address.
7273
/// * `token_b` - The second token address.
74+
/// * `fee_tier` - The fee tier in basis points (5, 30, or 100).
7375
///
7476
/// # Returns
7577
/// The address of the newly deployed pool.
76-
pub fn create_pool(env: Env, token_a: Address, token_b: Address) -> Address {
78+
///
79+
/// # Panics
80+
/// If tokens are the same, pool already exists, or fee_tier is invalid.
81+
pub fn create_pool(env: Env, token_a: Address, token_b: Address, fee_tier: u32) -> Address {
7782
if token_a == token_b {
7883
panic!("Tokens must be different");
7984
}
8085

86+
// Validate fee tier - only allow 5, 30, or 100 basis points
87+
if fee_tier != 5 && fee_tier != 30 && fee_tier != 100 {
88+
panic!("Invalid fee tier. Only 5, 30, or 100 basis points are supported");
89+
}
90+
8191
let (token_0, token_1) = Self::sort_tokens(token_a, token_b);
8292

8393
let mut pools: Map<(Address, Address), Pool> =
84-
env.storage().instance().get(&DataKey::Pools).unwrap_or(Map::new(&env));
94+
env.storage().instance().get(&DataKey::Pools).unwrap_or_else(|| Map::new(&env));
8595

8696
if pools.contains_key((token_0.clone(), token_1.clone())) {
8797
panic!("Pool already exists");
@@ -100,11 +110,21 @@ impl FactoryContract {
100110
// Deploy the new pool contract
101111
let pool_address = env.deployer().with_current_contract(salt).deploy(wasm_hash);
102112

113+
// Initialize the pool with the fee tier
114+
let init_args = vec![&env,
115+
env.current_contract_address().into_val(&env), // Factory as admin
116+
token_0.clone().into_val(&env),
117+
token_1.clone().into_val(&env),
118+
fee_tier.into_val(&env)
119+
];
120+
env.invoke_contract::<()>(&pool_address, &Symbol::new(&env, "init"), init_args);
121+
103122
// Store the new pool
104123
let pool = Pool {
105124
address: pool_address.clone(),
106125
token_a: token_0.clone(),
107126
token_b: token_1.clone(),
127+
fee_tier,
108128
paused: false,
109129
};
110130

0 commit comments

Comments
 (0)