019ba9bc-ec32-7329-bfc3-da15d78dd649
Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?
| ID | Type | Status | Attempts | Heartbeat |
|---|---|---|---|---|
| 37720 | artifact.fetch | complete | 1 / 3 | 3 months ago |
| 37721 | proxy.resolve | complete | 1 / 3 | 3 months ago |
| 37722 | tool.cast_disasm | complete | 1 / 3 | 3 months ago |
| 37723 | analysis.bundle | complete | 1 / 3 | 3 months ago |
| 37724 | capability.graph | complete | 1 / 3 | 3 months ago |
| 37725 | detector.run | complete | 1 / 3 | 3 months ago |
| 37726 | validation.fork | complete | 1 / 3 | 3 months ago |
| 37895 | report.consolidate | complete | 1 / 6 | 3 months ago |
{
"status": "not_proxy"
}
No slither job recorded yet.
{"no_findings":false,"summary":"Bytecode shows an owner-controlled SELFDESTRUCT path and multiple low-level CALLs with ETH value to computed targets (some owner-gated, one apparently user-accessible with effects-before-interactions). No delegatecall/proxy patterns detected in the bundle.","findings":[{"severity":"medium","category":"other","title":"Owner-reachable SELFDESTRUCT can permanently disable the contract","exploit_scenario":"If the owner key is compromised or misused, the SELFDESTRUCT path can be invoked to destroy the contract and send the remaining ETH to an arbitrary address, permanently disabling all functionality for users.","recommendation":"Remove SELFDESTRUCT or gate it behind a timelock/multisig and/or an irreversible disable after deployment. If it is intended, document the risk clearly.","evidence":"A SELFDESTRUCT opcode is reachable after an owner check (SLOAD slot0 masked vs CALLER). The path is invoked via the selector that jumps to pc 0x031c and culminates in SELFDESTRUCT at pc 0x0342.","locations":["selector:0xb9caebf4","pc:0x031d","pc:0x0342"]},{"severity":"medium","category":"access_control","title":"Privileged low-level CALLs with ETH to computed targets (centralization risk)","exploit_scenario":"An owner can trigger low-level CALLs that transfer ETH to computed targets (including a path that uses the contract balance), allowing full fund extraction or arbitrary external interactions if the owner is compromised or malicious.","recommendation":"If arbitrary execution is not required, restrict call targets/amounts or remove these calls. Otherwise, use a multisig + timelock and document the admin powers. Consider adding explicit allowlists or rate limits.","evidence":"Owner check occurs at pc 0x04c0 before two CALL sites that use computed targets/values (pc 0x0575 and pc 0x05b2). The sequence includes ADDRESS/BALANCE, implying ETH transfers under privileged control.","locations":["selector:0xf5bf7413","pc:0x04c0","pc:0x0575","pc:0x05b2"]},{"severity":"low","category":"reentrancy","title":"User-accessible CALL with value has no explicit reentrancy guard","exploit_scenario":"A user-invoked function performs a low-level CALL with value to a computed target. Although storage is updated before the call (effects-before-interactions), a malicious callee could reenter other functions that rely on transient invariants.","recommendation":"If any cross-function invariants exist, add a reentrancy guard to this call path or ensure all state updates are completed before external interaction. Document the intended reentrancy model.","evidence":"CALL at pc 0x066b occurs after an SSTORE at pc 0x0653 in the function reached by selector 0xfa89401a; no mutex/guard pattern is visible in the bytecode.","locations":["selector:0xfa89401a","pc:0x0653","pc:0x066b"]}]}
OpenAI Codex v0.77.0 (research preview)
--------
workdir: /tmp/codex-o1lrvfrs
model: gpt-5.2-codex
provider: openai
approval: never
sandbox: read-only
reasoning effort: xhigh
reasoning summaries: auto
session id: 019ba9bd-a2ac-7342-a478-2af4e073c94a
--------
user
You are a security auditor. You ONLY have runtime bytecode + analysis artifacts.
You MUST read `BYTECODE_BUNDLE.json` before concluding; it contains the bytecode summary,
evidence bundle, callsites, storage slots, and detector findings.
Special cases when reasoning from bytecode (be explicit about uncertainty):
- Selector inference is best-effort; missing selectors are common.
- Fallback/receive paths may be the only entrypoints.
- CALL vs DELEGATECALL semantics differ; DELEGATECALL executes in caller storage.
- Proxy patterns (EIP-1967, minimal proxies, beacon) change which storage is authoritative.
- Storage slots are raw; mappings/arrays appear via keccak patterns, names are unknown.
- Guard detection is heuristic; absence of guards does NOT mean unguarded.
- Returndata checking is unknown unless explicitly shown in evidence.
- Precompiles (0x1..0x9) and common ERC20 transfer selectors may appear; do not over-claim.
Output MUST be valid JSON matching the provided schema.
- If you find nothing meaningful: set no_findings=true and findings=[].
- Otherwise: set no_findings=false and include findings with severity/category/title.
- Locations can be pc references like "pc:0x123" or selectors like "selector:0xa9059cbb".
Focus on: reentrancy, access control, upgradeability/proxy issues, signature validation,
accounting/invariant breaks, dangerous delegatecall, and untrusted external calls.
Be conservative: if evidence is weak, mark severity low/medium and explain why.
mcp startup: no servers
thinking
**Reading BYTECODE_BUNDLE.json**
exec
/bin/bash -lc ls in /tmp/codex-o1lrvfrs succeeded in 7ms:
BYTECODE_BUNDLE.json
codex-output-schema.json
exec
/bin/bash -lc 'cat BYTECODE_BUNDLE.json' in /tmp/codex-o1lrvfrs succeeded in 8ms:
{
"analysis_artifact": {
"address": "0xd32c59bdf5409842c0dec13a546a3916b7485694",
"artifact_hash": "0x2bf44a9c729fa79ba25f4bea76b6b37b5caeb1a1715a6f0ff3eb42775aa1c852",
"artifact_json": {
"auth": {
"guards": []
},
"basic_blocks": [
{
"end_pc": 12,
"hash": "0x434198e72fc136da3a2e55595e8f204a47c8c94404eb84f07a7325db3defc927",
"opcodes": [
"PUSH1",
"PUSH1",
"MSTORE",
"PUSH1",
"CALLDATASIZE",
"LT",
"PUSH2",
thinking
**Analyzing bytecode bundle components**
exec
/bin/bash -lc 'rg -n "storage|slot|proxy|delegatecall|selfdestruct|upgrade|owner|admin|callsite|function" BYTECODE_BUNDLE.json' in /tmp/codex-o1lrvfrs succeeded in 25ms:
1887: "callsites": [
2424: "function_entries": [
2466: "functions": [
2475: "delegatecall": 0,
2476: "selfdestruct": 1,
2479: "storage": {
2481: "slots": [
2485: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2490: "slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
2495: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2500: "slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
2505: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2510: "slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
2515: "slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
2520: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2525: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2530: "slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
2535: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2540: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
2545: "slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
thinking
**Inspecting callsites near line 1887**
exec
/bin/bash -lc "sed -n '1860,1945p' BYTECODE_BUNDLE.json" in /tmp/codex-o1lrvfrs succeeded in 20ms:
"end_pc": 1760,
"hash": "0xfb083f0d7f122d6daac0c7b2d8c7055723b97b6732419d2c1cdf79486b8b9238",
"opcodes": [
"OP_A1",
"PUSH6",
"SHA3",
"OP_97",
"OP_EA",
"OP_E3",
"CALLDATASIZE",
"OP_92"
],
"start_pc": 1747
},
{
"end_pc": 1765,
"hash": "0x38c3348b4b24dc8c07eb5b01006ec4f62e5cbc1b284008c78921fa846ae276a5",
"opcodes": [
"JUMPDEST",
"EXTCODEHASH",
thinking
**Noting additional function entries**
exec
/bin/bash -lc "sed -n '2400,2525p' BYTECODE_BUNDLE.json" in /tmp/codex-o1lrvfrs succeeded in 6ms:
},
{
"from": "bb:1569",
"to": "bb:1655",
"type": "control_flow_fallthrough"
},
{
"from": "bb:1724",
"to": "bb:1739",
"type": "control_flow"
},
{
"from": "bb:1724",
"to": "bb:1738",
"type": "control_flow_fallthrough"
},
{
"from": "bb:1747",
"to": "bb:1761",
"type": "control_flow_fallthrough"
thinking
**Exploring further for write and self-destruct actions**
exec
/bin/bash -lc "sed -n '2525,2625p' BYTECODE_BUNDLE.json" in /tmp/codex-o1lrvfrs succeeded in 11ms:
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
"pc": 838,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 847,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
"pc": 895,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
"pc": 956,
thinking
**Investigating repeated function clones**
exec
/bin/bash -lc 'rg -n "SELFDESTRUCT" BYTECODE_BUNDLE.json' in /tmp/codex-o1lrvfrs succeeded in 7ms:
973: "SELFDESTRUCT"
5608: "sink": "SELFDESTRUCT"
5611: "title": "SELFDESTRUCT reachable",
5620: "sink": "SELFDESTRUCT",
thinking
**Checking opcode listing for SELFDESTRUCT**
exec
/bin/bash -lc "sed -n '930,1015p' BYTECODE_BUNDLE.json" in /tmp/codex-o1lrvfrs succeeded in 25ms:
"opcodes": [
"JUMPDEST",
"PUSH1",
"SLOAD",
"CALLER",
"PUSH1",
"PUSH1",
"PUSH1",
"EXP",
"SUB",
"OP_90",
"OP_81",
"AND",
"OP_91",
"AND",
"EQ",
"PUSH2",
"JUMPI"
],
"start_pc": 796
thinking
**Analyzing proxy admin storage slots**
exec
/bin/bash -lc "python - <<'PY'
import hashlib
keys = [
'eip1967.proxy.admin',
'eip1967.proxy.implementation',
'eip1967.proxy.beacon',
'eip1967.proxy.rollback',
'org.zeppelinos.proxy.admin',
'eip1967.proxy.owner',
'eip1967.proxy.operator',
'eip1967.proxy.proxiable',
'eip1967.proxy.masterCopy',
'eip1967.proxy.logic',
'openzeppelin.proxy.admin',
'EIP1967.proxy.admin',
'EIP1967.proxy.implementation',
'eip1967.admin',
'eip1967.proxy.implementation.v1',
]
for k in keys:
h = hashlib.sha3_256(k.encode()).hexdigest()
slot = int(h, 16) - 1
print(k, hex(slot))
# check known 0x8be0079c...
print('target', '0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0')
PY" in /tmp/codex-o1lrvfrs succeeded in 30ms:
eip1967.proxy.admin 0x5846d050da0e75d43b6055ae3cd6c2c65e1941ccb45afff84b891ff0c7a8e50e
eip1967.proxy.implementation 0x169aa7877a62aec264f92a4c78812101abc42f65cbb20781a5cb4084c2d639d7
eip1967.proxy.beacon 0x79d0e26f0ed6a26bf96d37944c615e11aedbfafe56e064339e13dad9525cda31
eip1967.proxy.rollback 0x9918ff29762f88fdc924c0a0ba5589b288a6baef366b4981f9a6f4309baada55
org.zeppelinos.proxy.admin 0xe59ed60ca6e4e7df6bd875f45f3199fa50d18f9f8eab0cbc73f528c3bf38189c
eip1967.proxy.owner 0xa94ebdd3c074493cb52768014c2ef842da51c56ea919459168310621970ad9d0
eip1967.proxy.operator 0x1bc57950e7e87ddb2e1fd468be7d386f14341c4f58f2e1b5ae9bc5c7057c7c0
eip1967.proxy.proxiable 0x834da78d022446a4e60e568318d9bfed539f9142721d47ae308f5f5f520c8e3a
eip1967.proxy.masterCopy 0xa1149e0101cd350b4e18716dc87535187a546b6fdc78f1ed2eeaa57ace633d94
eip1967.proxy.logic 0xd9ddb2e122446356b04c14be4d42e1c40d02245a18b9c1a18102de7f6cfa4786
openzeppelin.proxy.admin 0xd740b40f0f3f50e6209ada64c25a33f107517eb2c05de7e3397bfbb0f6cdbaf6
EIP1967.proxy.admin 0xe8d64b2e1e492bb293a88fd27a38d7b94c1f32274a34112849ae01f1d971ba62
EIP1967.proxy.implementation 0xbe58c6578a4ab1ecf11345a15902a106ecb5df07e4b8d27696b57d59fd6ec1a3
eip1967.admin 0xe8a91ba9591a6b855bd0b916a706dbcf487665ff4db3dd9eee2bce1a3093eaeb
eip1967.proxy.implementation.v1 0xaa322e21c3a5a7bc08f27560df6580721f4992390573e13da995f8f847c1c01c
target 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
thinking
**Investigating slot hashes and keccak differences**
exec
/bin/bash -lc "python - <<'PY'
try:
import sha3
print('sha3 module available')
k = sha3.keccak_256()
k.update(b'eip1967.proxy.admin')
h = int(k.hexdigest(),16)-1
print('admin slot', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.implementation'); h=int(k.hexdigest(),16)-1
print('impl slot', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.beacon'); h=int(k.hexdigest(),16)-1
print('beacon slot', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.rollback'); h=int(k.hexdigest(),16)-1
print('rollback', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.owner'); h=int(k.hexdigest(),16)-1
print('owner', hex(h))
k = sha3.keccak_256(); k.update(b'org.zeppelinos.proxy.admin'); h=int(k.hexdigest(),16)-1
print('zeppelin admin', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.masterCopy'); h=int(k.hexdigest(),16)-1
print('mastercopy', hex(h))
k = sha3.keccak_256(); k.update(b'EIP1967.proxy.admin'); h=int(k.hexdigest(),16)-1
print('cap admin', hex(h))
k = sha3.keccak_256(); k.update(b'openzeppelin.proxy.admin'); h=int(k.hexdigest(),16)-1
print('openzeppelin admin', hex(h))
k = sha3.keccak_256(); k.update(b'eip1967.proxy.logic'); h=int(k.hexdigest(),16)-1
print('logic', hex(h))
k = sha3.keccak_256(); k.update(b'PROXIABLE'); h=int(k.hexdigest(),16)
print('proxiable', hex(h))
k = sha3.keccak_256(); k.update(b'AccessControl'); h=int(k.hexdigest(),16)
print('accesscontrol', hex(h))
except Exception as e:
print('error', e)
PY" in /tmp/codex-o1lrvfrs succeeded in 17ms:
error No module named 'sha3'
thinking
**Analyzing callsites and contract behavior**
I'm examining call targets that seem to be self-calls, which might indicate internal ETH transfers or reentrancy risks, though external untrusted calls seem unlikely from trace data. I'm parsing callsite PCs and corresponding opcode blocks to assess call targets, access control (notably owner checks for selfdestruct), and function mappings, aware that analysis artifacts show some uncertainties—like uniform sink counts for all functions—meaning function boundaries and call details may be imprecise. I'm exploring whether calls use computed addresses from calldata or storage to better understand potential vulnerabilities.
exec
/bin/bash -lc 'rg -n "evidence|disasm|instruction|opcodes_with_pc|pc_map|analysis" BYTECODE_BUNDLE.json' in /tmp/codex-o1lrvfrs succeeded in 15ms:
2: "analysis_artifact": {
4006: "version": "analysis_artifact_v1"
4014: "version": "analysis_artifact_v1"
4016: "analysis_run": {
4040: "proxy_evidence": {
5499: "evidence_json": {
5551: "evidence_json": {
5603: "evidence_json": {
thinking
**Inspecting analysis_run for evidence**
exec
/bin/bash -lc "sed -n '3980,4085p' BYTECODE_BUNDLE.json" in /tmp/codex-o1lrvfrs succeeded in 6ms:
"pc": 1249,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 1297,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 1487,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000002"
},
{
"op": "SLOAD",
"pc": 1515,
"slot": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"op": "SLOAD",
thinking
**Decoding runtime bytecode**
I’m going to analyze the full runtime bytecode from the artifact by writing a Python script that disassembles the hex into EVM opcodes. I want to focus on key program counters such as known callsites and the selfdestruct opcode to better understand the contract’s functions and security aspects. This approach avoids relying on network tools and helps reveal the contract logic directly from the bytecode.
exec
/bin/bash -lc "python - <<'PY'
import json
# load runtime bytecode
with open('BYTECODE_BUNDLE.json','r') as f:
data = json.load(f)
code_hex = data['artifact']['runtime_bytecode']['full']
assert code_hex.startswith('0x')
code = bytes.fromhex(code_hex[2:])
# EVM opcode table
opcodes = {i: f'OP_{i:02X}' for i in range(256)}
# fill known
names = {
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT',
}
opcodes.update(names)
# disassemble
instrs=[]
pc=0
while pc < len(code):
op = code[pc]
name = opcodes.get(op, f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n = op - 0x5f
data = code[pc+1:pc+1+n]
instrs.append((pc, name, data.hex()))
pc += 1 + n
else:
instrs.append((pc, name, None))
pc += 1
# helper to print window around pc
def print_window(center, radius=20):
# find index
idx = next((i for i,(p,_,_) in enumerate(instrs) if p==center), None)
if idx is None:
# find nearest
idx = max(i for i,(p,_,_) in enumerate(instrs) if p<center)
start = max(0, idx-radius)
end = min(len(instrs), idx+radius)
for p,name,data in instrs[start:end]:
if data is None:
print(f\"{p:04x}: {name}\")
else:
print(f\"{p:04x}: {name} 0x{data}\")
print('---')
for center in [823, 1397, 1458, 1643]:
print('WINDOW', center)
print_window(center, radius=25)
# also print function selectors table from dispatcher
# find sequences of PUSH4 (selector) and JUMPI near start
print('Dispatcher selectors:')
for i,(p,name,data) in enumerate(instrs[:200]):
if name=='PUSH4':
print(f\"{p:04x}: selector 0x{data}\")
PY" in /tmp/codex-o1lrvfrs succeeded in 32ms:
WINDOW 823
0317: EXP
0318: SUB
0319: AND
031a: DUP2
031b: JUMP
031c: JUMPDEST
031d: PUSH1 0x00
031f: SLOAD
0320: CALLER
0321: PUSH1 0x01
0323: PUSH1 0xa0
0325: PUSH1 0x02
0327: EXP
0328: SUB
0329: SWAP1
032a: DUP2
032b: AND
032c: SWAP2
032d: AND
thinking
**Analyzing dynamic call patterns and dispatch table**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data = json.load(f)
code_hex = data['artifact']['runtime_bytecode']['full']
code = bytes.fromhex(code_hex[2:])
# opcode lengths
oplen = {**{i:1 for i in range(256)}, **{i:1 for i in range(0x60,0x80)}}
for i in range(0x60,0x80):
oplen[i] = 1 + (i - 0x5f)
# disasm with pc and immediate values
instrs=[]
pc=0
while pc < len(code):
op=code[pc]
name = op
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
instrs.append((pc, op, data))
pc += 1+n
else:
instrs.append((pc, op, None))
pc += 1
# extract dispatcher entries: look for pattern PUSH4 sel, EQ, PUSH2 dest, JUMPI
entries=[]
for i in range(len(instrs)-3):
p1,op1,data1 = instrs[i]
p2,op2,_= instrs[i+1]
p3,op3,data3 = instrs[i+2]
p4,op4,_= instrs[i+3]
if op1==0x63 and op2==0x14 and op3==0x61 and op4==0x57:
sel = data1.hex()
dest = int.from_bytes(data3, 'big')
entries.append((sel, dest, p1))
print('Dispatcher entries:')
for sel, dest, p in entries:
print(f\"selector 0x{sel} -> {dest} (at pc {p})\")
# map dest to first few instructions
opnames = {i: f'OP_{i:02X}' for i in range(256)}
name_map = {
0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT',
}
# create map from pc to index
idx_by_pc = {p:i for i,(p,_,_) in enumerate(instrs)}
for sel, dest, p in entries:
idx = idx_by_pc.get(dest)
if idx is None:
continue
# print first 8 instructions from dest
print(f\"\\nEntry 0x{sel} at pc {dest}\")
for p2,op,data in instrs[idx:idx+10]:
name = name_map.get(op,f'OP_{op:02X}')
if data is None:
print(f\" {p2:04x}: {name}\")
else:
print(f\" {p2:04x}: {name} 0x{data.hex()}\")
PY" in /tmp/codex-o1lrvfrs succeeded in 41ms:
Dispatcher entries:
selector 0x47fa061e -> 189 (at pc 65)
selector 0x8c52dc41 -> 244 (at pc 76)
selector 0x8da5cb5b -> 263 (at pc 87)
selector 0xb9caebf4 -> 310 (at pc 98)
selector 0xc19d93fb -> 341 (at pc 109)
selector 0xf2fde38b -> 396 (at pc 120)
selector 0xf340fa01 -> 427 (at pc 131)
selector 0xf5bf7413 -> 447 (at pc 142)
selector 0xfa89401a -> 487 (at pc 153)
Entry 0x47fa061e at pc 189
00bd: JUMPDEST
00be: CALLVALUE
00bf: ISZERO
00c0: PUSH2 0x00c8
00c3: JUMPI
00c4: PUSH1 0x00
00c6: DUP1
00c7: REVERT
thinking
**Investigating missing selector in dispatch**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={i:f'OP_{i:02X}' for i in range(256)}
# fill names same as before
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
pc=0
count=0
while pc < len(code) and count < 80:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
count+=1
PY" in /tmp/codex-o1lrvfrs succeeded in 28ms:
0000: PUSH1 0x60
0002: PUSH1 0x40
0004: MSTORE
0005: PUSH1 0x04
0007: CALLDATASIZE
0008: LT
0009: PUSH2 0x00a3
000c: JUMPI
000d: PUSH4 0xffffffff
0012: PUSH29 0x0100000000000000000000000000000000000000000000000000000000
0030: PUSH1 0x00
0032: CALLDATALOAD
0033: DIV
0034: AND
0035: PUSH4 0x1ef3755d
003a: DUP2
003b: EQ
003c: PUSH2 0x00a8
003f: JUMPI
0040: DUP1
thinking
**Analyzing function entries and control flow**
I'm parsing the bytecode to identify function selectors and their semantics, focusing on calls and access control by tracing jumps and function boundaries. I plan to disassemble each entry point, track internal jumps, and recognize typical return wrappers to understand the control flow and behaviors without source code or network access.
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# disasm function
opnames={i:f'OP_{i:02X}' for i in range(256)}
# add known names
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
# build mapping pc->(op,data)
instrs=[]
pc=0
while pc < len(code):
op = code[pc]
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
instrs.append((pc, op, data))
pc += 1+n
else:
instrs.append((pc, op, None))
pc += 1
idx_by_pc = {p:i for i,(p,_,_) in enumerate(instrs)}
# print around 0x00bb
start=idx_by_pc[0x00bb]
for p,op,data in instrs[start:start+20]:
name = opnames.get(op,f'OP_{op:02X}')
if data is None:
print(f\"{p:04x}: {name}\")
else:
print(f\"{p:04x}: {name} 0x{data.hex()}\")
PY" in /tmp/codex-o1lrvfrs succeeded in 28ms:
00bb: JUMPDEST
00bc: STOP
00bd: JUMPDEST
00be: CALLVALUE
00bf: ISZERO
00c0: PUSH2 0x00c8
00c3: JUMPI
00c4: PUSH1 0x00
00c6: DUP1
00c7: REVERT
00c8: JUMPDEST
00c9: PUSH2 0x00e2
00cc: PUSH1 0xff
00ce: PUSH1 0x04
00d0: CALLDATALOAD
00d1: AND
00d2: PUSH1 0x01
00d4: PUSH1 0xa0
00d6: PUSH1 0x02
00d8: EXP
thinking
**Tracing function callsites and STOP instruction**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={i:f'OP_{i:02X}' for i in range(256)}
# add names
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
# disasm
instrs=[]
pc=0
while pc < len(code):
op=code[pc]
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
instrs.append((pc, op, data))
pc += 1+n
else:
instrs.append((pc, op, None))
pc += 1
idx_by_pc = {p:i for i,(p,_,_) in enumerate(instrs)}
start=idx_by_pc[0x01ab]
end=start+120
for p,op,data in instrs[start:end]:
name = opnames.get(op,f'OP_{op:02X}')
if data is None:
print(f\"{p:04x}: {name}\")
else:
print(f\"{p:04x}: {name} 0x{data.hex()}\")
PY" in /tmp/codex-o1lrvfrs succeeded in 31ms:
01ab: JUMPDEST
01ac: PUSH2 0x00bb
01af: PUSH1 0x01
01b1: PUSH1 0xa0
01b3: PUSH1 0x02
01b5: EXP
01b6: SUB
01b7: PUSH1 0x04
01b9: CALLDATALOAD
01ba: AND
01bb: PUSH2 0x03e7
01be: JUMP
01bf: JUMPDEST
01c0: CALLVALUE
01c1: ISZERO
01c2: PUSH2 0x01ca
01c5: JUMPI
01c6: PUSH1 0x00
01c8: DUP1
01c9: REVERT
thinking
**Analyzing function entry points and events**
I'm piecing together which function selectors map to code locations and their roles, like deciding if they handle calls or state changes. I also confirmed the OwnershipTransferred event by matching its signature hash, and I'm sorting out some confusion between storage slots and event signature constants in the disassembly. There's a lot to untangle here!
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# quick disasm around 0x0360-0x03a0
opnames={i:f'OP_{i:02X}' for i in range(256)}
# names for key ops
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
# disasm window
pc=0x0340
while pc < 0x03b0:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 75ms:
0340: SUB
0341: AND
0342: SELFDESTRUCT
0343: JUMPDEST
0344: PUSH1 0x02
0346: SLOAD
0347: PUSH1 0xff
0349: AND
034a: DUP2
034b: JUMP
034c: JUMPDEST
034d: PUSH1 0x00
034f: SLOAD
0350: CALLER
0351: PUSH1 0x01
0353: PUSH1 0xa0
0355: PUSH1 0x02
0357: EXP
0358: SUB
0359: SWAP1
thinking
**Continuing process**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# simple disasm from 0x03ac to 0x0405
opnames={i:f'OP_{i:02X}' for i in range(256)}
# minimal names
names={0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',0x5b:'JUMPDEST',0x56:'JUMP',0x57:'JUMPI',0x54:'SLOAD',0x55:'SSTORE',0x52:'MSTORE',0x51:'MLOAD',0x60:'PUSH1',0x61:'PUSH2',0x7f:'PUSH32',0x73:'PUSH20',0x90:'SWAP1',0x91:'SWAP2',0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0xf3:'RETURN',0xfd:'REVERT'}
opnames.update(names)
pc=0x03a0
while pc < 0x0410:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 26ms:
03a0: PUSH32 0x9722a3daafe3b4186f6b6457e060405160405180910390a36000805473ffffff
03c1: OP_FF
03c2: OP_FF
03c3: OP_FF
03c4: OP_FF
03c5: OP_FF
03c6: OP_FF
03c7: OP_FF
03c8: OP_FF
03c9: OP_FF
03ca: OP_FF
03cb: OP_FF
03cc: OP_FF
03cd: OP_FF
03ce: OP_FF
03cf: OP_FF
03d0: OP_FF
03d1: OP_FF
03d2: OP_19
03d3: OP_16
thinking
**Correcting disassembly start address**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={i:f'OP_{i:02X}' for i in range(256)}
# names minimal
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
pc=0x038d
end=0x03f5
while pc < end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 26ms:
038d: PUSH32 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
03ae: PUSH1 0x40
03b0: MLOAD
03b1: PUSH1 0x40
03b3: MLOAD
03b4: DUP1
03b5: SWAP2
03b6: SUB
03b7: SWAP1
03b8: LOG3
03b9: PUSH1 0x00
03bb: DUP1
03bc: SLOAD
03bd: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
03d2: NOT
03d3: AND
03d4: PUSH1 0x01
03d6: PUSH1 0xa0
03d8: PUSH1 0x02
03da: EXP
thinking
**Analyzing storage slots and function signatures**
I’m piecing together the contract’s storage layout and functions by interpreting opcodes and events; slot 0 is likely the owner, slot 2 a boolean flag or mapping for allowances. The contract seems like a token or escrow managing balances, transfers, and ownership—with 9 selectors that don’t fully match ERC20, hinting at a wallet-like setup. I’m zeroing in on certain functions checking slot2 flags and ownership before calls that send ETH, aiming to verify proper access control and guards against vulnerabilities. Next, I’ll dissect the code around 0x04c0 to clarify these behaviors.
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# disasm function with pc labels
opnames={i:f'OP_{i:02X}' for i in range(256)}
# name map (subset)
name_map={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x40:'BLOCKHASH',0x41:'COINBASE',0x42:'TIMESTAMP',0x43:'NUMBER',0x44:'DIFFICULTY',0x45:'GASLIMIT',0x46:'CHAINID',0x47:'SELFBALANCE',0x48:'BASEFEE',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(name_map)
# disasm to list from 0x04c0 to 0x0600
pc=0x04c0
end=0x0605
while pc < end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 48ms:
04c0: JUMPDEST
04c1: PUSH1 0x00
04c3: SLOAD
04c4: CALLER
04c5: PUSH1 0x01
04c7: PUSH1 0xa0
04c9: PUSH1 0x02
04cb: EXP
04cc: SUB
04cd: SWAP1
04ce: DUP2
04cf: AND
04d0: SWAP2
04d1: AND
04d2: EQ
04d3: PUSH2 0x04db
04d6: JUMPI
04d7: PUSH1 0x00
04d9: DUP1
04da: REVERT
thinking
**Analyzing owner-only function with external calls**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# disasm from 0x0600 to 0x0710
opnames={i:f'OP_{i:02X}' for i in range(256)}
# names subset
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
pc=0x0600
end=0x0710
while pc < end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs exited 1 in 69ms:
0600: OP_40
0601: DUP1
0602: DUP4
0603: SHA3
0604: PUSH1 0x01
0606: PUSH1 0xa0
0608: PUSH1 0x02
060a: EXP
060b: SUB
060c: DUP6
060d: AND
060e: DUP5
060f: MSTORE
0610: SWAP1
0611: SWAP2
0612: MSTORE
0613: DUP2
0614: SHA3
0615: SLOAD
0616: SWAP1
thinking
**Analyzing bytecode for security risks**
I'm parsing bytecode to detect owner-controlled selfdestruct, owner-only arbitrary calls with ETH, and possible reentrancy; I see state updates before external calls which reduces reentrancy risk, but owner control of destructive and powerful functions poses centralization and security concerns.
thinking
**Exploring symbolic execution for call target analysis**
I’m planning a symbolic stack analysis from function entry to CALL instructions to trace if call targets and values depend on user inputs or storage, carefully handling jump logic and dependencies to clarify potential risks of untrusted external calls originating from owner and non-owner functions.
thinking
**Summarizing reentrancy and external call findings**
I’m organizing findings about calls after state updates without explicit reentrancy guards, owner-only external calls with ETH, user-accessible calls, and owner-controlled selfdestruct, preparing to produce a clear JSON report with severity, evidence, and recommendations.
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={i:f'OP_{i:02X}' for i in range(256)}
# minimal names
names={0x5b:'JUMPDEST',0x56:'JUMP',0x57:'JUMPI',0x34:'CALLVALUE',0x15:'ISZERO',0x61:'PUSH2',0x60:'PUSH1',0x35:'CALLDATALOAD',0x16:'AND',0x54:'SLOAD',0x55:'SSTORE',0x33:'CALLER',0xf3:'RETURN',0xfd:'REVERT'}
opnames.update(names)
pc=0x018c
end=0x0208
while pc < end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 31ms:
018c: JUMPDEST
018d: CALLVALUE
018e: ISZERO
018f: PUSH2 0x0197
0192: JUMPI
0193: PUSH1 0x00
0195: OP_80
0196: REVERT
0197: JUMPDEST
0198: PUSH2 0x00bb
019b: PUSH1 0x01
019d: PUSH1 0xa0
019f: PUSH1 0x02
01a1: OP_0A
01a2: OP_03
01a3: PUSH1 0x04
01a5: CALLDATALOAD
01a6: AND
01a7: PUSH2 0x034c
01aa: JUMP
thinking
**Analyzing ownership-related functions**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
opnames={i:f'OP_{i:02X}' for i in range(256)}
# minimal names
names={0x00:'STOP',0x01:'ADD',0x02:'MUL',0x03:'SUB',0x04:'DIV',0x05:'SDIV',0x06:'MOD',0x07:'SMOD',0x08:'ADDMOD',0x09:'MULMOD',0x0a:'EXP',0x0b:'SIGNEXTEND',
0x10:'LT',0x11:'GT',0x12:'SLT',0x13:'SGT',0x14:'EQ',0x15:'ISZERO',0x16:'AND',0x17:'OR',0x18:'XOR',0x19:'NOT',0x1a:'BYTE',0x1b:'SHL',0x1c:'SHR',0x1d:'SAR',
0x20:'SHA3',
0x30:'ADDRESS',0x31:'BALANCE',0x32:'ORIGIN',0x33:'CALLER',0x34:'CALLVALUE',0x35:'CALLDATALOAD',0x36:'CALLDATASIZE',0x37:'CALLDATACOPY',0x38:'CODESIZE',0x39:'CODECOPY',0x3a:'GASPRICE',0x3b:'EXTCODESIZE',0x3c:'EXTCODECOPY',0x3d:'RETURNDATASIZE',0x3e:'RETURNDATACOPY',0x3f:'EXTCODEHASH',
0x50:'POP',0x51:'MLOAD',0x52:'MSTORE',0x53:'MSTORE8',0x54:'SLOAD',0x55:'SSTORE',0x56:'JUMP',0x57:'JUMPI',0x58:'PC',0x59:'MSIZE',0x5a:'GAS',0x5b:'JUMPDEST',
0x60:'PUSH1',0x61:'PUSH2',0x62:'PUSH3',0x63:'PUSH4',0x64:'PUSH5',0x65:'PUSH6',0x66:'PUSH7',0x67:'PUSH8',0x68:'PUSH9',0x69:'PUSH10',0x6a:'PUSH11',0x6b:'PUSH12',0x6c:'PUSH13',0x6d:'PUSH14',0x6e:'PUSH15',0x6f:'PUSH16',
0x70:'PUSH17',0x71:'PUSH18',0x72:'PUSH19',0x73:'PUSH20',0x74:'PUSH21',0x75:'PUSH22',0x76:'PUSH23',0x77:'PUSH24',0x78:'PUSH25',0x79:'PUSH26',0x7a:'PUSH27',0x7b:'PUSH28',0x7c:'PUSH29',0x7d:'PUSH30',0x7e:'PUSH31',0x7f:'PUSH32',
0x80:'DUP1',0x81:'DUP2',0x82:'DUP3',0x83:'DUP4',0x84:'DUP5',0x85:'DUP6',0x86:'DUP7',0x87:'DUP8',0x88:'DUP9',0x89:'DUP10',0x8a:'DUP11',0x8b:'DUP12',0x8c:'DUP13',0x8d:'DUP14',0x8e:'DUP15',0x8f:'DUP16',
0x90:'SWAP1',0x91:'SWAP2',0x92:'SWAP3',0x93:'SWAP4',0x94:'SWAP5',0x95:'SWAP6',0x96:'SWAP7',0x97:'SWAP8',0x98:'SWAP9',0x99:'SWAP10',0x9a:'SWAP11',0x9b:'SWAP12',0x9c:'SWAP13',0x9d:'SWAP14',0x9e:'SWAP15',0x9f:'SWAP16',
0xa0:'LOG0',0xa1:'LOG1',0xa2:'LOG2',0xa3:'LOG3',0xa4:'LOG4',
0xf0:'CREATE',0xf1:'CALL',0xf2:'CALLCODE',0xf3:'RETURN',0xf4:'DELEGATECALL',0xf5:'CREATE2',0xfa:'STATICCALL',0xfd:'REVERT',0xfe:'INVALID',0xff:'SELFDESTRUCT'}
opnames.update(names)
pc=0x03e7
end=0x04c0
while pc < end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 30ms:
03e7: JUMPDEST
03e8: PUSH1 0x00
03ea: SLOAD
03eb: CALLER
03ec: PUSH1 0x01
03ee: PUSH1 0xa0
03f0: PUSH1 0x02
03f2: EXP
03f3: SUB
03f4: SWAP1
03f5: DUP2
03f6: AND
03f7: SWAP2
03f8: AND
03f9: EQ
03fa: PUSH2 0x0402
03fd: JUMPI
03fe: PUSH1 0x00
0400: DUP1
0401: REVERT
thinking
**Analyzing owner and user external calls**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# find push2 0x031c
for i in range(len(code)-2):
if code[i]==0x61 and code[i+1]==0x03 and code[i+2]==0x1c:
print(hex(i))
PY" in /tmp/codex-o1lrvfrs succeeded in 56ms:
0x151
thinking
**Analyzing bytecode for selector behavior**
exec
/bin/bash -lc "python - <<'PY'
import json
with open('BYTECODE_BUNDLE.json','r') as f:
data=json.load(f)
code=bytes.fromhex(data['artifact']['runtime_bytecode']['full'][2:])
# disasm around 0x0136
pc=0x0136
end=0x0158
opnames={i:f'OP_{i:02X}' for i in range(256)}
# minimal names
names={0x5b:'JUMPDEST',0x34:'CALLVALUE',0x15:'ISZERO',0x61:'PUSH2',0x60:'PUSH1',0x57:'JUMPI',0xfd:'REVERT',0x56:'JUMP'}
opnames.update(names)
while pc<end:
op=code[pc]
name=opnames.get(op,f'OP_{op:02X}')
if 0x60 <= op <= 0x7f:
n=op-0x5f
data=code[pc+1:pc+1+n]
print(f\"{pc:04x}: {name} 0x{data.hex()}\")
pc += 1+n
else:
print(f\"{pc:04x}: {name}\")
pc += 1
PY" in /tmp/codex-o1lrvfrs succeeded in 28ms:
0136: JUMPDEST
0137: CALLVALUE
0138: ISZERO
0139: PUSH2 0x0141
013c: JUMPI
013d: PUSH1 0x00
013f: OP_80
0140: REVERT
0141: JUMPDEST
0142: PUSH2 0x00bb
0145: PUSH1 0x01
0147: PUSH1 0xa0
0149: PUSH1 0x02
014b: OP_0A
014c: OP_03
014d: PUSH1 0x04
014f: OP_35
0150: OP_16
0151: PUSH2 0x031c
0154: JUMP
thinking
**Summarizing function selectors and behavior**
codex
{"no_findings":false,"summary":"Bytecode shows an owner-controlled SELFDESTRUCT path and multiple low-level CALLs with ETH value to computed targets (some owner-gated, one apparently user-accessible with effects-before-interactions). No delegatecall/proxy patterns detected in the bundle.","findings":[{"severity":"medium","category":"other","title":"Owner-reachable SELFDESTRUCT can permanently disable the contract","exploit_scenario":"If the owner key is compromised or misused, the SELFDESTRUCT path can be invoked to destroy the contract and send the remaining ETH to an arbitrary address, permanently disabling all functionality for users.","recommendation":"Remove SELFDESTRUCT or gate it behind a timelock/multisig and/or an irreversible disable after deployment. If it is intended, document the risk clearly.","evidence":"A SELFDESTRUCT opcode is reachable after an owner check (SLOAD slot0 masked vs CALLER). The path is invoked via the selector that jumps to pc 0x031c and culminates in SELFDESTRUCT at pc 0x0342.","locations":["selector:0xb9caebf4","pc:0x031d","pc:0x0342"]},{"severity":"medium","category":"access_control","title":"Privileged low-level CALLs with ETH to computed targets (centralization risk)","exploit_scenario":"An owner can trigger low-level CALLs that transfer ETH to computed targets (including a path that uses the contract balance), allowing full fund extraction or arbitrary external interactions if the owner is compromised or malicious.","recommendation":"If arbitrary execution is not required, restrict call targets/amounts or remove these calls. Otherwise, use a multisig + timelock and document the admin powers. Consider adding explicit allowlists or rate limits.","evidence":"Owner check occurs at pc 0x04c0 before two CALL sites that use computed targets/values (pc 0x0575 and pc 0x05b2). The sequence includes ADDRESS/BALANCE, implying ETH transfers under privileged control.","locations":["selector:0xf5bf7413","pc:0x04c0","pc:0x0575","pc:0x05b2"]},{"severity":"low","category":"reentrancy","title":"User-accessible CALL with value has no explicit reentrancy guard","exploit_scenario":"A user-invoked function performs a low-level CALL with value to a computed target. Although storage is updated before the call (effects-before-interactions), a malicious callee could reenter other functions that rely on transient invariants.","recommendation":"If any cross-function invariants exist, add a reentrancy guard to this call path or ensure all state updates are completed before external interaction. Document the intended reentrancy model.","evidence":"CALL at pc 0x066b occurs after an SSTORE at pc 0x0653 in the function reached by selector 0xfa89401a; no mutex/guard pattern is visible in the bytecode.","locations":["selector:0xfa89401a","pc:0x0653","pc:0x066b"]}]}
tokens used
110,307
{
"codex": {
"ran_at": "2026-01-10T21:20:20.825686+00:00",
"returncode": 0
},
"project": {
"mode": "bytecode",
"bytecode_length": 3582,
"bytecode_truncated": false,
"capability_graph_present": true,
"analysis_artifact_present": true
},
"summary": "Bytecode shows an owner-controlled SELFDESTRUCT path and multiple low-level CALLs with ETH value to computed targets (some owner-gated, one apparently user-accessible with effects-before-interactions). No delegatecall/proxy patterns detected in the bundle.",
"raw_final": {
"summary": "Bytecode shows an owner-controlled SELFDESTRUCT path and multiple low-level CALLs with ETH value to computed targets (some owner-gated, one apparently user-accessible with effects-before-interactions). No delegatecall/proxy patterns detected in the bundle.",
"findings": [
{
"title": "Owner-reachable SELFDESTRUCT can permanently disable the contract",
"category": "other",
"evidence": "A SELFDESTRUCT opcode is reachable after an owner check (SLOAD slot0 masked vs CALLER). The path is invoked via the selector that jumps to pc 0x031c and culminates in SELFDESTRUCT at pc 0x0342.",
"severity": "medium",
"locations": [
"selector:0xb9caebf4",
"pc:0x031d",
"pc:0x0342"
],
"recommendation": "Remove SELFDESTRUCT or gate it behind a timelock/multisig and/or an irreversible disable after deployment. If it is intended, document the risk clearly.",
"exploit_scenario": "If the owner key is compromised or misused, the SELFDESTRUCT path can be invoked to destroy the contract and send the remaining ETH to an arbitrary address, permanently disabling all functionality for users."
},
{
"title": "Privileged low-level CALLs with ETH to computed targets (centralization risk)",
"category": "access_control",
"evidence": "Owner check occurs at pc 0x04c0 before two CALL sites that use computed targets/values (pc 0x0575 and pc 0x05b2). The sequence includes ADDRESS/BALANCE, implying ETH transfers under privileged control.",
"severity": "medium",
"locations": [
"selector:0xf5bf7413",
"pc:0x04c0",
"pc:0x0575",
"pc:0x05b2"
],
"recommendation": "If arbitrary execution is not required, restrict call targets/amounts or remove these calls. Otherwise, use a multisig + timelock and document the admin powers. Consider adding explicit allowlists or rate limits.",
"exploit_scenario": "An owner can trigger low-level CALLs that transfer ETH to computed targets (including a path that uses the contract balance), allowing full fund extraction or arbitrary external interactions if the owner is compromised or malicious."
},
{
"title": "User-accessible CALL with value has no explicit reentrancy guard",
"category": "reentrancy",
"evidence": "CALL at pc 0x066b occurs after an SSTORE at pc 0x0653 in the function reached by selector 0xfa89401a; no mutex/guard pattern is visible in the bytecode.",
"severity": "low",
"locations": [
"selector:0xfa89401a",
"pc:0x0653",
"pc:0x066b"
],
"recommendation": "If any cross-function invariants exist, add a reentrancy guard to this call path or ensure all state updates are completed before external interaction. Document the intended reentrancy model.",
"exploit_scenario": "A user-invoked function performs a low-level CALL with value to a computed target. Although storage is updated before the call (effects-before-interactions), a malicious callee could reenter other functions that rely on transient invariants."
}
],
"no_findings": false
},
"no_findings": false,
"schema_version": 1
}
00000000: PUSH1 0x60 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0x04 00000007: CALLDATASIZE 00000008: LT 00000009: PUSH2 0x00a3 0000000c: JUMPI 0000000d: PUSH4 0xffffffff 00000012: PUSH29 0x0100000000000000000000000000000000000000000000000000000000 00000030: PUSH1 0x00 00000032: CALLDATALOAD 00000033: DIV 00000034: AND 00000035: PUSH4 0x1ef3755d 0000003a: DUP2 0000003b: EQ 0000003c: PUSH2 0x00a8 0000003f: JUMPI 00000040: DUP1 00000041: PUSH4 0x47fa061e 00000046: EQ 00000047: PUSH2 0x00bd 0000004a: JUMPI 0000004b: DUP1 0000004c: PUSH4 0x8c52dc41 00000051: EQ 00000052: PUSH2 0x00f4 00000055: JUMPI 00000056: DUP1 00000057: PUSH4 0x8da5cb5b 0000005c: EQ 0000005d: PUSH2 0x0107 00000060: JUMPI 00000061: DUP1 00000062: PUSH4 0xb9caebf4 00000067: EQ 00000068: PUSH2 0x0136 0000006b: JUMPI 0000006c: DUP1 0000006d: PUSH4 0xc19d93fb 00000072: EQ 00000073: PUSH2 0x0155 00000076: JUMPI 00000077: DUP1 00000078: PUSH4 0xf2fde38b 0000007d: EQ 0000007e: PUSH2 0x018c 00000081: JUMPI 00000082: DUP1 00000083: PUSH4 0xf340fa01 00000088: EQ 00000089: PUSH2 0x01ab 0000008c: JUMPI 0000008d: DUP1 0000008e: PUSH4 0xf5bf7413 00000093: EQ 00000094: PUSH2 0x01bf 00000097: JUMPI 00000098: DUP1 00000099: PUSH4 0xfa89401a 0000009e: EQ 0000009f: PUSH2 0x01e7 000000a2: JUMPI 000000a3: JUMPDEST 000000a4: PUSH1 0x00 000000a6: DUP1 000000a7: REVERT 000000a8: JUMPDEST 000000a9: CALLVALUE 000000aa: ISZERO 000000ab: PUSH2 0x00b3 000000ae: JUMPI 000000af: PUSH1 0x00 000000b1: DUP1 000000b2: REVERT 000000b3: JUMPDEST 000000b4: PUSH2 0x00bb 000000b7: PUSH2 0x0206 000000ba: JUMP 000000bb: JUMPDEST 000000bc: STOP 000000bd: JUMPDEST 000000be: CALLVALUE 000000bf: ISZERO 000000c0: PUSH2 0x00c8 000000c3: JUMPI 000000c4: PUSH1 0x00 000000c6: DUP1 000000c7: REVERT 000000c8: JUMPDEST 000000c9: PUSH2 0x00e2 000000cc: PUSH1 0xff 000000ce: PUSH1 0x04 000000d0: CALLDATALOAD 000000d1: AND 000000d2: PUSH1 0x01 000000d4: PUSH1 0xa0 000000d6: PUSH1 0x02 000000d8: EXP 000000d9: SUB 000000da: PUSH1 0x24 000000dc: CALLDATALOAD 000000dd: AND 000000de: PUSH2 0x027d 000000e1: JUMP 000000e2: JUMPDEST 000000e3: PUSH1 0x40 000000e5: MLOAD 000000e6: SWAP1 000000e7: DUP2 000000e8: MSTORE 000000e9: PUSH1 0x20 000000eb: ADD 000000ec: PUSH1 0x40 000000ee: MLOAD 000000ef: DUP1 000000f0: SWAP2 000000f1: SUB 000000f2: SWAP1 000000f3: RETURN 000000f4: JUMPDEST 000000f5: CALLVALUE 000000f6: ISZERO 000000f7: PUSH2 0x00ff 000000fa: JUMPI 000000fb: PUSH1 0x00 000000fd: DUP1 000000fe: REVERT 000000ff: JUMPDEST 00000100: PUSH2 0x00bb 00000103: PUSH2 0x029a 00000106: JUMP 00000107: JUMPDEST 00000108: CALLVALUE 00000109: ISZERO 0000010a: PUSH2 0x0112 0000010d: JUMPI 0000010e: PUSH1 0x00 00000110: DUP1 00000111: REVERT 00000112: JUMPDEST 00000113: PUSH2 0x011a 00000116: PUSH2 0x030d 00000119: JUMP 0000011a: JUMPDEST 0000011b: PUSH1 0x40 0000011d: MLOAD 0000011e: PUSH1 0x01 00000120: PUSH1 0xa0 00000122: PUSH1 0x02 00000124: EXP 00000125: SUB 00000126: SWAP1 00000127: SWAP2 00000128: AND 00000129: DUP2 0000012a: MSTORE 0000012b: PUSH1 0x20 0000012d: ADD 0000012e: PUSH1 0x40 00000130: MLOAD 00000131: DUP1 00000132: SWAP2 00000133: SUB 00000134: SWAP1 00000135: RETURN 00000136: JUMPDEST 00000137: CALLVALUE 00000138: ISZERO 00000139: PUSH2 0x0141 0000013c: JUMPI 0000013d: PUSH1 0x00 0000013f: DUP1 00000140: REVERT 00000141: JUMPDEST 00000142: PUSH2 0x00bb 00000145: PUSH1 0x01 00000147: PUSH1 0xa0 00000149: PUSH1 0x02 0000014b: EXP 0000014c: SUB 0000014d: PUSH1 0x04 0000014f: CALLDATALOAD 00000150: AND 00000151: PUSH2 0x031c 00000154: JUMP 00000155: JUMPDEST 00000156: CALLVALUE 00000157: ISZERO 00000158: PUSH2 0x0160 0000015b: JUMPI 0000015c: PUSH1 0x00 0000015e: DUP1 0000015f: REVERT 00000160: JUMPDEST 00000161: PUSH2 0x0168 00000164: PUSH2 0x0343 00000167: JUMP 00000168: JUMPDEST 00000169: PUSH1 0x40 0000016b: MLOAD 0000016c: DUP1 0000016d: DUP3 0000016e: PUSH1 0x02 00000170: DUP2 00000171: GT 00000172: ISZERO 00000173: PUSH2 0x0178 00000176: JUMPI 00000177: INVALID 00000178: JUMPDEST 00000179: PUSH1 0xff 0000017b: AND 0000017c: DUP2 0000017d: MSTORE 0000017e: PUSH1 0x20 00000180: ADD 00000181: SWAP2 00000182: POP 00000183: POP 00000184: PUSH1 0x40 00000186: MLOAD 00000187: DUP1 00000188: SWAP2 00000189: SUB 0000018a: SWAP1 0000018b: RETURN 0000018c: JUMPDEST 0000018d: CALLVALUE 0000018e: ISZERO 0000018f: PUSH2 0x0197 00000192: JUMPI 00000193: PUSH1 0x00 00000195: DUP1 00000196: REVERT 00000197: JUMPDEST 00000198: PUSH2 0x00bb 0000019b: PUSH1 0x01 0000019d: PUSH1 0xa0 0000019f: PUSH1 0x02 000001a1: EXP 000001a2: SUB 000001a3: PUSH1 0x04 000001a5: CALLDATALOAD 000001a6: AND 000001a7: PUSH2 0x034c 000001aa: JUMP 000001ab: JUMPDEST 000001ac: PUSH2 0x00bb 000001af: PUSH1 0x01 000001b1: PUSH1 0xa0 000001b3: PUSH1 0x02 000001b5: EXP 000001b6: SUB 000001b7: PUSH1 0x04 000001b9: CALLDATALOAD 000001ba: AND 000001bb: PUSH2 0x03e7 000001be: JUMP 000001bf: JUMPDEST 000001c0: CALLVALUE 000001c1: ISZERO 000001c2: PUSH2 0x01ca 000001c5: JUMPI 000001c6: PUSH1 0x00 000001c8: DUP1 000001c9: REVERT 000001ca: JUMPDEST 000001cb: PUSH2 0x00bb 000001ce: PUSH1 0x01 000001d0: PUSH1 0xa0 000001d2: PUSH1 0x02 000001d4: EXP 000001d5: SUB 000001d6: PUSH1 0x04 000001d8: CALLDATALOAD 000001d9: DUP2 000001da: AND 000001db: SWAP1 000001dc: PUSH1 0x24 000001de: CALLDATALOAD 000001df: AND 000001e0: PUSH1 0x44 000001e2: CALLDATALOAD 000001e3: PUSH2 0x04c0 000001e6: JUMP 000001e7: JUMPDEST 000001e8: CALLVALUE 000001e9: ISZERO 000001ea: PUSH2 0x01f2 000001ed: JUMPI 000001ee: PUSH1 0x00 000001f0: DUP1 000001f1: REVERT 000001f2: JUMPDEST 000001f3: PUSH2 0x00bb 000001f6: PUSH1 0x01 000001f8: PUSH1 0xa0 000001fa: PUSH1 0x02 000001fc: EXP 000001fd: SUB 000001fe: PUSH1 0x04 00000200: CALLDATALOAD 00000201: AND 00000202: PUSH2 0x05c7 00000205: JUMP 00000206: JUMPDEST 00000207: PUSH1 0x00 00000209: SLOAD 0000020a: CALLER 0000020b: PUSH1 0x01 0000020d: PUSH1 0xa0 0000020f: PUSH1 0x02 00000211: EXP 00000212: SUB 00000213: SWAP1 00000214: DUP2 00000215: AND 00000216: SWAP2 00000217: AND 00000218: EQ 00000219: PUSH2 0x0221 0000021c: JUMPI 0000021d: PUSH1 0x00 0000021f: DUP1 00000220: REVERT 00000221: JUMPDEST 00000222: PUSH1 0x02 00000224: DUP1 00000225: SLOAD 00000226: PUSH1 0xff 00000228: AND 00000229: DUP2 0000022a: DUP2 0000022b: GT 0000022c: ISZERO 0000022d: PUSH2 0x0232 00000230: JUMPI 00000231: INVALID 00000232: JUMPDEST 00000233: EQ 00000234: PUSH2 0x023c 00000237: JUMPI 00000238: PUSH1 0x00 0000023a: DUP1 0000023b: REVERT 0000023c: JUMPDEST 0000023d: PUSH1 0x00 0000023f: DUP1 00000240: SLOAD 00000241: PUSH21 0xff0000000000000000000000000000000000000000 00000257: NOT 00000258: DUP2 00000259: AND 0000025a: PUSH1 0xa0 0000025c: PUSH1 0x02 0000025e: EXP 0000025f: SWAP2 00000260: DUP3 00000261: SWAP1 00000262: DIV 00000263: PUSH1 0xff 00000265: SWAP1 00000266: DUP2 00000267: AND 00000268: PUSH1 0x01 0000026a: ADD 0000026b: AND 0000026c: SWAP1 0000026d: SWAP2 0000026e: MUL 0000026f: OR 00000270: SWAP1 00000271: SSTORE 00000272: PUSH1 0x02 00000274: DUP1 00000275: SLOAD 00000276: PUSH1 0xff 00000278: NOT 00000279: AND 0000027a: SWAP1 0000027b: SSTORE 0000027c: JUMP 0000027d: JUMPDEST 0000027e: PUSH1 0x01 00000280: PUSH1 0x20 00000282: SWAP1 00000283: DUP2 00000284: MSTORE 00000285: PUSH1 0x00 00000287: SWAP3 00000288: DUP4 00000289: MSTORE 0000028a: PUSH1 0x40 0000028c: DUP1 0000028d: DUP5 0000028e: KECCAK256 0000028f: SWAP1 00000290: SWAP2 00000291: MSTORE 00000292: SWAP1 00000293: DUP3 00000294: MSTORE 00000295: SWAP1 00000296: KECCAK256 00000297: SLOAD 00000298: DUP2 00000299: JUMP 0000029a: JUMPDEST 0000029b: PUSH1 0x00 0000029d: SLOAD 0000029e: CALLER 0000029f: PUSH1 0x01 000002a1: PUSH1 0xa0 000002a3: PUSH1 0x02 000002a5: EXP 000002a6: SUB 000002a7: SWAP1 000002a8: DUP2 000002a9: AND 000002aa: SWAP2 000002ab: AND 000002ac: EQ 000002ad: PUSH2 0x02b5 000002b0: JUMPI 000002b1: PUSH1 0x00 000002b3: DUP1 000002b4: REVERT 000002b5: JUMPDEST 000002b6: PUSH1 0x00 000002b8: PUSH1 0x02 000002ba: DUP1 000002bb: SLOAD 000002bc: PUSH1 0xff 000002be: AND 000002bf: SWAP1 000002c0: DUP2 000002c1: GT 000002c2: ISZERO 000002c3: PUSH2 0x02c8 000002c6: JUMPI 000002c7: INVALID 000002c8: JUMPDEST 000002c9: EQ 000002ca: PUSH2 0x02d2 000002cd: JUMPI 000002ce: PUSH1 0x00 000002d0: DUP1 000002d1: REVERT 000002d2: JUMPDEST 000002d3: PUSH1 0x02 000002d5: DUP1 000002d6: SLOAD 000002d7: PUSH1 0xff 000002d9: NOT 000002da: AND 000002db: PUSH1 0x01 000002dd: OR 000002de: SWAP1 000002df: SSTORE 000002e0: PUSH32 0x599d8e5a83cffb867d051598c4d70e805d59802d8081c1c7d6dffc5b6aca2b89 00000301: PUSH1 0x40 00000303: MLOAD 00000304: PUSH1 0x40 00000306: MLOAD 00000307: DUP1 00000308: SWAP2 00000309: SUB 0000030a: SWAP1 0000030b: LOG1 0000030c: JUMP 0000030d: JUMPDEST 0000030e: PUSH1 0x00 00000310: SLOAD 00000311: PUSH1 0x01 00000313: PUSH1 0xa0 00000315: PUSH1 0x02 00000317: EXP 00000318: SUB 00000319: AND 0000031a: DUP2 0000031b: JUMP 0000031c: JUMPDEST 0000031d: PUSH1 0x00 0000031f: SLOAD 00000320: CALLER 00000321: PUSH1 0x01 00000323: PUSH1 0xa0 00000325: PUSH1 0x02 00000327: EXP 00000328: SUB 00000329: SWAP1 0000032a: DUP2 0000032b: AND 0000032c: SWAP2 0000032d: AND 0000032e: EQ 0000032f: PUSH2 0x0337 00000332: JUMPI 00000333: PUSH1 0x00 00000335: DUP1 00000336: REVERT 00000337: JUMPDEST 00000338: DUP1 00000339: PUSH1 0x01 0000033b: PUSH1 0xa0 0000033d: PUSH1 0x02 0000033f: EXP 00000340: SUB 00000341: AND 00000342: SELFDESTRUCT 00000343: JUMPDEST 00000344: PUSH1 0x02 00000346: SLOAD 00000347: PUSH1 0xff 00000349: AND 0000034a: DUP2 0000034b: JUMP 0000034c: JUMPDEST 0000034d: PUSH1 0x00 0000034f: SLOAD 00000350: CALLER 00000351: PUSH1 0x01 00000353: PUSH1 0xa0 00000355: PUSH1 0x02 00000357: EXP 00000358: SUB 00000359: SWAP1 0000035a: DUP2 0000035b: AND 0000035c: SWAP2 0000035d: AND 0000035e: EQ 0000035f: PUSH2 0x0367 00000362: JUMPI 00000363: PUSH1 0x00 00000365: DUP1 00000366: REVERT 00000367: JUMPDEST 00000368: PUSH1 0x01 0000036a: PUSH1 0xa0 0000036c: PUSH1 0x02 0000036e: EXP 0000036f: SUB 00000370: DUP2 00000371: AND 00000372: ISZERO 00000373: ISZERO 00000374: PUSH2 0x037c 00000377: JUMPI 00000378: PUSH1 0x00 0000037a: DUP1 0000037b: REVERT 0000037c: JUMPDEST 0000037d: PUSH1 0x00 0000037f: SLOAD 00000380: PUSH1 0x01 00000382: PUSH1 0xa0 00000384: PUSH1 0x02 00000386: EXP 00000387: SUB 00000388: DUP1 00000389: DUP4 0000038a: AND 0000038b: SWAP2 0000038c: AND 0000038d: PUSH32 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 000003ae: PUSH1 0x40 000003b0: MLOAD 000003b1: PUSH1 0x40 000003b3: MLOAD 000003b4: DUP1 000003b5: SWAP2 000003b6: SUB 000003b7: SWAP1 000003b8: LOG3 000003b9: PUSH1 0x00 000003bb: DUP1 000003bc: SLOAD 000003bd: PUSH20 0xffffffffffffffffffffffffffffffffffffffff 000003d2: NOT 000003d3: AND 000003d4: PUSH1 0x01 000003d6: PUSH1 0xa0 000003d8: PUSH1 0x02 000003da: EXP 000003db: SUB 000003dc: SWAP3 000003dd: SWAP1 000003de: SWAP3 000003df: AND 000003e0: SWAP2 000003e1: SWAP1 000003e2: SWAP2 000003e3: OR 000003e4: SWAP1 000003e5: SSTORE 000003e6: JUMP 000003e7: JUMPDEST 000003e8: PUSH1 0x00 000003ea: SLOAD 000003eb: CALLER 000003ec: PUSH1 0x01 000003ee: PUSH1 0xa0 000003f0: PUSH1 0x02 000003f2: EXP 000003f3: SUB 000003f4: SWAP1 000003f5: DUP2 000003f6: AND 000003f7: SWAP2 000003f8: AND 000003f9: EQ 000003fa: PUSH2 0x0402 000003fd: JUMPI 000003fe: PUSH1 0x00 00000400: DUP1 00000401: REVERT 00000402: JUMPDEST 00000403: PUSH1 0x00 00000405: PUSH1 0x02 00000407: DUP1 00000408: SLOAD 00000409: PUSH1 0xff 0000040b: AND 0000040c: SWAP1 0000040d: DUP2 0000040e: GT 0000040f: ISZERO 00000410: PUSH2 0x0415 00000413: JUMPI 00000414: INVALID 00000415: JUMPDEST 00000416: EQ 00000417: PUSH2 0x041f 0000041a: JUMPI 0000041b: PUSH1 0x00 0000041d: DUP1 0000041e: REVERT 0000041f: JUMPDEST 00000420: PUSH1 0x00 00000422: DUP1 00000423: SLOAD 00000424: PUSH1 0xa0 00000426: PUSH1 0x02 00000428: EXP 00000429: SWAP1 0000042a: DIV 0000042b: PUSH1 0xff 0000042d: AND 0000042e: DUP2 0000042f: MSTORE 00000430: PUSH1 0x01 00000432: PUSH1 0x20 00000434: SWAP1 00000435: DUP2 00000436: MSTORE 00000437: PUSH1 0x40 00000439: DUP1 0000043a: DUP4 0000043b: KECCAK256 0000043c: PUSH1 0x01 0000043e: PUSH1 0xa0 00000440: PUSH1 0x02 00000442: EXP 00000443: SUB 00000444: DUP6 00000445: AND 00000446: DUP5 00000447: MSTORE 00000448: SWAP1 00000449: SWAP2 0000044a: MSTORE 0000044b: SWAP1 0000044c: KECCAK256 0000044d: SLOAD 0000044e: PUSH2 0x0457 00000451: SWAP1 00000452: CALLVALUE 00000453: PUSH2 0x06bc 00000456: JUMP 00000457: JUMPDEST 00000458: PUSH1 0x00 0000045a: DUP1 0000045b: SLOAD 0000045c: PUSH1 0xa0 0000045e: PUSH1 0x02 00000460: EXP 00000461: SWAP1 00000462: DIV 00000463: PUSH1 0xff 00000465: AND 00000466: DUP2 00000467: MSTORE 00000468: PUSH1 0x01 0000046a: PUSH1 0x20 0000046c: SWAP1 0000046d: DUP2 0000046e: MSTORE 0000046f: PUSH1 0x40 00000471: DUP1 00000472: DUP4 00000473: KECCAK256 00000474: PUSH1 0x01 00000476: PUSH1 0xa0 00000478: PUSH1 0x02 0000047a: EXP 0000047b: SUB 0000047c: DUP7 0000047d: AND 0000047e: DUP1 0000047f: DUP6 00000480: MSTORE 00000481: SWAP3 00000482: MSTORE 00000483: SWAP2 00000484: DUP3 00000485: SWAP1 00000486: KECCAK256 00000487: SWAP3 00000488: SWAP1 00000489: SWAP3 0000048a: SSTORE 0000048b: PUSH32 0x2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4 000004ac: SWAP1 000004ad: CALLVALUE 000004ae: SWAP1 000004af: MLOAD 000004b0: SWAP1 000004b1: DUP2 000004b2: MSTORE 000004b3: PUSH1 0x20 000004b5: ADD 000004b6: PUSH1 0x40 000004b8: MLOAD 000004b9: DUP1 000004ba: SWAP2 000004bb: SUB 000004bc: SWAP1 000004bd: LOG2 000004be: POP 000004bf: JUMP 000004c0: JUMPDEST 000004c1: PUSH1 0x00 000004c3: SLOAD 000004c4: CALLER 000004c5: PUSH1 0x01 000004c7: PUSH1 0xa0 000004c9: PUSH1 0x02 000004cb: EXP 000004cc: SUB 000004cd: SWAP1 000004ce: DUP2 000004cf: AND 000004d0: SWAP2 000004d1: AND 000004d2: EQ 000004d3: PUSH2 0x04db 000004d6: JUMPI 000004d7: PUSH1 0x00 000004d9: DUP1 000004da: REVERT 000004db: JUMPDEST 000004dc: PUSH1 0x00 000004de: PUSH1 0x02 000004e0: DUP1 000004e1: SLOAD 000004e2: PUSH1 0xff 000004e4: AND 000004e5: SWAP1 000004e6: DUP2 000004e7: GT 000004e8: ISZERO 000004e9: PUSH2 0x04ee 000004ec: JUMPI 000004ed: INVALID 000004ee: JUMPDEST 000004ef: EQ 000004f0: PUSH2 0x04f8 000004f3: JUMPI 000004f4: PUSH1 0x00 000004f6: DUP1 000004f7: REVERT 000004f8: JUMPDEST 000004f9: PUSH1 0x01 000004fb: PUSH1 0xa0 000004fd: PUSH1 0x02 000004ff: EXP 00000500: SUB 00000501: DUP4 00000502: AND 00000503: ISZERO 00000504: ISZERO 00000505: PUSH2 0x050d 00000508: JUMPI 00000509: PUSH1 0x00 0000050b: DUP1 0000050c: REVERT 0000050d: JUMPDEST 0000050e: PUSH1 0x02 00000510: DUP1 00000511: SLOAD 00000512: PUSH1 0xff 00000514: NOT 00000515: AND 00000516: DUP2 00000517: OR 00000518: SWAP1 00000519: SSTORE 0000051a: PUSH32 0x1cdde67b72a90f19919ac732a437ac2f7a10fc128d28c2a6e525d89ce5cd9d3a 0000053b: PUSH1 0x40 0000053d: MLOAD 0000053e: PUSH1 0x40 00000540: MLOAD 00000541: DUP1 00000542: SWAP2 00000543: SUB 00000544: SWAP1 00000545: LOG1 00000546: PUSH1 0x01 00000548: PUSH1 0xa0 0000054a: PUSH1 0x02 0000054c: EXP 0000054d: SUB 0000054e: DUP3 0000054f: AND 00000550: ISZERO 00000551: PUSH2 0x0585 00000554: JUMPI 00000555: PUSH1 0x01 00000557: PUSH1 0xa0 00000559: PUSH1 0x02 0000055b: EXP 0000055c: SUB 0000055d: DUP3 0000055e: AND 0000055f: DUP2 00000560: ISZERO 00000561: PUSH2 0x08fc 00000564: MUL 00000565: DUP3 00000566: PUSH1 0x40 00000568: MLOAD 00000569: PUSH1 0x00 0000056b: PUSH1 0x40 0000056d: MLOAD 0000056e: DUP1 0000056f: DUP4 00000570: SUB 00000571: DUP2 00000572: DUP6 00000573: DUP9 00000574: DUP9 00000575: CALL 00000576: SWAP4 00000577: POP 00000578: POP 00000579: POP 0000057a: POP 0000057b: ISZERO 0000057c: ISZERO 0000057d: PUSH2 0x0585 00000580: JUMPI 00000581: PUSH1 0x00 00000583: DUP1 00000584: REVERT 00000585: JUMPDEST 00000586: DUP3 00000587: PUSH1 0x01 00000589: PUSH1 0xa0 0000058b: PUSH1 0x02 0000058d: EXP 0000058e: SUB 0000058f: AND 00000590: PUSH2 0x08fc 00000593: ADDRESS 00000594: PUSH1 0x01 00000596: PUSH1 0xa0 00000598: PUSH1 0x02 0000059a: EXP 0000059b: SUB 0000059c: AND 0000059d: BALANCE 0000059e: SWAP1 0000059f: DUP2 000005a0: ISZERO 000005a1: MUL 000005a2: SWAP1 000005a3: PUSH1 0x40 000005a5: MLOAD 000005a6: PUSH1 0x00 000005a8: PUSH1 0x40 000005aa: MLOAD 000005ab: DUP1 000005ac: DUP4 000005ad: SUB 000005ae: DUP2 000005af: DUP6 000005b0: DUP9 000005b1: DUP9 000005b2: CALL 000005b3: SWAP4 000005b4: POP 000005b5: POP 000005b6: POP 000005b7: POP 000005b8: ISZERO 000005b9: ISZERO 000005ba: PUSH2 0x05c2 000005bd: JUMPI 000005be: PUSH1 0x00 000005c0: DUP1 000005c1: REVERT 000005c2: JUMPDEST 000005c3: POP 000005c4: POP 000005c5: POP 000005c6: JUMP 000005c7: JUMPDEST 000005c8: PUSH1 0x00 000005ca: PUSH1 0x01 000005cc: PUSH1 0x02 000005ce: DUP1 000005cf: SLOAD 000005d0: PUSH1 0xff 000005d2: AND 000005d3: SWAP1 000005d4: DUP2 000005d5: GT 000005d6: ISZERO 000005d7: PUSH2 0x05dc 000005da: JUMPI 000005db: INVALID 000005dc: JUMPDEST 000005dd: EQ 000005de: PUSH2 0x05e6 000005e1: JUMPI 000005e2: PUSH1 0x00 000005e4: DUP1 000005e5: REVERT 000005e6: JUMPDEST 000005e7: POP 000005e8: PUSH1 0x00 000005ea: DUP1 000005eb: SLOAD 000005ec: PUSH1 0xa0 000005ee: PUSH1 0x02 000005f0: EXP 000005f1: SWAP1 000005f2: DIV 000005f3: PUSH1 0xff 000005f5: AND 000005f6: DUP2 000005f7: MSTORE 000005f8: PUSH1 0x01 000005fa: PUSH1 0x20 000005fc: SWAP1 000005fd: DUP2 000005fe: MSTORE 000005ff: PUSH1 0x40 00000601: DUP1 00000602: DUP4 00000603: KECCAK256 00000604: PUSH1 0x01 00000606: PUSH1 0xa0 00000608: PUSH1 0x02 0000060a: EXP 0000060b: SUB 0000060c: DUP6 0000060d: AND 0000060e: DUP5 0000060f: MSTORE 00000610: SWAP1 00000611: SWAP2 00000612: MSTORE 00000613: DUP2 00000614: KECCAK256 00000615: SLOAD 00000616: SWAP1 00000617: DUP2 00000618: GT 00000619: PUSH2 0x0621 0000061c: JUMPI 0000061d: PUSH1 0x00 0000061f: DUP1 00000620: REVERT 00000621: JUMPDEST 00000622: PUSH1 0x00 00000624: DUP1 00000625: SLOAD 00000626: PUSH1 0xa0 00000628: PUSH1 0x02 0000062a: EXP 0000062b: SWAP1 0000062c: DIV 0000062d: PUSH1 0xff 0000062f: AND 00000630: DUP2 00000631: MSTORE 00000632: PUSH1 0x01 00000634: PUSH1 0x20 00000636: SWAP1 00000637: DUP2 00000638: MSTORE 00000639: PUSH1 0x40 0000063b: DUP1 0000063c: DUP4 0000063d: KECCAK256 0000063e: PUSH1 0x01 00000640: PUSH1 0xa0 00000642: PUSH1 0x02 00000644: EXP 00000645: SUB 00000646: DUP7 00000647: AND 00000648: DUP1 00000649: DUP6 0000064a: MSTORE 0000064b: SWAP3 0000064c: MSTORE 0000064d: DUP1 0000064e: DUP4 0000064f: KECCAK256 00000650: SWAP3 00000651: SWAP1 00000652: SWAP3 00000653: SSTORE 00000654: SWAP1 00000655: PUSH2 0x08fc 00000658: DUP4 00000659: ISZERO 0000065a: MUL 0000065b: SWAP1 0000065c: DUP4 0000065d: SWAP1 0000065e: MLOAD 0000065f: PUSH1 0x00 00000661: PUSH1 0x40 00000663: MLOAD 00000664: DUP1 00000665: DUP4 00000666: SUB 00000667: DUP2 00000668: DUP6 00000669: DUP9 0000066a: DUP9 0000066b: CALL 0000066c: SWAP4 0000066d: POP 0000066e: POP 0000066f: POP 00000670: POP 00000671: ISZERO 00000672: ISZERO 00000673: PUSH2 0x067b 00000676: JUMPI 00000677: PUSH1 0x00 00000679: DUP1 0000067a: REVERT 0000067b: JUMPDEST 0000067c: DUP2 0000067d: PUSH1 0x01 0000067f: PUSH1 0xa0 00000681: PUSH1 0x02 00000683: EXP 00000684: SUB 00000685: AND 00000686: PUSH32 0xd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d0651 000006a7: DUP3 000006a8: PUSH1 0x40 000006aa: MLOAD 000006ab: SWAP1 000006ac: DUP2 000006ad: MSTORE 000006ae: PUSH1 0x20 000006b0: ADD 000006b1: PUSH1 0x40 000006b3: MLOAD 000006b4: DUP1 000006b5: SWAP2 000006b6: SUB 000006b7: SWAP1 000006b8: LOG2 000006b9: POP 000006ba: POP 000006bb: JUMP 000006bc: JUMPDEST 000006bd: PUSH1 0x00 000006bf: DUP3 000006c0: DUP3 000006c1: ADD 000006c2: DUP4 000006c3: DUP2 000006c4: LT 000006c5: ISZERO 000006c6: PUSH2 0x06cb 000006c9: JUMPI 000006ca: INVALID 000006cb: JUMPDEST 000006cc: SWAP4 000006cd: SWAP3 000006ce: POP 000006cf: POP 000006d0: POP 000006d1: JUMP 000006d2: STOP 000006d3: LOG1 000006d4: PUSH6 0x627a7a723058 000006db: KECCAK256 000006dc: SWAP8 000006dd: UNKNOWN(0xEA) 000006de: UNKNOWN(0xE3) 000006df: CALLDATASIZE 000006e0: SWAP3 000006e1: JUMPDEST 000006e2: EXTCODEHASH 000006e3: GASLIMIT 000006e4: UNKNOWN(0xC5) 000006e5: PUSH25
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| high | other | detector | SELFDESTRUCT reachable | 65 | no | no |
viewtrace_id: 0x5c63b2513c60522bb708762e5916bd2aaa84ccfc488e89b4aafa6acef0a3849f
validation_json{
"sink": "SELFDESTRUCT",
"errors": 0,
"status": "unknown",
"attempts": 20,
"trace_id": "0x5c63b2513c60522bb708762e5916bd2aaa84ccfc488e89b4aafa6acef0a3849f",
"confirmed": false,
"trace_mode": "structLogs",
"call_targets": null,
"matched_probe": null,
"target_varies": null,
"classification": "no_sink"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x1ef3755d",
"selector": "0x1ef3755d",
"calldata_variants": [
"0x1ef3755d",
"0x1ef3755d0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x47fa061e",
"selector": "0x47fa061e",
"calldata_variants": [
"0x47fa061e",
"0x47fa061e0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8c52dc41",
"selector": "0x8c52dc41",
"calldata_variants": [
"0x8c52dc41",
"0x8c52dc410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8da5cb5b",
"selector": "0x8da5cb5b",
"calldata_variants": [
"0x8da5cb5b",
"0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xb9caebf4",
"selector": "0xb9caebf4",
"calldata_variants": [
"0xb9caebf4",
"0xb9caebf40000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xc19d93fb",
"selector": "0xc19d93fb",
"calldata_variants": [
"0xc19d93fb",
"0xc19d93fb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf2fde38b",
"selector": "0xf2fde38b",
"calldata_variants": [
"0xf2fde38b",
"0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf340fa01",
"selector": "0xf340fa01",
"calldata_variants": [
"0xf340fa01",
"0xf340fa010000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"guards_detected": [],
"selfdestruct_count": 1
}
|
| high | other | detector | Untrusted CALL target/value reachable | 60 | no | no |
viewtrace_id: 0xe8c70c7f02887cd01e67e3c7fadf191c1bd544f41ebf335f243c1a3c7e66bcbf
call_targets:
0xd32c59bdf5409842c0dec13a546a3916b7485694
target_varies:
no
classification:
constant_target
validation_json{
"sink": "CALL",
"errors": 0,
"status": "sink_reached",
"attempts": 1,
"trace_id": "0xe8c70c7f02887cd01e67e3c7fadf191c1bd544f41ebf335f243c1a3c7e66bcbf",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0xd32c59bdf5409842c0dec13a546a3916b7485694"
],
"matched_probe": null,
"target_varies": false,
"classification": "constant_target"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x1ef3755d",
"selector": "0x1ef3755d",
"calldata_variants": [
"0x1ef3755d",
"0x1ef3755d0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x47fa061e",
"selector": "0x47fa061e",
"calldata_variants": [
"0x47fa061e",
"0x47fa061e0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8c52dc41",
"selector": "0x8c52dc41",
"calldata_variants": [
"0x8c52dc41",
"0x8c52dc410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8da5cb5b",
"selector": "0x8da5cb5b",
"calldata_variants": [
"0x8da5cb5b",
"0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xb9caebf4",
"selector": "0xb9caebf4",
"calldata_variants": [
"0xb9caebf4",
"0xb9caebf40000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xc19d93fb",
"selector": "0xc19d93fb",
"calldata_variants": [
"0xc19d93fb",
"0xc19d93fb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf2fde38b",
"selector": "0xf2fde38b",
"calldata_variants": [
"0xf2fde38b",
"0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf340fa01",
"selector": "0xf340fa01",
"calldata_variants": [
"0xf340fa01",
"0xf340fa010000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 1397,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 1458,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 1643,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"call_count": 3,
"guards_detected": [],
"untrusted_call_count": 3
}
|
| high | other | detector | ETH value transfer possible | 55 | no | no |
viewtrace_id: 0xe8c70c7f02887cd01e67e3c7fadf191c1bd544f41ebf335f243c1a3c7e66bcbf
call_targets:
0xd32c59bdf5409842c0dec13a546a3916b7485694
target_varies:
no
classification:
constant_target
validation_json{
"sink": "CALL",
"errors": 0,
"status": "sink_reached",
"attempts": 1,
"trace_id": "0xe8c70c7f02887cd01e67e3c7fadf191c1bd544f41ebf335f243c1a3c7e66bcbf",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0xd32c59bdf5409842c0dec13a546a3916b7485694"
],
"matched_probe": null,
"target_varies": false,
"classification": "constant_target"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x1ef3755d",
"selector": "0x1ef3755d",
"calldata_variants": [
"0x1ef3755d",
"0x1ef3755d0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x47fa061e",
"selector": "0x47fa061e",
"calldata_variants": [
"0x47fa061e",
"0x47fa061e0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8c52dc41",
"selector": "0x8c52dc41",
"calldata_variants": [
"0x8c52dc41",
"0x8c52dc410000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8da5cb5b",
"selector": "0x8da5cb5b",
"calldata_variants": [
"0x8da5cb5b",
"0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xb9caebf4",
"selector": "0xb9caebf4",
"calldata_variants": [
"0xb9caebf4",
"0xb9caebf40000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xc19d93fb",
"selector": "0xc19d93fb",
"calldata_variants": [
"0xc19d93fb",
"0xc19d93fb0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf2fde38b",
"selector": "0xf2fde38b",
"calldata_variants": [
"0xf2fde38b",
"0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf340fa01",
"selector": "0xf340fa01",
"calldata_variants": [
"0xf340fa01",
"0xf340fa010000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 1397,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 1458,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
},
{
"pc": 1643,
"opcode": "CALL",
"returndata_checked": null,
"value_expression_category": "computed",
"target_expression_category": "computed"
}
],
"eth_value_calls": 3,
"guards_detected": []
}
|
| high | other | cast | SELFDESTRUCT present | 85 | no | — |
viewevidence_json{
"notes": "selfdestruct can remove contract code and send funds; review reachability",
"selfdestruct_count": 1
}
|
| medium | other | codex | Owner-reachable SELFDESTRUCT can permanently disable the contract | 75 | no | — |
viewevidence_json{
"evidence": "A SELFDESTRUCT opcode is reachable after an owner check (SLOAD slot0 masked vs CALLER). The path is invoked via the selector that jumps to pc 0x031c and culminates in SELFDESTRUCT at pc 0x0342.",
"locations": [
"selector:0xb9caebf4",
"pc:0x031d",
"pc:0x0342"
],
"recommendation": "Remove SELFDESTRUCT or gate it behind a timelock/multisig and/or an irreversible disable after deployment. If it is intended, document the risk clearly.",
"exploit_scenario": "If the owner key is compromised or misused, the SELFDESTRUCT path can be invoked to destroy the contract and send the remaining ETH to an arbitrary address, permanently disabling all functionality for users."
}
|
| medium | access_control | codex | Privileged low-level CALLs with ETH to computed targets (centralization risk) | 75 | no | — |
viewevidence_json{
"evidence": "Owner check occurs at pc 0x04c0 before two CALL sites that use computed targets/values (pc 0x0575 and pc 0x05b2). The sequence includes ADDRESS/BALANCE, implying ETH transfers under privileged control.",
"locations": [
"selector:0xf5bf7413",
"pc:0x04c0",
"pc:0x0575",
"pc:0x05b2"
],
"recommendation": "If arbitrary execution is not required, restrict call targets/amounts or remove these calls. Otherwise, use a multisig + timelock and document the admin powers. Consider adding explicit allowlists or rate limits.",
"exploit_scenario": "An owner can trigger low-level CALLs that transfer ETH to computed targets (including a path that uses the contract balance), allowing full fund extraction or arbitrary external interactions if the owner is compromised or malicious."
}
|
| low | reentrancy | codex | User-accessible CALL with value has no explicit reentrancy guard | 65 | no | — |
viewevidence_json{
"evidence": "CALL at pc 0x066b occurs after an SSTORE at pc 0x0653 in the function reached by selector 0xfa89401a; no mutex/guard pattern is visible in the bytecode.",
"locations": [
"selector:0xfa89401a",
"pc:0x0653",
"pc:0x066b"
],
"recommendation": "If any cross-function invariants exist, add a reentrancy guard to this call path or ensure all state updates are completed before external interaction. Document the intended reentrancy model.",
"exploit_scenario": "A user-invoked function performs a low-level CALL with value to a computed target. Although storage is updated before the call (effects-before-interactions), a malicious callee could reenter other functions that rely on transient invariants."
}
|