Skip to main content

Instruction Set

This page lists all of the instructions supported by the Aztec Virtual Machine (AVM).

The following notes are relevant to the table and sections below:

  • M[offset] notation is shorthand for context.machineState.memory[offset]
  • S[slot] notation is shorthand for an access to the specified slot in the current contract's public storage (context.worldState.publicStorage) after the slot has been siloed by the storage address (hash(context.environment.storageAddress, slot))
  • Any instruction whose description does not mention a program counter change simply increments it: context.machineState.pc++
  • All instructions update context.machineState.*GasLeft as detailed in "Gas limits and tracking"
  • Any instruction can lead to an exceptional halt as specified in "Exceptional halting"
  • The term hash used in expressions below represents a Poseidon hash operation.
  • Type structures used in world state tracing operations are defined in "Type Definitions"

Instructions Table

Click on an instruction name to jump to its section.

OpcodeNameSummaryExpression
0x00

Addition (a + b)

M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k
0x01

Subtraction (a - b)

M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k
0x02

Multiplication (a * b)

M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k
0x03

Unsigned integer division (a / b)

M[dstOffset] = M[aOffset] / M[bOffset]
0x04

Field division (a / b)

M[dstOffset] = M[aOffset] / M[bOffset]
0x05

Equality check (a == b)

M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0
0x06

Less-than check (a < b)

M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0
0x07

Less-than-or-equals check (a <= b)

M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0
0x08

Bitwise AND (a & b)

M[dstOffset] = M[aOffset] AND M[bOffset]
0x09

Bitwise OR (a | b)

M[dstOffset] = M[aOffset] OR M[bOffset]
0x0a

Bitwise XOR (a ^ b)

M[dstOffset] = M[aOffset] XOR M[bOffset]
0x0b

Bitwise NOT (inversion)

M[dstOffset] = NOT M[aOffset]
0x0c

Bitwise leftward shift (a << b)

M[dstOffset] = M[aOffset] << M[bOffset]
0x0d

Bitwise rightward shift (a >> b)

M[dstOffset] = M[aOffset] >> M[bOffset]
0x0e

Type cast

M[dstOffset] = cast<dstTag>(M[aOffset])
0x0f

Get the address of the currently executing l2 contract

M[dstOffset] = context.environment.address
0x10
M[dstOffset] = context.environment.storageAddress
0x11

Get the address of the sender (caller of the current context)

M[dstOffset] = context.environment.sender
0x12

Get the fee to be paid per "L2 gas" - constant for entire transaction

M[dstOffset] = context.environment.feePerL2Gas
0x13

Get the fee to be paid per "DA gas" - constant for entire transaction

M[dstOffset] = context.environment.feePerDaGas
0x14

Get the computed transaction fee during teardown phase, zero otherwise

M[dstOffset] = context.environment.transactionFee
0x15

Get how many contract calls deep the current call context is

M[dstOffset] = context.environment.contractCallDepth
0x16

Get this rollup's L1 chain ID

M[dstOffset] = context.environment.globals.chainId
0x17

Get this rollup's L2 version ID

M[dstOffset] = context.environment.globals.version
0x18

Get this L2 block's number

M[dstOffset] = context.environment.globals.blocknumber
0x19

Get this L2 block's timestamp

M[dstOffset] = context.environment.globals.timestamp
0x1a

Get the block's beneficiary address

M[dstOffset] = context.environment.globals.coinbase
0x1b

Total amount of "L2 gas" that a block can consume

M[dstOffset] = context.environment.globals.l2GasLimit
0x1c

Total amount of "DA gas" that a block can consume

M[dstOffset] = context.environment.globals.daGasLimit
0x1d

Copy calldata into memory

M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]
0x1e

Remaining "L2 gas" for this call (after this instruction)

M[dstOffset] = context.MachineState.l2GasLeft
0x1f

Remaining "DA gas" for this call (after this instruction)

M[dstOffset] = context.machineState.daGasLeft
0x20

Jump to a location in the bytecode

context.machineState.pc = loc
0x21

Conditionally jump to a location in the bytecode

context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc
0x22

Make an internal call. Push the current PC to the internal call stack and jump to the target location.

context.machineState.internalCallStack.push(context.machineState.pc)
context.machineState.pc = loc
0x23

Return from an internal call. Pop from the internal call stack and jump to the popped location.

context.machineState.pc = context.machineState.internalCallStack.pop()
0x24

Set a memory word from a constant in the bytecode

M[dstOffset] = const
0x25

Move a word from source memory location to destination

M[dstOffset] = M[srcOffset]
0x26
M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]
0x27

Load a word from this contract's persistent public storage. Zero is loaded for unwritten slots.

M[dstOffset] = S[M[slotOffset]]
0x28

Write a word to this contract's persistent public storage

S[M[slotOffset]] = M[srcOffset]
0x29

Check whether a note hash exists in the note hash tree (as of the start of the current block)

exists = context.worldState.noteHashes.has({
leafIndex: M[leafIndexOffset]
leaf: hash(context.environment.storageAddress, M[noteHashOffset]),
})
M[existsOffset] = exists
0x2a

Emit a new note hash to be inserted into the note hash tree

context.worldState.noteHashes.append(
hash(context.environment.storageAddress, M[noteHashOffset])
)
0x2b

Check whether a nullifier exists in the nullifier tree (including nullifiers from earlier in the current transaction or from earlier in the current block)

exists = pendingNullifiers.has(M[addressOffset], M[nullifierOffset]) || context.worldState.nullifiers.has(
hash(M[addressOffset], M[nullifierOffset])
)
M[existsOffset] = exists
0x2c

Emit a new nullifier to be inserted into the nullifier tree

context.worldState.nullifiers.append(
hash(context.environment.storageAddress, M[nullifierOffset])
)
0x2d

Check if a message exists in the L1-to-L2 message tree

exists = context.worldState.l1ToL2Messages.has({
leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset]
})
M[existsOffset] = exists
0x2e
exists = context.worldState.header.has({
leafIndex: M[blockIndexOffset], leaf: M[msgKeyOffset]
})
M[existsOffset] = exists
if exists:
header = context.worldState.headers.get(M[blockIndexOffset])
M[dstOffset] = header[M[memberIndexOffset]] // member
0x2f

Copies contract instance data to memory

M[dstOffset:dstOffset+CONTRACT_INSTANCE_SIZE+1] = [
instance_found_in_address,
instance.salt ?? 0,
instance.deployer ?? 0,
instance.contractClassId ?? 0,
instance.initializationHash ?? 0,
instance.portalContractAddress ?? 0,
instance.publicKeysHash ?? 0,
]
0x30

Emit an unencrypted log

context.accruedSubstate.unencryptedLogs.append(
UnencryptedLog {
address: context.environment.address,
eventSelector: M[eventSelectorOffset],
log: M[logOffset:logOffset+logSize],
}
)
0x31

Send an L2-to-L1 message

context.accruedSubstate.sentL2ToL1Messages.append(
SentL2ToL1Message {
address: context.environment.address,
recipient: M[recipientOffset],
message: M[contentOffset]
}
)
0x32

Call into another contract

// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
0x33

Call into another contract, disallowing World State and Accrued Substate modifications

// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=true, isDelegateCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
0x34
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
0x35

Halt execution within this context (without revert), optionally returning some data

context.contractCallResults.output = M[retOffset:retOffset+retSize]
halt
0x36
context.contractCallResults.output = M[retOffset:retOffset+retSize]
context.contractCallResults.reverted = true
halt
0x37

Convert a word to an array of limbs in little-endian radix form

TBD: Storage of limbs and if T[dstOffset] is constrained to U8

Instructions

ADD

Addition (a + b)

See in table.

  • Opcode: 0x00
  • Category: Compute - Arithmetic
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k
  • Details: Wraps on overflow
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

SUB

Subtraction (a - b)

See in table.

  • Opcode: 0x01
  • Category: Compute - Arithmetic
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k
  • Details: Wraps on undeflow
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

MUL

Multiplication (a * b)

See in table.

  • Opcode: 0x02
  • Category: Compute - Arithmetic
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k
  • Details: Wraps on overflow
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

DIV

Unsigned integer division (a / b)

See in table.

  • Opcode: 0x03
  • Category: Compute - Arithmetic
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] / M[bOffset]
  • Details: If the input is a field, it will be interpreted as an integer
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

FDIV

Field division (a / b)

See in table.

  • Opcode: 0x04
  • Category: Compute - Arithmetic
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] / M[bOffset]
  • Tag checks: T[aOffset] == T[bOffset] == field
  • Tag updates: T[dstOffset] = field
  • Bit-size: 120

EQ

Equality check (a == b)

See in table.

  • Opcode: 0x05
  • Category: Compute - Comparators
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = u8
  • Bit-size: 128

LT

Less-than check (a < b)

See in table.

  • Opcode: 0x06
  • Category: Compute - Comparators
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = u8
  • Bit-size: 128

LTE

Less-than-or-equals check (a <= b)

See in table.

  • Opcode: 0x07
  • Category: Compute - Comparators
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = u8
  • Bit-size: 128

AND

Bitwise AND (a & b)

See in table.

  • Opcode: 0x08
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] AND M[bOffset]
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

OR

Bitwise OR (a | b)

See in table.

  • Opcode: 0x09
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] OR M[bOffset]
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

XOR

Bitwise XOR (a ^ b)

See in table.

  • Opcode: 0x0a
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] XOR M[bOffset]
  • Tag checks: T[aOffset] == T[bOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

NOT

Bitwise NOT (inversion)

See in table.

  • Opcode: 0x0b
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = NOT M[aOffset]
  • Tag checks: T[aOffset] == inTag
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 96

SHL

Bitwise leftward shift (a << b)

See in table.

  • Opcode: 0x0c
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] << M[bOffset]
  • Tag checks: T[aOffset] == inTag, T[bOffset] == u8
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

SHR

Bitwise rightward shift (a >> b)

See in table.

  • Opcode: 0x0d
  • Category: Compute - Bitwise
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The tag/size to check inputs against and tag the destination with. field type is NOT supported for this instruction.
  • Args:
    • aOffset: memory offset of the operation's left input
    • bOffset: memory offset of the operation's right input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[aOffset] >> M[bOffset]
  • Tag checks: T[aOffset] == inTag, T[bOffset] == u8
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 128

CAST

Type cast

See in table.

  • Opcode: 0x0e
  • Category: Type Conversions
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • dstTag: The tag/size to tag the destination with but not to check inputs against.
  • Args:
    • aOffset: memory offset of word to cast
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = cast<dstTag>(M[aOffset])
  • Details: Cast a word in memory based on the dstTag specified in the bytecode. Truncates (M[dstOffset] = M[aOffset] mod 2^dstsize) when casting to a smaller type, left-zero-pads when casting to a larger type. See here for more details.
  • Tag updates: T[dstOffset] = dstTag
  • Bit-size: 96

ADDRESS

Get the address of the currently executing l2 contract

See in table.

  • Opcode: 0x0f
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.address
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

STORAGEADDRESS

Get the storage address of the currently executing context

See in table.

  • Opcode: 0x10
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.storageAddress
  • Details: The storage address is used for public storage accesses.
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

SENDER

Get the address of the sender (caller of the current context)

See in table.

  • Opcode: 0x11
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.sender
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

FEEPERL2GAS

Get the fee to be paid per "L2 gas" - constant for entire transaction

See in table.

  • Opcode: 0x12
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.feePerL2Gas
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

FEEPERDAGAS

Get the fee to be paid per "DA gas" - constant for entire transaction

See in table.

  • Opcode: 0x13
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.feePerDaGas
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

TRANSACTIONFEE

Get the computed transaction fee during teardown phase, zero otherwise

See in table.

  • Opcode: 0x14
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.transactionFee
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

CONTRACTCALLDEPTH

Get how many contract calls deep the current call context is

See in table.

  • Opcode: 0x15
  • Category: Execution Environment
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.contractCallDepth
  • Details: Note: security issues with EVM's tx.origin can be resolved by asserting calldepth == 0.
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

CHAINID

Get this rollup's L1 chain ID

See in table.

  • Opcode: 0x16
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.chainId
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

VERSION

Get this rollup's L2 version ID

See in table.

  • Opcode: 0x17
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.version
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

BLOCKNUMBER

Get this L2 block's number

See in table.

  • Opcode: 0x18
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.blocknumber
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

TIMESTAMP

Get this L2 block's timestamp

See in table.

  • Opcode: 0x19
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.timestamp
  • Tag updates: T[dstOffset] = u64
  • Bit-size: 56

COINBASE

Get the block's beneficiary address

See in table.

  • Opcode: 0x1a
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.coinbase
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

BLOCKL2GASLIMIT

Total amount of "L2 gas" that a block can consume

See in table.

  • Opcode: 0x1b
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.l2GasLimit
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

BLOCKDAGASLIMIT

Total amount of "DA gas" that a block can consume

See in table.

  • Opcode: 0x1c
  • Category: Execution Environment - Globals
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.environment.globals.daGasLimit
  • Tag updates: T[dstOffset] = field
  • Bit-size: 56

CALLDATACOPY

Copy calldata into memory

See in table.

  • Opcode: 0x1d
  • Category: Execution Environment - Calldata
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • cdOffset: offset into calldata to copy from
    • copySize: number of words to copy
    • dstOffset: memory offset specifying where to copy the first word to
  • Expression: M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]
  • Details: Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally.
  • Tag updates: T[dstOffset:dstOffset+copySize] = field
  • Bit-size: 120

L2GASLEFT

Remaining "L2 gas" for this call (after this instruction)

See in table.

  • Opcode: 0x1e
  • Category: Machine State - Gas
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.MachineState.l2GasLeft
  • Tag updates: T[dstOffset] = u32
  • Bit-size: 56

DAGASLEFT

Remaining "DA gas" for this call (after this instruction)

See in table.

  • Opcode: 0x1f
  • Category: Machine State - Gas
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = context.machineState.daGasLeft
  • Tag updates: T[dstOffset] = u32
  • Bit-size: 56

JUMP

Jump to a location in the bytecode

See in table.

  • Opcode: 0x20
  • Category: Machine State - Control Flow
  • Args:
    • loc: target location to jump to
  • Expression: context.machineState.pc = loc
  • Details: Target location is an immediate value (a constant in the bytecode).
  • Bit-size: 48

JUMPI

Conditionally jump to a location in the bytecode

See in table.

  • Opcode: 0x21
  • Category: Machine State - Control Flow
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • loc: target location conditionally jump to
    • condOffset: memory offset of the operations 'conditional' input
  • Expression: context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc
  • Details: Target location is an immediate value (a constant in the bytecode). T[condOffset] is not checked because the greater-than-zero suboperation is the same regardless of type.
  • Bit-size: 88

INTERNALCALL

Make an internal call. Push the current PC to the internal call stack and jump to the target location.

See in table.

  • Opcode: 0x22
  • Category: Machine State - Control Flow
  • Args:
    • loc: target location to jump/call to
  • Expression:
context.machineState.internalCallStack.push(context.machineState.pc)
context.machineState.pc = loc
  • Details: Target location is an immediate value (a constant in the bytecode).
  • Bit-size: 48

INTERNALRETURN

Return from an internal call. Pop from the internal call stack and jump to the popped location.

See in table.

  • Opcode: 0x23
  • Category: Machine State - Control Flow
  • Expression: context.machineState.pc = context.machineState.internalCallStack.pop()
  • Bit-size: 16

SET

Set a memory word from a constant in the bytecode

See in table.

  • Opcode: 0x24
  • Category: Machine State - Memory
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
    • inTag: The type/size to check inputs against and tag the destination with. field type is NOT supported for SET.
  • Args:
    • const: an N-bit constant value from the bytecode to store in memory (any type except field)
    • dstOffset: memory offset specifying where to store the constant
  • Expression: M[dstOffset] = const
  • Details: Set memory word at dstOffset to const's immediate value. const's bit-size (N) can be 8, 16, 32, 64, or 128 based on inTag. It cannot be 254 (field type)!
  • Tag updates: T[dstOffset] = inTag
  • Bit-size: 64+N

MOV

Move a word from source memory location to destination

See in table.

  • Opcode: 0x25
  • Category: Machine State - Memory
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • srcOffset: memory offset of word to move
    • dstOffset: memory offset specifying where to store that word
  • Expression: M[dstOffset] = M[srcOffset]
  • Tag updates: T[dstOffset] = T[srcOffset]
  • Bit-size: 88

CMOV

Move a word (conditionally chosen) from one memory location to another (d \= cond \> 0 ? a : b)

See in table.

  • Opcode: 0x26
  • Category: Machine State - Memory
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • aOffset: memory offset of word 'a' to conditionally move
    • bOffset: memory offset of word 'b' to conditionally move
    • condOffset: memory offset of the operations 'conditional' input
    • dstOffset: memory offset specifying where to store operation's result
  • Expression: M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]
  • Details: One of two source memory locations is chosen based on the condition. T[condOffset] is not checked because the greater-than-zero suboperation is the same regardless of type.
  • Tag updates: T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]
  • Bit-size: 152

SLOAD

Load a word from this contract's persistent public storage. Zero is loaded for unwritten slots.

See in table.

  • Opcode: 0x27
  • Category: World State - Public Storage
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • slotOffset: memory offset of the storage slot to load from
    • dstOffset: memory offset specifying where to store operation's result
  • Expression:
M[dstOffset] = S[M[slotOffset]]
  • Details:
// Expression is shorthand for
leafIndex = hash(context.environment.storageAddress, M[slotOffset])
exists = context.worldState.publicStorage.has(leafIndex) // exists == previously-written
if exists:
value = context.worldState.publicStorage.get(leafIndex: leafIndex)
else:
value = 0
M[dstOffset] = value
  • World State access tracing:
context.worldStateAccessTrace.publicStorageReads.append(
TracedStorageRead {
callPointer: context.environment.callPointer,
slot: M[slotOffset],
exists: exists, // defined above
value: value, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Storage slot siloing (hash with contract address), public data tree membership check
  • Tag updates: T[dstOffset] = field
  • Bit-size: 88

SSTORE

Write a word to this contract's persistent public storage

See in table.

  • Opcode: 0x28
  • Category: World State - Public Storage
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • srcOffset: memory offset of the word to store
    • slotOffset: memory offset containing the storage slot to store to
  • Expression:
S[M[slotOffset]] = M[srcOffset]
  • Details:
// Expression is shorthand for
context.worldState.publicStorage.set({
leafIndex: hash(context.environment.storageAddress, M[slotOffset]),
leaf: M[srcOffset],
})
  • World State access tracing:
context.worldStateAccessTrace.publicStorageWrites.append(
TracedStorageWrite {
callPointer: context.environment.callPointer,
slot: M[slotOffset],
value: M[srcOffset],
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Storage slot siloing (hash with contract address), public data tree update
  • Bit-size: 88

NOTEHASHEXISTS

Check whether a note hash exists in the note hash tree (as of the start of the current block)

See in table.

  • Opcode: 0x29
  • Category: World State - Notes & Nullifiers
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • noteHashOffset: memory offset of the note hash
    • leafIndexOffset: memory offset of the leaf index
    • existsOffset: memory offset specifying where to store operation's result (whether the note hash leaf exists)
  • Expression:
exists = context.worldState.noteHashes.has({
leafIndex: M[leafIndexOffset]
leaf: hash(context.environment.storageAddress, M[noteHashOffset]),
})
M[existsOffset] = exists
  • World State access tracing:
context.worldStateAccessTrace.noteHashChecks.append(
TracedNoteHashCheck {
callPointer: context.environment.callPointer,
leafIndex: M[leafIndexOffset]
noteHash: M[noteHashOffset],
exists: exists, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Note hash siloing (hash with storage contract address), note hash tree membership check
  • Tag updates: T[existsOffset] = u8
  • Bit-size: 120

EMITNOTEHASH

Emit a new note hash to be inserted into the note hash tree

See in table.

  • Opcode: 0x2a
  • Category: World State - Notes & Nullifiers
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • noteHashOffset: memory offset of the note hash
  • Expression:
context.worldState.noteHashes.append(
hash(context.environment.storageAddress, M[noteHashOffset])
)
  • World State access tracing:
context.worldStateAccessTrace.newNoteHashes.append(
TracedNoteHash {
callPointer: context.environment.callPointer,
noteHash: M[noteHashOffset], // unsiloed note hash
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Note hash siloing (hash with contract address), note hash tree insertion.
  • Bit-size: 56

NULLIFIEREXISTS

Check whether a nullifier exists in the nullifier tree (including nullifiers from earlier in the current transaction or from earlier in the current block)

See in table.

  • Opcode: 0x2b
  • Category: World State - Notes & Nullifiers
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • nullifierOffset: memory offset of the unsiloed nullifier
    • addressOffset: memory offset of the storage address
    • existsOffset: memory offset specifying where to store operation's result (whether the nullifier exists)
  • Expression:
exists = pendingNullifiers.has(M[addressOffset], M[nullifierOffset]) || context.worldState.nullifiers.has(
hash(M[addressOffset], M[nullifierOffset])
)
M[existsOffset] = exists
  • World State access tracing:
context.worldStateAccessTrace.nullifierChecks.append(
TracedNullifierCheck {
callPointer: context.environment.callPointer,
nullifier: M[nullifierOffset],
storageAddress: M[addressOffset],
exists: exists, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Nullifier siloing (hash with storage contract address), nullifier tree membership check
  • Tag updates: T[existsOffset] = u8
  • Bit-size: 120

EMITNULLIFIER

Emit a new nullifier to be inserted into the nullifier tree

See in table.

  • Opcode: 0x2c
  • Category: World State - Notes & Nullifiers
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • nullifierOffset: memory offset of nullifier
  • Expression:
context.worldState.nullifiers.append(
hash(context.environment.storageAddress, M[nullifierOffset])
)
  • World State access tracing:
context.worldStateAccessTrace.newNullifiers.append(
TracedNullifier {
callPointer: context.environment.callPointer,
nullifier: M[nullifierOffset], // unsiloed nullifier
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
  • Triggers downstream circuit operations: Nullifier siloing (hash with contract address), nullifier tree non-membership-check and insertion.
  • Bit-size: 56

L1TOL2MSGEXISTS

Check if a message exists in the L1-to-L2 message tree

See in table.

  • Opcode: 0x2d
  • Category: World State - Messaging
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • msgHashOffset: memory offset of the message hash
    • msgLeafIndexOffset: memory offset of the message's leaf index in the L1-to-L2 message tree
    • existsOffset: memory offset specifying where to store operation's result (whether the message exists in the L1-to-L2 message tree)
  • Expression:
exists = context.worldState.l1ToL2Messages.has({
leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset]
})
M[existsOffset] = exists
  • World State access tracing:
context.worldStateAccessTrace.l1ToL2MessagesChecks.append(
L1ToL2Message {
callPointer: context.environment.callPointer,
leafIndex: M[msgLeafIndexOffset],
msgHash: M[msgHashOffset],
exists: exists, // defined above
}
)
  • Triggers downstream circuit operations: L1-to-L2 message tree membership check
  • Tag updates:
T[existsOffset] = u8,
  • Bit-size: 120

HEADERMEMBER

Check if a header exists in the archive tree and retrieve the specified member if so

See in table.

  • Opcode: 0x2e
  • Category: World State - Archive Tree & Headers
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • blockIndexOffset: memory offset of the block index (same as archive tree leaf index) of the header to access
    • memberIndexOffset: memory offset of the index of the member to retrieve from the header of the specified block
    • existsOffset: memory offset specifying where to store operation's result (whether the leaf exists in the archive tree)
    • dstOffset: memory offset specifying where to store operation's result (the retrieved header member)
  • Expression:
exists = context.worldState.header.has({
leafIndex: M[blockIndexOffset], leaf: M[msgKeyOffset]
})
M[existsOffset] = exists
if exists:
header = context.worldState.headers.get(M[blockIndexOffset])
M[dstOffset] = header[M[memberIndexOffset]] // member
  • World State access tracing:
context.worldStateAccessTrace.archiveChecks.append(
TracedArchiveLeafCheck {
leafIndex: M[blockIndexOffset], // leafIndex == blockIndex
leaf: exists ? hash(header) : 0, // "exists" defined above
}
)
  • Additional AVM circuit checks: Hashes entire header to archive leaf for tracing. Aggregates header accesses and so that a header need only be hashed once.
  • Triggers downstream circuit operations: Archive tree membership check
  • Tag updates:
T[existsOffset] = u8
T[dstOffset] = field
  • Bit-size: 152

GETCONTRACTINSTANCE

Copies contract instance data to memory

See in table.

  • Opcode: 0x2f
  • Category: Other
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • addressOffset: memory offset of the contract instance address
    • dstOffset: location to write the contract instance information to
  • Expression:
M[dstOffset:dstOffset+CONTRACT_INSTANCE_SIZE+1] = [
instance_found_in_address,
instance.salt ?? 0,
instance.deployer ?? 0,
instance.contractClassId ?? 0,
instance.initializationHash ?? 0,
instance.portalContractAddress ?? 0,
instance.publicKeysHash ?? 0,
]
  • Additional AVM circuit checks: TO-DO
  • Triggers downstream circuit operations: TO-DO
  • Tag updates: T[dstOffset:dstOffset+CONTRACT_INSTANCE_SIZE+1] = field
  • Bit-size: 88

EMITUNENCRYPTEDLOG

Emit an unencrypted log

See in table.

  • Opcode: 0x30
  • Category: Accrued Substate - Logging
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • eventSelectorOffset: memory offset of the event selector
    • logOffset: memory offset of the data to log
    • logSize: number of words to log
  • Expression:
context.accruedSubstate.unencryptedLogs.append(
UnencryptedLog {
address: context.environment.address,
eventSelector: M[eventSelectorOffset],
log: M[logOffset:logOffset+logSize],
}
)
  • Bit-size: 120

SENDL2TOL1MSG

Send an L2-to-L1 message

See in table.

  • Opcode: 0x31
  • Category: Accrued Substate - Messaging
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • recipientOffset: memory offset of the message recipient
    • contentOffset: memory offset of the message content
  • Expression:
context.accruedSubstate.sentL2ToL1Messages.append(
SentL2ToL1Message {
address: context.environment.address,
recipient: M[recipientOffset],
message: M[contentOffset]
}
)
  • Bit-size: 88

CALL

Call into another contract

See in table.

  • Opcode: 0x32
  • Category: Control Flow - Contract Calls
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • gasOffset: offset to two words containing {l2GasLeft, daGasLeft}: amount of gas to provide to the callee
    • addrOffset: address of the contract to call
    • argsOffset: memory offset to args (will become the callee's calldata)
    • argsSizeOffset: memory offset for the number of words to pass via callee's calldata
    • retOffset: destination memory offset specifying where to store the data returned from the callee
    • retSize: number of words to copy from data returned by callee
    • successOffset: destination memory offset specifying where to store the call's success (0: failure, 1: success)
  • Expression:
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
  • Details: Creates a new (nested) execution context and triggers execution within that context. Execution proceeds in the nested context until it reaches a halt at which point execution resumes in the current/calling context. A non-existent contract or one with no code will return success. "Nested contract calls" provides a full explanation of this instruction along with the shorthand used in the expression above. The explanation includes details on charging gas for nested calls, nested context derivation, world state tracing, and updating the parent context after the nested call halts.
  • Tag checks: T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32
  • Tag updates:
T[successOffset] = u8
T[retOffset:retOffset+retSize] = field
  • Bit-size: 248

STATICCALL

Call into another contract, disallowing World State and Accrued Substate modifications

See in table.

  • Opcode: 0x33
  • Category: Control Flow - Contract Calls
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • gasOffset: offset to two words containing {l2GasLeft, daGasLeft}: amount of gas to provide to the callee
    • addrOffset: address of the contract to call
    • argsOffset: memory offset to args (will become the callee's calldata)
    • argsSizeOffset: memory offset for the number of words to pass via callee's calldata
    • retOffset: destination memory offset specifying where to store the data returned from the callee
    • retSize: number of words to copy from data returned by callee
    • successOffset: destination memory offset specifying where to store the call's success (0: failure, 1: success)
  • Expression:
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=true, isDelegateCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
  • Details: Same as CALL, but disallows World State and Accrued Substate modifications. "Nested contract calls" provides a full explanation of this instruction along with the shorthand used in the expression above. The explanation includes details on charging gas for nested calls, nested context derivation, world state tracing, and updating the parent context after the nested call halts.
  • Tag checks: T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32
  • Tag updates:
T[successOffset] = u8
T[retOffset:retOffset+retSize] = field
  • Bit-size: 248

DELEGATECALL

Call into another contract, but keep the caller's sender and storageAddress

See in table.

  • Opcode: 0x34
  • Category: Control Flow - Contract Calls
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • gasOffset: offset to two words containing {l2GasLeft, daGasLeft}: amount of gas to provide to the callee
    • addrOffset: address of the contract to call
    • argsOffset: memory offset to args (will become the callee's calldata)
    • argsSizeOffset: memory offset for the number of words to pass via callee's calldata
    • retOffset: destination memory offset specifying where to store the data returned from the callee
    • retSize: number of words to copy from data returned by callee
    • successOffset: destination memory offset specifying where to store the call's success (0: failure, 1: success)
  • Expression:
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false, isDelegateCall=true)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
  • Details: Same as CALL, but sender and storageAddress remains the same in the nested call as they were in the caller. "Nested contract calls" provides a full explanation of this instruction along with the shorthand used in the expression above. The explanation includes details on charging gas for nested calls, nested context derivation, world state tracing, and updating the parent context after the nested call halts.
  • Tag checks: T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32
  • Tag updates:
T[successOffset] = u8
T[retOffset:retOffset+retSize] = field
  • Bit-size: 248

RETURN

Halt execution within this context (without revert), optionally returning some data

See in table.

  • Opcode: 0x35
  • Category: Control Flow - Contract Calls
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • retOffset: memory offset of first word to return
    • retSize: number of words to return
  • Expression:
context.contractCallResults.output = M[retOffset:retOffset+retSize]
halt
  • Details: Return control flow to the calling context/contract. Caller will accept World State and Accrued Substate modifications. See "Halting" to learn more. See "Nested contract calls" to see how the caller updates its context after the nested call halts.
  • Bit-size: 88

REVERT

Halt execution within this context as reverted, optionally returning some data

See in table.

  • Opcode: 0x36
  • Category: Control Flow - Contract Calls
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • retOffset: memory offset of first word to return
    • retSize: number of words to return
  • Expression:
context.contractCallResults.output = M[retOffset:retOffset+retSize]
context.contractCallResults.reverted = true
halt
  • Details: Return control flow to the calling context/contract. Caller will reject World State and Accrued Substate modifications. See "Halting" to learn more. See "Nested contract calls" to see how the caller updates its context after the nested call halts.
  • Bit-size: 88

TORADIXLE

Convert a word to an array of limbs in little-endian radix form

See in table.

  • Opcode: 0x37
  • Category: Conversions
  • Flags:
    • indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like M[M[offset]] instead of the more standard M[offset].
  • Args:
    • srcOffset: memory offset of word to convert.
    • dstOffset: memory offset specifying where the first limb of the radix-conversion result is stored.
    • radix: the maximum bit-size of each limb.
    • numLimbs: the number of limbs the word will be converted into.
  • Expression: TBD: Storage of limbs and if T[dstOffset] is constrained to U8
  • Details: The limbs will be stored in a contiguous memory block starting at dstOffset.
  • Tag checks: T[srcOffset] == field
  • Bit-size: 152
  • Instructions Table
  • Instructions
    • ADD
    • SUB
    • MUL
    • DIV
    • FDIV
    • EQ
    • LT
    • LTE
    • AND
    • OR
    • XOR
    • NOT
    • SHL
    • SHR
    • CAST
    • ADDRESS
    • STORAGEADDRESS
    • SENDER
    • FEEPERL2GAS
    • FEEPERDAGAS
    • TRANSACTIONFEE
    • CONTRACTCALLDEPTH
    • CHAINID
    • VERSION
    • BLOCKNUMBER
    • TIMESTAMP
    • COINBASE
    • BLOCKL2GASLIMIT
    • BLOCKDAGASLIMIT
    • CALLDATACOPY
    • L2GASLEFT
    • DAGASLEFT
    • JUMP
    • JUMPI
    • INTERNALCALL
    • INTERNALRETURN
    • SET
    • MOV
    • CMOV
    • SLOAD
    • SSTORE
    • NOTEHASHEXISTS
    • EMITNOTEHASH
    • NULLIFIEREXISTS
    • EMITNULLIFIER
    • L1TOL2MSGEXISTS
    • HEADERMEMBER
    • GETCONTRACTINSTANCE
    • EMITUNENCRYPTEDLOG
    • SENDL2TOL1MSG
    • CALL
    • STATICCALL
    • DELEGATECALL
    • RETURN
    • REVERT
    • TORADIXLE