A-3 プロキシ不在 検証(追試・改ざん可)A-3 Proxy-absence verification (re-runnable, tamperable)

プロキシ不在の検証 — 3チェーン7契約、改ざん可Proxy-absence verification — 7 contracts across 3 chains, tamperable  v1

A-3Base / Sepolia / Arbitrumeth_getStorageAt + eth_getCode

各契約の EIP-1967 スロット(implementation/admin/beacon)が全部空か、かつ EIP-1167 クローンのバイトコードで始まらない(本体ロジックが乗っている)かを読み、アップグレード可能プロキシでないことを確認します。
「わざと壊す」で判定条件を反転すると実際に赤くなります=always-pass ではありません。
For each contract, reads whether all EIP-1967 slots (implementation/admin/beacon) are empty and whether the bytecode does not begin with an EIP-1167 clone prefix (real logic is present), confirming it is not an upgradeable proxy.
Sanity-break inverts the criterion and actually turns it red — it is not always-pass.

読むスロット(keccak256(label) − 1):
implementation 0x360894a1…d382bbc/admin 0xb5312768…b5d6103/beacon 0xa3f0ad74…5133d50
EIP-1167 クローン先頭:0x363d3d373d3d3d363d73
Slots read (keccak256(label) − 1):
implementation 0x360894a1…d382bbc/admin 0xb5312768…b5d6103/beacon 0xa3f0ad74…5133d50
EIP-1167 clone prefix: 0x363d3d373d3d3d363d73

方法A(おすすめ):下の「検証する」を押すだけ。7契約の EIP-1967 スロットとコードを自動取得し、非プロキシ判定まで完結します。「わざと壊す」で実際に赤くなることも確認できます。Method A (recommended): just press Verify. It fetches the EIP-1967 slots and code for all 7 contracts and judges non-proxy in one step. Sanity-break confirms it really goes red.

方法B:コマンドで確認(自分のノードで完結・貼り付け不要)Method B: confirm via command (all on your own node, no paste)

自動取得(方法A)が拡張機能などで塞がれても、ノードで実行して出力を期待値と見比べるだけで確認できます。下の ethers と curl は同じことを別ツールでやる代替です(順番ではありません・どちらか一方で OK)。Even if auto-fetch (Method A) is blocked by an extension, you can run it on your node and compare the output against expectations. The ethers and curl commands below are two alternative ways to do the same thing (not sequential — either one is fine).

自動取得が弾かれる/一部チェーンが未到達のときは、下のコマンドで。各契約とも 3スロットが空(0x0…0)かつ非クローンなら非プロキシです。If auto-fetch is blocked or a chain is unreachable, use the commands below. Per contract: all 3 slots zero (0x0…0) and not a clone ⇒ non-proxy.

ethers v6(自分のノードの client ディレクトリで実行・先頭の cd は自分のパスに置き換え・7件3チェーン)ethers v6 (run in your node’s client dir — replace the leading cd with your own path; all 7 across 3 chains)

cd /var/www/あなたのドメインyour-domain/client
node -e 'const {ethers}=require("ethers");const base=new ethers.JsonRpcProvider("https://base-sepolia-rpc.publicnode.com");const sep=new ethers.JsonRpcProvider("https://ethereum-sepolia-rpc.publicnode.com");const arb=new ethers.JsonRpcProvider("https://arbitrum-sepolia-rpc.publicnode.com");const S={impl:"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",admin:"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103",beacon:"0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50"};const Z="0x0000000000000000000000000000000000000000000000000000000000000000";const CLONE="0x363d3d373d3d3d363d73";const C=[[base,"0x5674e4658b988Ed9337DD0CAa493C6aA908006af","CawActions@L2"],[base,"0x0c3e245f3939B4D9f30e088988dD9D7C8F86b11d","CawProfileL2@L2"],[base,"0x3b2A9ac4f274eE6E73CbAD198F80f455e70C3C05","CawActionsArchive@L2"],[base,"0x8195A9a8a97658672d5384e19a763804D6E16639","CawChallengeRelay@L2"],[sep,"0xD20bE35D2365C0f7DaF563A47b29eB5a165C2007","CawActions@L1"],[sep,"0x9CEffADC838a39D10a241d9A473844Ef0cB6274f","CawProfileURI@L1"],[arb,"0x287b249B58bF65411D4Da89dAdEF0e30496a0D4c","CawActions@L2b"]];(async()=>{for(const [p,a,name] of C){const im=await p.getStorage(a,S.impl);const ad=await p.getStorage(a,S.admin);const be=await p.getStorage(a,S.beacon);const code=await p.getCode(a);const empty=(im===Z&&ad===Z&&be===Z);const clone=code.startsWith(CLONE);console.log(name.padEnd(22),(empty&&!clone)?"non-proxy OK":"CHECK","| 1967 empty:",empty,"| clone:",clone,"| codeLen:",(code.length-2)/2);}})();'

curl(依存ゼロ・implementation スロット1件例)curl (no deps, one slot)

curl -s https://base-sepolia-rpc.publicnode.com -X POST -H 'content-type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"eth_getStorageAt","params":["0x5674e4658b988Ed9337DD0CAa493C6aA908006af","0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc","latest"]}'

返り値が 0x000…000(32バイトゼロ)なら、そのスロットは空です。admin/beacon、他チェーンは slot/RPC を差し替えて。A return of 0x000…000 (32 zero bytes) means that slot is empty. For admin/beacon or other chains, swap the slot/RPC.

🔎 開発者ツールで実通信を自分の目で見るsee the real traffic yourself in DevTools
  1. F12 で開発者ツールを開き「Network」タブを選ぶOpen DevTools (F12) → Network tab.
  2. 「検証する」を押すClick Verify.
  3. 各契約への eth_getStorageAteth_getCode リクエストが出ます。クリックで送信内容と返ってきた生の値が見えます。An eth_getStorageAteth_getCode request appears per contract. Click to see what was sent and the raw value returned.
  4. 上の「叩いたリクエスト」「生の値」と一致するか確認。ブラウザの記録なので細工できません。Check it matches the “request made” / raw value above. It is the browser’s own log — it cannot be faked.
この検証の中身と範囲scope & independence

このツールが見る範囲(オンチェーン):7契約について EIP-1967 の3スロットが空か+EIP-1167 クローンでないか。

ツール対象外(記事側の手動ソース走査):UUPS・Transparent・Beacon・Diamond・Initializable の有無、constructor 初期化か、selfdestruct 不在――これらは A-3 記事のソース全走査で扱っています。ツールは「動いている実体がプロキシでない」ことを担保し、記事が「ソースにも差し替え機構が無い」ことを担保します。

・検証する契約7件:
Base Sepolia CawActions 0x5674…06af, CawProfileL2 0x0c3e…b11d, CawActionsArchive 0x3b2A…3C05, CawChallengeRelay 0x8195…6639 / Sepolia CawActions 0xD20b…2007, CawProfileURI 0x9CEf…274f / Arbitrum CawActions 0x287b…0D4c

・各チェーンとも Blockscout (GET) → publicnode → drpc を自動で試します。あるチェーンの公開 RPC が全滅したら「未到達(?)」と表示し、不一致(✗)と区別します。

独立性:ソース可読・判定はスロット空判定とクローン先頭判定のみ・RPC は CLI で自分のノードに差し替え可。「わざと壊す」で実際に赤くなります。
What this tool checks (on-chain): for the 7 contracts, whether the 3 EIP-1967 slots are empty + not an EIP-1167 clone.

Out of scope here (the article’s manual source scan): presence of UUPS / Transparent / Beacon / Diamond / Initializable, constructor-based init, absence of selfdestruct — covered by the full source scan in the A-3 article. The tool assures “the running instance is not a proxy”; the article assures “the source has no swap mechanism either.”

Contracts checked (7):
Base Sepolia CawActions 0x5674…06af, CawProfileL2 0x0c3e…b11d, CawActionsArchive 0x3b2A…3C05, CawChallengeRelay 0x8195…6639 / Sepolia CawActions 0xD20b…2007, CawProfileURI 0x9CEf…274f / Arbitrum CawActions 0x287b…0D4c

Each chain tries Blockscout (GET) → publicnode → drpc in order. If every public RPC for a chain fails, it shows “unreachable(?)” — kept distinct from a mismatch (✗).

Independence: readable source; the check is only slot-emptiness and clone-prefix; RPC swappable to your own node via CLI. Sanity-break actually turns it red.