Agent skill
flash-loan-interaction
Trigger Pattern FLASH_LOAN flag (required) or BALANCE_DEPENDENT flag (optional complement) - Inject Into Breadth agents, depth-token-flow, depth-edge-case
Install this agent skill to your Project
npx add-skill https://github.com/PlamenTSV/plamen/tree/main/agents/skills/sui/flash-loan-interaction
SKILL.md
FLASH_LOAN_INTERACTION Skill (Sui)
Trigger Pattern: FLASH_LOAN flag (required) or BALANCE_DEPENDENT flag (optional complement) Inject Into: Breadth agents, depth-token-flow, depth-edge-case Purpose: Analyze flash loan attack vectors in Sui Move protocols, focusing on hot potato receipt patterns and PTB-based atomic composition
For every flash-loan-accessible state variable or precondition in the protocol:
STEP PRIORITY: Steps 5 (Defense Audit) and 5b (Defense Parity) are where HIGH/CRITICAL severity findings most commonly hide. Do NOT rush these steps. If constrained, skip conditional sections (0c, 4) before skipping 5, 5b, or 3d.
0. External Flash Susceptibility Check
Before analyzing the protocol's OWN flash loan paths, check whether external protocols the contract interacts with are susceptible to third-party flash manipulation.
0a: External Interaction Inventory
| External Protocol | Interaction Type | State Read by Our Protocol | Can 3rd Party Flash-Manipulate That State? |
|---|---|---|---|
| {DEX/pool/vault} | {swap/deposit/query} | {reserves, price, balance} | {YES if spot state / NO if TWAP or time-weighted} |
Sui-specific: Check interactions with known flash loan providers on the target chain (e.g., CLMM DEXs, lending protocols, orderbook DEXs). Each may provide flash loan functionality via hot potato receipts within PTBs.
0b: Third-Party Flash Attack Modeling
For each external state marked YES in 0a, model:
- Before: Protocol reads external state X (e.g., pool reserves, spot price)
- Flash manipulate: Attacker flash-borrows from {source} and trades on the external protocol to move state X
- Victim call: Attacker calls OUR protocol function that reads manipulated state X -- all within the SAME PTB
- Restore: Attacker reverses the external manipulation
- Impact: What did the attacker gain from our protocol acting on manipulated state?
Key question: Does our protocol use spot state (manipulable) or time-weighted state (resistant)?
0c: DEX Price Manipulation Cost Estimation
For each external DEX/pool whose spot state is read by the protocol, estimate manipulation cost:
| Pool | Liquidity (USD) | Target Price Change | Est. Trade Size | Slippage Cost | Protocol Extractable Value | Profitable? |
|---|---|---|---|---|---|---|
| {pool} | {TVL} | {%} | {USD} | {USD} | {USD} | {YES/NO} |
Sui DEX types:
- CLOB (DeepBook): Manipulation via limit order placement + market orders. Cost depends on order book depth.
- CLMM DEXs: Concentrated liquidity -- manipulation cost depends on liquidity in active tick range, not total TVL.
- AMM (other): Standard constant-product --
price_impact = trade_size / (reserve + trade_size).
1. Flash-Loan-Accessible State Inventory
Enumerate ALL protocol state that can be manipulated within a single PTB via flash-borrowed capital:
| State Variable / Query | Location | Read By | Write Path | Flash-Accessible? | Manipulation Cost |
|---|---|---|---|---|---|
balance::value(&pool.balance) |
{module} | {functions} | deposit/withdraw | YES | Deposit amount |
pool.total_supply |
{module} | {functions} | mint/burn | YES if permissionless | Deposit amount |
| DEX pool reserves | {external} | {functions} | Swap | YES | Slippage cost |
| Oracle spot price | {external} | {functions} | Trade on source | YES | Market depth |
| Threshold/quorum state | {module} | {functions} | Deposit/stake | YES | Threshold amount |
Sui-specific flash loan mechanics:
- Flash loans on Sui use the hot potato pattern: a
FlashLoanReceiptstruct with NO abilities (nokey,store,copy, ordrop). It MUST be consumed by the repay function in the same PTB. - PTBs allow up to 1024 commands -- an attacker can compose: borrow -> N manipulations -> exploit -> repay in a single atomic transaction.
- No callback mechanism needed -- PTB command sequencing handles atomicity.
- Flash loan sources: lending protocols (
flash_loan/repay_flash_loanpatterns), DEX flash swaps, flash mint mechanisms.
For each YES entry: trace all functions that READ this state and make decisions based on it.
Rule 15 check: For each balance/oracle/threshold/rate precondition, model the flash loan atomic sequence within a PTB.
2. Atomic Attack Sequence Modeling
For each flash-loan-accessible state identified in Step 1:
Attack Template (PTB-Based)
PTB Commands:
1. BORROW: Call flash_loan({amount}, {token}) on {source} -> receive Coin<T> + FlashLoanReceipt
2. MANIPULATE: {action} to change {state_variable} from {value_before} to {value_after}
3. CALL: Invoke {target_function} on our protocol which reads manipulated state
4. EXTRACT: {what_is_gained} -- quantify: {amount}
5. RESTORE: {action} to return state (if needed for repayment)
6. REPAY: Call repay_flash_loan(receipt, coin) -- consumes hot potato receipt
7. PROFIT: {extract - fee - gas} = {net_profit}
Profitability gate: If net_profit <= 0 for all realistic amounts -> document as NON-PROFITABLE but check Step 3 for multi-call chains.
For each sequence, verify:
- Can steps 2-5 execute within a single PTB (max 1024 commands)?
- Does any step abort under normal conditions?
- Is the manipulation detectable/preventable by the protocol?
- What is the minimum flash loan amount needed?
- Does the hot potato receipt enforce correct repayment (amount + fee)?
3. Cross-Function Flash Loan Chains
Model multi-call atomic sequences within a single PTB:
| PTB Cmd | Function Called | Shared Object State Before | State After | Enables Next Step? |
|---|---|---|---|---|
| 1 | {function_A} | {state} | {state'} | YES -- changes {X} |
| 2 | {function_B} | {state'} | {state''} | YES -- enables {Y} |
| N | {function_N} | {state^N} | {final} | EXTRACT profit |
Key question: Can calling function A then function B in the same PTB produce a state that neither function alone could create?
Common Sui multi-call patterns:
- Deposit -> manipulate share price -> withdraw (sandwich own deposit)
- Stake -> trigger reward calculation -> unstake (flash-stake rewards)
- Flash borrow -> inflate collateral value -> borrow against inflated collateral -> repay flash loan
- Deposit to inflate shares -> withdraw deflated shares
- Flash borrow -> manipulate oracle state -> liquidate others -> repay
3b. Flash-Loan-Enabled Debounce DoS
For each permissionless function with a cooldown/debounce stored in a shared object: Can attacker flash-borrow -> call debounced function -> trigger cooldown, blocking legitimate callers?
| Function | Cooldown Scope | Shared Across Users? | Flash-Triggerable? | DoS Duration |
|---|
Sui-specific: Cooldowns on Sui typically use clock::timestamp_ms(clock) comparisons stored in shared objects. If the cooldown timestamp is global (not per-user), a flash loan can trigger it for all users.
If cooldown is global/shared AND function is permissionless AND flash-triggerable -> FINDING (R2, minimum Medium).
3c. No-Op Resource Consumption
For each state-modifying function with a limited-use resource (cooldown, one-time flag, epoch-bound action): Can it be called with parameters producing zero economic effect (amount=0, same-token swap, self-transfer) while consuming the resource?
| Function | Resource Consumed | No-Op Parameters | Resource Wasted? | Impact |
|---|
If a no-op call consumes a resource blocking legitimate use -> FINDING (R2, resource waste).
3d. External Flash x Debounce Cross-Reference (MANDATORY)
For EACH external protocol flagged as flash-susceptible in Section 0:
| External Protocol | Flash-Accessible Action | Debounce/Cooldown Affected (from 3b) | Combined Severity |
|---|
Cross-reference: Can the external flash loan trigger ANY debounce/cooldown found in Step 3b? If YES:
- Is the debounce consumption permanent (no admin reset) or temporary (auto-expires)?
- If permanent: is there ANY on-chain path to reset? (admin cap function, epoch reset, time-based expiry)
- Combined finding inherits the HIGHER severity of the two individual findings
- Tag:
[TRACE:flash({external}) -> call({debounce_fn}) -> cooldown consumed -> {duration/permanent}]
If no debounce functions exist from 3b: mark N/A and skip.
4. Hot Potato Receipt Integrity
For every flash loan implementation in the protocol (or external flash loan receipt consumed by the protocol):
4a. Receipt Struct Analysis
| Receipt Struct | Abilities | Can Be Constructed Outside Module? | Fields Validated on Repay? | Amount+Fee Enforced? |
|---|---|---|---|---|
| {struct_name} | {none / key / store / etc.} | YES/NO | {list fields checked} | YES/NO |
Critical checks:
- Receipt struct MUST have zero abilities (no
key,store,copy,drop). If it hasdrop-> borrower can discard receipt without repaying (free flash loan). - Receipt struct MUST be defined in the lending module with no public constructor. If any public function returns a freshly created receipt -> attacker can fabricate receipts.
- Repayment function MUST validate returned
Coin<T>value >= borrowed amount + fee. If it only checks receipt existence -> underpayment.
4b. Receipt Replay / Fabrication
- Can the receipt be split or partially consumed? (e.g., paying back in multiple calls)
- Can two receipts from different borrows be combined or swapped?
- Is the receipt tied to a specific pool/object ID? If not -> cross-pool receipt confusion.
- Can a receipt be constructed via
test_utilsortest_scenarioin production? (should be test-only)
4c. PTB Receipt Composition
- Can multiple flash loan receipts from different pools coexist in the same PTB?
- If two receipts exist, can the repayment coins be swapped (pay Pool A's receipt with Pool B's funds)?
- Does the receipt encode the borrow pool's ID to prevent cross-pool repayment?
5. Flash Loan + Donation Compound Attacks
Combine flash loan capital with unsolicited token transfers:
| Donation Target | Flash Loan Action | Combined Effect | Profitable? |
|---|---|---|---|
| Shared pool object balance | Deposit/withdraw | Rate manipulation | {YES/NO} |
| DEX pool reserves | Swap | Price oracle manipulation | {YES/NO} |
| Governance voting power | Vote/propose | Quorum manipulation | {YES/NO} |
Sui-specific donation vectors:
transfer::public_transfer(coin, @pool_address)sends Coin<T> to a shared object's address -- but this creates a NEW owned object at that address, NOT added to the shared object'sBalance<T>. However, some protocols usedynamic_fieldor accept arbitrary coins.- Check: Does the protocol have a function that accepts arbitrary
Coin<T>and adds to itsBalance<T>without proper accounting? (e.g., adonate()ortop_up()function) - Check: Does the protocol read
balance::value()of its own balance and use it for exchange rate calculation? If so, any path to increase the balance without minting shares is a donation attack vector.
6. Flash Loan Defense Audit
For each flash-loan-accessible attack path identified:
| Defense | Present? | Effective? | Bypass? |
|---|---|---|---|
| Hot potato receipt validation (amount + fee) | YES/NO | {analysis} | {if YES: how} |
| Same-epoch prevention (epoch comparison) | YES/NO | {analysis} | Multi-epoch possible? |
| TWAP instead of spot price | YES/NO | TWAP window length: {N} | Short TWAP vulnerable? |
| Minimum lock period / cooldown | YES/NO | Duration: {N epochs/seconds} | Bypass via partial? |
| Balance snapshot (before/after in same function) | YES/NO | {analysis} | {if YES: how} |
| Flash loan fee exceeds profit | YES/NO | Fee: {X}, max profit: {Y} | Fee < profit? |
| PTB command limit (1024) constrains attack | YES/NO | Commands needed: {N} | N < 1024? |
Sui-specific defenses:
- Hot potato pattern inherently prevents cross-transaction flash loans -- but does NOT prevent within-PTB manipulation.
tx_context::epoch()checks prevent cross-epoch attacks but NOT same-PTB attacks.- Shared object contention: high-contention shared objects may naturally serialize, but this is NOT a reliable defense.
6b. Defense Parity Audit (Cross-Module)
For each user-facing action that exists in multiple modules (stake, withdraw, claim, exit):
| Action | Module A | Flash Defense | Module B | Flash Defense | Parity? |
|---|---|---|---|---|---|
| {action} | {module} | {defense list} | {module} | {defense list} | {GAP if different} |
Key question: If ModuleA::stake() has a cooldown that prevents flash-stake-claim-withdraw, but ModuleB::stake() has NO cooldown for the same economic action -- can an attacker use ModuleB as the undefended path to extract the same value?
For each GAP found:
- Can the undefended module be used to achieve the same economic outcome?
- Does the defended module's protection become meaningless if the undefended path exists?
- Is the defense difference intentional (documented) or accidental?
Finding Template
**ID**: [FL-N]
**Severity**: [based on profitability and fund impact]
**Step Execution**: check0,1,2,3,4,5,6 | x(reasons) | ?(uncertain)
**Rules Applied**: [R2:check, R4:check, R10:check, R15:check]
**Location**: module::function:LineN
**Title**: Flash loan enables [manipulation] via [mechanism] within PTB
**Description**: [Full atomic PTB attack sequence with amounts]
**Impact**: [Quantified profit/loss with realistic flash loan amounts]
Instantiation Parameters
{CONTRACTS} -- Move modules to analyze
{FLASH_SOURCES} -- Flash loan providers identified during recon (lending protocols, DEXs, etc.)
{SHARED_OBJECTS} -- Shared objects with flash-accessible state
{BALANCE_VARS} -- Balance<T> fields readable by protocol
{DEX_POOLS} -- External DEX pools interacted with
{PTB_COMPOSABLE} -- Functions composable within PTBs
Output Schema
| Field | Required | Description |
|---|---|---|
| flash_state_inventory | yes | All flash-loan-accessible state |
| atomic_sequences | yes | PTB-based attack sequences modeled |
| cross_function_chains | yes | Multi-call chains within PTBs |
| defense_audit | yes | Defenses present and effectiveness |
| defense_parity | yes | Cross-module defense consistency |
| finding | yes | CONFIRMED / REFUTED / CONTESTED |
| evidence | yes | Code locations with line numbers |
| step_execution | yes | Status for each step |
Step Execution Checklist (MANDATORY)
| Section | Required | Completed? | Notes |
|---|---|---|---|
| 0. External Flash Susceptibility Check | YES | check/x/? | For each external protocol interaction |
| 1. Flash-Loan-Accessible State Inventory | YES | check/x/? | |
| 2. Atomic Attack Sequence Modeling | YES | check/x/? | For each accessible state |
| 3. Cross-Function Flash Loan Chains | YES | check/x/? | |
| 3b. Flash-Loan-Enabled Debounce DoS | YES | check/x/? | Shared cooldown functions |
| 3c. No-Op Resource Consumption | YES | check/x/? | Zero-effect calls consuming resources |
| 3d. External Flash x Debounce Cross-Ref | YES | check/x/? | Cross-reference 0 x 3b |
| 4. Hot Potato Receipt Integrity | YES | check/x/? | Receipt abilities + repayment validation |
| 5. Flash Loan + Donation Compounds | IF BALANCE_DEPENDENT | check/x(N/A)/? | |
| 6. Flash Loan Defense Audit | YES | check/x/? | For each attack path |
| 6b. Defense Parity Audit | YES | check/x/? | For each action in multiple modules |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
integration-hazard-research
Protocol Type Trigger NAMED_EXTERNAL_PROTOCOL (detected when recon finds import/interface for an identifiable external protocol — not standard libraries). Researches known integration hazards of the target protocol.
outcome-determinism
Protocol Type Trigger outcome_determinism - detected when EITHER of these code patterns are present - - Selection from finite depletable pool with fallback behavior (while(full)...
governance-attack-vectors
Protocol Type Trigger governance (detected when Governor, Timelock, voting, proposal, quorum, delegate patterns found) - Inject Into Breadth agents, depth-external, depth-edge-case
vault-accounting
Protocol Type Trigger vault (detected in recon TASK 0 Step 1) - Inject Into Core state agent OR economic design agent (merge via M4 hierarchy)
lending-protocol-security
Protocol Type Trigger lending (detected when recon finds liquidate|borrow|repay|collateral|lend|loan|LTV|healthFactor|interestRate|debtToken) - Inject Into Breadth agents, depth...
dex-integration-security
Protocol Type Trigger dex_integration (detected when recon finds swap|addLiquidity|removeLiquidity|IUniswapV2Router|ISwapRouter|amountOutMin|amountOutMinimum|slippage - AND the...
Didn't find tool you were looking for?