Implement Base Reserve Storage Layer #35#36
Merged
phertyameen merged 4 commits intobridgelet-org:mainfrom Feb 25, 2026
Merged
Conversation
…n of my reserve contract
phertyameen
approved these changes
Feb 25, 2026
Contributor
phertyameen
left a comment
There was a problem hiding this comment.
@Joaco2603
This is awesome. Learnt alot from the well explained pr message. I will create the issue to handle the sweep controller failled tests too. Could really use your expertise soon. Could you drop your telegram username as a comment so I can add you to the bridglet group?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement Base Reserve Storage Layer #35
Closes #35
Purpose
reserve_contractis a focused Soroban smart contract that stores and exposes the base reserve configuration for the Bridgelet system.In the Stellar network, every account must keep a minimum XLM balance (the base reserve) to remain open. Bridgelet's ephemeral accounts query this value to know how much XLM is network overhead (that must be returned to the creator on close) versus how much belongs to the actual user payment.
This contract answers one question: "what is the configured base reserve, in stroops?"
File Structure
Public API
All entry points are defined in
src/lib.rsonReserveContract.initialize(admin: Address) → Result<(), Error>One-time setup. Stores the admin address that will be allowed to set the reserve. Calling it a second time returns
Error::AlreadyInitialized(code#4).set_base_reserve(amount: i128) → Result<(), Error>Stores a new base reserve value (in stroops). Only the admin may call this. Overwrites any previous value and emits a
BaseReserveUpdatedevent for off-chain auditability.Safety ceiling:
MAX_RESERVE_STROOPS = 100_000_000_000(10,000 XLM). This prevents accidental misconfiguration (e.g. passing a value in XLM instead of stroops).get_base_reserve() → Option<i128>Returns
Some(amount)if configured,Noneotherwise. Safe default — callers must handle the unset case explicitly.require_base_reserve() → Result<i128, Error>Returns the reserve or
Error::ReserveNotSet(#2) if not configured. Use this when the consumer requires the value to exist before proceeding (e.g. during a sweep flow).has_base_reserve() → boolCheaper presence check — returns
true/falsewithout reading the actual value.get_admin() → Option<Address>Returns the admin address if the contract has been initialized.
Storage
All data lives in instance storage, meaning it is tied to the contract instance's lifecycle and shares one TTL with the contract itself.
DataKey)BaseReservei128AdminAddressTTL is proactively extended on every public entry-point call (reads included) to prevent the contract from being archived during inactivity.
Errors
Defined in
src/errors.rsas a#[contracterror]enum:#1InvalidAmount#2ReserveNotSetrequire_base_reservecalled before any value is stored#3Unauthorized#4AlreadyInitializedinitializecalled more than once#5NotInitializedset_base_reservecalled beforeinitialize#6AmountTooLargeEvents
Defined in
src/events.rs:"init"ContractInitializedadmin: Address"reserve"BaseReserveUpdatedold_value: i128,new_value: i128,admin: Addressold_valueis0when no prior reserve existed, making event history self-contained for off-chain indexers.Access Control Flow
Test Coverage
20 tests in
src/test.rs, grouped by concern:test_initialize_stores_admin,test_initialize_twice_panicstest_set_base_reserve_before_initialize_panicstest_get_base_reserve_returns_none_when_not_set,test_has_base_reserve_returns_false_when_not_set,test_require_base_reserve_panics_when_not_settest_set_and_get_base_reserve,test_set_base_reserve_minimum_valid_valuetest_set_base_reserve_overwrites_previous_valuetest_set_base_reserve_zero_is_rejected,test_set_base_reserve_negative_is_rejected,test_set_base_reserve_min_i128_is_rejectedtest_set_base_reserve_at_max_is_accepted,test_set_base_reserve_above_max_is_rejected,test_set_base_reserve_huge_value_is_rejectedtest_two_contracts_are_independenttest_get_admin_returns_none_before_init,test_get_admin_returns_admin_after_inittest_ttl_extended_after_read,test_ttl_extended_after_writeTest helpers
create_env()— builds aEnvwithmin_persistent_entry_ttl = 50(below TTL threshold) andmax_entry_ttl = 600_000(above extend target) so TTL assertions are reliable.setup()— deploys and initializes a contract; returns(env, client, admin, contract_id).setup_uninitialized()— deploys only, noinitializecall.assert_ttl_extended(env, contract_id)— reads the instance TTL inside the contract context and asserts it is ≥ 518,400 ledgers.Running the Tests
cargo test -p reserve_contractAll 20 tests should pass. Snapshots live in
test_snapshots/test/test/and are updated automatically when the contract's observable behaviour changes.🐛 Bug Report:
sweep_controller— Integration Tests FailingDate: 2026-02-23
Contract:
contracts/sweep_controllerFiles affected:
contracts/sweep_controller/tests/integration.rscontracts/sweep_controller/src/authorization.rsDescription
The integration tests in
contracts/sweep_controller/tests/integration.rsdo not pass. Multiple tests fail or produce misleading results because they use hardcoded dummy Ed25519 signatures (e.g.,[0u8; 64],[1u8; 64],[2u8; 64]) while the contract performs real cryptographic Ed25519 verification viaenv.crypto().ed25519_verify().In the Soroban SDK,
ed25519_verifydoes not return aResult— it panics when the signature is invalid. This causes tests that expect a successful sweep to panic unexpectedly, and tests that attempt to catch errors viastd::panic::catch_unwindto catch the wrong kind of failure.