Skip to content

feat(abstract-eth): add ERC20Votes delegateBySig EIP-712 helpers#8660

Open
0xPrabh wants to merge 1 commit intomasterfrom
prabhsharansingh540/cgd-842-erc20-votes-delegatebysig-support
Open

feat(abstract-eth): add ERC20Votes delegateBySig EIP-712 helpers#8660
0xPrabh wants to merge 1 commit intomasterfrom
prabhsharansingh540/cgd-842-erc20-votes-delegatebysig-support

Conversation

@0xPrabh
Copy link
Copy Markdown
Contributor

@0xPrabh 0xPrabh commented Apr 30, 2026

Summary

Adds a productized path for cold-custody governance participation via EIP-712
delegateBySig meta-transactions. Cold wallet holders can now delegate voting
power to a self-custody hot wallet without moving funds or paying gas — BitGo
signs the EIP-712 typed data with the cold wallet's ETH MPC keys, and any relayer
can submit the delegateBySig(delegatee, nonce, expiry, v, r, s) call on-chain.

See ticket CGD-842 for context — this
is the BitGoJS half; WP companion changes ship separately in
BitGo/bitgo-microservices#58250.

What's included

New: @bitgo/abstract-eth ERC20Votes delegation helpers (modules/abstract-eth/src/lib/eip712/)

  • buildErc20VotesDelegationTypedData({ domain, message }) — canonical OZ
    Delegation(address delegatee,uint256 nonce,uint256 expiry) payload with
    proper EIP712Domain block and normalized fields.
  • encodeErc20VotesDelegationTypedDataDigest(Hex) — v4 digest
    (\x19\x01 || hashStruct(domain) || hashStruct(message)) for BitGo
    typed-data tx requests (messageEncoded / typedDataEncoded).
  • encodeDelegateBySigCalldata({ delegatee, nonce, expiry, v, r, s })
    ABI-encoded on-chain submission payload for any relayer.
  • wlfiEthereumMainnetDelegationDomain() — reference domain for the WLFI
    proxy at 0xda5e1988097297dcdc1f90d4dfe7909e847cbef6. The same pattern works
    for UNI, COMP, ARB, ENS, OP and every OZ-ERC20Votes token.

Wire MessageStandardType.EIP712 through the typed-data signing path
so WP can distinguish delegation messages from plain signMessage intents and
route them to the dedicated TAT Kafka topic rather than sendQ:

  • modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts:
    IntentOptionsForTypedData and PopulatedIntentForTypedDataSigning now
    carry an optional messageStandardType.
  • modules/sdk-core/src/bitgo/utils/tss/baseTSSUtils.ts: passes
    messageStandardType through createTxRequestBase when building the intent
    for message signing.
  • modules/sdk-core/src/bitgo/wallet/wallet.ts: signTypedData explicitly
    sets MessageStandardType.EIP712 on the intent.

Runnable example: examples/ts/eth/push-erc20-votes-delegation-txrequest.ts
pushes a WLFI delegation tx request to WP via wallet.signTypedData(...).

Tests

  • modules/abstract-eth/test/unit/eip712/erc20VotesDelegation.ts:
    • domain + message hash stability against OZ struct
    • v4 digest hex matches TypedDataUtils.eip712Hash
    • delegateBySig calldata matches the canonical ABI encoding

Test plan

  • yarn test --scope @bitgo/abstract-eth (new eip712/erc20VotesDelegation suite)
  • yarn test --scope @bitgo/sdk-core covering typed-data intent creation (createTxRequestWithIntentForTypedDataSigning)
  • End-to-end manual run of examples/ts/eth/push-erc20-votes-delegation-txrequest.ts against a staging ETH MPC cold wallet, verifying WP returns a tx request with messages[0].messageStandardType === 'EIP712' and intent.intentType === 'signTypedStructuredData'
  • After the WP PR merges, confirm the signed message lands on the new typed-data-delegation-signing-request Kafka topic (not sendQ)

Rollout

  • Ship behind the companion WP topic (BitGo/bitgo-microservices#58250); consumers that don't handle the new topic are unaffected because the new messageStandardType field is optional and existing signMessage intents remain unchanged.

References

Made with Cursor

Adds reusable EIP-712 builders for OpenZeppelin `ERC20Votes`-style
`delegateBySig` so cold-custody clients can delegate voting power to a
self-custody hot wallet without moving funds:

- `buildErc20VotesDelegationTypedData` returns the canonical
  `Delegation(address delegatee,uint256 nonce,uint256 expiry)` typed
  data with a well-formed `EIP712Domain` block.
- `encodeErc20VotesDelegationTypedDataDigest(Hex)` produces the v4
  `\x19\x01 || hashStruct(domain) || hashStruct(message)` digest used
  by BitGo typed-data tx requests (`messageEncoded` / `typedDataEncoded`).
- `encodeDelegateBySigCalldata` returns the ABI-encoded on-chain
  submission payload so any relayer can post the signature.
- Ships a WLFI Ethereum mainnet domain helper as a reference template.

Also:
- Wires `MessageStandardType.EIP712` through
  `createTxRequestWithIntentForTypedDataSigning` /
  `IntentOptionsForTypedData` / `PopulatedIntentForTypedDataSigning` so
  WP can distinguish typed-data delegation messages from plain
  `signMessage` intents.
- Adds a runnable example under
  `examples/ts/eth/push-erc20-votes-delegation-txrequest.ts` that pushes
  a delegation tx request to WP via `wallet.signTypedData(...)`.
- Unit tests cover the domain/message hash, digest hex, and calldata.

Ticket: CGD-842
Made-with: Cursor
@0xPrabh 0xPrabh requested review from a team as code owners April 30, 2026 10:03
@linear
Copy link
Copy Markdown

linear Bot commented Apr 30, 2026

@vinhkhangtieu
Copy link
Copy Markdown

@claude review this pr in 500 words

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants