# TRSRY susceptible to loan / withdraw confusion

TRSRY shares one approval mapping for loans and withdrawals, letting a policy withdraw loan-approved funds directly without loan bookkeeping.

- Payout: Contest reward
- Severity: medium
- Program: Olympus DAO
- Credited: Trust
- Disclosed: 2022-10-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-08-olympus-findings/issues/75
- Library page: https://bugbountylibrary.com/r/c4%3A2022-08-olympus%3AM-29
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** TRSRY treasury module (Solidity smart contract)
**Root cause:** withdrawReserves() and getLoan() both validate and decrement the same withdrawApproval mapping via _checkApproval(), so loan approval is indistinguishable from withdraw approval.
**Steps:**
1. Policy P is granted getLoan permission and setApprovalFor(P, token, amount) is called for a loan.
2. P calls `withdrawReserves(address, token, amount)` instead of getLoan().
3. _checkApproval() passes against the shared withdrawApproval mapping and decrements it.
4. Funds leave treasury without being recorded as an outstanding loan.
**How found:** Code reading of TRSRY.sol withdrawReserves/getLoan: noticed both paths call the same _checkApproval() against a single withdrawApproval mapping, so no distinction exists between loan and withdraw authorization.
**Exploitation:** A policy with loan approval calls withdrawReserves directly, consuming the loan approval and extracting tokens with no loan bookkeeping, potentially leading to loss of funds (per judge reference to issue #293).
**Insight:** When two functions with different accounting semantics share one approval/allowance mapping, check whether consuming the shared allowance in the cheaper path skips the bookkeeping the other path enforces.
