fix(governance-api): normalize EVM (MetaMask) submitters to their Zilliqa address#778
Merged
Merged
Conversation
…liqa address MetaMask users signed with their 0x (Keccak) address, but the gZIL gate, the voter-scoring snapshot, and space members all key off the Zilliqa (SHA256) address - a different address for the same key - so EVM users failed every check. - Add zilliqaAddressFromEVMSignature(): recover the pubkey from the EVM personal_sign signature and derive the canonical Zilliqa address. - In POST /api/message, after verifying the EVM signature, replace body.address with the derived Zilliqa address. Covers proposals and votes (same handler); the gate, IPFS pin, and DB record then use the real Zilliqa identity. - Add a regression test and wire it into npm test. New submissions only; no migration. Frontend unchanged (a MetaMask user may not see the 'You' badge on their own items - cosmetic, tracked separately).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
MetaMask (EVM) users are broken across every on-chain identity check. They sign with their EVM
0xaddress (Keccak256-derived), but the governance checks all key off the user's Zilliqa address (SHA256-derived) — a different address for the same key:message.ts): the EVM address holds no gZIL → alwaysMIN_BALANCE.get-scores.tsreadsproposal.balances[addr]): the EVM voter isn't in the Zilliqa-keyed snapshot → score 0 → dropped from the tally.Proposals.vue):membersarezil1…(Zilliqa base16); an EVM author never matches.Fix
Recover the signer's public key from the EVM
personal_signsignature, derive the canonical Zilliqa address (the one ZilPay shows for that key, where the user's gZIL/ZRC2 balances and membership live), and use it as the stored identity.lib/utils/verify-evm-signature.ts: addzilliqaAddressFromEVMSignature()—hashMessage→SigningKey.recoverPublicKey→ compress →getAddressFromPublicKey(all from already-installedethers@6+@zilliqa-js/crypto).lib/routes/message.ts: at the singlePOST /api/messagechoke point, after the EVM signature is verified, replacebody.addresswith the derived Zilliqa address. Everything downstream (gZIL gategetLiquidity, IPFS pin, DBMessage.create) then uses the real Zilliqa identity — for both proposals and votes (same handler).No frontend changes: with the stored address now a real Zilliqa base16, the members compare,
toBech32Addressdisplay, and scoring all line up.Scope / decisions
User.vuecompares the stored address to the connected EVM account, so a MetaMask user may not see the "You" badge on their own items. Out of scope (would need a client-side Zilliqa-address derivation).Tests
lib/utils/verify-evm-signature.test.ts: signs with a fixed test key and assertszilliqaAddressFromEVMSignature(msg, sig)equals the ground-truthgetAddressFromPublicKey(compress(pubkey))and differs from the EVM address. Wired intonpm test(now runs both suites; green).Security review
Reviewed (security-reviewer): 0 critical / 0 major. Identity binding is sound — the Zilliqa address is derived from the same signature already verified against
body.address, so a user can only obtain their own address; forging would require a valid secp256k1 signature for the target key. Crypto verified by round-trip; malformed signatures throw and are caught (→ 400).Pre-existing follow-up (not introduced here):
body.sig.messageis never reconciled withbody.msgon either the EVM or Schnorr path — a client can sign one string and submit a different proposal body. Worth a separate fix (assertsig.message === body.msg).Verify on staging
npm testgreen ingovernance-api.201(noMIN_BALANCE); confirmGET /api/<space>/proposalsstored a0x…Zilliqa address (not the EVM one)."EVM identity normalized to Zilliqa address"with the derivedzilAddress.