{"post_stream":{"posts":[{"id":62963,"name":"Daniil Ankushin","username":"AnkushinDaniil","avatar_template":"/user_avatar/ethresear.ch/ankushindaniil/{size}/16277_2.png","created_at":"2026-11-06T13:00:56.101Z","cooked":"\u003cp\u003e\u003cem\u003eDaniil Ankushin, Nethermind. Verify-budget figures: method by Daniil Ankushin, benchmark and measurements by Manuel Arto.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eOn frame transactions a shielded pool pays its own gas, so a private withdrawal needs no relayer. We ran a real BN254 Groth16 pool this way on current Nethermind master: a withdrawal costs 679,322 gas. With EIP-8250 nonce keys, many withdrawals can come from the one pool address at once. Two things do not work yet. The proof check is over the spec cap on validation gas, and a pool cannot pay for a call from the user’s own address.\u003c/p\u003e\n\u003cp\u003eThe pool we ran is soispoke’s minimal-shielded-pool (\u003ca href=\"https://github.com/soispoke/minimal-shielded-pool\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003eGitHub - soispoke/minimal-shielded-pool · GitHub\u003c/a\u003e).\u003c/p\u003e\n\u003ch2\u003e\u003ca name=\"p-62963-how-a-withdrawal-works-1\" class=\"anchor\" href=\"#p-62963-how-a-withdrawal-works-1\" aria-label=\"Heading link\"\u003e\u003c/a\u003eHow a withdrawal works\u003c/h2\u003e\n\u003cp\u003eIn a withdrawal the pool is the sender. Its VERIFY code checks the zk proof and approves execution and payment. The user needs no funded account and does not appear in the transaction.\u003c/p\u003e\n\u003cp\u003eTwo drafts make this safe in a public mempool. With EIP-8250 the pool uses the note’s nullifiers as nonce keys. Each withdrawal has its own nonce key, so withdrawals with the pool as sender do not compete for one nonce. A side effect: a nullifier that was already used is a used nonce key, so the protocol refuses a double spend before the pool’s code runs. With EIP-8272 the transaction checks the pool’s Merkle root against a contract of recent roots before the pool’s code runs, so a mempool node never reads the pool’s storage.\u003c/p\u003e\n\u003cp\u003e\u003cdiv class=\"lightbox-wrapper\"\u003e\u003ca class=\"lightbox\" href=\"https://ethresear.ch/uploads/default/original/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea.png\" data-download-href=\"https://ethresear.ch/uploads/default/7dab7d3493d78fffc199a0541ea712880a29e6ea\" title=\"withdrawal flow with the pool as sender\"\u003e\u003cimg src=\"https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_690x296.png\" alt=\"withdrawal flow with the pool as sender\" data-base62-sha1=\"hVJ62GyWF2LhpUzWBYMvvcNZymC\" width=\"690\" height=\"296\" srcset=\"https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_690x296.png, https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_1035x444.png 1.5x, https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_1380x592.png 2x\" data-dominant-color=\"F8F7F1\"\u003e\u003cdiv class=\"meta\"\u003e\u003csvg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"\u003e\u003cuse href=\"#far-image\"\u003e\u003c/use\u003e\u003c/svg\u003e\u003cspan class=\"filename\"\u003ewithdrawal flow with the pool as sender\u003c/span\u003e\u003cspan class=\"informations\"\u003e1392×598 51.7 KB\u003c/span\u003e\u003csvg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"\u003e\u003cuse href=\"#discourse-expand\"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/div\u003e\u003c/a\u003e\u003c/div\u003e\u003c/p\u003e\n\u003ch2\u003e\u003ca name=\"p-62963-what-it-costs-2\" class=\"anchor\" href=\"#p-62963-what-it-costs-2\" aria-label=\"Heading link\"\u003e\u003c/a\u003eWhat it costs\u003c/h2\u003e\n\u003cp\u003eAll values are from mined receipts on Nethermind master 4bcb9e30, single node.\u003c/p\u003e\n\u003cdiv class=\"md-table\"\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eStep\u003c/th\u003e\n\u003cth\u003eGas\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDeposit a note, frame tx\u003c/td\u003e\n\u003ctd\u003e990,503\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eof which state gas\u003c/td\u003e\n\u003ctd\u003e195,840\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDeposit a note, plain EIP-1559 call\u003c/td\u003e\n\u003ctd\u003e958,555\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWithdrawal, whole transaction\u003c/td\u003e\n\u003ctd\u003e679,322\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003erecent-root VERIFY frame\u003c/td\u003e\n\u003ctd\u003e5,515\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003epool VERIFY frame (proof check and APPROVE)\u003c/td\u003e\n\u003ctd\u003e405,979\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eof which execution\u003c/td\u003e\n\u003ctd\u003e210,139\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eof which state gas for two nullifier keys\u003c/td\u003e\n\u003ctd\u003e195,840\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esettle SENDER frame\u003c/td\u003e\n\u003ctd\u003e25,526\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eclaim frame\u003c/td\u003e\n\u003ctd\u003e198,338\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eoutside the frames (intrinsic, calldata, key access)\u003c/td\u003e\n\u003ctd\u003e43,964\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBare Groth16 check, as its own transaction, including the 21,000 base\u003c/td\u003e\n\u003ctd\u003e222,991\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eTransfer, two notes in and two out, whole transaction\u003c/td\u003e\n\u003ctd\u003e1,333,766\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eof which state gas\u003c/td\u003e\n\u003ctd\u003e293,760\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e\u003cp\u003eThe two nullifier keys cost 195,840 state gas, exactly two times the EIP-8250 price: “each fresh key costs \u003ccode\u003e97920\u003c/code\u003e state gas”. EIP-8250 also charges 12,100 execution gas per key and adds the same amount to the calldata floor.\u003c/p\u003e\n\u003cp\u003eThe proof does not fit the shared budget. The validation prefix declares 233,000 execution gas and uses 215,654, over the EIP-8141 cap \u003ccode\u003eMAX_VERIFY_GAS\u003c/code\u003e. An open change (\u003ca href=\"https://github.com/ethereum/EIPs/pull/12301\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003eUpdate EIP-8141: define MAX_VERIFY_GAS as a shared mempool floor by AnkushinDaniil · Pull Request #12301 · ethereum/EIPs · GitHub\u003c/a\u003e) would make that cap a shared mempool floor, with each node free to run higher, and set its value from measurements. Nethermind’s default node budget is already 300,000 (\u003ca href=\"https://github.com/NethermindEth/nethermind/pull/14992\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003efix(txpool): separate verification floor from node headroom by SIDDHANTCOOKIE · Pull Request #14992 · NethermindEth/nethermind · GitHub\u003c/a\u003e), so a default node admitted our withdrawal; a node at the floor would not. The published measurement note (\u003ca href=\"https://hackmd.io/@0Eo_JbIrQIKnf-o35CQ9EQ/H12MW5GsMg\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003eSizing MAX_VERIFY_GAS: how much unpaid work a node can absorb - HackMD\u003c/a\u003e) measured Nethermind d804d33b on an AMD EPYC 4344P and a GCE c2-standard-8, the two local builder machines. There a 300,000 budget held one attacker peer on Nethermind at 100 failing transactions per second when block building may slow by 25 ms, and at 117 at 50 ms. We re-ran the same suites on current Nethermind master (1f6469e64ee) on one shared 12 vCPU AMD EPYC 9645 host. There a 250,000 budget holds one attacker peer on Nethermind at 25 ms with no margin (100 failing transactions per second, against about 100 that one peer gets processed). A 300,000 budget holds 83 at 25 ms, so it holds one peer only at 50 ms (117). The about 100 per peer comes from Nethermind’s flood controller; other clients bound a peer less. Both comparisons cross machines, so these runs cannot tell whether the change comes from the code or the machine. Our 233,000 fits under both. For a pool to work on every node, either the floor rises from measurement, or proof checks leave the per-node budget, for example through proof aggregation.\u003c/p\u003e\n\u003cp\u003eNew storage is a large part of the cost. In the withdrawal, state gas is 379,440 of 679,322: 195,840 for the two nullifier keys and 183,600 in the claim frame.\u003c/p\u003e\n\u003ch2\u003e\u003ca name=\"p-62963-double-spends-3\" class=\"anchor\" href=\"#p-62963-double-spends-3\" aria-label=\"Heading link\"\u003e\u003c/a\u003eDouble spends\u003c/h2\u003e\n\u003cp\u003eWe sent a second withdrawal with the same nullifier keys and a new body. The node refused it at admission: “keyed nonce sequence not current”. When we forced it into a block through the builder, the block included zero transactions. After the first withdrawal, both nullifier slots in the nonce manager read 1.\u003c/p\u003e\n\u003ch2\u003e\u003ca name=\"p-62963-the-open-question-a-pool-that-only-pays-4\" class=\"anchor\" href=\"#p-62963-the-open-question-a-pool-that-only-pays-4\" aria-label=\"Heading link\"\u003e\u003c/a\u003eThe open question: a pool that only pays\u003c/h2\u003e\n\u003cp\u003eAbove, the call comes from the pool. Often the user wants to act from their own address while the pool pays the gas out of a note.\u003c/p\u003e\n\u003cp\u003eHere EIP-8250 stops helping. It stores each key under (sender, key). With the user as sender, the same nullifier sent from two addresses is two different keys, and the pool gets no spent-once mark from the protocol.\u003c/p\u003e\n\u003cp\u003eThe pool cannot use its own storage instead. Under the EIP-8141 public mempool rules, “\u003ccode\u003eSLOAD\u003c/code\u003e can be used only to access \u003ccode\u003etx.sender\u003c/code\u003e storage”, and here the pool is not the sender. The same rules allow \u003ccode\u003eMAX_PENDING_TXS_USING_NON_CANONICAL_PAYMASTER = 1\u003c/code\u003e pending transaction per non-canonical paymaster, so a pool that only pays serves one user at a time on each node. jstinhw raised the case in the MATCHA thread (\u003ca href=\"https://ethresear.ch/t/25949\" class=\"inline-onebox\"\u003eMempool Account Transaction Capacity from Historical Activity (MATCHA)\u003c/a\u003e): 100 transactions from 100 senders, each with a valid proof for the same note. mmjahanara’s reply in the same thread reaches the same conclusion.\u003c/p\u003e\n\u003cp\u003e\u003cdiv class=\"lightbox-wrapper\"\u003e\u003ca class=\"lightbox\" href=\"https://ethresear.ch/uploads/default/original/3X/a/a/aa740248cc9818d2f158ff0aa1e64c3a78790a8a.png\" data-download-href=\"https://ethresear.ch/uploads/default/aa740248cc9818d2f158ff0aa1e64c3a78790a8a\" title=\"two senders, one nullifier\"\u003e\u003cimg src=\"https://ethresear.ch/uploads/default/optimized/3X/a/a/aa740248cc9818d2f158ff0aa1e64c3a78790a8a_2_690x250.png\" alt=\"two senders, one nullifier\" data-base62-sha1=\"ojTIvNaYzwPgFCNuxZTvIYfIfA6\" width=\"690\" height=\"250\" srcset=\"https://ethresear.ch/uploads/default/optimized/3X/a/a/aa740248cc9818d2f158ff0aa1e64c3a78790a8a_2_690x250.png, https://ethresear.ch/uploads/default/optimized/3X/a/a/aa740248cc9818d2f158ff0aa1e64c3a78790a8a_2_1035x375.png 1.5x, https://ethresear.ch/uploads/default/optimized/3X/a/a/aa740248cc9818d2f158ff0aa1e64c3a78790a8a_2_1380x500.png 2x\" data-dominant-color=\"F6F6F2\"\u003e\u003cdiv class=\"meta\"\u003e\u003csvg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"\u003e\u003cuse href=\"#far-image\"\u003e\u003c/use\u003e\u003c/svg\u003e\u003cspan class=\"filename\"\u003etwo senders, one nullifier\u003c/span\u003e\u003cspan class=\"informations\"\u003e1392×506 49.1 KB\u003c/span\u003e\u003csvg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"\u003e\u003cuse href=\"#discourse-expand\"\u003e\u003c/use\u003e\u003c/svg\u003e\u003c/div\u003e\u003c/a\u003e\u003c/div\u003e\u003c/p\u003e\n\u003cp\u003eWe proposed a spec change for this: let a transaction place its keys under the account that approves payment (\u003ca href=\"https://github.com/ethereum/EIPs/pull/12422\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003eUpdate EIP-8250: let a transaction scope its nonce keys to the payer by AnkushinDaniil · Pull Request #12422 · ethereum/EIPs · GitHub\u003c/a\u003e). nerolation, an author of EIP-8250, answered:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI’m wondering whether improving that app-level nullifier tracking is worth adding a new field and weakening the invariant that all transaction nonces belong to tx.sender. My feeling is no and we may not need the 2d nonces for payers when tx.sender != payer.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eWe closed the PR. The invariant is worth more than one saved transaction.\u003c/p\u003e\n\u003cp\u003eWe also tried this shape on master with the unchanged pool: the user’s account approves execution, and the pool’s VERIFY frame approves payment. The node refused it at admission: “frame transaction validation-prefix simulation failed, validation prefix frame reverted”. The pool’s VERIFY code assumes the pool is the sender, so this refusal says nothing about the spec.\u003c/p\u003e\n\u003cp\u003eSo today two shapes work in the public mempool: the pool is the sender, as measured above, or two transactions, where the user withdraws to an address that then pays for itself. The third shape stays open: a pool that pays for a call from the user’s own address, in one transaction, through the public mempool. We see no way with the current drafts and have no gas number for it.\u003c/p\u003e\n\u003ch2\u003e\u003ca name=\"p-62963-how-to-reproduce-5\" class=\"anchor\" href=\"#p-62963-how-to-reproduce-5\" aria-label=\"Heading link\"\u003e\u003c/a\u003eHow to reproduce\u003c/h2\u003e\n\u003cp\u003eNethermind master 4bcb9e30986a86061fc8b7efe33abeeaa31f745a, one node, EIP-8141, EIP-8250, EIP-8272 and EIP-7906 active from block 1. Genesis holds the EIP-8272 recent-root code and the EIP-8250 nonce manager code. Pool: \u003ca href=\"https://github.com/soispoke/minimal-shielded-pool\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\"\u003eGitHub - soispoke/minimal-shielded-pool · GitHub\u003c/a\u003e at bb45b3b9, with the recent-root contract address and the fee parameter index updated to the current specs. Proofs come from the repository’s own tooling.\u003c/p\u003e","post_number":1,"post_type":1,"posts_count":3,"updated_at":"2026-11-06T13:00:56.101Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"incoming_link_count":47,"reads":10,"readers_count":9,"score":211.6,"yours":false,"topic_id":26223,"topic_slug":"a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet","display_username":"Daniil Ankushin","primary_group_name":null,"flair_name":null,"flair_url":null,"flair_bg_color":null,"flair_color":null,"flair_group_id":null,"badges_granted":[],"version":1,"can_edit":false,"can_delete":false,"can_recover":false,"can_see_hidden_post":false,"can_wiki":false,"link_counts":[{"url":"https://github.com/soispoke/minimal-shielded-pool","internal":false,"reflection":false,"title":"GitHub - soispoke/minimal-shielded-pool · GitHub","clicks":1},{"url":"https://github.com/NethermindEth/nethermind/pull/14992","internal":false,"reflection":false,"clicks":0},{"url":"https://hackmd.io/@0Eo_JbIrQIKnf-o35CQ9EQ/H12MW5GsMg","internal":false,"reflection":false,"title":"Sizing MAX_VERIFY_GAS: how much unpaid work a node can absorb - HackMD","clicks":0},{"url":"https://ethresear.ch/t/mempool-account-transaction-capacity-from-historical-activity-matcha/25949","internal":true,"reflection":false,"title":"Mempool Account Transaction Capacity from Historical Activity (MATCHA)","clicks":0},{"url":"https://github.com/ethereum/EIPs/pull/12422","internal":false,"reflection":false,"title":"Update EIP-8250: let a transaction scope its nonce keys to the payer by AnkushinDaniil · Pull Request #12422 · ethereum/EIPs · GitHub","clicks":0},{"url":"https://github.com/ethereum/EIPs/pull/12301","internal":false,"reflection":false,"title":"Update EIP-8141: define MAX_VERIFY_GAS as a shared mempool floor by AnkushinDaniil · Pull Request #12301 · ethereum/EIPs · GitHub","clicks":0}],"read":true,"user_title":null,"bookmarked":false,"actions_summary":[],"moderator":false,"admin":false,"staff":false,"user_id":11817,"hidden":false,"trust_level":1,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"post_url":"/t/a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet/26223/1","reactions":[],"current_user_reaction":null,"reaction_users_count":0,"current_user_used_main_reaction":false,"can_accept_answer":false,"can_unaccept_answer":false,"accepted_answer":false,"topic_accepted_answer":null,"can_vote":false},{"id":62964,"name":"soispoke","username":"soispoke","avatar_template":"/user_avatar/ethresear.ch/soispoke/{size}/12076_2.png","created_at":"2026-11-06T15:19:36.261Z","cooked":"\u003cp\u003ethanks for the post \u003ca class=\"mention\" href=\"/u/ankushindaniil\"\u003e@AnkushinDaniil\u003c/a\u003e!\u003c/p\u003e\n\u003cp\u003eI agree with everything that’s in the post, but I think my main q is about: “Often the user wants to act from their own address while the pool pays the gas out of a note.”\u003c/p\u003e\n\u003cp\u003eWhat actual use cases would be unlocked by this? Do we have an idea of user flows or concrete examples of how often users would need this level of composability?\u003c/p\u003e","post_number":2,"post_type":1,"posts_count":3,"updated_at":"2026-11-06T15:19:36.261Z","reply_count":1,"reply_to_post_number":null,"quote_count":0,"incoming_link_count":0,"reads":8,"readers_count":7,"score":6.2,"yours":false,"topic_id":26223,"topic_slug":"a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet","display_username":"soispoke","primary_group_name":null,"flair_name":null,"flair_url":null,"flair_bg_color":null,"flair_color":null,"flair_group_id":null,"badges_granted":[],"version":1,"can_edit":false,"can_delete":false,"can_recover":false,"can_see_hidden_post":false,"can_wiki":false,"read":true,"user_title":null,"bookmarked":false,"actions_summary":[],"moderator":false,"admin":false,"staff":false,"user_id":8473,"hidden":false,"trust_level":2,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"post_url":"/t/a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet/26223/2","reactions":[],"current_user_reaction":null,"reaction_users_count":0,"current_user_used_main_reaction":false,"can_accept_answer":false,"can_unaccept_answer":false,"accepted_answer":false,"topic_accepted_answer":null},{"id":62965,"name":"Daniil Ankushin","username":"AnkushinDaniil","avatar_template":"/user_avatar/ethresear.ch/ankushindaniil/{size}/16277_2.png","created_at":"2026-11-06T18:23:35.040Z","cooked":"\u003cp\u003efair q, we didn’t measure how often. the cases i had in mind are ones where the address itself matters: repaying or closing a lending position, claiming a vesting or airdrop, voting with tokens that sit on that address. if that address has no eth, today it has to be funded from somewhere public, which links it to wherever the eth came from.\u003c/p\u003e\n\u003cp\u003efor smart accounts i think the pool-as-sender shape mostly covers it: the pool’s sender frame calls the account, and the account checks the user’s signature and acts as itself. so the gap is narrower than the post says, mostly eoas and accounts without that kind of execute path. though today the proof check alone is over MAX_VERIFY_GAS, so that path only works on nodes that run a higher budget.\u003c/p\u003e\n\u003cp\u003edoes that match what you see from pool users?\u003c/p\u003e","post_number":3,"post_type":1,"posts_count":3,"updated_at":"2026-11-06T18:23:35.040Z","reply_count":0,"reply_to_post_number":2,"quote_count":0,"incoming_link_count":0,"reads":6,"readers_count":5,"score":0.8,"yours":false,"topic_id":26223,"topic_slug":"a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet","display_username":"Daniil Ankushin","primary_group_name":null,"flair_name":null,"flair_url":null,"flair_bg_color":null,"flair_color":null,"flair_group_id":null,"badges_granted":[],"version":1,"can_edit":false,"can_delete":false,"can_recover":false,"can_see_hidden_post":false,"can_wiki":false,"read":true,"user_title":null,"reply_to_user":{"id":8473,"username":"soispoke","name":"soispoke","avatar_template":"/user_avatar/ethresear.ch/soispoke/{size}/12076_2.png"},"bookmarked":false,"actions_summary":[],"moderator":false,"admin":false,"staff":false,"user_id":11817,"hidden":false,"trust_level":1,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"post_url":"/t/a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet/26223/3","reactions":[],"current_user_reaction":null,"reaction_users_count":0,"current_user_used_main_reaction":false,"can_accept_answer":false,"can_unaccept_answer":false,"accepted_answer":false,"topic_accepted_answer":null}],"stream":[62963,62964,62965]},"timeline_lookup":[[1,2]],"suggested_topics":[],"tags":[],"tags_descriptions":{},"fancy_title":"A privacy pool on frame transactions: what works, and the case that does not yet","id":26223,"title":"A privacy pool on frame transactions: what works, and the case that does not yet","posts_count":3,"created_at":"2026-11-06T13:00:55.933Z","views":99,"reply_count":1,"like_count":0,"last_posted_at":"2026-11-06T18:23:35.040Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"a-privacy-pool-on-frame-transactions-what-works-and-the-case-that-does-not-yet","category_id":36,"word_count":1498,"deleted_at":null,"user_id":11817,"featured_link":null,"pinned_globally":false,"pinned_at":null,"pinned_until":null,"image_url":"https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_1024x439.png","slow_mode_seconds":0,"draft":null,"draft_key":"topic_26223","draft_sequence":null,"unpinned":null,"pinned":false,"current_post_number":1,"highest_post_number":3,"deleted_by":null,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":false},{"id":8,"count":0,"hidden":false,"can_act":false},{"id":10,"count":0,"hidden":false,"can_act":false},{"id":7,"count":0,"hidden":false,"can_act":false}],"chunk_size":20,"bookmarked":false,"topic_timer":null,"message_bus_last_id":17,"participant_count":2,"show_read_indicator":false,"thumbnails":[{"max_width":null,"max_height":null,"width":1392,"height":598,"url":"https://ethresear.ch/uploads/default/original/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea.png"},{"max_width":1024,"max_height":1024,"width":1024,"height":439,"url":"https://ethresear.ch/uploads/default/optimized/3X/7/d/7dab7d3493d78fffc199a0541ea712880a29e6ea_2_1024x439.png"}],"slow_mode_enabled_until":null,"valid_reactions":["heart","+1","laughing","open_mouth","clap","confetti_ball","hugs"],"has_accepted_answer":false,"can_create_shared_issue":false,"shared_issue_visible":false,"can_vote":false,"vote_count":0,"user_voted":false,"discourse_zendesk_plugin_zendesk_id":null,"discourse_zendesk_plugin_zendesk_url":"https://your-url.zendesk.com/agent/tickets/","details":{"can_edit":false,"notification_level":1,"participants":[{"id":11817,"username":"AnkushinDaniil","name":"Daniil Ankushin","avatar_template":"/user_avatar/ethresear.ch/ankushindaniil/{size}/16277_2.png","post_count":2,"primary_group_name":null,"flair_name":null,"flair_url":null,"flair_color":null,"flair_bg_color":null,"flair_group_id":null,"trust_level":1},{"id":8473,"username":"soispoke","name":"soispoke","avatar_template":"/user_avatar/ethresear.ch/soispoke/{size}/12076_2.png","post_count":1,"primary_group_name":null,"flair_name":null,"flair_url":null,"flair_color":null,"flair_bg_color":null,"flair_group_id":null,"trust_level":2}],"created_by":{"id":11817,"username":"AnkushinDaniil","name":"Daniil Ankushin","avatar_template":"/user_avatar/ethresear.ch/ankushindaniil/{size}/16277_2.png"},"last_poster":{"id":11817,"username":"AnkushinDaniil","name":"Daniil Ankushin","avatar_template":"/user_avatar/ethresear.ch/ankushindaniil/{size}/16277_2.png"},"links":[{"url":"https://github.com/soispoke/minimal-shielded-pool","title":"GitHub - soispoke/minimal-shielded-pool · GitHub","internal":false,"attachment":false,"reflection":false,"clicks":1,"user_id":11817,"domain":"github.com","root_domain":"github.com"}]},"bookmarks":[]}