B-3 LayerZero delegate 検証(追試・改ざん可)B-3 LayerZero delegate verification (re-runnable, tamperable)

delegate = owner = 単一 EOA の照合 — 3チェーン7 OApp、編集・改ざん可delegate = owner = single EOA — 7 OApps across 3 chains, editable & tamperable  v1

B-3Base / Sepolia / Arbitrumdelegates() & owner()

各 OApp について、LayerZero EndpointV2delegates(oapp)0x587cde1e)と、その OApp の owner()0x8da5cb5b)を読み、delegate と owner の両方が同一の期待 EOA を返すか照合します。
期待値は編集でき、「わざと壊す」で実際に赤くなります=always-pass ではありません。
For each OApp, reads delegates(oapp) (0x587cde1e) on the LayerZero EndpointV2 and the OApp’s owner() (0x8da5cb5b), and checks whether both the delegate and the owner return the same expected EOA.
The expected value is editable; the sanity-break button actually turns it red — it is not always-pass.

方法A(おすすめ):下の「検証する」を押すだけ。7 OApp の delegate と owner を自動取得し、両方が期待 EOA と一致するか照合まで完結します。「わざと壊す」で実際に赤くなることも確認できます。Method A (recommended): just press Verify. It fetches the delegate and owner of all 7 OApps and checks both against the expected EOA — 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 the expected value. The ethers and curl commands below are two alternative ways to do the same thing (not sequential — either one is fine).

各 OApp とも delegate == owner == 期待 EOA(既定 0xF713…4a95)なら一致です。非OApp の CawProfile(L1本体)delegates() がゼロを返すため対象外です。A match is delegate == owner == expected EOA (default 0xF713…4a95) on each OApp. The non-OApp CawProfile (L1 base) returns zero from delegates() and is out of scope.

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

cd /var/www/あなたのドメインyour-domain/client
node -e 'const {ethers}=require("ethers");const EP="0x6EDCE65403992e310A62460808c4b910D972f10f";const epAbi=["function delegates(address) view returns (address)"];const oAbi=["function owner() view returns (address)"];const G=[["https://ethereum-sepolia-rpc.publicnode.com",[["CawProfileL2_L1mirror","0x9fcbb3d6880cD3293F1a731Fe6c958a6621a74bF"],["CawProfile_L1base(non-OApp)","0x9CEffADC838a39D10a241d9A473844Ef0cB6274f"]]],["https://base-sepolia-rpc.publicnode.com",[["CawProfileL2_L2","0x0c3e245f3939B4D9f30e088988dD9D7C8F86b11d"],["CawChallengeRelay_L2","0x8195A9a8a97658672d5384e19a763804D6E16639"],["CawActionsArchive_L2","0x3b2A9ac4f274eE6E73CbAD198F80f455e70C3C05"]]],["https://arbitrum-sepolia-rpc.publicnode.com",[["CawProfileL2_L2b","0xbB9c2A3e8222d13f9E8469BB71cE62c3c2E82941"],["CawChallengeRelay_L2b","0x5bCbB34f51156D605331f9d6F76a44DEa1d279E5"],["CawActionsArchive_L2b","0x454450aA713A99B06EE4aA05Ede5d80ca1bd3075"]]]];(async()=>{for(const [rpc,items] of G){const p=new ethers.JsonRpcProvider(rpc);for(const [name,a] of items){const d=await new ethers.Contract(EP,epAbi,p).delegates(a);const o=await new ethers.Contract(a,oAbi,p).owner();console.log(name.padEnd(28),"del",d,"own",o,d.toLowerCase()===o.toLowerCase()?"OK":"DIFF");}}})();'

curl(依存ゼロ・delegate 1件例)curl (no deps, one delegate example)

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

curl の data は delegates のセレクタ 0x587cde1e + OApp アドレス(32バイト左ゼロ詰め)。返り値の末尾 40 桁が delegate です。owner は to=OApp, data=0x8da5cb5b で読みます。L1/L2b は RPC を各チェーンのものに差し替えてください。The curl data is the delegates selector 0x587cde1e + the OApp address (left-zero-padded to 32 bytes); the last 40 hex of the return is the delegate. Read owner with to=OApp, data=0x8da5cb5b. For L1/L2b, swap in each chain’s RPC.

🔎 開発者ツールで実通信を自分の目で見るsee the real traffic yourself in DevTools
  1. F12 で開発者ツールを開き「Network」タブを選ぶOpen DevTools (F12) → Network tab.
  2. 「検証する」を押すClick Verify.
  3. 各 OApp につき delegates(oapp)(EndpointV2 宛)と owner()(OApp 宛)の2本の eth_call が出ます。クリックすると送信内容と返ってきた生の 32 バイトが見えます。Two eth_call requests appear per OApp — delegates(oapp) (to EndpointV2) and owner() (to the OApp). Click one to see what was sent and the raw 32 bytes returned.
  4. 上の「叩いたリクエスト」「生返り値」と一致するか確認。ブラウザの記録なのでページ側で細工できません。Check it matches the “request made” / raw value above. This is the browser’s own log — the page cannot fake it.
この検証の中身と独立性what it does & independence

・対象の OApp 7件:
Sepolia (L1)CawProfileL2_L1mirror 0x9fcb…74bF
Base Sepolia (L2)CawProfileL2_L2 0x0c3e…b11d, CawChallengeRelay_L2 0x8195…6639, CawActionsArchive_L2 0x3b2A…3C05
Arbitrum Sepolia (L2b)CawProfileL2_L2b 0xbB9c…2941, CawChallengeRelay_L2b 0x5bCb…79E5, CawActionsArchive_L2b 0x4544…3075

・呼び出し:eth_call { to: EndpointV2, data: 0x587cde1e + oapp } で delegate、eth_call { to: oapp, data: 0x8da5cb5b } で owner。EndpointV2 は全チェーン共通 0x6EDCE…f10f

・各チェーンとも Blockscout (GET) → publicnode → drpc を自動で試します。ある OApp の delegate/owner のどちらかが全 RPC で取得できない場合は「未到達(?)」と表示し、不一致(✗)と区別します。

CawProfile(L1本体 0x9CEf…274f)は OApp を継承せず delegates() がゼロのため対象外として表示します(7件には数えません)。

独立性:ソース可読・判定はアドレス一致比較のみ・RPC は CLI で自分のノードに差し替え可。期待値は編集でき、「わざと壊す」で実際に赤くなります。本ツールは「delegate がロックされている」とは主張しません(setDelegate は public onlyOwner のままで、変更権限は owner に帰着するという観測です)。
OApps checked (7):
Sepolia (L1)CawProfileL2_L1mirror 0x9fcb…74bF
Base Sepolia (L2)CawProfileL2_L2 0x0c3e…b11d, CawChallengeRelay_L2 0x8195…6639, CawActionsArchive_L2 0x3b2A…3C05
Arbitrum Sepolia (L2b)CawProfileL2_L2b 0xbB9c…2941, CawChallengeRelay_L2b 0x5bCb…79E5, CawActionsArchive_L2b 0x4544…3075

Calls: eth_call { to: EndpointV2, data: 0x587cde1e + oapp } for the delegate, and eth_call { to: oapp, data: 0x8da5cb5b } for the owner. EndpointV2 is shared on all chains: 0x6EDCE…f10f.

Each chain tries Blockscout (GET) → publicnode → drpc in order. If either the delegate or owner of an OApp cannot be read from any RPC, it shows “unreachable(?)” — kept distinct from a mismatch (✗).

CawProfile (L1 base, 0x9CEf…274f) does not inherit OApp and returns zero from delegates(), so it is shown as out of scope (not counted in the 7).

Independence: readable source, plain address-equality only, RPC swappable to your own node via CLI. The expected value is editable and the sanity-break button actually turns it red. This tool does not assert “the delegate is locked” (it observes that setDelegate remains public onlyOwner and the change authority reduces to the owner).