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: 0x81
Introduced: Frontier (EVM genesis)
DUP2 duplicates the 2nd stack item and pushes it to the top of the stack. The original 2th item remains in place.
Specification
Stack Input:
[..., value, item1, ..., item1]
Stack Output:
[..., value, item1, ..., item1, value]
Gas Cost: 3 (GasFastestStep)
Operation:
value = stack[depth - 2]
stack.push(value)
Behavior
DUP2 copies the 2th-from-top stack item without removing it. Requires stack depth ≥ 2.
Key characteristics:
- Requires stack depth ≥ 2
- Original value unchanged
- New copy pushed to top
- StackUnderflow if depth < 2
- Stack depth increases by 1
Examples
Basic Usage
import { handler_0x81_DUP2 } from '@tevm/voltaire/evm/stack/handlers';
import { createFrame } from '@tevm/voltaire/evm/Frame';
// Duplicate 2th item
const frame = createFrame({
stack: [200n, 100n],
gasRemaining: 1000n
});
const err = handler_0x81_DUP2(frame);
console.log(frame.stack); // [200n, 100n, 100n] - 2th item duplicated
console.log(frame.gasRemaining); // 997n (3 gas consumed)
Solidity Compilation
contract Example {
function swap() public pure {
uint256 a = 10;
uint256 b = 20;
// Access a again
// Stack: [b, a]
// DUP2 // Stack: [b, a, a]
}
}
Assembly Usage
assembly {
push1 0x01
push1 0x02
// Stack: [0x01, 0x02]
dup2
// Stack: [0x01, 0x02, 0x01] - first item duplicated
}
Gas Cost
Cost: 3 gas (GasFastestStep)
All DUP1-16 operations cost the same despite different stack depths accessed.
Comparison:
| Operation | Gas | Note |
|---|
| DUP2 | 3 | Duplicate 2th item |
| PUSH1-32 | 3 | Same cost tier |
| POP | 2 | Cheaper |
Common Usage
Access Previous Value
assembly {
let a := 10
let b := 20
dup2 // Get 'a' again
// Stack: [b, a, a]
}```
### 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
// DUP2 requires 2 items on stack
assembly {
push1 0x01
// Only 1 items - DUP2 will fail!
dup2 // StackUnderflow
}
Safe Usage
assembly {
push1 0x01
push1 0x02
// Exactly 2 items - safe
dup2 // Success
}
Implementation
/**
* DUP2 opcode (0x81) - Duplicate 2nd stack item
*
* Stack: [..., value, ...] => [..., value, ..., value]
* Gas: 3 (GasFastestStep)
*/
export function handler_0x81_DUP2(frame: FrameType): EvmError | null {
const gasErr = consumeGas(frame, FastestStep);
if (gasErr) return gasErr;
if (frame.stack.length < 2) {
return { type: "StackUnderflow" };
}
const value = frame.stack[frame.stack.length - 2];
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: [100n] // Only 1 item
});
const err = handler_0x81_DUP2(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_0x81_DUP2(frame);
console.log(err); // { type: "StackOverflow" }
Out of Gas
// Insufficient gas
const frame = createFrame({
stack: [100n, 100n],
gasRemaining: 2n // Need 3
});
const err = handler_0x81_DUP2(frame);
console.log(err); // { type: "OutOfGas" }
Maximum Value
// Duplicate max uint256
const MAX = (1n << 256n) - 1n;
const frame = createFrame({
stack: [0n, MAX]
});
handler_0x81_DUP2(frame);
console.log(frame.stack[frame.stack.length - 1]); // MAX (duplicated)
References