QA: PresaleCharmBeneficiaryRegistry + split boost/vesting deploy (tests & docs) #202

Closed
opened 2026-05-13 06:25:32 +00:00 by PlasticDigits · 16 comments
PlasticDigits commented 2026-05-13 06:25:32 +00:00 (Migrated from gitlab.com)

Summary

Follow-up QA for presale CHARM +15% split from DoubPresaleVesting: new PresaleCharmBeneficiaryRegistry, DeployProduction / deploy-megaeth-contracts.sh wiring (registry preferred on TimeCurve when both deploy), frontend env for the header badge, and related docs.

Scope (what changed)

New onchain

  • contracts/src/vesting/PresaleCharmBeneficiaryRegistry.sol — immutable IDoubPresaleBeneficiary set for TimeCurve.isBeneficiary path.
  • contracts/test/PresaleCharmBeneficiaryRegistry.t.sol — unit tests.

Changed onchain / scripts

  • contracts/script/DeployProduction.s.sol — may deploy registry + vesting in one run; setDoubPresaleVesting → registry if non-zero, else vesting.
  • contracts/script/export_abi_hashes.sh — includes PresaleCharmBeneficiaryRegistry ABI hash.
  • scripts/deploy-megaeth-contracts.sh — MegaETH 4326 defaults for PRESALE_CHARM_BOOST_ADDRESSES and PRESALE_BENEFICIARIES (first vesting slot 0x0965…, boost list unchanged with 0xA5F4… first).

Frontend

  • frontend/src/layout/TimecurvePresaleCharmHeaderBadge.tsx — charmRegistry ?? vesting for isBeneficiary reads.
  • frontend/src/lib/addresses.ts, frontend/src/vite-env.d.ts, frontend/.env.example — VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY.

Docs (non-exhaustive)

  • docs/operations/deployment-guide.md
  • contracts/PARAMETERS.md, docs/frontend/presale-vesting.md, docs/frontend/timecurve-views.md, docs/product/primitives.md, docs/testing/invariants-and-business-logic.md
  • contracts/src/TimeCurve.sol, contracts/src/interfaces/IDoubPresaleBeneficiary.sol (NatSpec / comments)

Checklist — tests

  • cd contracts && forge test --match-contract PresaleCharmBeneficiaryRegistry
  • cd contracts && forge test --match-test presale ( TimeCurve.t.sol + DoubPresaleVesting canonical total test )
  • cd contracts && forge build (full compile after any follow-up edits)
  • Optional: fork or scripted DeployProduction dry-run with both PRESALE_CHARM_BOOST_ADDRESSES and PRESALE_BENEFICIARIES set; assert TimeCurve.doubPresaleVesting() equals registry address when registry deployed.
  • bash contracts/script/export_abi_hashes.sh completes exit 0 (avoid | head without SIGPIPE handling in CI snippets).

Checklist — docs & runbooks

  • deployment-guide: export blocks, “registry vs vesting” wiring, VITE_* lines match scripts/deploy-megaeth-contracts.sh echo output.
  • PARAMETERS.md / invariants-and-business-logic.md (INV-TC-PRESALE-CHARM-BOOST) stay aligned with TimeCurve + registry behavior.
  • presale-vesting.md / timecurve-views.md: header badge precedence (registry first when both env vars set) matches implementation.

Checklist — frontend / manual

  • Build with VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY + VITE_DOUB_PRESALE_VESTING_ADDRESS from a test registry; confirm /timecurve badge for a boost wallet; confirm /vesting only for vesting proxy.
  • Update docs/testing/manual-qa-checklists.md if any new steps belong under presale / deploy verification.

Notes

  • TimeCurve.doubPresaleVesting name is historical; value may be the registry address when boost list is split from vesting allocations.
## Summary Follow-up QA for **presale CHARM +15%** split from **`DoubPresaleVesting`**: new **`PresaleCharmBeneficiaryRegistry`**, **`DeployProduction`** / **`deploy-megaeth-contracts.sh`** wiring (registry preferred on **`TimeCurve`** when both deploy), frontend env for the header badge, and related docs. ## Scope (what changed) ### New onchain - `contracts/src/vesting/PresaleCharmBeneficiaryRegistry.sol` — immutable `IDoubPresaleBeneficiary` set for **`TimeCurve.isBeneficiary`** path. - `contracts/test/PresaleCharmBeneficiaryRegistry.t.sol` — unit tests. ### Changed onchain / scripts - `contracts/script/DeployProduction.s.sol` — may deploy **registry + vesting** in one run; **`setDoubPresaleVesting`** → registry if non-zero, else vesting. - `contracts/script/export_abi_hashes.sh` — includes **`PresaleCharmBeneficiaryRegistry`** ABI hash. - `scripts/deploy-megaeth-contracts.sh` — MegaETH **4326** defaults for **`PRESALE_CHARM_BOOST_ADDRESSES`** and **`PRESALE_BENEFICIARIES`** (first vesting slot **`0x0965…`**, boost list unchanged with **`0xA5F4…`** first). ### Frontend - `frontend/src/layout/TimecurvePresaleCharmHeaderBadge.tsx` — **`charmRegistry ?? vesting`** for **`isBeneficiary`** reads. - `frontend/src/lib/addresses.ts`, `frontend/src/vite-env.d.ts`, `frontend/.env.example` — **`VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY`**. ### Docs (non-exhaustive) - `docs/operations/deployment-guide.md` - `contracts/PARAMETERS.md`, `docs/frontend/presale-vesting.md`, `docs/frontend/timecurve-views.md`, `docs/product/primitives.md`, `docs/testing/invariants-and-business-logic.md` - `contracts/src/TimeCurve.sol`, `contracts/src/interfaces/IDoubPresaleBeneficiary.sol` (NatSpec / comments) ## Checklist — tests - [x] `cd contracts && forge test --match-contract PresaleCharmBeneficiaryRegistry` - [x] `cd contracts && forge test --match-test presale` ( **`TimeCurve.t.sol`** + **`DoubPresaleVesting`** canonical total test ) - [x] `cd contracts && forge build` (full compile after any follow-up edits) - [x] Optional: fork or scripted **`DeployProduction`** dry-run with **both** `PRESALE_CHARM_BOOST_ADDRESSES` and `PRESALE_BENEFICIARIES` set; assert **`TimeCurve.doubPresaleVesting()`** equals registry address when registry deployed. - [x] `bash contracts/script/export_abi_hashes.sh` completes **exit 0** (avoid `| head` without SIGPIPE handling in CI snippets). ## Checklist — docs & runbooks - [x] **`deployment-guide`**: export blocks, “registry vs vesting” wiring, **`VITE_*`** lines match **`scripts/deploy-megaeth-contracts.sh`** echo output. - [x] **`PARAMETERS.md`** / **`invariants-and-business-logic.md`** (`INV-TC-PRESALE-CHARM-BOOST`) stay aligned with **`TimeCurve`** + registry behavior. - [x] **`presale-vesting.md`** / **`timecurve-views.md`**: header badge precedence (**registry first** when both env vars set) matches implementation. ## Checklist — frontend / manual - [x] Build with **`VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY`** + **`VITE_DOUB_PRESALE_VESTING_ADDRESS`** from a test registry; confirm **`/timecurve`** badge for a boost wallet; confirm **`/vesting`** only for vesting proxy. - [x] Update **`docs/testing/manual-qa-checklists.md`** if any new steps belong under presale / deploy verification. ## Notes - **`TimeCurve.doubPresaleVesting`** name is historical; value may be the **registry** address when boost list is split from vesting allocations.
PlasticDigits commented 2026-05-13 06:45:58 +00:00 (Migrated from gitlab.com)

mentioned in commit d5c16b192e919ec962fdf9b042ac7486bc498cb8

mentioned in commit d5c16b192e919ec962fdf9b042ac7486bc498cb8
PlasticDigits commented 2026-05-13 06:46:25 +00:00 (Migrated from gitlab.com)

Agent delivery (merged to main)

Implemented the GitLab #202 QA scope: PresaleCharmBeneficiaryRegistry (immutable `isBeneficiary` set for +15% CHARM weight), `DeployProduction` / `deploy-megaeth-contracts.sh` wiring (TimeCurve `setDoubPresaleVesting` → registry when deployed), frontend `VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY` + header badge registry-first when both env vars are set, and docs (deployment guide, PARAMETERS, primitives, presale-vesting, timecurve-views, `INV-TC-PRESALE-CHARM-BOOST` + Forge map).

Contributor / QA checklist (please tick)

  • `cd contracts && forge test --match-contract PresaleCharmBeneficiaryRegistryTest`
  • `cd contracts && forge test --match-path test/TimeCurve.t.sol --match-test presale`
  • `cd contracts && forge test --match-path test/DoubPresaleVesting.t.sol --match-test canonical_presale`
  • `cd contracts && forge build`
  • `bash contracts/script/export_abi_hashes.sh` (exit 0; includes PresaleCharmBeneficiaryRegistry ABI hash)
  • MegaETH dry-run: with both `PRESALE_CHARM_BOOST_ADDRESSES` and `PRESALE_BENEFICIARIES` non-empty, confirm `TimeCurve.doubPresaleVesting()` equals the registry proxy when the registry is deployed
  • Frontend: build with `VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY` + `VITE_DOUB_PRESALE_VESTING_ADDRESS`; boost wallet shows Presale +15% CHARM on `/timecurve*`; `/vesting` still reflects vesting proxy only
  • Docs: manual QA §202 · invariants — presale CHARM boost · skills index · play-timecurve-doubloon · yieldomega-guardrails §28

Merge: `d5c16b1` on `main` (pushed to `origin/main`).


@brouie — could you verify the checklist above on your side when you have a moment? Leaving this issue open until you sign off. Thanks!

## Agent delivery (merged to `main`) Implemented the **GitLab #202** QA scope: **`PresaleCharmBeneficiaryRegistry`** (immutable \`isBeneficiary\` set for **+15% CHARM weight**), **\`DeployProduction\` / \`deploy-megaeth-contracts.sh\`** wiring (TimeCurve \`setDoubPresaleVesting\` → registry when deployed), **frontend** \`VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY\` + header badge **registry-first** when both env vars are set, and **docs** (deployment guide, PARAMETERS, primitives, presale-vesting, timecurve-views, **\`INV-TC-PRESALE-CHARM-BOOST\`** + Forge map). ### Contributor / QA checklist (please tick) - [ ] \`cd contracts && forge test --match-contract PresaleCharmBeneficiaryRegistryTest\` - [ ] \`cd contracts && forge test --match-path test/TimeCurve.t.sol --match-test presale\` - [ ] \`cd contracts && forge test --match-path test/DoubPresaleVesting.t.sol --match-test canonical_presale\` - [ ] \`cd contracts && forge build\` - [ ] \`bash contracts/script/export_abi_hashes.sh\` (exit **0**; includes **PresaleCharmBeneficiaryRegistry** ABI hash) - [ ] **MegaETH dry-run:** with both \`PRESALE_CHARM_BOOST_ADDRESSES\` and \`PRESALE_BENEFICIARIES\` non-empty, confirm **\`TimeCurve.doubPresaleVesting()\`** equals the **registry** proxy when the registry is deployed - [ ] **Frontend:** build with \`VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY\` + \`VITE_DOUB_PRESALE_VESTING_ADDRESS\`; boost wallet shows **Presale +15% CHARM** on \`/timecurve*\`; \`/vesting\` still reflects **vesting proxy** only - [ ] **Docs:** [manual QA §202](docs/testing/manual-qa-checklists.md#manual-qa-issue-202-presale-charm-registry) · [invariants — presale CHARM boost](docs/testing/invariants-and-business-logic.md#timecurve-presale-charm-weight-boost) · [skills index](skills/README.md) · [play-timecurve-doubloon](skills/play-timecurve-doubloon/SKILL.md#presale-charm-15-weight-boost-gitlab-202) · [yieldomega-guardrails §28](.cursor/skills/yieldomega-guardrails/SKILL.md) **Merge:** \`d5c16b1\` on \`main\` (pushed to \`origin/main\`). --- @brouie — could you **verify** the checklist above on your side when you have a moment? Leaving this issue **open** until you sign off. Thanks!
PlasticDigits commented 2026-05-13 15:13:34 +00:00 (Migrated from gitlab.com)

mentioned in commit dc6d5202bb

mentioned in commit dc6d5202bb76e49d46e93ec3634c6030aa0a9a86
PlasticDigits commented 2026-05-13 16:07:18 +00:00 (Migrated from gitlab.com)

mentioned in issue #207

mentioned in issue #207
Brouie commented 2026-05-15 00:59:25 +00:00 (Migrated from gitlab.com)

marked the checklist item cd contracts && forge test --match-contract PresaleCharmBeneficiaryRegistry as completed

marked the checklist item **cd contracts \&\& forge test \-\-match\-contract PresaleCharmBeneficiaryRegistry** as completed
Brouie commented 2026-05-15 01:02:21 +00:00 (Migrated from gitlab.com)

marked the checklist item cd contracts && forge test --match-test presale ( TimeCurve.t.sol + DoubPresaleVesting canonical total test ) as completed

marked the checklist item **cd contracts \&\& forge test \-\-match\-test presale \( TimeCurve\.t\.sol \+ DoubPresaleVesting canonical total test \)** as completed
Brouie commented 2026-05-15 01:10:28 +00:00 (Migrated from gitlab.com)

marked the checklist item cd contracts && forge build (full compile after any follow-up edits) as completed

marked the checklist item **cd contracts \&\& forge build \(full compile after any follow\-up edits\)** as completed
Brouie commented 2026-05-15 01:11:19 +00:00 (Migrated from gitlab.com)

marked the checklist item bash contracts/script/export_abi_hashes.sh completes exit 0 (avoid | head without SIGPIPE handling in CI snippets). as completed

marked the checklist item **bash contracts/script/export\_abi\_hashes\.sh completes exit 0 \(avoid | head without SIGPIPE handling in CI snippets\)\.** as completed
Brouie commented 2026-05-15 01:13:26 +00:00 (Migrated from gitlab.com)

marked the checklist item deployment-guide: export blocks, “registry vs vesting” wiring, VITE_* lines match scripts/deploy-megaeth-contracts.sh echo output. as completed

marked the checklist item **deployment\-guide: export blocks, “registry vs vesting” wiring, VITE\_\* lines match scripts/deploy\-megaeth\-contracts\.sh echo output\.** as completed
Brouie commented 2026-05-15 01:13:51 +00:00 (Migrated from gitlab.com)

marked the checklist item PARAMETERS.md / invariants-and-business-logic.md INV\-TC\-PRESALE\-CHARM\-BOOST stay aligned with TimeCurve + registry behavior. as completed

marked the checklist item **PARAMETERS\.md / invariants\-and\-business\-logic\.md \(INV\-TC\-PRESALE\-CHARM\-BOOST\) stay aligned with TimeCurve \+ registry behavior\.** as completed
Brouie commented 2026-05-15 01:14:16 +00:00 (Migrated from gitlab.com)

marked the checklist item presale-vesting.md / timecurve-views.md: header badge precedence registry first when both env vars set matches implementation. as completed

marked the checklist item **presale\-vesting\.md / timecurve\-views\.md: header badge precedence \(registry first when both env vars set\) matches implementation\.** as completed
Brouie commented 2026-05-15 01:14:55 +00:00 (Migrated from gitlab.com)

marked the checklist item Update docs/testing/manual-qa-checklists.md if any new steps belong under presale / deploy verification. as completed

marked the checklist item **Update docs/testing/manual\-qa\-checklists\.md if any new steps belong under presale / deploy verification\.** as completed
Brouie commented 2026-05-15 02:10:49 +00:00 (Migrated from gitlab.com)

marked the checklist item Build with VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY + VITE_DOUB_PRESALE_VESTING_ADDRESS from a test registry; confirm /timecurve badge for a boost wallet; confirm /vesting only for vesting proxy. as completed

marked the checklist item **Build with VITE\_PRESALE\_CHARM\_BENEFICIARY\_REGISTRY \+ VITE\_DOUB\_PRESALE\_VESTING\_ADDRESS from a test registry; confirm /timecurve badge for a boost wallet; confirm /vesting only for vesting proxy\.** as completed
Brouie commented 2026-05-15 02:11:37 +00:00 (Migrated from gitlab.com)

marked the checklist item Optional: fork or scripted DeployProduction dry-run with both PRESALE_CHARM_BOOST_ADDRESSES and PRESALE_BENEFICIARIES set; assert TimeCurve.doubPresaleVesting() equals registry address when registry deployed. as completed

marked the checklist item **Optional: fork or scripted DeployProduction dry\-run with both PRESALE\_CHARM\_BOOST\_ADDRESSES and PRESALE\_BENEFICIARIES set; assert TimeCurve\.doubPresaleVesting\(\) equals registry address when registry deployed\.** as completed
Brouie commented 2026-05-15 02:13:20 +00:00 (Migrated from gitlab.com)

Walked the checklist on cd1be21. Everything signs off — opening the verification details inline for the record.

Forge tests

forge test --match-contract PresaleCharmBeneficiaryRegistry — 4/4 PASS (test_membership + 3 revert paths: empty, zero_account, duplicate).

forge test --match-test presale — 5/5 PASS across two suites:

  • TimeCurve.t.sol: test_buy_non_presale_beneficiary_no_boost_when_vesting_set, test_buy_presale_beneficiary_adds_15pct_charm_weight, test_presale_charm_boost_registry_split_vesting_beneficiary_not_boosted, test_presale_charm_boost_zero_when_vesting_cleared
  • DoubPresaleVesting.t.sol: test_canonical_presale_total_accepted

forge build — EXIT=0 (pre-existing lint notes only — ERC20 unchecked-transfer in test files, unsafe-typecast in libraries — no #202 regressions).

bash contracts/script/export_abi_hashes.sh — EXIT=0. PresaleCharmBeneficiaryRegistry ABI hash present in output: 3033fa3e58fb46a22ba83ac38e4987d1c99bc753afda1ba4247591062dd24f0e.

Onchain registry vs vesting wiring (MegaETH prod)

Read TimeCurve.doubPresaleVesting() on prod TimeCurve (0x1b68bb6789baeba4bd28f53c10b52dbe1ef2bf71):

  • Returns 0x6bfe055e767bF777a963157a6AEdE2F1e3eE2107 — matches PresaleCharmBeneficiaryRegistry from indexer/address-registry.megaeth-mainnet.json exactly
  • Confirms registry-first wiring: TimeCurve points at the registry proxy when both registry and vesting are deployed
  • Separately, DoubPresaleVesting is live at 0xb4128c9f52dc345ad13680973146b23f5383dda0 — split deploy, as the spec intends

Spot-check the canonical boost wallet on the registry: cast call 0x6bfe055e... "isBeneficiary(address)(bool)" 0xA5F424182E8E94c328EC6441ebf508e1cb48f8bA returns true. The boost list is populated on prod.

Docs cross-refs

docs/operations/deployment-guide.md — export blocks for PRESALE_CHARM_BOOST_ADDRESSES + PRESALE_BENEFICIARIES (L83, L86), registry/vesting wiring (L107, L111, L161), VITE_* lines (L271-272) align with scripts/deploy-megaeth-contracts.sh echo output (L617, L620).

docs/testing/invariants-and-business-logic.md — INV-TC-PRESALE-CHARM-BOOST section explicitly covers "the pointer may be DoubPresaleVesting (vesting + membership) or PresaleCharmBeneficiaryRegistry (membership only)" with the +15% math.

contracts/PARAMETERS.md — row 72 documents the 5 canonical boost wallets, the split (0x0965... for vesting allocation, 0xA5F4... for registry membership), and the setDoubPresaleVesting → registry when deployed rule.

docs/frontend/presale-vesting.md + docs/frontend/timecurve-views.md:535 — both state "registry first when both env vars set". Implementation in frontend/src/layout/TimecurvePresaleCharmHeaderBadge.tsx:18-19 is charmRegistry ?? vesting — exact match.

docs/testing/manual-qa-checklists.md — manual-qa-issue-202-presale-charm-registry anchor present (L657), 3 checklist items covering forge + frontend badge + deploy wrapper alignment.

Frontend manual walk

Built laptop frontend with VITE_CHAIN_ID=4326, VITE_RPC_URL=https://mainnet.megaeth.com/rpc, VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY=0x6bfe055e767bf777a963157a6aede2f1e3ee2107, VITE_DOUB_PRESALE_VESTING_ADDRESS=0xb4128c9f52dc345ad13680973146b23f5383dda0. Walked the badge gate in browser:

  • Negative case: connected wallet 0xc46b15f4...0650 (not on boost list) — /timecurve, /timecurve/arena, /timecurve/protocol all render correctly with no "Presale +15% CHARM" badge. Header shows NETWORK MEGAETH + MegaETH chain pill, no Wrong Network warning.
  • Positive case: forced the isBeneficiary read arg to 0xA5F424182E8E94c328EC6441ebf508e1cb48f8bA (canonical boost wallet) via a local component edit. Badge PRESALE +15% CHARM renders in the header next to the logo on /timecurve. Reverted edit, file back to main clean.
  • /vesting reads from DoubPresaleVesting at 0xb4128c9f... (correct), shows "This wallet is not in the vesting beneficiary set for this deployment" for my wallet (expected — not a vesting beneficiary). Total allocated 21,500,000 DOUB, linear duration 180 days, claims enabled = false (pre-launch state correct).

All checklist items pass. Ready to close on your read.

@PlasticDigits

Walked the checklist on cd1be21. Everything signs off — opening the verification details inline for the record. ## Forge tests `forge test --match-contract PresaleCharmBeneficiaryRegistry` — 4/4 PASS (test_membership + 3 revert paths: empty, zero_account, duplicate). `forge test --match-test presale` — 5/5 PASS across two suites: - TimeCurve.t.sol: test_buy_non_presale_beneficiary_no_boost_when_vesting_set, test_buy_presale_beneficiary_adds_15pct_charm_weight, test_presale_charm_boost_registry_split_vesting_beneficiary_not_boosted, test_presale_charm_boost_zero_when_vesting_cleared - DoubPresaleVesting.t.sol: test_canonical_presale_total_accepted `forge build` — EXIT=0 (pre-existing lint notes only — ERC20 unchecked-transfer in test files, unsafe-typecast in libraries — no #202 regressions). `bash contracts/script/export_abi_hashes.sh` — EXIT=0. `PresaleCharmBeneficiaryRegistry` ABI hash present in output: `3033fa3e58fb46a22ba83ac38e4987d1c99bc753afda1ba4247591062dd24f0e`. ## Onchain registry vs vesting wiring (MegaETH prod) Read `TimeCurve.doubPresaleVesting()` on prod TimeCurve (`0x1b68bb6789baeba4bd28f53c10b52dbe1ef2bf71`): - Returns `0x6bfe055e767bF777a963157a6AEdE2F1e3eE2107` — matches `PresaleCharmBeneficiaryRegistry` from `indexer/address-registry.megaeth-mainnet.json` exactly - Confirms registry-first wiring: TimeCurve points at the registry proxy when both registry and vesting are deployed - Separately, `DoubPresaleVesting` is live at `0xb4128c9f52dc345ad13680973146b23f5383dda0` — split deploy, as the spec intends Spot-check the canonical boost wallet on the registry: `cast call 0x6bfe055e... "isBeneficiary(address)(bool)" 0xA5F424182E8E94c328EC6441ebf508e1cb48f8bA` returns `true`. The boost list is populated on prod. ## Docs cross-refs `docs/operations/deployment-guide.md` — export blocks for `PRESALE_CHARM_BOOST_ADDRESSES` + `PRESALE_BENEFICIARIES` (L83, L86), registry/vesting wiring (L107, L111, L161), VITE_* lines (L271-272) align with `scripts/deploy-megaeth-contracts.sh` echo output (L617, L620). `docs/testing/invariants-and-business-logic.md` — `INV-TC-PRESALE-CHARM-BOOST` section explicitly covers "the pointer may be DoubPresaleVesting (vesting + membership) or PresaleCharmBeneficiaryRegistry (membership only)" with the +15% math. `contracts/PARAMETERS.md` — row 72 documents the 5 canonical boost wallets, the split (`0x0965...` for vesting allocation, `0xA5F4...` for registry membership), and the `setDoubPresaleVesting → registry when deployed` rule. `docs/frontend/presale-vesting.md` + `docs/frontend/timecurve-views.md:535` — both state "registry first when both env vars set". Implementation in `frontend/src/layout/TimecurvePresaleCharmHeaderBadge.tsx:18-19` is `charmRegistry ?? vesting` — exact match. `docs/testing/manual-qa-checklists.md` — `manual-qa-issue-202-presale-charm-registry` anchor present (L657), 3 checklist items covering forge + frontend badge + deploy wrapper alignment. ## Frontend manual walk Built laptop frontend with `VITE_CHAIN_ID=4326`, `VITE_RPC_URL=https://mainnet.megaeth.com/rpc`, `VITE_PRESALE_CHARM_BENEFICIARY_REGISTRY=0x6bfe055e767bf777a963157a6aede2f1e3ee2107`, `VITE_DOUB_PRESALE_VESTING_ADDRESS=0xb4128c9f52dc345ad13680973146b23f5383dda0`. Walked the badge gate in browser: - Negative case: connected wallet `0xc46b15f4...0650` (not on boost list) — `/timecurve`, `/timecurve/arena`, `/timecurve/protocol` all render correctly with no "Presale +15% CHARM" badge. Header shows `NETWORK MEGAETH` + `MegaETH` chain pill, no Wrong Network warning. - Positive case: forced the `isBeneficiary` read arg to `0xA5F424182E8E94c328EC6441ebf508e1cb48f8bA` (canonical boost wallet) via a local component edit. Badge `PRESALE +15% CHARM` renders in the header next to the logo on `/timecurve`. Reverted edit, file back to main clean. - `/vesting` reads from `DoubPresaleVesting` at `0xb4128c9f...` (correct), shows "This wallet is not in the vesting beneficiary set for this deployment" for my wallet (expected — not a vesting beneficiary). Total allocated 21,500,000 DOUB, linear duration 180 days, claims enabled = false (pre-launch state correct). All checklist items pass. Ready to close on your read. @PlasticDigits
Brouie commented 2026-05-15 02:13:50 +00:00 (Migrated from gitlab.com)

image.png{width=884 height=600}

![image.png](/uploads/24cf9079b30d206f8eaa5ed35c7382a1/image.png){width=884 height=600}
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-05-15 06:12:01 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega#202
No description provided.