Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions soroban/contracts/factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ const TTL_EXTEND_TO: u32 = 1_036_800;
/// per-ledger `credit_rate`. See `daily_rate_to_credit_rate`.
const LEDGERS_PER_DAY: u128 = 17_280;

/// Mirror of `farming_pool::MAX_MIN_LOCK_PERIOD`: the factory rejects any
/// `min_lock_period` above this ceiling in `create_pool` before deploying a
/// pool, consistent with the pool-side check in `initialize`. See #132.
///
/// `2 years × 365 × 86_400 s/day / 5 s/ledger = 12_614_400 ledgers`.
const MAX_MIN_LOCK_PERIOD: u32 = 12_614_400; // ~2 years at 5 s/ledger

/// Convert a "credits per day" figure into the deployed pool's native
/// "credits per ledger" `credit_rate`.
///
Expand Down Expand Up @@ -434,6 +441,10 @@ impl Factory {
let min_lock_period: u32 = min_lock_period
.try_into()
.map_err(|_| FactoryError::MinLockPeriodOutOfRange)?;
// Mirror the farming-pool ceiling — see #132.
if min_lock_period > MAX_MIN_LOCK_PERIOD {
return Err(FactoryError::MinLockPeriodAboveCeiling);
}

let pool_id: u32 = env.storage().instance().get(&DataKey::PoolCount).unwrap();
let next_count = pool_id
Expand Down
32 changes: 32 additions & 0 deletions soroban/contracts/factory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,38 @@ fn test_create_pool_rejects_min_lock_period_out_of_u32_range() {
assert_eq!(result, Err(Ok(FactoryError::MinLockPeriodOutOfRange)));
}

// ── #132: factory-side upper ceiling on min_lock_period ───────────────────────

#[test]
fn test_create_pool_rejects_min_lock_period_above_ceiling() {
let t = setup();
let asset = Address::generate(&t.env);

// MAX_MIN_LOCK_PERIOD + 1, still fits in u32 (12_614_401 << u32::MAX), so
// the u32-range check passes and only the new ceiling check fires.
let above_ceiling = (MAX_MIN_LOCK_PERIOD + 1) as u64;
let result = t
.client
.try_create_pool(&asset, &1_728_000u128, &2u32, &above_ceiling, &0i128);
assert_eq!(result, Err(Ok(FactoryError::MinLockPeriodAboveCeiling)));
}

#[test]
fn test_create_pool_accepts_min_lock_period_exactly_at_ceiling() {
let t = setup();
let asset = Address::generate(&t.env);

let pool_id = t.client.create_pool(
&asset,
&1_728_000u128,
&2u32,
&(MAX_MIN_LOCK_PERIOD as u64),
&0i128,
);
let record = t.client.get_pool(&pool_id);
assert_eq!(record.min_lock_period, MAX_MIN_LOCK_PERIOD);
}

#[test]
fn test_get_pool_bumps_pool_record_ttl() {
let t = setup();
Expand Down
2 changes: 2 additions & 0 deletions soroban/contracts/factory/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,6 @@ pub enum FactoryError {
InvalidGlobalMultiplier = 7,
/// `create_pool` cannot allocate another monotonically increasing pool ID.
PoolCountOverflow = 8,
/// `create_pool`'s `min_lock_period` exceeded `MAX_MIN_LOCK_PERIOD`. See #132.
MinLockPeriodAboveCeiling = 9,
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"generators": {
"address": 1,
"nonce": 0,
"mux_id": 0
},
"auth": [
[],
[]
],
"ledger": {
"protocol_version": 25,
"sequence_number": 0,
"timestamp": 0,
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
"base_reserve": 0,
"min_persistent_entry_ttl": 4096,
"min_temp_entry_ttl": 16,
"max_entry_ttl": 6312000,
"ledger_entries": [
{
"entry": {
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
"key": "ledger_key_contract_instance",
"durability": "persistent",
"val": {
"contract_instance": {
"executable": {
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"storage": null
}
}
}
},
"ext": "v0"
},
"live_until": 4095
},
{
"entry": {
"last_modified_ledger_seq": 0,
"data": {
"contract_code": {
"ext": "v0",
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"code": ""
}
},
"ext": "v0"
},
"live_until": 4095
}
]
},
"events": []
}
Loading