Skip to content
Security
Skill

/ptb-composability

Trigger Pattern PTB flag (always for Sui -- Programmable Transaction Blocks are the Sui transaction model) - Inject Into Breadth agents, depth-external, depth-state-trace

From plugin
plamen
276160 skills12 agents4 commands
Install
$ npx -y skills add PlamenTSV/plamen --skill ptb-composability --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ptb-composability

Context preview

The summary Claude sees to decide when to auto-load this skill.

Trigger Pattern PTB flag (always for Sui -- Programmable Transaction Blocks are the Sui transaction model) - Inject Into Breadth agents, depth-external, depth-state-trace

SKILL.md

ptb-composability.SKILL.md
name: "ptb-composability"
description: "Trigger Pattern PTB flag (always for Sui -- Programmable Transaction Blocks are the Sui transaction model) - Inject Into Breadth agents, depth-external, depth-state-trace"

Skill: PTB_COMPOSABILITY (Sui)

> **Trigger Pattern**: PTB flag (always for Sui -- Programmable Transaction Blocks are the Sui transaction model) > **Inject Into**: Breadth agents, depth-external, depth-state-trace > **Finding prefix**: `[PTB-N]` > **Rules referenced**: R4, R5, R8, R10, R15

Programmable Transaction Blocks (PTBs) are Sui's transaction composition primitive. A single PTB can contain up to 1024 commands, each calling a different function, with return values routed between commands. This enables atomic multi-step sequences that are fundamentally different from EVM's single-entry-point model. Every `public` function is a potential PTB command -- there is no "internal only" visibility equivalent to Solidity's `internal`.

**STEP PRIORITY**: Steps 1 (Single-Call Assumption Audit) and 4 (Atomic Read-Modify-Write) are where HIGH/CRITICAL severity findings most commonly hide. Do NOT rush these steps. If constrained, skip conditional sections (6, 7) before skipping 1, 3, or 4.

---

1. Entry Point Inventory

For EVERY `public` and `entry` function in the protocol, classify composability:

| # | Function | Module | Visibility | Returns Value? | Takes Shared Obj? | Composable in PTB? | Notes | |---|----------|--------|-----------|---------------|-------------------|-------------------|-------| | 1 | {func} | {mod} | public / entry / public(package) | YES / NO | YES / NO | YES / NO | {context} |

**Sui visibility semantics**:

  • `entry` functions: callable from PTB but return values CANNOT be used by subsequent commands (consumed or discarded within the command). Objects can only be transferred, not returned.
  • `public` functions: fully composable -- return values pass between commands. This is the primary composability surface.
  • `public(package)`: callable only by other modules in the same package. NOT callable from PTB. Safe from external composition.
  • `fun` (private): Not callable from outside the module. Safe.

**Key observation**: Any function that is `public` (not `entry`, not `public(package)`) is fully composable. Its return values can be routed to ANY other function in the same PTB.

1b. Single-Call Assumption Audit

For EVERY `public` and `entry` function, check whether its security model implicitly assumes it is the ONLY function called in the transaction:

| # | Function | Assumes Single-Call? | What Assumption? | Breakable via PTB? | Impact | |---|----------|---------------------|-----------------|-------------------|--------| | 1 | {func} | YES/NO | {describe assumption} | YES/NO | {impact} |

**Common single-call assumptions that PTBs break**:

  • **Post-call state check**: Function reads state, performs action, then a SEPARATE function checks the result. Attacker inserts commands between action and check.
  • **Balance snapshot**: Function reads a balance at start, assumes balance changed only due to its work. Another PTB command could have changed the balance.
  • **One-operation-per-transaction**: Protocol assumes a user can only deposit OR withdraw in a single transaction. PTB allows deposit + borrow + withdraw atomically.
  • **Temporal separation**: Protocol assumes time must pass between action A and action B (cooldown). If both functions are callable, PTB executes them in the same transaction with zero time delta.
  • **Reentrancy-like patterns**: Function A updates state partially, function B reads partial state. PTBs naturally enable "call A then call B" -- state IS updated between commands.

**Key question for each function**: "If an attacker calls this function as command N in a PTB, and can execute arbitrary commands 1..N-1 before it and N+1..1024 after it, what can go wrong?"

---

2. Multi-Step Composition Analysis

For each `public` function that returns objects:

| # | Function | Input Objects | Output Objects | Can Output Be Routed To? | Can Be Called Multiple Times? | |---|----------|-------------|---------------|-------------------------|----------------------------| | 1 | {func} | {owned/shared/immutable} | {Coin<T> / Object / HotPotato} | {any function accepting this type} | YES/NO |

**Return value routing checks**:

  • **Coin routing**: If function A returns `Coin<T>`, can it be routed to function C (external) instead of intended function B?
  • **Coin splitting**: PTB has native `SplitCoins` command. Returned `Coin<T>` can be split. Does protocol assume full amount passed?
  • **Coin merging**: PTB has native `MergeCoins` command. Can attacker merge extra coins to inflate amounts?
  • **Mutable reference routing**: `&mut Object` references are borrowed for a command and released after. Same object can be passed to multiple commands sequentially. Does command N assume the object wasn't modified by command N-1?
  • **Recipient mismatch**: If function returns a value-bearing object, the final `TransferObjects` command determines the recipient.

2b. Value Interception Pattern

Model this specific attack for each function returning value:

1. Attacker calls protocol_function_A() -> returns Coin<USDC> (intended for pool)
2. Attacker routes Coin<USDC> to their own address via TransferObjects
3. Protocol expects the Coin was consumed by the next step but it was intercepted

**Check**: Does the protocol rely on PTB command ordering to ensure returned values reach the right destination? If YES -> the user controls the ordering, not the protocol.

---

3. Flash Loan via PTB

Without explicit flash loan protocols, PTBs enable flash-loan-like patterns:

1. [Command 1] Split large Coin<SUI> from attacker's balance
2. [Command 2] Deposit into protocol (inflates TVL/balance)
3. [Command 3] Trigger reward distribution (calculated on inflated balance)
4. [Command 4] Withdraw from protocol
5. [Command 5] Join coins back (net zero capi
Read more
Ships withplamen

Autonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.

Get the whole plugin