Files: contracts/token/src/lib.rs lines 12 to 31, test at 1275; contracts/vesting/src/lib.rs lines 13 to 26, test at 780; unclamped extend_ttl sites at token 216, 262, 265, 294, 511, 514, 612, 615 and vesting 689
Issue: #341 correctly replaced the copy-pasted "52 weeks" expression with one named constant. The constant's ceiling is wrong:
/// ... (`max_entry_ttl` in the network config; 6,312,000 ledgers on mainnet).
const MAX_ENTRY_TTL_LEDGERS: u32 = 6_312_000;
const TTL_LEDGERS: u32 = {
const YEAR_LEDGERS: u64 = 365 * 24 * 60 * 60 / 5; // 6,307,200
if YEAR_LEDGERS < MAX_ENTRY_TTL_LEDGERS as u64 { YEAR_LEDGERS as u32 }
else { MAX_ENTRY_TTL_LEDGERS }
};
6,312,000 is not the mainnet value. It is the soroban-sdk test-environment default, at soroban-sdk-21.7.7/src/env.rs:514:
max_entry_ttl: 6_312_000,
The live setting, read from the STATE_ARCHIVAL config-setting ledger entry on 2026-07-30, is 3,110,400 on both testnet and mainnet (min_persistent_ttl differs between them — 120,960 on testnet, 2,073,600 on mainnet — but max_entry_ttl does not). So TTL_LEDGERS resolves to 6,307,200, which is 2.03x what either network will honour, and the clamp that was added to guard against exactly this can never fire.
This does not brick anything, and it is important to be precise about why. soroban-env-host treats the two durabilities differently (storage.rs:521-537): for persistent entries it silently lowers new_live_until to the network maximum, and only for temporary entries does it return Storage/InvalidAction. All eight unclamped token sites and the one vesting site write persistent entries, so they are quietly clamped.
The real consequences are:
Note the contract already reads the value at runtime in two places (token lib.rs:558, vesting lib.rs:644), so the correct pattern is present in both files and simply not used at the other nine sites.
Fix: Delete MAX_ENTRY_TTL_LEDGERS and clamp every site with env.storage().max_ttl() at call time, keeping TTL_LEDGERS only as a desired-duration hint. Rewrite the doc comment to say the effective window is whatever the network allows, currently about 180 days, and that holders relying on longer must interact within it. Replace the test with one asserting TTL_LEDGERS >= env.storage().max_ttl() so the clamp is what is exercised. Note the test harness will keep reporting 6,312,000, so any test that hardcodes a network figure will mislead.
Files:
contracts/token/src/lib.rslines 12 to 31, test at 1275;contracts/vesting/src/lib.rslines 13 to 26, test at 780; unclampedextend_ttlsites at token 216, 262, 265, 294, 511, 514, 612, 615 and vesting 689Issue: #341 correctly replaced the copy-pasted "52 weeks" expression with one named constant. The constant's ceiling is wrong:
6,312,000 is not the mainnet value. It is the
soroban-sdktest-environment default, atsoroban-sdk-21.7.7/src/env.rs:514:The live setting, read from the
STATE_ARCHIVALconfig-setting ledger entry on 2026-07-30, is 3,110,400 on both testnet and mainnet (min_persistent_ttldiffers between them — 120,960 on testnet, 2,073,600 on mainnet — butmax_entry_ttldoes not). SoTTL_LEDGERSresolves to 6,307,200, which is 2.03x what either network will honour, and the clamp that was added to guard against exactly this can never fire.This does not brick anything, and it is important to be precise about why.
soroban-env-hosttreats the two durabilities differently (storage.rs:521-537): for persistent entries it silently lowersnew_live_untilto the network maximum, and only for temporary entries does it returnStorage/InvalidAction. All eight unclamped token sites and the one vesting site write persistent entries, so they are quietly clamped.The real consequences are:
test_ttl_ledgers_is_about_one_year(lib.rs:1275) assertsdays == 365and never compares the constant toenv.storage().max_ttl(), so it locks in the wrong figure and would fail if someone corrected it.Note the contract already reads the value at runtime in two places (
token lib.rs:558,vesting lib.rs:644), so the correct pattern is present in both files and simply not used at the other nine sites.Fix: Delete
MAX_ENTRY_TTL_LEDGERSand clamp every site withenv.storage().max_ttl()at call time, keepingTTL_LEDGERSonly as a desired-duration hint. Rewrite the doc comment to say the effective window is whatever the network allows, currently about 180 days, and that holders relying on longer must interact within it. Replace the test with one assertingTTL_LEDGERS >= env.storage().max_ttl()so the clamp is what is exercised. Note the test harness will keep reporting 6,312,000, so any test that hardcodes a network figure will mislead.