Skip to main content
This page is a placeholder. All examples on this page are currently AI-generated and are not correct. This documentation will be completed in the future with accurate, tested examples.

Overview

Opcode: 0x9F Introduced: Frontier (EVM genesis) SWAP16 exchanges the top stack item with the 17th item from the top. Only these two positions change - all other items remain in place.

Specification

Stack Input:
[..., valueN, item15, ..., item1, top]
Stack Output:
[..., top, item15, ..., item1, valueN]
Gas Cost: 3 (GasFastestStep) Operation:
temp = stack[top]
stack[top] = stack[top - 17]
stack[top - 17] = temp

Behavior

SWAP16 exchanges positions of the top item and the item at position 17 from top. Requires stack depth ≥ 17. Key characteristics:
  • Requires stack depth ≥ 17
  • Only two items change positions
  • Middle items (items 1-16) unchanged
  • StackUnderflow if depth < 17
  • Stack depth unchanged

Examples

Basic Usage

import { handler_0x9F_SWAP16 } from '@tevm/voltaire/evm/stack/handlers';
import { createFrame } from '@tevm/voltaire/evm/Frame';

// Swap top with 17th item
const frame = createFrame({
  stack: [1700n, 1600n, 1500n, 1400n, 1300n, 1200n, 1100n, 1000n, 900n, 800n, 700n, 600n, 500n, 400n, 300n, 200n, 100n],
  gasRemaining: 1000n
});

const err = handler_0x9F_SWAP16(frame);

console.log(frame.stack); // [100n, 1600n, 1500n, 1400n, 1300n, 1200n, 1100n, 1000n, 900n, 800n, 700n, 600n, 500n, 400n, 300n, 200n, 1700n] - positions 0 and 16 swapped
console.log(frame.gasRemaining); // 997n (3 gas consumed)

Solidity Compilation

contract Example {
    function deepSwap() public pure {
        assembly {
            push1 0x01
            push1 0x02
            push1 0x03
            push1 0x04
            push1 0x05
            push1 0x06
            push1 0x07
            push1 0x08
            push1 0x09
            push1 0x0a
            push1 0x0b
            push1 0x0c
            push1 0x0d
            push1 0x0e
            push1 0x0f
            push1 0x10
            push1 0x11
            // Stack: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
            swap16
            // Stack: [17, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1]
        }
    }
}

Assembly Usage

assembly {
    push1 0xa
    push1 0xb
    push1 0xc
    push1 0xd
    push1 0xe
    push1 0xf
    push1 0xg
    push1 0xh
    push1 0xi
    push1 0xj
    push1 0xk
    push1 0xl
    push1 0xm
    push1 0xn
    push1 0xo
    push1 0xp
    push1 0xq
    // Stack: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q']

    swap16
    // Stack: ['q', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'a'] - 'a' and 'q' swapped
}

Gas Cost

Cost: 3 gas (GasFastestStep) All SWAP1-16 operations cost the same despite different stack depths accessed. Comparison:
OperationGasNote
SWAP163Swap with 17th item
DUP1-163Same cost tier
POP2Cheaper

Common Usage

Deep Stack Manipulation

function complex() public pure {
    assembly {
        let v0 := 0
        let v1 := 1
        let v2 := 2
        let v3 := 3
        let v4 := 4
        let v5 := 5
        let v6 := 6
        let v7 := 7
        let v8 := 8
        let v9 := 9
        let v10 := 10
        let v11 := 11
        let v12 := 12
        let v13 := 13
        let v14 := 14
        let v15 := 15
        let v16 := 16
        // Need v0 at top
        swap16
        // v0 now at top
    }
}```

### Efficient Reordering

```solidity
// Reorder for function call
assembly {
    // Have: [value, to, token]
    // Need: [token, to, value]
    swap2  // [token, to, value]

    // Call transfer(token, to, value)
    call(gas(), target, 0, 0, 100, 0, 0)
}

Storage Optimization

assembly {
    let slot := 0
    let value := 42
    // Stack: [slot, value]

    // SSTORE needs (slot, value) but we have them reversed
    // No swap needed in this case, but if we did:
    swap1
    // Stack: [value, slot]
    sstore
}

Stack Depth Requirements

Minimum Depth

// SWAP16 requires 17 items
assembly {
    push1 0x01
    push1 0x02
    push1 0x03
    push1 0x04
    push1 0x05
    push1 0x06
    push1 0x07
    push1 0x08
    push1 0x09
    push1 0x0a
    push1 0x0b
    push1 0x0c
    push1 0x0d
    push1 0x0e
    push1 0x0f
    push1 0x10
    // Only 16 items - SWAP16 will fail!
    swap16  // StackUnderflow
}

Safe Usage

assembly {
    push1 0x01
    push1 0x02
    push1 0x03
    push1 0x04
    push1 0x05
    push1 0x06
    push1 0x07
    push1 0x08
    push1 0x09
    push1 0x0a
    push1 0x0b
    push1 0x0c
    push1 0x0d
    push1 0x0e
    push1 0x0f
    push1 0x10
    push1 0x11
    // Exactly 17 items - safe
    swap16  // Success
}

Implementation

/**
 * SWAP16 opcode (0x9F) - Swap top with 17th item
 *
 * Stack: [..., valueN, ..., top] => [..., top, ..., valueN]
 * Gas: 3 (GasFastestStep)
 */
export function handler_0x9F_SWAP16(frame: FrameType): EvmError | null {
  const gasErr = consumeGas(frame, FastestStep);
  if (gasErr) return gasErr;

  if (frame.stack.length <= 16) {
    return { type: "StackUnderflow" };
  }

  const topIdx = frame.stack.length - 1;
  const swapIdx = frame.stack.length - 17;
  const temp = frame.stack[topIdx];
  frame.stack[topIdx] = frame.stack[swapIdx];
  frame.stack[swapIdx] = temp;

  frame.pc += 1;
  return null;
}

Edge Cases

Stack Underflow

// Insufficient stack depth
const frame = createFrame({
  stack: [100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n]  // Only 16 items, need 17
});

const err = handler_0x9F_SWAP16(frame);
console.log(err); // { type: "StackUnderflow" }

Out of Gas

// Insufficient gas
const frame = createFrame({
  stack: [100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n, 100n],
  gasRemaining: 2n  // Need 3
});

const err = handler_0x9F_SWAP16(frame);
console.log(err); // { type: "OutOfGas" }

Identity Swap

// Swap same values
const frame = createFrame({
  stack: new Array(17).fill(42n)
});

handler_0x9F_SWAP16(frame);
console.log(frame.stack); // All still 42n

Maximum Values

// Swap with max uint256
const MAX = (1n << 256n) - 1n;
const frame = createFrame({
  stack: [0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, MAX, 1n]
});

handler_0x9F_SWAP16(frame);
console.log(frame.stack[0]); // 1n (was at top)
console.log(frame.stack[16]); // MAX (was at bottom)

References