Module: meridian-contracts/contracts/risk_pool/src/lib.rs
Problem
payout_claim (lib.rs:132) and withdraw_liquidity (lib.rs:99) both transfer
tokens to a recipient before updating on-chain accounting. The token
transfer (client.transfer, lib.rs:145) is a cross-contract call into an
arbitrary Stellar asset contract. A malicious or re-entrant token contract can
re-enter payout_claim/withdraw_liquidity (or another entry that mutates the
same AvailableCapital/ProviderStake storage) before balances are finalized,
double-spending pool capital. Stellar asset contracts are user-deployable, so
this is a real attack surface, not theoretical.
Deliverables
- Apply the checks-effects-interactions pattern: update all
AvailableCapital,
TotalCapital, ClaimsPaid and ProviderStake storage before the
token::Client::transfer call in payout_claim, withdraw_liquidity, and
deposit_liquidity.
- Add an explicit re-entrancy guard (a transient
Instance/Persistent bool
flag set at entry, cleared at exit) mirroring the require_not_paused pattern
used in the escrow contract (meridian-contracts/contracts/escrow/src/validation.rs).
- Write an integration test using a malicious mock token contract that attempts
to re-enter during the transfer and assert capital is conserved.
- Document the invariant in a short comment on each affected function.
Acceptance criteria
- All three functions update storage before external calls.
- A re-entrancy test fails before the fix and passes after.
Module:
meridian-contracts/contracts/risk_pool/src/lib.rsProblem
payout_claim(lib.rs:132) andwithdraw_liquidity(lib.rs:99) both transfertokens to a recipient before updating on-chain accounting. The token
transfer (
client.transfer, lib.rs:145) is a cross-contract call into anarbitrary Stellar asset contract. A malicious or re-entrant token contract can
re-enter
payout_claim/withdraw_liquidity(or another entry that mutates thesame
AvailableCapital/ProviderStakestorage) before balances are finalized,double-spending pool capital. Stellar asset contracts are user-deployable, so
this is a real attack surface, not theoretical.
Deliverables
AvailableCapital,TotalCapital,ClaimsPaidandProviderStakestorage before thetoken::Client::transfercall inpayout_claim,withdraw_liquidity, anddeposit_liquidity.Instance/Persistentboolflag set at entry, cleared at exit) mirroring the
require_not_pausedpatternused in the escrow contract (
meridian-contracts/contracts/escrow/src/validation.rs).to re-enter during the transfer and assert capital is conserved.
Acceptance criteria