Skip to main content

Overview

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

Specification

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

Behavior

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

Examples

Basic Usage

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

// Swap top with 9th item
const frame = createFrame({
  stack: [900n, 800n, 700n, 600n, 500n, 400n, 300n, 200n, 100n],
  gasRemaining: 1000n
});

const err = handler_0x97_SWAP8(frame);

console.log(frame.stack); // [100n, 800n, 700n, 600n, 500n, 400n, 300n, 200n, 900n] - positions 0 and 8 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
            // Stack: [1, 2, 3, 4, 5, 6, 7, 8, 9]
            swap8
            // Stack: [9, 2, 3, 4, 5, 6, 7, 8, 1]
        }
    }
}

Assembly Usage

assembly {
    push1 0xa
    push1 0xb
    push1 0xc
    push1 0xd
    push1 0xe
    push1 0xf
    push1 0xg
    push1 0xh
    push1 0xi
    // Stack: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

    swap8
    // Stack: ['i', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a'] - 'a' and 'i' swapped
}

Gas Cost

Cost: 3 gas (GasFastestStep) All SWAP1-16 operations cost the same despite different stack depths accessed. Comparison:
OperationGasNote
SWAP83Swap with 9th 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
        // Need v0 at top
        swap8
        // 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

// SWAP8 requires 9 items
assembly {
    push1 0x01
    push1 0x02
    push1 0x03
    push1 0x04
    push1 0x05
    push1 0x06
    push1 0x07
    push1 0x08
    // Only 8 items - SWAP8 will fail!
    swap8  // StackUnderflow
}

Safe Usage

assembly {
    push1 0x01
    push1 0x02
    push1 0x03
    push1 0x04
    push1 0x05
    push1 0x06
    push1 0x07
    push1 0x08
    push1 0x09
    // Exactly 9 items - safe
    swap8  // Success
}

Implementation

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

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

  const topIdx = frame.stack.length - 1;
  const swapIdx = frame.stack.length - 9;
  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]  // Only 8 items, need 9
});

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

Out of Gas

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

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

Identity Swap

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

handler_0x97_SWAP8(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, MAX, 1n]
});

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

References