用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/PlamenTSV/plamen --skill token-flow-tracing命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Trigger Pattern Always (run during recon TASK 0, not breadth) - Inject Into Recon agent only (meta_buffer.md enrichment)
Trigger Pattern Always (run during recon TASK 0, not breadth) - Inject Into Recon agent only (meta_buffer.md enrichment)
Trigger STABLESWAP_FORK flag (fork-ancestry detects Curve/StableSwap parent via get_d/get_y/ramp_a/StableSwap patterns) - Agent Type general-purpose (standalone niche agent, 1 budget slot)
基于 SOC 职业分类
正在显示 SKILL.md
| name | token-flow-tracing |
| description | Trigger Pattern BALANCE_DEPENDENT flag (required) - Inject Into Depth-token-flow, breadth agents |
Trigger Pattern: BALANCE_DEPENDENT flag (required) Inject Into: Depth-token-flow, breadth agents Purpose: Trace all Coin and Balance flows through Sui Move protocols to identify accounting desync, unsolicited deposit vectors, type confusion, and token lifecycle issues
For every token the protocol handles:
Enumerate ALL Coin<T> and Balance<T> types the protocol handles:
| Token Type | Representation | Location (module::struct field) | Owned or Shared? | Entry Functions | Exit Functions |
|---|---|---|---|---|---|
| {e.g., SUI} | Balance | pool::Pool.balance | Shared object | deposit() | withdraw() |
| {e.g., USDC} | Coin | (function parameter) | Owned (user) | swap_in() | swap_out() |
Sui-specific representations:
Coin<T>: Owned object with id: UID and balance: Balance<T>. Has key + store abilities -- freely transferable to any address via transfer::public_transfer. This is the primary unsolicited transfer vector on Sui.Balance<T>: Value type with store ability only (no key). Stored inside other objects. Cannot exist as a standalone on-chain object. Must live inside a struct with key.TreasuryCap<T>: Capability to mint/burn. Must be tracked.Balance<T>: Hidden balance storage -- check dynamic_field::add/borrow/remove.Where can tokens enter the protocol?
| Entry Path | Function | Token Form | Accounting Update | Validated? |
|---|---|---|---|---|
| Standard deposit | {module::deposit} | Coin parameter | {state variable updated} | YES/NO |
| PTB coin splitting | (PTB splits user coin) | Coin from split | {same as above?} | N/A |
| Direct transfer | transfer::public_transfer | Coin to address | NONE -- creates new owned object | NO |
| Balance merge | balance::join | Balance | {state variable updated?} | YES/NO |
| Mint | coin::from_balance / coin::mint | TreasuryCap | {supply tracking} | YES/NO |
| Side-effect receipt | {external call returns coin} | Coin | {handled?} | YES/NO |
Sui-specific entry analysis:
coin::into_balance(coin) converts Coin to Balance -- does the protocol track this conversion?coin::split(&mut coin, amount, ctx) creates a new Coin -- does the protocol validate the split amount?coin::zero<T>(ctx))Where can tokens leave the protocol?
| Exit Path | Function | Token Form | Accounting Update | Authorized? |
|---|---|---|---|---|
| Standard withdraw | {module::withdraw} | Coin returned | {state variable decremented} | {access check} |
| Transfer out | transfer::public_transfer | Coin | {accounting updated?} | {access check} |
| Balance extraction | balance::split | Balance | {state variable decremented?} | {access check} |
| Burn | coin::burn / balance::decrease_supply | TreasuryCap | {supply tracking} | {cap holder} |
| Fee distribution | {fee function} | Coin or Balance | {fee accounting} | {access check} |
| Emergency withdraw | {emergency function} | Coin | {does it clear ALL state?} | {admin cap?} |
For each exit: does the tracked balance decrease BEFORE or AFTER the actual balance extraction? For each transfer/withdrawal: can the source be underfunded at execution time? (funds deployed externally, locked, or lent out → transfer aborts) Check for:
balance::split before state update -> can the function abort between split and update?balance::split -> can state be inconsistent if split aborts?For each transfer function: can the sender and recipient be the same address/object? If YES: does a self-transfer update accounting state (fees credited, rewards claimed, snapshots updated, share ratios changed) without net token movement? Flag as FINDING.
For each token in the protocol:
| Token | Internal Tracking Variable | Actual Balance Source | Can They Desync? | Desync Vector |
|---|---|---|---|---|
| {token} | {e.g., pool.total_deposited} | balance::value(&pool.balance) | YES/NO | {how} |
Red flags:
balance::value() directly instead of tracked internal variablebalance::join(&mut pool.balance, deposit_balance) without incrementing tracked counterSui-specific desync vectors:
balance::join into a shared object's Balance without updating the tracking variableCan tokens be added to the protocol's balance without going through deposit logic?
Sui object model considerations:
Coin<T> via transfer::public_transfer to a shared object's address creates a NEW owned object at that address -- it does NOT add to the shared object's Balance<T>. The protocol would need to explicitly receive and merge it.Balance<T> fields without going through the module's public API.Coin<T> and calls balance::join without proper accounting, this IS a donation vector.| Donation Path | Possible? | Changes Protocol Balance? | Breaks Accounting? | Impact |
|---|---|---|---|---|
| transfer::public_transfer to pool address | YES (creates owned obj) | NO (not auto-merged) | NO (unless protocol sweeps) | {analysis} |
| Public function accepting Coin without accounting | {YES/NO} | YES | YES | {analysis} |
| Dynamic field injection | {YES/NO -- needs module API} | {YES/NO} | {YES/NO} | {analysis} |
| Reward/fee distribution to protocol address | {YES/NO} | {YES/NO} | {YES/NO} | {analysis} |
For EVERY external token type the protocol holds, queries, or receives as side effects -- not just the protocol's primary token:
| Token Type | Can Be Sent to Protocol? | Changes Protocol Accounting? | Blocks Operations? | Triggers Side Effects? |
|---|---|---|---|---|
| {token_a} | YES/NO | YES/NO | YES/NO | YES/NO |
RULE: If ANY token type can enter the protocol's balance AND affects state -> analyze each consequence:
Can the wrong Coin<T> type be passed to protocol functions?
| Function | Expected Type Parameter | Validated? | What if Wrong Type? |
|---|---|---|---|
| {function} | Coin | {by Move type system / runtime check} | {impact} |
Sui Move type safety: Move's type system provides strong static guarantees -- Coin<USDC> and Coin<SUI> are different types at compile time. However:
fun deposit<T>(coin: Coin<T>) accept ANY Coin<T> -- is T validated?T against an allowed list? (e.g., assert!(type_name::get<T>() == allowed_type))Coin<ATTACKER_TOKEN> to a generic function?Pool<A, B> called with Coin<B> where Coin<A> expected)Analyze coin::split() and coin::join() / balance::split() and balance::join() operations:
| Operation | Location | Amount Source | Validated? | Edge Cases |
|---|---|---|---|---|
| coin::split(&mut coin, amount, ctx) | {location} | {user input / computed} | {amount <= coin.value?} | {amount = 0? amount = full value?} |
| coin::join(&mut coin_a, coin_b) | {location} | {coin_b.value} | {overflow check?} | {coin_b is zero?} |
| balance::split(&mut bal, amount) | {location} | {computed} | {amount <= bal.value?} | {amount = 0?} |
| balance::join(&mut bal_a, bal_b) | {location} | {bal_b.value} | {overflow check?} | {bal_b is zero?} |
Check:
coin::split(&mut coin, 0, ctx) creates a zero-value coin -- does the protocol handle this?What happens with zero-value tokens?
| Operation | Zero Input Behavior | Impact |
|---|---|---|
| deposit(coin::zero()) | {aborts / succeeds / mints zero shares} | {accounting impact} |
| withdraw(0) | {aborts / succeeds / burns zero shares} | {accounting impact} |
| swap(coin::zero()) | {aborts / succeeds} | {state change without value?} |
| claim_rewards() when rewards = 0 | {aborts / succeeds} | {side effects?} |
Check: Can zero-value operations be used to:
For protocols with multiple token types:
| Interaction | Token A | Token B | Dependency | Impact |
|---|---|---|---|---|
| Exchange rate | {A type} | {B type} | {A balance affects B's rate?} | {if A manipulated, B price changes?} |
| Collateral/debt | {collateral type} | {debt type} | {collateral value gates borrowing} | {if collateral inflated, excess borrowing} |
| LP composition | {A type} | {B type} | {ratio determines share value} | {imbalance vector} |
**ID**: [TF-N]
**Severity**: [based on fund impact]
**Step Execution**: check1,2,3,4,5,6,7,8,9 | x(reasons) | ?(uncertain)
**Rules Applied**: [R1:check, R11:check, R4:check, R10:check]
**Location**: module::function:LineN
**Title**: [Token type] can enter/exit via [path] without [expected accounting update]
**Description**: [Trace the token flow and where it diverges from expected]
**Impact**: [What breaks: exchange rates, user balances, protocol insolvency]
{CONTRACTS} -- Move modules to analyze
{TOKEN_TYPES} -- Coin<T>/Balance<T> types handled
{SHARED_OBJECTS} -- Shared objects holding balances
{ENTRY_FUNCTIONS} -- Token deposit/entry functions
{EXIT_FUNCTIONS} -- Token withdraw/exit functions
{GENERIC_FUNCTIONS} -- Functions with type parameter <T>
| Field | Required | Description |
|---|---|---|
| asset_inventory | yes | All Coin and Balance types |
| entry_points | yes | All token entry paths |
| exit_points | yes | All token exit paths |
| balance_tracking | yes | Internal vs actual balance analysis |
| unsolicited_analysis | yes | Donation/unsolicited deposit vectors |
| type_confusion | yes | Type parameter validation |
| finding | yes | CONFIRMED / REFUTED / CONTESTED |
| evidence | yes | Code locations with line numbers |
| step_execution | yes | Status for each step |
| Section | Required | Completed? | Notes |
|---|---|---|---|
| 1. Asset Inventory | YES | check/x/? | |
| 2. Token Entry Points | YES | check/x/? | |
| 3. Token Exit Points | YES | check/x/? | |
| 4. Balance Tracking and Desync | YES | check/x/? | |
| 5. Unsolicited Deposit Analysis | YES | check/x/? | |
| 5b. Unsolicited Transfer Matrix (All Types) | YES | check/x/? | MANDATORY -- never skip |
| 6. Token Type Confusion | YES | check/x/? | |
| 7. Coin Splitting and Merging | YES | check/x/? | |
| 8. Zero-Value Operations | YES | check/x/? | |
| 9. Cross-Token Interactions | IF multi-token | check/x(N/A)/? |
After Section 5 (Unsolicited Deposit Analysis):
After Section 7 (Coin Splitting and Merging):
After Section 8 (Zero-Value Operations):