Skip to content

docs(fee-abstraction): say that the wallet must support CIP-64, and which do - #2304

Open
GigaHierz wants to merge 3 commits into
mainfrom
GigaHierz/cip64-wallet-support
Open

docs(fee-abstraction): say that the wallet must support CIP-64, and which do#2304
GigaHierz wants to merge 3 commits into
mainfrom
GigaHierz/cip64-wallet-support

Conversation

@GigaHierz

@GigaHierz GigaHierz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

The hole, and the fix

fee-abstraction/overview.mdx said fee abstraction "works with any externally owned account (EOA). No smart contract wallets, no relayers, no extra infrastructure needed." True of the protocol, and it reads as "every wallet works". Nothing said that feeCurrency is a field on a CIP-64 transaction, so the wallet signing it has to implement CIP-64, and nothing described what happens when it does not.

This adds a ## Wallet support for CIP-64 section to the overview: the requirement, a <Warning> describing the failure mode, and a table of the wallets whose behaviour is confirmed from source. Both wallet directories (tooling/wallets/index.mdx and home/wallets.mdx) link to it, gain a Hardware Wallets section with Ledger, and have their Ledger support: field renamed to Hardware wallet support: so it can no longer be read as a fee-abstraction answer.

Found by the docs assistant (#2250): asked which wallets support fee abstraction, it faithfully summarised these pages and produced an answer that was accurate to the docs and useless to the reader.

What the table says, and where each row was verified

Wallet Behaviour Verified in
MiniPay Pays in the user's largest stablecoin; may override a dApp's feeCurrency build-on-minipay/overview.mdx (in-repo)
Valora Builds CIP-64; deletes a dApp's feeCurrency and re-selects, CELO first, then highest-value fee currency valora-xyz/wallet-stack walletConnect/saga.ts (deletes tx.feeCurrency), viem/prepareTransactions.ts (no explicit type, viem's celo chain emits 0x7b), tokens/selectors.ts (native-first ordering)
Ledger Live Own send flow builds CIP-64, user picks the fee currency; Ledger Live 4.8+ and Celo app 1.8+ LedgerHQ/ledger-live coin-celo/src/bridge/signOperation.ts (type: "cip64"), LedgerHQ/app-celo-spender ethUstream.h (CIP64 = 0x7b)
MetaMask Not supported; feeCurrency dropped, gas in CELO MetaMask/core transaction-controller/src/utils/utils.ts NORMALIZERS has no feeCurrency key

A Ledger used through MetaMask therefore does not get CIP-64 either, and the Ledger row says so. Nothing outside those four is claimed; the page says an unlisted wallet is unconfirmed rather than unsupported.

Other corrections in this PR

  • The overview's library sentence claimed wallets on viem or wagmi "inherit" feeCurrency support. Wrong: a wallet using viem internally does not forward a dApp's field. Replaced with a sentence separating library support from wallet support, pointing at the canonical library section.
  • That canonical sentence on using-fee-abstraction.mdx said Ethers.js and web3.js do not support the field. Two SDK pages in this repo document Celo plugins for both. It now says neither supports it natively and links the wrapper and the plugin.
  • No dates. Minimum versions are stated where they exist; change history is not.
  • The MiniPay fee-section heading lost its apostrophe (### Gas is paid in stablecoins) so the deep link from the table has a stable slug. No other page linked the old anchor. Verified rendered.

Verification

$ mint broken-links
success no broken links found

$ bash scripts/check-orphans.sh
No orphan pages found.

Anchors checked by hand on mint dev, since broken-links does not validate them: #wallet-support-for-cip-64, #using-fee-abstraction-with-viem, #gas-is-paid-in-stablecoins all present in the rendered HTML.

Not in this PR

Part of #2303.

…hich do

The overview said fee abstraction "works with any externally owned
account (EOA) ... no extra infrastructure needed", which is true of the
protocol and reads as "every wallet works". Nothing said that
feeCurrency is a field on a CIP-64 transaction, so the wallet signing it
has to implement CIP-64.

The failure mode was undocumented and is silent: a wallet without
support submits a normal transaction, gas is charged in CELO, and
nothing errors. A developer sees their feeCurrency ignored with no
indication that the wallet, rather than their code or the adapter
address, is the cause.

Adds the requirement, the failure mode, and a support table for the
wallets that are confirmed. Ledger shipped CIP-64 in July 2026 and was
absent from the wallets page entirely, so it is added there too.

Also disambiguates the existing "Ledger support" field, which records
whether a wallet works with a Ledger device — unrelated to CIP-64, and
actively confusing beside this question.

mint broken-links: success, no broken links found.

Refs #2303

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@palango palango left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed dfbee68d8f14bc2fca534f927a09eec266e174a8, which contains current main. I checked the factual claims against the repo, against #2303's acceptance criteria, and against outside sources for the Ledger announcement.

Verdict: REQUEST-CHANGES. One round of targeted fixes, not a rethink. The section belongs on this page and most of the prose is right.

What holds up

The core point is correct, and nothing on the fee-abstraction pages said it: feeCurrency is a CIP-64 field, the wallet builds the transaction, so a dApp setting it is necessary but not sufficient.

I checked the Ledger claims independently. blog.celo.org does return 403 to automated fetching, as you said, but July 2026, the 18 tokens, the December 2025 Ledger Live groundwork and the 8M+ user figure are all corroborated by separate coverage (ChainCatcher, Blockchain.News, CoinMarketCal via TradingView). The substance is sound. What follows is about framing and placement.

MiniPay's "may override" is sourced correctly to build-on-celo/build-on-minipay/overview.mdx:53. I also checked the new anchor #wallets-with-cip-64-support by hand, against the repo's own precedent at #adapters-for-non-18-decimal-tokens, and it resolves. Worth stating, because AGENTS.md §6 says mint broken-links does not validate anchors, so the green check is not evidence for that link.

Blocking

1. home/wallets.mdx is a second wallet directory, and it gets left behind.

It sits in the nav at docs.json:70, duplicates the MiniPay, Valora and Celo Terminal entries, and line 60 already reads: "Note that some wallets do not support fee abstraction for gas payments with different tokens." The grep in the PR body and in #2303 was too narrow to catch that phrasing, so the premise that the failure mode was undocumented doesn't hold. After this PR the two pages disagree. home/wallets.mdx has no CIP-64 note, no Ledger entry, and still shows Ledger support: No on both wallets that do support fee abstraction. Either mirror the <Note> and the disambiguation there, or fold the two pages into one and redirect.

2. build-on-celo/fee-abstraction/overview.mdx:57, on viem and wagmi.

"Wallets that route through viem or wagmi inherit feeCurrency support from the library" contradicts the sentence fifteen lines above it, and it is mechanically wrong. viem serializes CIP-64 only when it holds the key and a Celo chain from viem/chains is passed to createWalletClient. A wallet that happens to use viem internally does not thereby forward a dApp's feeCurrency arriving over eth_sendTransaction, and wagmi is a viem wrapper rather than a second path. A reader concludes "we're on wagmi, we're covered" and ships the exact bug the section exists to prevent. Cut the clause.

3. Same line: "Ethers.js and web3.js do not support the field."

Two pages in this repo say otherwise. tooling/libraries-sdks/web3/index.mdx:46 documents @celo/web3-plugin-transaction-types making eth.sendTransaction use the CIP-64 serializer on web3 4.13.1 and up, with a runnable example. tooling/libraries-sdks/ethers/index.mdx:7 documents @celo-tools/celo-ethers-wrapper for the same thing. The accurate version is that neither supports it natively and both need a Celo plugin. The sentence was copied from using-fee-abstraction.mdx:76, so as written this duplicates an existing error onto a second page, and §7 says the fact should live on one page anyway.

4. Dated change history, against AGENTS.md §4.

The rule is "Document what is true now… Change history belongs in Notices and release notes." Three instances here: "Yes, since July 2026" in the table, the same in the Ledger bullet, and "added support… in December 2025, and… in July 2026" in the prose. What a reader needs is that Ledger supports it. Make it "Yes", and put the prose in present tense.

5. The <Warning> contradicts itself, and claims more than was verified.

"gas is paid in CELO. Nothing errors." is followed three lines later by "a user with no CELO sees the transaction fail for want of gas". Both can't describe the same run. Separately, "it submits a standard transaction instead" is asserted for every non-CIP-64 wallet, while the PR body concedes that no such wallet was tested. A wallet that validates its RPC params rejects the unknown field loudly, which is the opposite of what the callout promises. Either name the wallet you saw the silent fallback in, or give both outcomes: the field is dropped without error, and then either gas comes out in CELO, or the transaction fails with a generic insufficient-funds error that doesn't point at the wallet.

6. The Ledger row answers a different question than the table asks, and #2303 made that a gate.

The issue says: "OPEN — confirm before publishing: whether support is Ledger Live, the Celo Ledger app, or both, and whether any minimum version applies." Still open. What's verified is that Ledger Live pays gas in Celo assets. Whether a dApp connecting a Ledger over WalletConnect gets feeCurrency honoured is a separate question, and it's the one this table implies it's answering. Scope the row to Ledger Live until the device path is confirmed.

7. Valora's "Yes" doesn't meet the standard the table sets for itself.

#2303 says it plainly: Valora is "asserted in-repo (tooling/wallets/index.mdx:36)… but not as CIP-64 specifically." Paying fees with stablecoins is the observable behaviour, not evidence about the transaction type. The table's own rule is that it lists only what's confirmed. Confirm with Valora, or mark the row as reported rather than confirmed.

Should fix

8. Fee abstraction (CIP-64): Yes appears on the Ledger entry and nowhere else. MiniPay and Valora get no such bullet, so the wallets page implies Ledger is the only one, while the table in this same PR says all three. That's the inverse inference the PR body set out to avoid. Add the field to every native-wallet entry, or drop it and let the <Note> link carry it.

9. Ledger is in the wrong section, and it skips five existing Ledger pages. ## Celo Native Wallets is introduced as "Build apps to be listed inside of these wallets", and you can't list a Mini App in Ledger Live. Meanwhile tooling/wallets/ledger/{setup,to-celo-web,to-celo-terminal,to-celo-cli,eip712-workaround} are all in the nav at docs.json:271-275, directly beside this index, and the new entry links to none of them. A reader who wants to connect a Ledger gets ledger.com three times.

10. Adding a wallet named Ledger makes the Ledger support: collision worse. The <Note> explains that the field means hardware-device compatibility, then forty lines later ### [Ledger] shows up as a wallet on the same page, so MiniPay's Ledger support: No now reads plausibly as "doesn't work with the Ledger wallet above". That misreading didn't exist before this PR. The body defers the rename as touching every entry, but it's three occurrences per file across two files, and Hardware wallet support: is a smaller edit than the <Note> that documents the ambiguity instead of removing it. It would also close the fourth acceptance box properly.

11. "18 Celo-native assets" restates a moving number. §7 keeps counts on one canonical page, and /tooling/contracts/fee-currencies is generated from the on-chain allowlist, so this line drifts on the next governance vote with nothing to regenerate it. "Celo-native" is also wrong for USDT, USDC and WETH. Say "Celo fee currencies" and link that page.

12. The closing paragraph is stranded. "For implementation details, see Using Fee Abstraction…" used to close ## How It Works. It now renders at the tail of ### Wallets with CIP-64 support, so those two links read as being about wallet support. Move it above the new H2.

Nits

  • ## The wallet has to support it too: "it" and "too" only resolve against the previous section, so the heading says nothing in a sidebar, a search result, or a retrieved chunk. ## Wallet support for CIP-64 names the thing, and it makes the H3 beneath it redundant, which also fixes 12.
  • CIP-64 is named seven times across the diff and never linked, on the page that introduces it. Every other page that names it links out.
  • Both MiniPay links in the table point at the same bare URL. The "may override" one wants #gas-is-paid-in-the-users-stablecoin. Check that anchor by hand.
  • The table's middle column reads Yes / Yes / Yes under a heading that already says "with CIP-64 support", and the closing <Note> restates the <Warning> four lines above it.
  • ## Related gains no link to the wallets page, though the wallets page now links here. The frontmatter description is untouched too, and since #2250's retrieval is what surfaced this gap, that field is what decides whether the assistant opens the page at all.

GigaHierz and others added 2 commits September 3, 2026 13:25
…e, rename the Ledger field, fix library claims

Findings from review, in order:

1. home/wallets.mdx is a second wallet directory and disagreed with the
   new page. It now carries the same note, the same field rename and a
   Ledger entry, so the two pages say the same thing.
2. The viem/wagmi 'inherit feeCurrency support' clause was wrong: a wallet
   that uses viem internally does not thereby forward a dApp's
   feeCurrency. Cut, replaced with a sentence saying library support and
   wallet support are separate questions.
3. 'Ethers.js and web3.js do not support the field' contradicted the two
   SDK pages. The canonical sentence on using-fee-abstraction.mdx now says
   neither supports it natively and links the Celo wrapper and the web3
   plugin; the overview links there instead of restating it.
4. Dated change history removed. Present tense throughout.
5. The Warning gives both outcomes of a dropped feeCurrency (gas in CELO,
   or a generic insufficient-funds failure) and names MetaMask as the
   wallet confirmed to drop the field, with the source.
6. Ledger row scoped to Ledger Live's own send flow, with the minimum
   Ledger Live and Celo app versions, and an explicit statement that a
   Ledger used through MetaMask does not get CIP-64. Verified in
   LedgerHQ/ledger-live coin-celo (type 'cip64' serialisation),
   LedgerHQ/app-celo-spender (0x7b parser), and MetaMask/core's
   transaction-controller normalisers (no feeCurrency key).
7. Valora row verified in valora-xyz/wallet-stack: it builds CIP-64 and
   deletes a dApp-supplied feeCurrency, re-selecting CELO first and then
   the highest-value fee currency. The row says so and links the source.
8. The per-entry 'Fee abstraction (CIP-64)' bullet is gone; the table is
   the one place that answers it.
9. Ledger moved out of Celo Native Wallets into a Hardware Wallets section
   that links the five existing Ledger guides.
10. 'Ledger support:' renamed to 'Hardware wallet support:' on both wallet
    pages (six occurrences), which removes the ambiguity instead of
    documenting it.
11. The '18 Celo-native assets' count is gone; the fee-currencies page is
    the canonical list.
12. The closing implementation-details paragraph moved back above the new
    H2.

Nits: heading is now 'Wallet support for CIP-64' with no H3 under it,
CIP-64 links to the proposal on first use, the MiniPay link deep-links to
the fee section (the heading lost its apostrophe so the slug is stable and
verified rendered), the Yes/Yes/Yes column is gone, the closing Note is
folded into one sentence, Related links the wallets page, and the
frontmatter description mentions wallet support.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@GigaHierz
GigaHierz requested review from a team as code owners September 3, 2026 11:36
@GigaHierz
GigaHierz requested review from palango and removed request for a team September 3, 2026 11:36
@GigaHierz

Copy link
Copy Markdown
Contributor Author

All twelve worked, plus the nits, in 49dfa9b1 on top of a merge from main. I checked each of your claims against the code before acting on it, and the two you left open I resolved from wallet source rather than by asking anyone.

1 — home/wallets.mdx. Mirrored rather than folded: same <Note>, same field rename, a Hardware Wallets section with Ledger, and line 60 now links the table instead of asserting the failure mode in passing. Folding the two pages is a redirect-and-audience question that belongs in its own change.

2 — viem/wagmi. Cut. Checked viem's celo chain: sendTransaction with a JSON-RPC account hands feeCurrency to eth_sendTransaction and the wallet decides, so "inherit" was wrong exactly as you said. Replaced with one sentence that library support and wallet support are separate questions.

3 — ethers/web3. Fixed at the source. using-fee-abstraction.mdx:74 now says neither supports it natively and links /tooling/libraries-sdks/ethers and /tooling/libraries-sdks/web3; the overview links there rather than restating it.

4 — dates. Gone. Minimum versions are stated where they exist because they are true now; history is not.

5 — the <Warning>. Gives both outcomes and names the wallet: MetaMask. MetaMask/core transaction-controller/src/utils/utils.ts builds params from a NORMALIZERS whitelist with no feeCurrency key, so the field is dropped before signing. That is the silent fallback with a source, so MetaMask also gets a row as the one confirmed negative.

6 — Ledger. Scoped to Ledger Live's own send flow. LedgerHQ/ledger-live coin-celo/src/bridge/signOperation.ts:66-67 serialises type: "cip64" when a fee currency is chosen; LedgerHQ/app-celo-spender ethUstream.h parses CIP64 = 0x7b and refuses unknown fee tokens rather than blind-signing. The device path from a dApp is a no: Ledger Live's WalletConnect app lists no Celo chain, and a Ledger behind MetaMask signs what MetaMask builds, which is finding 5. Minimum versions on the row: Ledger Live 4.8, Celo app 1.8.

7 — Valora. Confirmed as CIP-64, and with a wrinkle worth documenting. valora-xyz/wallet-stack walletConnect/saga.ts:455-457 deletes a dApp's gas and feeCurrency and re-runs its own selection; viem/prepareTransactions.ts sets no explicit type and viem's celo chain emits 0x7b; tokens/selectors.ts:420-423 orders candidates native-first. So Valora pays in CELO when the balance covers the fee and otherwise in the highest-value fee currency. The row says that and links the file.

8, 9, 10. The per-entry bullet is gone; Ledger is in a ## Hardware Wallets section that links all five Ledger guides; Ledger support: is Hardware wallet support: on both pages, six occurrences, which removes the ambiguity rather than documenting it.

11. Count gone. 12. Paragraph moved back above the H2.

Nits. Heading is ## Wallet support for CIP-64 with no H3; CIP-64 links the proposal on first use; the middle column is gone; the closing Note is one sentence after the table; Related links the wallets page; the description names wallet support.

The MiniPay anchor was the one that did not hold up: the rendered id keeps a curly apostrophe (gas-is-paid-in-the-user’s-stablecoin), so #gas-is-paid-in-the-users-stablecoin would have 404'd. I renamed the heading to ### Gas is paid in stablecoins, checked no other page linked the old anchor, and confirmed the new id renders.

mint broken-links and check-orphans green; the three anchors present in mint dev HTML. Body rewritten around the verified table.

@palango palango left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 49dfa9b1. All twelve points and the nits from the last round are in, and I checked the new source claims myself rather than taking the comment's word for them. The branch is level with main, CI is green, and the three anchors are present in mint dev HTML at this head. One fact still has no source, so one more short round.

Needs a change

The "Celo app 1.8 or later" minimum has no source I can find. The Celo Ledger app has parsed CIP-64 since March 2024 (feat: implement CIP64 transaction processing, 27456b7f), and src_common/ethUstream.h at the 1.7.0 tag already has the parser. The only app version Ledger Live enforces in code is 1.7.0, for the 44'/60' derivation-path change (libs/live-signer-celo/src/deviceAuthorization.ts:8). The 1.8.0 release itself was a ticker-buffer fix for long token names (app-celo-spender #40). Neither the Celo blog post nor Ledger's release notes name an app version. Either cite where 1.8 comes from, or drop the app version and keep only the Ledger Live one. Ledger Live prompts for app updates on its own.

The Ledger Live number does hold up, and now has a source: the 4.8.0 release notes (2026-06-11, #17901) say "Implements the Celo fee currency selection plugin across mobile and desktop". Desktop alone had it from 4.3.0 (#15326). So 4.8 is the right bound for a row that says desktop and mobile.

Should fix

  • The version line now appears on three pages: the overview table, tooling/wallets/index.mdx and home/wallets.mdx. That's the same §7 drift as the "18" count last round. Keep it in the table; the two directory entries already link there.
  • The <Warning> says "Most drop the field and sign a standard transaction, as MetaMask does". One wallet was verified. "Some wallets, MetaMask among them" is what the evidence supports.
  • The two directory <Note>s disagree with each other and with the Warning. tooling/wallets/index.mdx says the field is dropped "without an error". home/wallets.mdx says gas is "charged in CELO instead". The Warning itself allows for a wallet that rejects the request. Pick one sentence and use it on both pages.

Nits

  • The Valora and MetaMask rows link source files on main and say "Confirmed in the wallet source". Line-level claims move with the branch. Pin to a commit, or drop the phrase and keep the link.
  • Out of scope, but §7 asks for a grep when a fact changes: home/manage/self-custody.mdx:59 still says the latest Celo Ledger app is 1.1.8, which this PR's version line now contradicts. Worth a follow-up.

What I verified

Claim Where I looked
MetaMask drops feeCurrency NORMALIZERS in transaction-controller/src/utils/utils.ts has keys accessList, authorizationList, data, from, gas, gasLimit, gasPrice, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, estimatedBaseFee, type; normalizeTransactionParams iterates only those. Code search across MetaMask/core: 0 hits for feeCurrency.
Valora deletes and re-selects, CELO first, then highest value walletConnect/saga.ts:455-457 deletes gas and feeCurrency on Celo. prepareTransactions takes the first fee currency whose balance covers max gas. feeCurrenciesByNetworkIdSelector (tokens/selectors.ts:448-455, not 420-423) orders native first, then USD balance.
Ledger Live builds CIP-64 coin-celo/src/bridge/signOperation.ts:66-68 sets type: "cip64" when a fee currency is chosen.
Celo app parses CIP-64 src_common/ethUstream.h:108, CIP64 = 0x7b.
Anchors wallet-support-for-cip-64, using-fee-abstraction-with-viem, gas-is-paid-in-stablecoins all present in the rendered HTML. No remaining reference to the old MiniPay anchor anywhere in the repo.
Structure Both Hardware Wallets sections render with the same rule pattern as the existing sections. Every page the diff links is in docs.json.

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.

3 participants