A-5 immutable


A-1 は「動いているコードが公開ソースと一致するか」を確かめました。ですがその比較では、コンストラクタで焼き込まれる immutable 値(LayerZero エンドポイント等の参照アドレス)を正規化して(ゼロに伏せて)一致を取っています。つまり「正しいコードを、誤った/悪意あるコンストラクタ引数でデプロイする」余地は A-1 だけでは塞げません。この項目では、live V1 テストネットの各契約に焼き込まれた immutable の実際の値を読み出し、正当なアドレスを指しているかを確かめます。とくに最重要なのは、すべての OApp が指す LayerZero エンドポイント――プロトコルの信頼の根(trust root)です。

やさしく言うと

A-1 は「機械の設計図が公開版と同じか」を確かめました。でも機械は工場出荷時に、設計図には書かれていない具体的な部品(参照先アドレス)が差し込まれます。A-1 はその部品穴にカバーをかけたまま形を比べていました。A-5 はカバーを外し、差し込まれた部品が一つひとつ本物かを確かめます。

設計図は一致A-1

でも部品は出荷時に挿入immutable

部品が本物か確認A-5

いちばん大事な部品が、すべての契約が外部とやり取りする窓口=LayerZero エンドポイントです。ここが偽物を指していたら、他の確認はすべて静かに無効になります。結果、エンドポイントは 8/8 すべて正規。さらに内部配線(参照先アドレス)を全数読み出しても、すべて正しい相手を指しており、ズレ(ドリフト)は1件もありませんでした。

このページは検証台帳A-5 項目の詳細記録です。コードの同一性(A-1)が「コードが本物か」なら、A-5 は「そのコードに焼き込まれた参照先が本物か」を担保します。両者は表裏で、A-1 が伏せた部分を A-5 が引き受けます。

1. 主張(検証対象)

live V1 の各契約に焼き込まれた security-critical な immutable が、すべて期待される正当なアドレスを指していること。とりわけ、全 OApp の LayerZero エンドポイントが正規の EndpointV2(0x6EDCE…f10f)であり、内部配線(CawActions.cawProfileexternalSelfRelay.cawActionsProfileL2.layer1EndpointId 等)が live のアドレス集合と整合すること。

2. 検証方法

1

immutable を全列挙

ソースから immutable を全部洗い出す(自動生成 getter で読み出せる)。V1 の CawActionseip712DomainHashcawProfileexternalSelf の3つのみで、後の版にある capOracleerc1271SiblingzkVerifier は V1 には存在しません(より薄い実装)。OApp 群(CawProfile・CawProfileL2・Archive・Relay)は endpoint を持ちます。

2

期待値を確定

エンドポイント=各チェーンの正規 EndpointV2、内部配線=live のアドレス集合、設定値=deploy 設定(L1 eid=40161)。記憶ではなく、production ノードが実際に使うアドレス集合(ノードの addresses.ts)とソースから機械生成。

3

オンチェーンで全数照合

3チェーン(Sepolia/Base Sepolia/Arbitrum Sepolia)の各 getter を読み出し、期待値と突き合わせる。自己参照などのズレが無いかを1件ずつ確認。

3. 判定

信頼の根は 8/8 一致。内部配線も全数整合。ドリフトは0件。
8/8 の OApp で LayerZero エンドポイントが正規値。CawActionscawProfileexternalSelfRelaycawActionsProfileL2layer1EndpointId など内部配線はすべて live のアドレスと整合し、3チェーンとも自己参照などのズレはありません。

  • 一致 LayerZero エンドポイント 8/8(CawProfile@L1・CawProfileL2×3・CawActionsArchive×2・CawChallengeRelay×2)がすべて正規 EndpointV2 0x6EDCE…f10f。信頼の根は固定されています。
  • 一致 内部配線:CawActions.cawProfile=各チェーンの CawProfileL2、externalSelf=自分自身、Relay.cawActions=各チェーンの CawActions、ProfileL2.layer1EndpointId=40161。すべて整合。
  • 一致 L1 ミラー(CawProfileL2_L1)は bypassLZ=truecawProfile=L1 の CawProfile。設計どおり(L1 は LayerZero を介さず直接呼ぶ co-deploy 構成)。

4. receipt(公開証明)

信頼の根の確認は、各 OApp の endpoint() を読むだけで再現できます。8つすべて同じ正規エンドポイントを返します。

信頼の根:各 OApp の endpoint() を読むと、8つすべてが正規 EndpointV2 0x6EDCE…f10f を返します。

内部配線も同様に、getter を読むだけで「正しい相手を指している」ことを確認できます。

内部配線:CawActions.cawProfile()0x0c3e…6b11d(CawProfileL2@L2)、externalSelf()0x5674…06af(自分自身)、L1 ミラーは bypassLZ()true。いずれも期待どおりで、再現コマンドは下のツール(ethers v6/curl)に用意しています。

▶ ブラウザでこの検証を再現する(別窓)

押すと、L2 上で endpoint(信頼の根)と CawActions の内部配線を eth_call で読み、正規アドレスに一致するか一括照合します。弾かれる場合はツール内「コマンドで確認」へ(Chrome で出ないときは Edge かシークレットウィンドウでも)。 さらに「わざと壊す」で全期待値を改変すると実際に赤くなる(=常に合格ではない)ことや、生の返り値・叩いたリクエスト、開発者ツールの Network タブで実通信を確認できます。

5. 注記・限界

この項目(A-5)が扱うのは、信頼モデルの中心にある security-critical な immutable(LZ エンドポイント・内部配線・設定値)です。周辺の経済系コントラクト(BuyAndBurn/Minter/Marketplace)が持つ外部 DeFi アドレス(WETH/router/pair)は、テストネットでは中心から外れるため今回の必須照合からは外しており、「外部・低優先」として扱っています。なお eip712DomainHash はアドレスではなく構築時に計算される bytes32 で、その正しさは A-1(構築コードがソースと一致)から従います。

全部 PASS と書きたい誘惑こそ、いちばん危ない。
だからこそ、見ているのが本番の地かどうかを、まず疑う。

A-1 confirmed that the running code matches the public source. But that comparison normalizes (zeroes out) the immutable values baked in by the constructor — the reference addresses such as the LayerZero endpoint. So “deploy the correct code with wrong or malicious constructor arguments” is a gap A-1 alone cannot close. Here we read the actual values of those immutables on the live V1 testnet and check they point to legitimate addresses. The most important one is the LayerZero endpoint every OApp points to — the protocol’s trust root.

In plain terms

A-1 checked whether “the machine’s blueprint matches the public one.” But at the factory, the machine gets specific parts (reference addresses) slotted in that the blueprint doesn’t fix. A-1 compared shapes with a cover left over those part-slots. A-5 lifts the cover and checks each slotted part is the genuine one.

blueprint matchesA-1

but parts slotted at the factoryimmutable

check each part is genuineA-5

The most important part is the window every contract uses to talk to the outside — the LayerZero endpoint. If that pointed at a fake, every other check would be quietly voided. It checked out: the endpoint is genuine on all 8 OApps. Reading the internal wiring in full as well, every reference points at the right counterpart — there was not a single drift.

This page is the detailed record for item A-5 of the verification ledger. If code identity (A-1) is “is the code genuine,” A-5 secures “are the references baked into that code genuine.” They are two sides of one coin — A-5 takes over exactly the part A-1 covered up.

1. Claim under test

That every security-critical immutable baked into the live V1 contracts points to its expected, legitimate address. In particular, that every OApp’s LayerZero endpoint is the canonical EndpointV2 (0x6EDCE…f10f), and that the internal wiring (CawActions.cawProfile / externalSelf, Relay.cawActions, ProfileL2.layer1EndpointId, etc.) is consistent with the live address set.

2. How we checked

1

Enumerate every immutable

From the source, list every immutable (each has an auto-generated getter, so it is readable). The V1 CawActions has only threeeip712DomainHash, cawProfile, externalSelf; the capOracle / erc1271Sibling / zkVerifier immutables of later versions do not exist in V1 (a leaner build). The OApps (CawProfile, CawProfileL2, Archive, Relay) carry endpoint.

2

Fix the expected values

Endpoint = the chain’s canonical EndpointV2; internal wiring = the live address set; config = the deploy config (L1 eid = 40161). Generated from the address set the production nodes actually use (the node’s addresses.ts) and the source, not from memory.

3

Reconcile on-chain, in full

Read each getter on all three chains (Sepolia / Base Sepolia / Arbitrum Sepolia) and compare to expected, checking each value for self-reference or any other drift.

3. Verdict

Trust root matches 8/8. Internal wiring consistent throughout. Zero drift.
All 8 OApps carry the canonical LayerZero endpoint. The internal wiring — CawActions.cawProfile / externalSelf, Relay.cawActions, ProfileL2.layer1EndpointId — is consistent with the live addresses on all three chains, with no self-references or other drift.

  • match LayerZero endpoint 8/8 (CawProfile@L1, CawProfileL2×3, CawActionsArchive×2, CawChallengeRelay×2) all the canonical EndpointV2 0x6EDCE…f10f. The trust root is fixed.
  • match Internal wiring: CawActions.cawProfile = each chain’s CawProfileL2, externalSelf = self, Relay.cawActions = each chain’s CawActions, ProfileL2.layer1EndpointId = 40161. All consistent.
  • match The L1 mirror (CawProfileL2_L1) has bypassLZ=true and cawProfile = the L1 CawProfile — as designed (L1 hosts a co-deployed mirror that is called directly, bypassing LayerZero).

4. Receipt (public proof)

The trust-root check reproduces by simply reading each OApp’s endpoint(). All eight return the same canonical endpoint.

Trust root: reading endpoint() on each OApp, all eight return the canonical EndpointV2 0x6EDCE…f10f.

The internal wiring reproduces the same way — each getter shows it points at the right counterpart.

Internal wiring: CawActions.cawProfile()0x0c3e…6b11d (CawProfileL2@L2), externalSelf()0x5674…06af (itself); the L1 mirror has bypassLZ()true — all as expected. Reproduce with the tool below (ethers v6 / curl).

▶ Reproduce this check in your browser (new tab)

Reads endpoint() (the trust root) and CawActions’ internal wiring via eth_call on L2, and checks they match the canonical addresses. If blocked, use “CLI commands” inside the tool (or try Edge / an incognito window). You can also hit “Sanity-break” to corrupt every expected value and watch it turn red (not always-pass), and inspect the raw returns and the real traffic in the DevTools Network tab.

5. Notes & limits

This item (A-5) covers the security-critical immutables at the center of the trust model (the LZ endpoint, internal wiring, config values). The external DeFi addresses (WETH, router, pair) on the peripheral economic contracts (BuyAndBurn, Minter, Marketplace) sit off-center on testnet, so they are not part of the required reconciliation here and are treated as “external / low-priority.” Note that eip712DomainHash is not an address but a constructor-computed bytes32, and its correctness follows from A-1 (the constructor code matches source).

The urge to write “all PASS” is the most dangerous one.
Which is why the first thing to doubt is whether you are looking at the live ground at all.
Copyright ©  CAW JAPAN.com All Rights Reserved.
PAGE TOP
夜の薔薇園へ