fix(frontend): EVM Legal Accept dead-ends on portal (Binance Web3 / MetaMask iOS) #16
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Community report (2026-08-30) on production Legal portal: after consent, Connect & sign showed
Error: No EVM wallet found (install MetaMask or similar)for Binance Web3 and again for MetaMask on iOS.That failure is implemented in Legal (
web/src/pages/evm.ts) — tracked as cl8y-ecosystem-legal#15. Voting is the EVM integrator that sends users into it.This dApp can connect MetaMask / WalletConnect on
vote.cl8y.com(Bridge-style wagmi, #6). Unsigned EVM wallets then hitConnectedTermsGate→ Accept Terms → full navigation tosign_urls.evm(https://terms.cl8y.com/sign/evm?property=vote.cl8y.com). The Legal page does not inherit the voting WalletConnect session. Safari / Chrome still have nowindow.ethereum. The user is stranded after they already connected here.Terra already has
LegalKeplrInAppHintfor the same class of problem (DEX #554 / WC-M12). EVM has no equivalent.skills/AGENTS_LEGAL_CLICKWRAP.mdalready says: “Same class of hint for EVM in-app browsers.”Current codebase
frontend/src/components/legal/ConnectedTermsGate.tsx— after connect,TermsGatewithnetworkfromuseConnectedIdentity: Terra →TerraClassic,0x…→EVM.buildSignUrl(sign_urls.evm, { redirectUri, appName }). Published@plasticdigits/cl8y-clickwrapTermsGatealso passesaccount. Voting’s vendor fallbackfrontend/src/vendor/cl8y-clickwrap-react.tsxdoes not passaccount.frontend/src/vendor/cl8y-clickwrap.tsbuildSignUrlhas noaccountoption.LegalKeplrInAppHintreturnsnullunlessnetwork === 'TerraClassic'.evmSign.tsis for votes, not terms.VITE_PLAYWRIGHT_E2E=trueskips the gate; production must stay gated (#12: WC success must not skip TermsGate).Why this is needed
vote.cl8y.comdoes not follow the user toterms.cl8y.com.account=0x…for continuity once Legal binds it, (3) to re-verify the round-trip after Legal ships.Constraints / guardrails
POST /signatures/walletin voting. Portal full navigation only — no iframe Accept, no in-dApp termspersonal_sign(#5,AGENTS_LEGAL_CLICKWRAP.md).network="EVM"/ statusEVM. Do not checkTERRA_CLASSICfor a0xaccount (or the reverse).redirect_uri: keepresolveLegalRedirectUrisanitize +https://vote.cl8y.comallowlist. Portal allowlist remains authoritative (#8/vote200). Do not mint redirect fromHost. Deep-link / copy-link targets are the Legal sign URL, not an arbitrary query URL.accountquery: pass the connected checksum/0xaddress only as the integrator-claimed account. Never treataccountas a redirect target. Do not put other users’ addresses on the Accept URL from untrusted input.ADMIN_TOKENin this frontend. No new WalletConnect Cloud id for terms (Legal owns portal WC).connect-src https:.prodEnvGuards/ Dockerfile still fail ifVITE_PLAYWRIGHT_E2Eis set on Coolify.LegalKeplrInAppHint(or a shared “Legal in-app browser” helper) over a second gate. Terra Keplr copy must keep working.Relevant files
frontend/src/components/legal/ConnectedTermsGate.tsxfrontend/src/components/legal/LegalKeplrInAppHint.tsx,frontend/src/utils/legalKeplrInAppHint.tsfrontend/src/hooks/useConnectedIdentity.tsfrontend/src/utils/legalClickwrap.tsfrontend/src/vendor/cl8y-clickwrap.ts,frontend/src/vendor/cl8y-clickwrap-react.tsxfrontend/src/components/legal/__tests__/ConnectedTermsGate.test.tsxskills/AGENTS_LEGAL_CLICKWRAP.md,skills/AGENTS_WALLET_CONNECTORS.mdRecommended direction
Stage on voting; do not wait to document the dead-end:
legalNetwork === 'EVM',signed_latest === false, and there is no injected EIP-1193 in this page (or user connected via WalletConnect), show the same class of CTA as Keplr: Open in MetaMask, Open in Binance Web3 (documented universal / dapp-browser links whoseurlis the Legal sign URL withproperty,redirect_uri,app_name, andaccount), plus Copy link. Idle copy: Chrome/Safari cannot finish terms; open the Legal page in the wallet app browser. If a documented Binance dapp URL cannot be confirmed, still ship Copy-link + MetaMask rather than inventing a scheme.account: use published SDKbuildSignUrl({ account })(and align vendor fallback). Connected0x…must appear on the portal query so Legal can bind continuity when #15 lands.signed_latestfor(vote.cl8y.com, EVM, 0x…)via portal Open-in-app or portal WalletConnect — then return to allowlistedvote.cl8y.compath (#8).personal_signinside voting to “avoid” Legal.Acceptance criteria
No EVM wallet found (install MetaMask or similar)with no next step on voting (hint and/or copy Legal link) and Legal #15 remaining the portal fix.property=vote.cl8y.com(orVITE_LEGAL_PROPERTY), sanitizedredirect_uri,app_name=CL8Y Voting, and connectedaccount=0x….LegalKeplrInAppHintstill shows for unsigned Terra without Keplr extension; still hidden for EVM.signed_latestis false or status errors. WC connect does not skip the gate.signed_latest: truefor EVM → return to voting page (200, not/vote404).buildSignUrl/TermsGatepassaccountif the published package is missing.Test plan (functional paths)
sign/evm, property, redirect_uri origin allowlisted,accountmatches connected address (checksum vs lowercase both OK to send; portal lowercases).resolveLegalRedirectUristill drops non-allowlisted origins (existing sanitize tests).TERRA_CLASSIC.VITE_PLAYWRIGHT_E2E=truestill skips gate in e2e only.vote.cl8y.com.Test plan (attack / abuse / hack vectors)
signed_latest(#12)account=on Accept URL for a different 0x than connectedaccountfrom query to overwriteredirect_uriopen redirect via Acceptjavascript:sign_urls(or constructed fromgetLegalTermsBaseUrl+ property). Do not open arbitraryhttps://from wallet payloadsevmSign.tspayloads stay separate; Legal URL not used for register/propose/voteVITE_PLAYWRIGHT_E2Ein prod imageVerification criteria
https://vote.cl8y.com— sees a working next step for terms (copy/open in MetaMask or Binance), not a silent trip to Legal #15 with no explanation.GET /api/v1/signatures/status?property=vote.cl8y.com&network=EVM&account=0x…issigned_latest: true; return URL is voting origin.ConnectedTermsGateunit tests green for EVM hint presence/absence andaccounton Accept URL.Depends on: cl8y-ecosystem-legal#15 for the portal sign itself. This issue is the voting gate / hint /
accountcontinuity.mentioned in merge request !27
mentioned in merge request !28
mentioned in issue #17
!28 merge review (no automerge, did not wait for CI)
MR !28 is merged onto
main(f000040). GitLab reported no conflicts (can_be_merged). Source branchfix/16-evm-legal-copywas removed on origin.Sanity check
Chrome and Safari cannot finish terms…) because cl8y-ecosystem-legal#15 is closed. Product-correct; do not revert to the dead-end sentence.@plasticdigits/cl8y-clickwraponmainis already ^0.1.1 (Acceptaccount=). !28 did not bump the package again. A leftover local stash (evm copy) still had ^0.1.0 — not merged (would regress Accept).legalEvmInAppHint+ConnectedTermsGate19 passed; full frontend 110 passed.Acceptance criteria vs tree
vote.cl8y.comafter this mergeproperty, sanitizedredirect_uri,app_name=CL8Y Voting, connectedaccount=0x…LegalKeplrInAppHintstill Terra-onlysigned_latest: true→ return 200accountDo not close this issue until live unsigned EVM on
https://vote.cl8y.comshows:Accept opens the Legal page. On a phone, open it in MetaMask or paste the link in Binance Web3.and Accept still hasaccount=.Problems
2804368993failed every job withci_quota_exceeded(no runner, no traces). Merge settings do not require a green pipeline. Local tests are the only check that ran.No other open MRs. Leftover
fix/16-evm-legal-inapp-hint/fix/16-evm-legal-copyworktrees were already contained inmain; dangling stash would downgrade clickwrap and was not applied.Verify pass (2026-09-01) — in-tree only; this issue stays open
Pushed
d7f4d51tomain.In-tree (pass)
LEGAL_EVM_INAPP_HINT; Terra Keplr hint stays Terra-only.redirect_uri,app_name=CL8Y Voting, connectedaccount=(clickwrap ^0.1.1 + vendor fallback).ConnectedTermsGate/legalEvmInAppHint).AGENTS_LEGAL_CLICKWRAP.mdtreats the EVM hint as required and points at the Coolify rebuild (issue 17).Live (remaining AC)
vote.cl8y.comstill servesChrome and Safari cannot finish terms…(index-cN5sRfvA.js). Rebuild is issue 17.Checklist
accounton Acceptaccount=signed_latest: true→ return 200 on voting originStays open: live copy and human wallet round-trip are still required.
Redeploy check — closing on in-tree + live copy
After the Coolify rebuild, live
vote.cl8y.comserves the !28 hint (Accept opens the Legal page…) and still constructs/sign/evmwithaccount=. Clickwrap onmainis^0.1.1. Legal portal next-steps (ecosystem-legal issue 15) are already closed.In-tree: EVM hint unit tests, Terra Keplr still Terra-only, TermsGate fail-closed, vendor fallback
account. Playwright hatch is not device QA.Not re-run here: MetaMask iOS / Binance Web3 full sign round-trip, desktop injected Accept. Those stay manual on issue 7 live wallet QA. Product dead-end on voting is fixed.