Skip to main content

Overview

Opcode: 0x80 Introduced: Frontier (EVM genesis) DUP1 duplicates the top stack item and pushes it to the top of the stack. The original item remains in place.

Specification

Stack Input:
[..., value]
Stack Output:
[..., value, value]
Gas Cost: 3 (GasFastestStep) Operation:
value = stack[depth - 1]
stack.push(value)

Behavior

DUP1 copies the top stack item without removing it. Requires stack depth ≥ 1. Key characteristics:
  • Requires stack depth ≥ 1
  • Original value unchanged
  • New copy pushed to top
  • StackUnderflow if depth < 1
  • Stack depth increases by 1

Examples

Basic Usage

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

// Duplicate top item
const frame = createFrame({
  stack: [100n],
  gasRemaining: 1000n
});

const err = handler_0x80_DUP1(frame);

console.log(frame.stack); // [100n, 100n] - top duplicated
console.log(frame.gasRemaining); // 997n (3 gas consumed)

Solidity Compilation

contract Example {
    function reuse() public pure returns (uint256, uint256) {
        uint256 x = 42;
        // Need x twice
        return (x, x);  // Compiler uses DUP1
        // PUSH1 0x2a
        // DUP1
        // DUP1
    }
}

Assembly Usage

assembly {
    push1 0x01
    // Stack: [0x01]

    dup1
    // Stack: [0x01, 0x01] - first item duplicated
}

Gas Cost

Cost: 3 gas (GasFastestStep) All DUP1-16 operations cost the same despite different stack depths accessed. Comparison:
OperationGasNote
DUP13Duplicate 1th item
PUSH1-323Same cost tier
POP2Cheaper

Common Usage

Value Reuse

assembly {
    let x := 100
    dup1  // Reuse x
    dup1  // Reuse again
    // Stack: [100, 100, 100]
    add   // Use first two
    // Stack: [200, 100]
}```

### Efficient Copies

```solidity
// Instead of multiple loads
assembly {
    let value := sload(slot)  // Expensive
    // Use value
    let value2 := sload(slot) // Wasteful!
}

// Use DUP to reuse
assembly {
    let value := sload(slot)  // Load once
    dup1                       // Copy
    // Use both copies
}

Conditional Logic

assembly {
    let condition := calldataload(0)
    dup1  // Keep condition for later
    iszero
    jumpi(skip)
    // Use condition again
    skip:
}

Stack Depth Requirements

Minimum Depth

// DUP1 requires 1 items on stack
assembly {
    
    // Only 0 items - DUP1 will fail!
    dup1  // StackUnderflow
}

Safe Usage

assembly {
    push1 0x01
    // Exactly 1 items - safe
    dup1  // Success
}

Implementation

/**
 * DUP1 opcode (0x80) - Duplicate 1st stack item
 *
 * Stack: [..., value] => [..., value, value]
 * Gas: 3 (GasFastestStep)
 */
export function handler_0x80_DUP1(frame: FrameType): EvmError | null {
  const gasErr = consumeGas(frame, FastestStep);
  if (gasErr) return gasErr;

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

  const value = frame.stack[frame.stack.length - 1];
  const pushErr = pushStack(frame, value);
  if (pushErr) return pushErr;

  frame.pc += 1;
  return null;
}

Edge Cases

Stack Underflow

// Insufficient stack depth
const frame = createFrame({
  stack: []  // Only 0 items
});

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

Stack Overflow

// Stack at maximum, can't add more
const frame = createFrame({
  stack: new Array(1024).fill(0n)
});

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

Out of Gas

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

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

Maximum Value

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

handler_0x80_DUP1(frame);
console.log(frame.stack[frame.stack.length - 1]); // MAX (duplicated)

References