| type | Feature |
|---|---|
| title | Add a clear_sme_collateral_commitment entrypoint to release recorded collateral metadata |
| labels | type:feature, area:collateral, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN |
| assignees |
record_sme_collateral_commitment in escrow/src/lib.rs writes a metadata-only DataKey::SmeCollateralPledge and emits CollateralRecordedEvt, but there is no way to remove it. Once recorded, the commitment lingers in storage and is surfaced by get_sme_collateral_commitment forever, even after the underlying pledge is released off-chain — so indexers and dashboards report stale collateral on a settled or cancelled invoice.
This issue adds an SME-authorized clear_sme_collateral_commitment() that removes the pledge entry and emits a dedicated retirement event, mirroring the existing record path.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add
clear_sme_collateral_commitment(env) -> ()that loads the escrow viaload_escrow_require_sme, asserts a commitment exists (append-only typed errorNoCollateralToClear), removesDataKey::SmeCollateralPledge, and emits a newCollateralClearedEvt#[contractevent]carryinginvoice_idand the prior amount. - Preserve the metadata-only semantics documented on
record_sme_collateral_commitment: no token movement, no balance reservation. - Keep guard ordering consistent with ADR-002 (read-only existence check, then
require_auth, then the storage remove and event). - Do not renumber existing
EscrowErrorcodes; append the new variant.
- Fork the repo and create a branch
git checkout -b feature/contracts-clear-sme-collateral- Implement changes
- Write code in:
escrow/src/lib.rs—clear_sme_collateral_commitment,CollateralClearedEvt,NoCollateralToClear. - Write comprehensive tests in:
escrow/src/tests/coverage.rs— record then clear, clear-without-record rejection, non-SME caller rejection, event payload. - Add documentation: update
docs/escrow-sme-collateral.mdand the README entrypoint table. - Include NatSpec-style
///comments on the new entrypoint and event. - Validate security: SME-only auth, no token movement, idempotent removal.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: clear with no prior commitment, wrong caller, clear after settle/cancel.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add clear_sme_collateral_commitment entrypoint to retire collateral metadata with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Expose the configured yield-tier table through a read-only view" labels: type:feature, area:read-api, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
init in escrow/src/lib.rs persists an optional DataKey::YieldTierTable (validated by validate_yield_tiers_table) and fund_with_commitment consumes it via effective_yield_for_commitment, but there is no public getter for the tier table. Investors deciding which committed_lock_secs to pick, and dashboards rendering the tier ladder, cannot read the on-chain tiers — they must reconstruct them from the EscrowInitialized event or off-chain config.
This issue adds a pure get_yield_tiers(env) -> Vec<YieldTier> read returning the stored table (empty when none was configured).
- Repository scope: Liquifact/Liquifact-contracts only.
- Add
get_yield_tiers(env) -> Vec<YieldTier>readingDataKey::YieldTierTable, returning an emptyVecwhen unset (matching theinit"empty tiers not stored" behavior). - Pure read: no auth, no state change; consistent with the other
get_*views. - Document that the returned order matches the validated non-decreasing tier ordering enforced at
init.
- Fork the repo and create a branch
git checkout -b feature/contracts-get-yield-tiers- Implement changes
- Write code in:
escrow/src/lib.rs—get_yield_tiersview. - Write comprehensive tests in:
escrow/src/tests/funding.rs— table round-trips through init, empty when no tiers, ordering preserved. - Add documentation: update
docs/escrow-read-api.mdand ADR-005. - Include NatSpec-style
///comments on the view. - Validate security: pure read, no auth, no mutation.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: no tiers, single tier, multi-tier ordering, legacy instance.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add get_yield_tiers read view for the configured tier table with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add a funding deadline so under-funded escrows can expire and become cancellable" labels: type:feature, area:funding, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The escrow in escrow/src/lib.rs has no time limit on the open (status 0) funding window: fund_impl accepts deposits indefinitely while status == 0, and cancel_funding requires the admin to act manually. There is no on-chain signal that a primary issuance has stalled, so investors' principal can sit in an open escrow with no automatic recovery trigger.
This issue adds an optional funding_deadline (ledger timestamp) configured at init: after it passes, new fund calls are rejected and the escrow is eligible for cancellation/refund recovery.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add an
Option<u64> funding_deadlineparameter toinit, validated (0/absent ⇒ no deadline; otherwise must be> now), stored under a newDataKey::FundingDeadline. - In
fund_impl, after the status/legal-hold checks, reject deposits when a deadline is set andnow > deadlinewith an append-only typed errorFundingDeadlinePassed. - Add a pure
get_funding_deadline(env) -> Option<u64>view and anis_funding_expired(env) -> boolhelper. - Preserve the
funding_deadline == 0"no deadline" semantics; do not affect already-funded (status 1) escrows.
- Fork the repo and create a branch
git checkout -b feature/contracts-funding-deadline- Implement changes
- Write code in:
escrow/src/lib.rs—DataKey::FundingDeadline, init param/validation, fund gate, views, error. - Write comprehensive tests in:
escrow/src/tests/funding.rs— fund before/after deadline, no-deadline default,is_funding_expiredtransitions usingLedgertestutils. - Add documentation: update
docs/escrow-lifecycle.mdanddocs/escrow-ledger-time.md. - Include NatSpec-style
///comments on the new param, views, and error. - Validate security: deadline cannot retroactively trap funded escrows; ledger-time trust model documented.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: no deadline, exactly at deadline, after deadline, funded before deadline.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add optional funding deadline gating fund and recovery with tests and docs
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add an admin entrypoint to rebind the off-chain registry reference" labels: type:feature, area:admin, stack:soroban, stack:rust, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
init in escrow/src/lib.rs optionally stores DataKey::RegistryRef, surfaced by get_registry_ref, but the pointer is write-once at init — there is no entrypoint to update it. If the off-chain registry contract is redeployed or the address was set incorrectly, the escrow points at a stale registry for its entire life with no recovery short of redeploying the whole escrow.
This issue adds an admin-gated set_registry_ref(new_registry: Option<Address>) so the reference can be corrected or cleared.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add
set_registry_ref(env, new_registry: Option<Address>)gated viaload_escrow_require_admin;SomesetsDataKey::RegistryRef,Noneremoves it. - Emit a new
RegistryRefUpdated#[contractevent]carryinginvoice_id, the prior registry (if any), and the new value for indexers. - The registry is an informational pointer only; document that rebinding does not migrate or revalidate any registry-side state.
- Keep ADR-002 guard ordering: load escrow + admin
require_authbefore the storage write.
- Fork the repo and create a branch
git checkout -b feature/contracts-set-registry-ref- Implement changes
- Write code in:
escrow/src/lib.rs—set_registry_ref,RegistryRefUpdatedevent. - Write comprehensive tests in:
escrow/src/tests/admin.rs— set, clear, non-admin rejection,get_registry_refreflects update, event payload. - Add documentation: update
docs/escrow-data-model.mdand the README entrypoint table. - Include NatSpec-style
///comments on the entrypoint and event. - Validate security: admin-only, no impact on funds or status.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: set from none, overwrite existing, clear to none, non-admin caller.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add admin set_registry_ref entrypoint to rebind the registry pointer with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add a remaining-funding-capacity read view for the open funding window" labels: type:enhancement, area:read-api, stack:soroban, stack:rust, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
Front-ends sizing a deposit must currently read InvoiceEscrow::funding_target and funded_amount separately from get_escrow/get_escrow_summary (escrow/src/lib.rs) and subtract them client-side, re-deriving the saturating semantics. There is no single on-chain view that answers "how much more can be funded before the target is reached?", and over-funding past the target is permitted, which clients frequently mishandle.
This issue adds a pure get_remaining_funding_capacity(env) -> i128 view returning max(0, funding_target - funded_amount).
- Repository scope: Liquifact/Liquifact-contracts only.
- Add
get_remaining_funding_capacity(env) -> i128returningfunding_target.saturating_sub(funded_amount)clamped at0so it never goes negative when over-funded. - Pure read, no auth, no mutation; reuse the loaded escrow.
- Document that this is informational only —
fundmay still accept deposits that over-fund past the target whilestatus == 0.
- Fork the repo and create a branch
git checkout -b feature/contracts-remaining-capacity-view- Implement changes
- Write code in:
escrow/src/lib.rs—get_remaining_funding_capacityview. - Write comprehensive tests in:
escrow/src/tests/funding.rs— capacity at zero/partial/exact/over-funded states. - Add documentation: update
docs/escrow-read-api.md. - Include NatSpec-style
///comments on the view. - Validate security: clamped non-negative, no mutation.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: unfunded, partially funded, exactly funded, over-funded.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add get_remaining_funding_capacity read view with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Extend EscrowSummary with collateral commitment and attestation status" labels: type:enhancement, area:read-api, stack:soroban, stack:rust, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
get_escrow_summary in escrow/src/lib.rs bundles core state (escrow, legal hold, snapshot, funder count, allowlist flag, schema version) into a single EscrowSummary host call, but it omits two metadata families that callers must fetch separately: the SME collateral commitment (get_sme_collateral_commitment) and the attestation binding (get_primary_attestation_hash / append-log length). Dashboards therefore make three extra round-trips for a complete view.
This issue extends EscrowSummary (additively) with collateral presence/amount and attestation status so one call returns the full picture.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add fields to
EscrowSummary: an optional collateral commitment (Option<SmeCollateralCommitment>), whether a primary attestation hash is bound (bool), and the attestation append-log length (u32). - Populate them in
get_escrow_summaryby reusing existing getters; keep the existing fields and their order stable per the additive-key policy (ADR-007). - Pure read, no auth; ensure legacy instances with no collateral/attestation return the unset/zero defaults.
- Fork the repo and create a branch
git checkout -b feature/contracts-summary-collateral-attestation- Implement changes
- Write code in:
escrow/src/lib.rs— extendEscrowSummaryandget_escrow_summary. - Write comprehensive tests in:
escrow/src/tests/coverage.rs— summary with/without collateral and attestations, log-length accuracy. - Add documentation: update
docs/escrow-read-api.mdanddocs/escrow-data-model.md. - Include NatSpec-style
///comments on the new fields. - Validate security: pure read, defaults for legacy state, stable field ordering.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: no collateral, recorded collateral, no attestation, bound + appended attestations.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: extend EscrowSummary with collateral and attestation status with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Make the dust-sweep per-call ceiling an admin-configurable parameter" labels: type:feature, area:treasury, stack:soroban, stack:rust, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
sweep_terminal_dust in escrow/src/lib.rs hard-caps each sweep at the compile-time constant MAX_DUST_SWEEP_AMOUNT (100_000_000 base units), rejecting larger requests with SweepAmountExceedsMax. For high-decimal tokens or large rounding residues this fixed ceiling can be too small, forcing many repeated sweeps; for low-value tokens it may be looser than desired. The cap cannot be tuned per deployment.
This issue adds an optional admin-configured override stored at init/via an admin setter, falling back to MAX_DUST_SWEEP_AMOUNT when unset.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add
DataKey::MaxDustSweepOverride(i128); add an admin entrypointset_max_dust_sweep(env, cap: i128)validated tocap > 0, gated viaload_escrow_require_admin, emitting aMaxDustSweepUpdatedevent. - In
sweep_terminal_dust, use the override when present, otherwiseMAX_DUST_SWEEP_AMOUNT; keep the liability-floor invariant unchanged. - Add a
get_max_dust_sweep(env) -> i128view returning the effective cap. - Append any new
EscrowErrorcodes; never renumber.
- Fork the repo and create a branch
git checkout -b feature/contracts-configurable-dust-cap- Implement changes
- Write code in:
escrow/src/lib.rs— override key,set_max_dust_sweep, getter, sweep cap logic, event. - Write comprehensive tests in:
escrow/src/tests/integration.rs— default cap, raised cap allows larger sweep, lowered cap rejects, non-admin setter rejection, liability floor still holds. - Add documentation: update
docs/escrow-gas-storage-notes.mdand ADR-006. - Include NatSpec-style
///comments on the setter, getter, and event. - Validate security: admin-only override, positive bound, floor invariant preserved.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: unset default, exactly at override, above override, non-admin caller, floor interaction.
- Include full
cargo testoutput and a short security notes section in the PR.
feat: add admin-configurable dust-sweep cap overriding the compile-time max with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add tests for the attestation bind and bounded append-log flow" labels: type:test, area:attestations, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
bind_primary_attestation_hash and append_attestation_digest in escrow/src/lib.rs implement a write-once primary hash plus a bounded append-only audit chain (capped at MAX_ATTESTATION_APPEND_ENTRIES = 32), with typed errors PrimaryAttestationAlreadyBound and AttestationAppendLogCapacityReached. These admin-gated funds-adjacent provenance writes need dedicated coverage in escrow/src/tests/attestations.rs to prove write-once, capacity, indexing, and auth boundaries.
This issue adds an exhaustive attestation test suite.
- Repository scope: Liquifact/Liquifact-contracts only.
- Assert
bind_primary_attestation_hashsucceeds once and rejects a second bind withPrimaryAttestationAlreadyBound;get_primary_attestation_hashreflects the bound value. - Assert
append_attestation_digestappends in order, increments the index inAttestationDigestAppended, and rejects the 33rd entry withAttestationAppendLogCapacityReached;get_attestation_append_logreturns the full ordered vector. - Assert both entrypoints reject non-admin callers via
mock_auths. - No production change unless a real gap surfaces (then file/fix separately).
- Fork the repo and create a branch
git checkout -b test/contracts-attestation-flow- Implement changes
- Write code in:
escrow/src/lib.rs— only if a gap surfaces. - Write comprehensive tests in:
escrow/src/tests/attestations.rs— bind, re-bind rejection, append ordering, capacity, auth. - Add documentation: cross-link scenarios in
docs/escrow-attestations.md. - Include NatSpec-style
///comments on shared helpers. - Validate security: write-once primary, bounded log growth, admin-only.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: empty log, full log boundary, double bind, non-admin caller.
- Include full
cargo testoutput and a short security notes section in the PR.
test: add coverage for attestation bind and bounded append-log flow
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add tests for the SME collateral commitment record and replace path" labels: type:test, area:collateral, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
record_sme_collateral_commitment in escrow/src/lib.rs is a metadata-only write with non-trivial validation: positive amount (CollateralAmountNotPositive), non-empty asset symbol (CollateralAssetEmpty), monotonic recorded_at on replacement (CollateralTimestampBackwards), SME-only auth, and a CollateralRecordedEvt carrying the prior amount. This path has no dedicated coverage proving each validation branch and the replace-overwrite behavior.
This issue adds a focused collateral-commitment test suite.
- Repository scope: Liquifact/Liquifact-contracts only.
- Assert a first record succeeds and
get_sme_collateral_commitmentreturns the asset/amount/timestamp; the event'sprior_amountis0. - Assert replacement overwrites and emits the prior amount; assert a backwards ledger timestamp is rejected with
CollateralTimestampBackwardsusingLedgertestutils. - Assert rejection of zero/negative amount and empty asset symbol, and that a non-SME caller is rejected.
- Confirm the metadata-only invariant: no token balance changes occur.
- Fork the repo and create a branch
git checkout -b test/contracts-collateral-commitment- Implement changes
- Write code in:
escrow/src/lib.rs— only if a gap surfaces. - Write comprehensive tests in:
escrow/src/tests/coverage.rs— record, replace, validation rejections, auth, no token movement. - Add documentation: cross-link scenarios in
docs/escrow-sme-collateral.md. - Include NatSpec-style
///comments on helpers. - Validate security: SME-only, validation completeness, metadata-only.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: zero amount, empty asset, backwards timestamp, replace, non-SME caller.
- Include full
cargo testoutput and a short security notes section in the PR.
test: add coverage for SME collateral commitment record and replace path
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add dual-authorization tests for the beneficiary rotation entrypoint" labels: type:test, area:beneficiary-rotation, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
rotate_beneficiary in escrow/src/lib.rs is a funds-routing-critical entrypoint: it changes sme_address (the withdrawal recipient) and uniquely requires both the outgoing SME and the admin to authorize, only in pre-settlement states (status 0 or 1), with a no-op guard (NewSmeSameAsCurrent), a state guard (RotationNotOpen), and a legal-hold gate. This dual-auth path has no dedicated test asserting that a single signer is insufficient.
This issue adds a rotation test suite covering both signers, the guards, and the emitted event.
- Repository scope: Liquifact/Liquifact-contracts only.
- Assert rotation succeeds only when both SME and admin authorize; assert it fails with only SME, only admin, or neither (via
mock_auths). - Assert
BeneficiaryRotatedcarries the correct prior/new SME and that a subsequentwithdrawwould route to the new beneficiary. - Assert guards:
NewSmeSameAsCurrent(no-op),RotationNotOpen(settled/withdrawn/cancelled), andLegalHoldBlocksBeneficiaryRotationwhile a hold is active. - No production change unless a guard gap surfaces.
- Fork the repo and create a branch
git checkout -b test/contracts-beneficiary-rotation- Implement changes
- Write code in:
escrow/src/lib.rs— only if a gap surfaces. - Write comprehensive tests in:
escrow/src/tests/admin.rs— dual-auth matrix, guards, event, post-rotation withdraw target. - Add documentation: cross-link scenarios in
docs/ESCROW_BENEFICIARY_ROTATION.md. - Include NatSpec-style
///comments on helpers. - Validate security: both signers required; rotation blocked post-settlement and under hold.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: missing one signer, same-address no-op, wrong status, legal hold active.
- Include full
cargo testoutput and a short security notes section in the PR.
test: add dual-auth and guard tests for rotate_beneficiary
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Add boundary tests for min-contribution floor and the per-investor and unique caps" labels: type:test, area:investor-caps, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
fund_impl in escrow/src/lib.rs enforces three independent limits: a per-call minimum (MinContributionFloor ⇒ FundingBelowMinContribution), a cumulative per-investor cap (MaxPerInvestorCap ⇒ InvestorContributionExceedsCap), and a distinct-funder cap (MaxUniqueInvestorsCap ⇒ UniqueInvestorCapReached), plus their init-time validation (MinContributionNotPositive, MinContributionExceedsAmount, MaxPerInvestorNotPositive, MaxUniqueInvestorsNotPositive). These boundary conditions need exhaustive coverage at the exact limit values.
This issue adds boundary tests for each floor/cap, including the interaction with follow-on deposits.
- Repository scope: Liquifact/Liquifact-contracts only.
- Floor: deposit below floor rejected, exactly at floor accepted, follow-on below floor still rejected (floor applies per call).
- Per-investor cap: cumulative deposits exactly at cap accepted, one over rejected (across multiple
fundcalls). - Unique cap: distinct funders up to the cap accepted, the next new funder rejected, while follow-on deposits from existing funders still succeed.
- Init validation: assert each
init-time rejection for non-positive/over-amount configurations.
- Fork the repo and create a branch
git checkout -b test/contracts-caps-and-floor-boundaries- Implement changes
- Write code in:
escrow/src/lib.rs— only if a gap surfaces. - Write comprehensive tests in:
escrow/src/tests/cap_validation.rs— floor, per-investor cap, unique cap, init validation boundaries. - Add documentation: cross-link scenarios in
docs/escrow-investor-caps.md. - Include NatSpec-style
///comments on helpers. - Validate security: caps and floor are inclusive/exclusive exactly as documented.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: exact floor, exact per-investor cap, exact unique cap, follow-on deposits, init validation failures.
- Include full
cargo testoutput and a short security notes section in the PR.
test: add boundary tests for min-contribution floor and investor caps
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Convert the tiered second-deposit panic in fund_with_commitment to a typed error" labels: type:security, area:errors, stack:soroban, stack:rust, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
fund_impl (reached via fund_with_commitment) in escrow/src/lib.rs still uses a raw assert! with a panic string — "Additional principal after a tiered first deposit must use fund(), not fund_with_commitment()" — when an investor with an existing contribution (prev != 0) calls the commitment path again. Every other funding guard uses the append-only EscrowError enum, and the contract's SDK contract is that callers "branch on the numeric code rather than legacy panic strings". This one assert breaks that discipline on a funding-critical path.
This issue replaces the assert with a typed error.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add an append-only
EscrowErrorvariant (e.g.TieredSecondDepositNotAllowed); never renumber existing codes. - Replace the
assert!(prev == 0, ...)in the tiered branch withensure(&env, prev == 0, EscrowError::TieredSecondDepositNotAllowed). - Preserve exact behavior and guard ordering — only the revert type changes;
fund()follow-on deposits remain unaffected.
- Fork the repo and create a branch
git checkout -b security/contracts-tiered-second-deposit-typed-error- Implement changes
- Write code in:
escrow/src/lib.rs— new error variant andensurecall. - Write comprehensive tests in:
escrow/src/tests/funding.rs— assert the typed error viatry_fund_with_commitmentafter a prior deposit; assertfund()follow-on still works. - Add documentation: update
docs/escrow-error-messages.mdand ADR-005. - Include NatSpec-style
///comments on the new variant. - Validate security: identical revert condition, stable numeric codes.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: tiered first deposit then tiered second (rejected), tiered first then
fund(accepted). - Include full
cargo testoutput and a short security notes section in the PR.
fix: replace tiered second-deposit panic with typed EscrowError in fund_with_commitment with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Bound the commitment lock so an investor claim cannot be locked past maturity" labels: type:security, area:tiered-yield, stack:soroban, stack:rust, priority:high, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
In fund_impl (escrow/src/lib.rs) a tiered deposit derives InvestorClaimNotBefore = now + committed_lock_secs, enforced later in claim_investor_payout via InvestorCommitmentLockNotExpired. The lock is only checked for arithmetic overflow (InvestorClaimTimeOverflow); it is not bounded relative to the escrow's maturity. A tier lock longer than the maturity window means a settled escrow (status 2) holds an investor's payout claim hostage past the point where principal is due — funds the investor is entitled to are unclaimable until the lock expires.
This issue rejects, at deposit time, any commitment lock that would push the claim time beyond settlement maturity.
- Repository scope: Liquifact/Liquifact-contracts only.
- When
committed_lock_secs > 0and the escrow has a maturity lock (maturity > 0), reject the deposit ifnow + committed_lock_secs > maturitywith a new append-onlyEscrowError(e.g.CommitmentLockExceedsMaturity). - Preserve the
committed_lock_secs == 0(no lock) andmaturity == 0(no maturity lock) semantics — only constrain when both are set. - Keep the existing
InvestorClaimTimeOverflowoverflow guard; this is an additional, narrower bound.
- Fork the repo and create a branch
git checkout -b security/contracts-commitment-lock-bound- Implement changes
- Write code in:
escrow/src/lib.rs— bound check in the tiered branch, new error variant. - Write comprehensive tests in:
escrow/src/tests/funding.rs— lock within maturity accepted, lock past maturity rejected, no-maturity escrow unaffected, zero-lock unaffected, usingLedgertestutils. - Add documentation: update ADR-005 and
docs/escrow-legal-hold.mdcross-reference for claim timing. - Include NatSpec-style
///comments on the new bound and error. - Validate security: no payout can be locked beyond the funds-due maturity.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: lock exactly at maturity, lock one second past maturity, no maturity, zero lock.
- Include full
cargo testoutput and a short security notes section in the PR.
fix: bound commitment lock to settlement maturity in fund_with_commitment with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Document the SME collateral commitment model and its metadata-only guarantees" labels: type:docs, area:collateral, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
record_sme_collateral_commitment in escrow/src/lib.rs carries an important and easily-misread guarantee: it is metadata-only — it writes DataKey::SmeCollateralPledge and emits CollateralRecordedEvt but does not transfer tokens, reserve balances, verify custody, create an on-chain encumbrance, or block any flow. Misreading this as an enforced lien is a material risk for integrators. The existing docs/escrow-sme-collateral.md should be made authoritative and code-accurate.
This issue produces a complete, code-accurate collateral-commitment document.
- Repository scope: Liquifact/Liquifact-contracts only.
- Document the SME-only auth, the validation rules (positive amount, non-empty asset symbol, monotonic
recorded_aton replace), and replacement semantics with theprior_amountevent field. - Prominently state the metadata-only limitations and contrast with the on-chain custody flows so integrators do not treat it as an enforced encumbrance.
- Reference the
SmeCollateralCommitmentstruct fields and theCollateralRecordedEvttopic/payload.
- Fork the repo and create a branch
git checkout -b docs/contracts-collateral-model- Implement changes
- Write code in:
escrow/src/lib.rs— only rustdoc clarifications if the inline comment drifts from docs. - Write comprehensive tests in:
escrow/src/tests/coverage.rs— a test asserting no token-balance change accompanies a record, anchoring the metadata-only claim. - Add documentation: rewrite/expand
docs/escrow-sme-collateral.md; cross-link fromREADME.md. - Include NatSpec-style
///comments where clarified. - Validate security: documented behavior matches enforced rules.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: record with/without replacement, asset symbol formatting, anchoring no-balance-change test.
- Include full
cargo testoutput and a short security notes section in the PR.
docs: document SME collateral commitment metadata-only model with anchoring test
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Document the beneficiary rotation flow and its dual-authorization requirement" labels: type:docs, area:beneficiary-rotation, stack:soroban, stack:rust, priority:medium, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
rotate_beneficiary in escrow/src/lib.rs changes the SME withdrawal recipient and is the only entrypoint requiring both the outgoing SME and the admin to sign, restricted to pre-settlement states (status 0/1), with a no-op guard and a legal-hold gate. Because it redirects where funded principal is eventually disbursed, its authorization model and timing constraints need a precise, code-accurate operator-facing document; docs/ESCROW_BENEFICIARY_ROTATION.md should be the authoritative reference.
This issue produces a complete rotation document.
- Repository scope: Liquifact/Liquifact-contracts only.
- Document the dual SME+admin
require_authrequirement, why both are needed, and the exact guard ordering (legal hold, status, no-op, dual auth). - Document the allowed states (open/funded only) and the rejection codes
RotationNotOpen,NewSmeSameAsCurrent,LegalHoldBlocksBeneficiaryRotation. - Explain the downstream effect on
withdraw(funds route to the newsme_address) and theBeneficiaryRotatedevent for indexers.
- Fork the repo and create a branch
git checkout -b docs/contracts-beneficiary-rotation- Implement changes
- Write code in:
escrow/src/lib.rs— only rustdoc corrections if inline docs drift. - Write comprehensive tests in:
escrow/src/tests/admin.rs— a test asserting post-rotation withdrawal target matches the new SME, anchoring the doc. - Add documentation: rewrite/expand
docs/ESCROW_BENEFICIARY_ROTATION.md; reconcile with ADR-002. - Include NatSpec-style
///comments where clarified. - Validate security: documented dual-auth matches enforced auth.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: rotation in open vs funded, blocked post-settlement, hold active, post-rotation withdraw target.
- Include full
cargo testoutput and a short security notes section in the PR.
docs: document beneficiary rotation dual-auth flow with anchoring test
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward. ++++++
type: Feature title: "Extract the repeated legal-hold and terminal-status gate checks into shared guard helpers" labels: type:refactor, area:guards, stack:soroban, stack:rust, priority:low, MAYBE REWARDED, GRANTFOX OSS, OFFICIAL CAMPAIGN assignees: ''
The legal-hold gate ensure(&env, !Self::legal_hold_active(&env), EscrowError::LegalHoldBlocks*) is repeated across fund_impl, settle, withdraw, claim_investor_payout, cancel_funding, rotate_beneficiary, and sweep_terminal_dust in escrow/src/lib.rs, each with a different error variant. Likewise the terminal-state check (status == 2 || status == 3 || status == 4) and the open-state check (status == 0) recur verbatim. The repeated, hand-written gates are error-prone — a future entrypoint can omit the hold check or mis-pick a status.
This issue extracts small named guard helpers parameterized by the error code, with no behavior change.
- Repository scope: Liquifact/Liquifact-contracts only.
- Add private helpers, e.g.
guard_not_legal_hold(&env, err: EscrowError),is_terminal_status(status: u32) -> bool, andguard_status_eq(&env, escrow_status, expected, err). - Replace the inline checks at each call site, preserving the exact error variant and ADR-002 guard ordering (legal-hold/status checks before
require_authwhere they already are). - No new errors, no behavior change; this is a readability/safety refactor only.
- Fork the repo and create a branch
git checkout -b refactor/contracts-shared-gate-helpers- Implement changes
- Write code in:
escrow/src/lib.rs— guard helpers and call-site replacement. - Write comprehensive tests in:
escrow/src/tests/coverage.rs— assert each refactored entrypoint still emits the same legal-hold/status error as before. - Add documentation: note the helpers in ADR-002 and
docs/escrow-security-checklist.md. - Include NatSpec-style
///comments on the helpers. - Validate security: identical gate conditions and error codes at every site.
- Write code in:
- Test and commit
- Run
cargo fmt --all -- --check,cargo build, andcargo test. - Cover edge cases: legal-hold-blocked path per entrypoint, terminal vs non-terminal status, open-state guard.
- Include full
cargo testoutput and a short security notes section in the PR.
refactor: extract shared legal-hold and status-gate helpers with tests
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.