Crossing the Chasm with Shielded Actions

Introduction

This is a strategic document written to make the case for shielded actions as a product line we pursue in the short term. The document can be read in three parts. The first is strategic insights. The second is analyzing the business case. The third section contains a minimal MVP specification for shielded swaps. Claude Opus, Gemini and discussions with several Heliax employees helped me refine the proposal in part three though it may still not be ideal – constructive criticisms welcome. (note LLMs are only used where noted specifically, the majority of the writing is just me riffing including the em dashes which I picked up from @cwgoes writing years ago).

In particular I’d appreciate feedback from: @Michael @maurice @mariari @jonathan @cwgoes @thespacecatjr @sugo @ArtemG @vveiln

tl;dr

  • Shielded actions allow us to ship incremental products that maybe popular with public blockchain users, who want privacy where they are. This simplifies liquidity bootstrapping process, something privacy chains failed at.
  • An iterative product approach affords us many learning opportunities and a ton of flexibility.
  • The medium/long-term financial viability of this class of products will depend on how many funds we have locked in Anoma contracts on public blockchains. There is little benefit of privacy provided by this product line without a large anonymity set.

Iterating on Products as a path to Success

There are many different ways to be successful as a startup. One way is to sell products and/or services that solve problems for paying customers. You have to build the thing first. But it is one strategy that works effectively. One strategic implication – you need to determine what problems are worth solving and how to go about building products that solve problems without losing out on monetization potential.

Last week Packy McCormick published an article “Many Small Steps for Robots, One Giant Leap for Mankind” on his not boring blog about Robotics. It’s a fascinating read overall and I recommend it to anyone reading this post. The article was co-written by a guest contributor Evan Beard, who is the co-founder and CEO of a company called Standard Bots. The article explores the future of the robotics industry.

The core thesis of the article is that progress in robotics will come from small steps and not giant leaps. While most venture capital funding will focus on the promise of giant leaps, it is not realistic to expect this approach to work. The reason the author argues is because the bottleneck for the research labs is data, not algorithms.

Therefore, Standard Bots decided to take a pragmatic approach. Rather than stay in the lab and cook the absolutely perfect humanoid that can do everything your heart desires, they sell industrial robotic arms to customers today. They also help with the deployment and maintenance of the robotic arms. Evan Beard claims this allows Standard Bots to achieve more 9s of reliability. The company also chose to vertically integrate their hardware and software stacks, allowing them to build the best product for their customers without unreliable “modular” components. In particular, Standard Bots found that data collection and analysis is far more efficient when it is aligned with the specific hardware and software stacks.

Executing on this strategy has allowed the company to acquire customers, generate substantial revenue, build their brand, and most importantly collect data in real world factory settings which is very difficult to simulate (sounds easy but its not). Over time as customers become ready for more robotics integrations and humanoid-level sophistication, Standard Bots is well positioned to capture additional market share. Crucially, they are continuing R&D work, but now have direct feedback which can inform their explorations and future product cycles. It’s going to be difficult for any of the labs attempting one shot solutions (giant leaps) to compete. By the time these labs are ready to come to market they will have missed the opportunity. Why? Because acquiring customers and building trust with them is not something that can be done overnight. Business still relies on human discretion and making pragmatic decisions which are not always related to “using the most cutting edge technology”.

Simply put, the bet is that Standard Bots can make money, learn how to improve their robotics, collect data and customer feedback, whilst making switching costs incrementally higher for customers with each new added feature. Recall that Amazon started by selling books from a rented house in Seattle. It is true that Bezos did have the vision for the everything store before starting Amazon. His old colleagues at D.E. Shaw even will attest to it. However, it was books where Amazon found product market fit in a nascent e-commerce environment before eventually becoming the logistics powerhouse and web services provider they are today.

The lesson to take from this anecdote is that starting small, vertically integrating, acquiring customers in a niche, and iterating with new product lines and features is a well trodden path towards success. And while we may find ourselves in a position that we did not expect two years ago when we began go to market planning for Anoma, we still have an opportunity to do something remarkable.

I believe that the AnomaPay application provided us with a critical opportunity to begin the process of shipping Anoma. Strategically this allows us to start small in a niche, vertically integrate, acquire customers in a niche, and iterate with new product lines and features.

Note: Crossing the chasm is the process of tech startups going from innovators (private beta users) to early adopters (public beta users) to the early majority (fintech users). In particular the concept comes from Geoffry Moore’s book and focuses on moving from early adopters to early majority from the B2B perspective. This may or may not rhyme with our product offerings we maybe more B2C or B2B2C.

The reason I named the post with this particular title is because I want to emphasize the idea of forward progress and using products to help us progress towards larger Anoma goals over time. This proposal is one of many potential ideas that can help us get there. There maybe better ideas, but I think these are solid. Shielded actions in the context of the Anoma PA for EVM was discussed at the prior HHH. Indeed, I want to see if we still have alignment on this idea and test the idea for robustness and see if this line of products should be something specifically added to the near-term roadmap.

Motivation & Strategic insights

Previously what the crypto industry had thought was that there would be thriving application specific privacy chains. Privacy chains would build architectures similar to the Zcash [Penumbra, Namada, Aleo, Aztec], but enable more types of assets and programability, possibly shipping function privacy. Teams did ship. However, these chains failed to grow a consistent user base, which in turn made economic and social sustainability impossible.

Part of the reason “privacy chains” (I know this is not the best way to categorize but its generally how the crypto community thinks) were unable to attract users in the first place was because of UX friction. For example, in order to interact, users would need to move funds out of existing ecosystems where they held assets (i.e. Ethereum, Solana, Bitcoin) into new ecosystems. Often users would need bridge or first execute a swap by routing via a centralized exchange with multiple front-ends and mobile apps to move assets into these “privacy chains”. The UX friction was a major hurdle. Also many of the privacy chains that have come to market were not part of major ecosystems, they faced a significant distribution challenge – Cosmos was unable to sustain itself.

Note: Some investors have argued that there was a go to market issue including poor token designs. That may also be true in some senses. We would be wise to think about this with respect to AnomaPay and future go to markets.

Eventually it became clear that what users really want is privacy where they’re at – as in, “can I have privacy for my trade using my favorite aggregator 0x, on Ethereum main-net where I keep my ETH?” One of the challenges with delivering this affordance is retro fitting privacy onto existing chains. For a long time the consensus thought was, you leak too much information, the best you can get is delinking assets and wallets but not meta data. Practically speaking much of this type of privacy actually is what users need and want.

If this conjecture is true then, if Tornado Cash exists why doesn’t everyone just use it? Part of the reason that users and developers have been reticent to use and build these types of offerings is because of the tornado cash sanctions in August 2022 and arrests of Roman Storm and Alexey Pertsev. From this point on most of the crypto community decided not to work on privacy projects on transparent EVM chains because of legal risks (The Namada bridge may or may not have been deprecated Ethereum bridge for reasons). Users faced risks like being booted from centralized exchanges for having interacted with the sanctioned contracts (Binance and OKX did this even retroactively).

But now as the regulatory landscape shifts you’ve also seen a new consensus bet on privacy in the industry, especially as projects begin to court institutional capital/clients. Privacy is now understood as a necessity. It’s no longer a nice thing to have. Today, public blockchains are twitter for your bank account – that’s simply untenable. The other thing we know now is that users generally want privacy where they’re at. More accurately we know users do not want to bridge their fund to a new chain to get privacy, they just use a centralized exchange for that, which is much worse.Users want to use the same apps they already use, just with added privacy. Retrofitting these chains with privacy is possible. However, getting the full programability aspect of privacy on the EVM or SVM is a little bit trickier.

I think we have an opportunity to eventually get there by iterating on our early products. Shielded actions provides us with an iterative path towards this vision i.e. re-writing existing apps on the RM for better privacy gaurantees and taking full advantage of the RM including the controllers stack. But more importantly, shielded actions allows us if successful to make money while learning things about ourselves, our technology, and future customers.

Shielded actions allow us to iterate and Learn

AnomaPay enables users to shield ERC20 tokens and transfer them to other Anoma accounts enabling shielded transfers. AnomaPay is built on top of the Anoma Protocol Adaptor that was designed for the Ethereum Virtual Machine. Currently the product is in private beta on Base. We have a variety of exciting features on the roadmap potentially including MASP, local proving, name registry service, faster proving, deposits, and other stuff between v1 and v2.

One nice thing about the protocol adaptor is that it can “settle” any Anoma formatted transaction. In principle this means developers can re-write existing applications and net new applications on the resource machine. While this may be ideal, we still don’t have a development stack for this. Hence, it may take developers some time to reason about the Resource Machine, as it provides an alternative state architecture to that of the EVM. Writing RM applications is not the same as writing them directly for the EVM. As such, the organization made a conscious decision to focus on a vertically integrated product (modulo Risc0 verifier) instead.

If we want to expand the features of AnomaPay to do more than shielded transfers we can do two things. Ideally we could re-write existing applications for swaps, prediction markets, borrowing and lending, and perpetuals on top of the PA. One challenge here is that we still need intents and solving if we want to do this properly. Also, because the PA requires shielded transactions, proving overhead for many of the applications may produce undesirable latency for end users. For example if it takes 60 seconds to execute a swap due to counterparty discovery and proof generation time it may be difficult to convince a user to use this feature. Even if we could magically convince this user to enjoy this high-latency-shielded-experience, we’d need to bootstrap liquidity for each of these products. Meaning there would need to be a considerable amount of tokens held in Forwarder contracts to make trading worthwhile - this would be much more than needed for shielded actions to be successful. Not to mention we still need to figure out the intents and solving part. (we have plenty of ideas but nothing that has materialized in anything close to a production ready implementation that I am aware of).

Is there another way to offer these types of features to end users? After-all, one of the advantages of deploying the protocol adaptor on EVM chains is that there is existing users and liquidity there. Before we launched the protocol adaptor, some members of the Heliax team worked on a blockchain project called Namada. One feature we spec’d and began to implement was “shielded actions”. This would allow users from Namada to unshield their balances to a fresh address, swap on osmosis or another ibc compatible chain, then move funds back to namada’s MASP. From the users perspective, this would be one programmable action.

One reason this was not successful was due to the death of the Cosmos ecosystem, lack of user interest, and liquidity. Ethereum and Solana do not have these issues (crypto could die yes that is possible, but assuming it doesn’t these two ecosystems should survive). In particular we could construct a type of shielded action with the Anoma protocol adaptor, forwarder contracts, and transaction service. One reason to take this approach is that we would be allowing users to park their funds “in Anoma” and then execute actions on the EVM whilst keeping their account balances private. There are some privacy trade-offs, like the tx service can see user addresses and could store a history of transactions for all user accounts making tx requests if it needed or desired.

However this is a nice point on the trade-off spectrum between no privacy, full privacy and pragmatic privacy. The other nice thing about this approach is it allows us to offer new products to AnomaPay users, engage in business partnerships with existing DeFi projects, gain more EVM users in general, and begin to monetize our product stack. Users will pay for shielded actions, they already do with products like Railgun and Privacy Cash today. Though, questions remain;

  • What is the size of the market comparative to the rest of DeFi?
  • How long will it take to monetize?
  • How much are users willing to pay?

The Market Opportunity

  • There are about $100B locked in DeFi across the top 59 chains in a data set I used for part of this analysis. Of those 59 chains there is about $14B of daily DEX volume.

The top DefI categories that users care about across Solana and EVM chains are

Stable coin issuance, perps trading, launch pads, and dexes tend to be the most profitable according to DeFiLlama.

Note here that revenue does not equal total fees. Also if you look into many of these protocols and try to do your own calculations you’ll find that there isn’t a standard language for comparing each category or even projects within the same category.

More importantly if we zoom into each chain you can clearly see which apps users care about, which is likely more important than making a broad bet on one category based on market penetration. Below let’s look at Ethereum main-net, Arbitrum, Base, and Solana.

As a fun aside I spent a couple days working with Claude trying to build my own comprehensive dashboard. It was an arduous process which required painful review each time. Ultimately I decided to scrap it and use DeFi Llama even if I disagree with some of their methods of categorization and formulas.

Ethereum Main-net

Below applications are ordered by annual fees generated.

  • Lido (liquid staking), Aave (lending), Sky (lending), Etherfi (Liquid staking, consumer payments), Uniswap (DEX), Morpho (Lending), and Ondo (RWA) dominate.
    • Flashbots does not actually make money this way. DeFi Llama is simply tracking payments paid to all block proposers through MEV-Boost (which is not accurate).
  • What you can see overall is that Ethereum main-net users like staking ETH, receiving yield on their ETH, lending out stable coins, borrowing stable coins, looping their staked ETH and executing swaps.

Arbitrum

  • The top five applications by fees include Uniswap, a DEX, clearly with the most fees, followed by GMX which is a derivatives exchange (perps trading), Sushi another DEX and Ostium another derivatives trading platform.
  • Aave is the only application in the top 5 that is not a trading venue.

Base

  • Base has a different composition of applications but with a similar story. Uniswap and Aerodrome dominate in terms of fees followed by Morpho a Lending/vault application.
  • Base has historically focused on onboarding creators and builders with out there ideas, including their prolonged content coin initiative. However recently they have pivoted away from creator/content coins to being DeFi focused.

Solana

  • One interesting thing to note about successful Solana applications. They generally are only deployed on Solana.
  • Even the 10th ranked fee capturing application on Solana rakes in more fees monthly than the # 1application on Arbitrum and would sit 3rd on Base.
  • Note the top apps are all trading focused with the exception of Jito (MEV infra)

Indeed, Part of the reason for this is that Solana has consistently higher DEX volume per 24hrs than Ethereum or its rollups. Their architecture was optimized specifically for high throughput and low latency trading. In addition, over the last 2-3 years Solana has established itself as the premier place to speculate on meme coins. Beyond this they already have tokenized equities, wrapped assets, and natively issued stable coins.

  • Ignoring the other metrics and simply looking at DEX vol per 24 hours you can see that Solana does significantly more volume than its competitors

  • Solana also has a higher stable coin turnover ratio [Dex volume/stablecoin marketcap] than Ethereum or any EVM forks. This indicates more active trading per dollar of stable coin.

Now that we’ve looked at some data of the top fee generating apps of the top public blockchains let’s attempt to understand how quickly these apps achieved meaningful revenue. This should help us set expectations and understand how easy or difficult the task of generating-meaningful-revenue actually is.

How long until we reach revenue Milestones

Doing some historical analysis I looked at how long leading-public-blockchain-applications, including in the privacy space, took to reach milestones $10k in revenue per day and $500K in revenue per month, sprinkling in current monthly revenue. For revenue just think fees users pay. Each protocol accounts for this slightly differently and has their own unique distribution/fee capture mechanism (and expenses ofc). The full dashboard used in this analysis can be viewed here.

  • Most applications (these are the winners not the losers) achieved $10k in daily revenue fairly quickly i.e. in the first thirty days
  • It took 2-3 quarters for most applications to achieve $500k per month revenue.
  • Privacy projects have moved much slower on this front ~ 2 years

It is important we have specific fee capture/revenue milestones that are measurable. Without setting clear goals here it will be difficult to measure and track success.It is relatively clear is that adding swap functionality is probably the most important feature to start with. There might be other low hanging fruit like working shielded liquid staking for example.

One question we do want to consider – what is our take rate, where, when, and how will we take it. For example we could do a few things.

  • charge a fee for every time the tx service is used. what’s nice about this is that there is a clear value proposition and link between a service and a fee paid for this service. Once we have client side proving enabled its possible users will not want to use this service and we may deprecate it. Or we may find it provides a better UX for shielded actions and keep it running
  • charge a fee every time a user deposits funds into an “Anoma contract”. This is clean and simple which is pay to play. Users will understand this model. You want privacy and access to depositing into a shielded pool? pay x fee.
  • charge users everytime they exit an “Anoma contract”. the nice thing about this approach is that there is a soft incentive not to withdraw funds from the shielded pool unless necessary.
  • charge users only for shielded actions. Its a custom feature we provide that not many others do and as such users would likely be willing to pay for this.
  • some combination of these things like charging a fee for swaps and for deposits or withdrawals. Alternatively charging no fee for swaps, but for deposits and withdraws.
  • Would users be willing to pay a subscription service? nice thing about this is its a fixed cost for them and we take on the variable pricing risk. I’m not sure this will work without heavy reliance on the tx service as in users don’t want client side proofs for reasons or maybe for shielded actions its easier for the tx service to do the proof generation.

Note that regardless of which fee model we eventually choose we need to think carefully about the incentives.

  • Is there a way to use XAN to incentivize deposits?
  • Are we willing to subsidize user transactions up to a certain $ amount or number of transactions.
  • Do we allow users who lock XAN for a specified amount of time to get a discount on transactions as we will subsidize some by way of refund post execution?

Again there are many options to consider here, and I hope this brief exploration on incentives and fee mechanisms can unlock more robust and transparent discussions around this topic. One question we did not answer yet is how much are users willing to pay for privacy.

How Much are users willing to pay for Privacy?

Note: Gemini helped me research and write this section

The answer is whatever we can convince them to pay. But beyond this tongue and cheek if we want to make a reasonable assessment let’s look at the handful of existing models today.

Fee Mechanisms

The shielding fee mechanism varies by protocol. They generally fall into two distinct categories:

  • Volume-Based Fee (% of Amount): You pay a percentage of the total crypto you are moving (like a tax).
  • Service-Based Fee (Gas + Markup): You pay for the computational work, regardless of how much money you are moving (like a postage stamp).

Railgun

  • Fee Mechanism: 0.25% on the Total Amount (Volume-Based) on entry/exit + optional “broadcaster fee” if not self-broadcasting (works similar to TC/PP)
  • Applies to: Both shielding (depositing) and unshielding (withdrawing).
  • Breakdown:
    • If you shield 100,000 USDC, the protocol takes 250 USDC as a fee.
    • If you shield 10 USDC, the protocol takes 0.025 USDC.
  • Where the Money Flows: This 0.25% goes to the Railgun DAO Treasury. It is eventually distributed to users who stake the RAIL token (Active Governors) as a reward for governing the protocol.
  • Note: You may also pay a separate “Relayer Fee” (gas markup) if you use a relayer to execute the transaction for you, but the 0.25% is hard-coded into the protocol itself.

The smart contracts take a 0.25% deduction per shield and unshield interaction which is then sent to the “treasury address”. Protocol deductions are distributed to RAILGUN decentralized governance participants over time to RAIL stakers in the form of Active Governor Allocation.

To use RAILGUN, users can supply a Broadcaster to facilitate their interactions (users can self-relay interactions if they want to save on gas). Broadcasters require a % premium of the overall gas price for the interaction, but not for the interaction amount. Thus, Broadcaster Premiums do not increase with interaction size.

  • Railgun docs

Tornado Cash (Classic)

  • Fee Mechanism: Gas + Relayer Markup (Service-Based)
  • Applies to: Withdrawing (Unshielding).
  • Breakdown:
    • The protocol itself charges 0% on your deposit amount.
    • However, to break the link between your wallets, you typically use a relayer. The Relayer pays the gas fee for you and charges you that cost back plus a profit margin (roughly ~ 10-20% of the gas cost).
    • Whether you withdraw 1 ETH or 100 ETH, the fee is roughly the same (e.g., $50 worth of ETH for gas/service), making it very expensive for small amounts but very cheap (percentage-wise) for whales.
  • Where the Money Flows: The entire fee goes to the relayer (the independent node operator). The Tornado Cash protocol/treasury receives nothing from individual transactions.

Therefore, relayers act as third parties and manage the entire withdrawal. They pay for transaction fees by deducting them directly from the transferred amount. They also charge an additional fee for their services.

Since the implementation of the Relayer Registry proposal, the protocol collects a fee directly from the relayer’s staked balance through the StakingReward contract for each withdrawal. This fee percentage may vary from one pool to another and is also subject to change through on-chain governance.

  • Tornado Cash docs

Privacy Pools

  • Fee Mechanism: Gas + Relayer Markup (Service-Based)
  • Applies to: Withdrawals
  • Breakdown:
    • Similar to Tornado Cash, the smart contract currently takes 0% of the principal.
    • Users pay a Relayer to process the “proof of innocence” (exclusion proof) and the transaction

Privacy Pools docs

Privacy Cash (Solana)

  • Fee Mechanism: 0.35% on the Total Amount (volume-based)
  • Applies to: withdrawals and swaps.
  • Breakdown:
    • The protocol charges a flat 0.35% on the volume plus a small fixed fee (e.g., ~0.006 SOL).
    • If you withdraw $1,000 worth of SOL, the fee is roughly $3.50.
  • Where the Money Flows: This flows to the project’s treasury as revenue. Since Solana gas fees are negligible (fractions of a cent), this fee is purely a revenue model for the service provider.
// Withdrawing 1 SOL
const withdrawAmount = 1_000_000_000 // 1 SOL in lamports

// Fee calculation:
// Base: 0.006 SOL = 6,000,000 lamports
// Protocol: 1 SOL × 0.35% = 0.0035 SOL = 3,500,000 lamports
// Total fee: ~9,500,000 lamports (~0.0095 SOL)

const result = await client.withdraw({
  lamports: withdrawAmount,
  recipientAddress: 'RECIPIENT'
})

console.log('Requested:', withdrawAmount / 1e9, 'SOL')
console.log('Received:', result.amount_in_lamports / 1e9, 'SOL')
console.log('Fee:', result.fee_in_lamports / 1e9, 'SOL')

swap fee

Private swaps will increase your anonymity, because it makes it harder for observers to do amount based analysis (you can partially swap your SOL deposits into USDC).

Swap Fees: 0.008 SOL (or equivalent for SPL) + 0.35% of swap amount + Jupiter fees

  • Privacy Cash docs

Penumbra (long live Penumbra)

  • Fee Mechanism: Network Gas Only (Service-Based)
  • Applies to: All transactions.
  • Breakdown:
    • There is no “privacy tax” or percentage fee on the amount shielded.
    • You only pay the standard network fee to validators to process the block. Because Penumbra is its own blockchain (Layer 1) rather than a dApp on Ethereum, these fees are typically very low.
  • Where the Money Flows: Fees go to validators and the community pool.
    • Hidden Cost: Penumbra uses an “opportunity cost” model. Unshielded/unbonded tokens do not earn staking rewards, effectively “taxing” you via inflation if you hold idle funds for too long without staking them.

There are three fee tiers for sending transactions. You should select the tier that describes how quickly you need the transaction to be included in a block.

Fees can be paid using the UM staking token, or alternative fee tokens such as OSMO. Since transaction fees are public, using the UM staking token for fees provides the strongest privacy guarantees, as it helps transactions blend in with other Penumbra users. Using other assets for fees may make transactions more distinguishable.

  • Penumbra docs

Here is a summary of the above information for a quick recap:

Protocol Fee Type Fee Base Best For…
Railgun % Tax 0.25% of amount (entry & exit tax) Users who want convenience on EVM chains; less efficient for massive whales due to % scaling.
Tornado Cash & Privacy Pools Gas Markup ~Flat fee Whales. Moving $1M costs the same gas as moving $100.
Privacy Cash % Tax 0.35% of amount (exit tax + swap fee) Solana users needing a specific dApp service; cost scales with volume.
Penumbra Network Fee Gas fee only High-frequency users who want privacy as a default state, not a paid service.

Do we want to subsidize users, enter a price war, or match what our potential competitors are doing for a time? As you can see there are several approaches to choose from. I’m not sure what the best model for our products are and would appreciate input from @maurice. However I do like Privacy Cash’s strategy.

Okay, now that we’ve discussed motivations, strategic insights, and engaged in some market analysis its time to look at a potential proposal from shielded swaps on EVM chains.

Shielded Actions - Swaps (Proposed technical Architecture)

Note: I’ve had many conversations with LLMs about this topic (Gemini and Claude) as well as @ArtemG, @jonathan & @maurice. This architecture maybe completely wrong or unworkable. However, given we have no specific proposals this seems like a reasonable place to start.

Shielded actions are shielded DeFi operations that allow users to interact with onchain smart contracts deployed to the EVM while keeping their transaction graph, balances, and activity patterns private.

  • The core constraint: ZK proofs require knowing output values at proof generation time, but swap outputs are determined at execution time. You cannot create a resource for an amount you don’t know.
  • Potential solution: Create a resource for the minimum amount in Tx 1 (known at proof time). The SwapForwarder captures any surplus, which is claimed in Tx 2 minus a protocol fee.

The transaction service is a UX optimization, not an architectural requirement. Users can generate proofs locally and submit transactions directly.

Architecture

The system has three layers:

  • Protocol Adapter: Deployed on Base. Verifies ZK proofs, manages the commitment tree and nullifier set, and orchestrates forwarder calls. The PA is the entry point for all shielded transactions.
  • ERC20Forwarder: One forwarder for ERC-20 tokens (USDC, USDT, WETH, etc.). This is the canonical custody layer. The contract holds the actual tokens that back shielded resources. When a user wraps tokens, they go into the ERC20Forwarder. When they unwrap, tokens come out of it.
  • SwapForwarder: Executes swaps against external DEXs (Uniswap, Aerodrome). It pulls tokens from the ERC20Forwarder, swaps via DEX, and pushes the output back to the ERC20Forwarder. It holds surplus temporarily until claimed.
Component Responsibility
Protocol Adapter Verify proofs, manage commitments/nullifiers, orchestrate forwarder calls
ERC20Forwarder Hold all ERC-20 tokens. Canonical custody layer.
SwapForwarder Execute swaps, route tokens, hold surplus temporarily

Transaction Flow

Transaction 1: Swap and Create Minimum Resource

  • The user submits a proof to the PA. The proof commits to consuming a 1000 USDC resource and creating a 995 USDT resource (the minimum acceptable output given their slippage tolerance).
  • The PA verifies the proof and publishes the nullifier, marking the USDC resource as spent. Then the PA calls the SwapForwarder.
  • The SwapForwarder pulls 1000 USDC from the ERC20Forwarder, executes the swap on Uniswap, and receives 1002 USDT back. It sends 995 USDT (the minimum) to the ERC20Forwarder and stores the 7 USDT surplus under an escrow key.
  • The PA creates a commitment for the new 995 USDT resource. The user now has usable shielded funds immediately.

Transaction 2: Claim Surplus

  • The user submits a second proof to claim their surplus. The proof commits to creating a 6.65 USDT resource (surplus minus 5% [hypothetical for this example] fee).
  • The PA verifies the proof and calls the SwapForwarder. The SwapForwarder sends 0.35 USDT to the “Anoma treasury” (some account we control) and 6.65 USDT to the ERC20Forwarder. The PA creates a commitment for the new 6.65 USDT resource.

Result: The user has two separate resources (995 + 6.65 USDT) backed by tokens in the ERC20Forwarder. Resources are immutable; users can merge them later if desired.

Authorization Model

The proof is the authorization. No additional signatures required.

The trust chain works as follows: The user proves ownership of the resource via their nullifier key. The PA verifies this proof and publishes the nullifier. The PA then calls the SwapForwarder. The SwapForwarder calls the ERC20Forwarder to pull tokens. The ERC20Forwarder checks that the caller is a PA-registered forwarder, and allows the transfer.


// ERC20Forwarder

function pullFrom(address token, uint128 amount, address to) external {

require(protocolAdapter.isRegisteredForwarder(msg.sender), "unauthorized");

IERC20(token).safeTransfer(to, amount);

}

Forwarders trust each other via PA registration. The PA only calls forwarders when a valid proof has been verified. Thus, a forwarder call implies user authorization.

Key Properties

Property Value
Transactions required 2
Usable funds after Tx 1 Minimum amount (immediate)
Tx 2 urgency Non-urgent / batchable
User signatures 1 (Permit2 for initial wrap)
Time to usable funds ~2s on Base
Token custody ERC20Forwarder

Privacy Model

Aspect Private?
User identity
Transaction graph
Resource balances
That a swap occurred
Swap amounts

An observer sees “someone swapped 1000 USDC for 1002 USDT” but cannot determine who or link it to other activity, beyond that the funds came from an Anoma forwarder contract.

Open Questions

  1. Surplus key derivation — How to attribute surplus to correct user without linking Tx 1 and Tx 2?
  2. Fee collection — Where does treasury fee accumulate? SwapForwarder? Separate contract?
  3. Dust threshold — Below what surplus amount should we skip Tx 2 entirely?

Again, this architecture could be incorrect and not exactly what we want. However, I think its worth getting the ball rolling on this idea by sharing it with others.

High-level Takeaways

  • Giving users privacy where they are at and solving the problem of retro-fitting privacy for popular public blockchains is a worthy goal. Shielded actions progresses us towards solving that problem whilst letting us build a brand reputation, acquire customers, refine our distribution and communication strategies all while iterating on the product in real time.
  • Solana applications benefit from the higher asset turnover than Ethereum and L2s measured by DEX volume per 24hrs. Also note that transaction inclusion is often cheaper on Solana than EVM domains. This may not apply to our applications but it is worth considering this point.
    • Both Ethereum main-net and Solana look promising for future deployments based solely off volumes.
  • Ultimately, the success of the product(s) will depend on how much value at rest we can keep in our system (contracts). If there is no value at rest measured by TVL in the “Anoma contracts”, then users will not benefit much from shielded swaps or any other functionality.

Additional Open questions and areas of exploration

  • Alternative architectures
  • Business integration options
    • integrate into AnomaPortal
    • business partnership including technical integration
    • widget integration, stable API for anyone i.e. wallets, CEX, bridges.

The End: Thanks for reading, cheers.
:high_voltage: :fight_cloud:

3 Likes

In terms of specific product deployment I think there are three options but perhaps more we could pursue with this strategy.

  • as part of a B2B offering (Solana post forthcoming will link here), it is possible swaps is a feature these specific customers may want as their use case focuses on (i) salary payments, (ii) hackathon payouts, and (iii) writing investment checks on chain. a hypothetical customer who may want to store their USDC and SOL in the yet to be deployed Solana forwarder contracts will likely want to execute “shielded swaps” from time to time. This can also apply to businesses operating on EVM chains.
  • added functionality to AnomaPay building towards the super app. the post already outlines this approach and even specifically discusses it as its core thesis without saying “super app” explicitly. regardless I think the understanding here is clear. the deployment would likely be B2C or B2B2C in this scenario. Both can be argued as higher degrees of difficulty than B2B. One thing to note is Solana has the edge on trading volume but Ethereum main-net has the edge on lending/borrowing volume (as seen in the post above). My specific recommendation would be to figure out how to integrate with an aggregator like 0x or CowSwap on Ethereum, Jupiter on Solana, which would ensure users get the best price rather than integrating with a particular DEX as in Uniswap V4 directly.
  • another idea which I began to consider recently was that we could write our own EVM solidity application with the intent of making it “shielded”. As in we could do something like create a crowd funding application i.e. Public Signal, and then integrate it into the Anoma Portal or AnomaPay dashboard as “shielded crowd funding”. We could even create our own DEX or vault protocol doing exactly this as well. while this would be a different line of business/products in a sense it would be a clear vertical integration play.

This is broadly being implemented in the AnomaSwaps demo. We are side-stepping the problem of surplus but essentially just giving a fixed rate to the end-user. Anything above that fixed rate due to market movements just because a fee for us.

1 Like

AnomaSwap as initially designed in the Demo is a completely different product than shielded actions. I know the team has since considered shielded actions designs, but they were born out of two separate schools of thought.

We are side-stepping the problem of surplus but essentially just giving a fixed rate to the end-user.

that sounds like a suboptimal UX that will not be competitive in the long-run.

That may be true (with regards to the different schools of thought). The current AnomaSwap implementation is based on this post though.

Potentially I agree that this isn’t competitive in the long-run (almost certainly actually), but for the short-run it’s sufficient, especially if we can try it very quickly now. Also I do wonder how much normal users care about fees, given that the default Coinbase/Kraken/Binance UI (the one in the app and not the pro version) just defaults to something like 3%. It’s clear that DEX powerusers care about fees but it’s far from clear that normies care about them at all.

Just in case I wanted to mention that it is not the only way we can deal with fees in the AnomaSwap. We discussed this with @graphomath but generally there is nothing stopping us from implementing a design in which e.g. we get only a part of the suprlus or even none (i.e. user gets all of it)[1] just in several EVM txs instead of one, but still possibly private.


  1. currently actually this is what the code practically does as the surplus is just left at the hotwallet ↩︎

1 Like

https://www.kraken.com/features/fee-schedule

The most i can find is that kraken is 1% without pro, not 3%, but there is a heavy convenience of being the place where you first offramp real USD into USD you don’t have. You have a lot more guys to compete with and it depends on the specific niche and market where you want to sell this to.

I believe the implementation team found out about this post after the fact, so I don’t believe this is accurate.

I am very surprised to read this. What makes you believe so?

From what I understood, the initial implementation came at the problem from a different approach, and only recently (read 2 weeks) you guys were introduced to this post more formally.

Didn’t actually think you guys have started on this path yet, great if so. Is there anywhere I can read about the latest developments? I’ve watched the video you made but the bi-weekly update didn’t come in due to the meeting being cancelled this week

Thanks a lot Artem for giving such a clear and succinct picture. Indeed, right now, the user that is creating the fresh EOA can do whatever they want with the remaining output from the DEX. For reasons of privacy, it makes sense to have a second transaction issued by heliax/the bundler[1], which deals with the remainder, potentially at a point in time that is chosen by the user (by means of calling finalizeSwap—a function that we could add to the contract). For the user nothing needs to change (although they may be given the option to choose the timing of the finalizeSwap call and they may also provide an additional nullifier key commitment for the remainder). In any case,

TL;DR all matters of fees can be handled by the finalizeSwap function/call.

Now, we come to the main point :sparkles: if we can provide a stellar price, the user may be willing to let us take 50% of the surplus, if what they get is much better than everything else on the market. @maurice has pointed me to tycho and we could use that to get a good price. Having a fixed DEX hardcoded was just to have a PoC out early: shielded swap is possible.


  1. (even if in the current design relayer would be the better word—see also this issue) ↩︎

That’s an excellent question. There is the hole glory of mess in this repository; draft PR1 gives a good picture of that point in time, in particular Artem’s comments. If you feel like playing around, you could probably in no time come up with a better TUI mimicking the railgun wallet, which I clauded together as the frontend debugging was not finished yet on Monday. However, technicalities aside, IMHO, the main point is really getting agreement on the product we want to build and what the value proposition for the user is.

TL;DR: right now, here is a good entry point.

1 Like

AUSRET: atomic unshield-swap-rewrap ethereum transactions

The main idea of the shielded swap can be reduced to the following three items:

  1. unshield/unwrap;
  2. swap;
  3. shield/wrap.

I can recommend @apriori’s post on shielded actions for more context; in particular, the following two paragraphs shall serve as comparison point.

  • The user submits a proof to the PA. The proof commits to consuming a 1000 USDC resource and creating a 995 USDT resource (the minimum acceptable output given their slippage tolerance).
  • The PA verifies the proof and publishes the nullifier, marking the USDC resource as spent. Then the PA calls the SwapForwarder.
  • The SwapForwarder pulls 1000 USDC from the ERC20Forwarder, executes the swap on Uniswap, and receives 1002 USDT back. It sends 995 USDT (the minimum) to the ERC20Forwarder and stores the 7 USDT surplus under an escrow key.
  • The PA creates a commitment for the new 995 USDT resource. The user now has usable shielded funds immediately.
  • The user submits a second proof to claim their surplus. The proof commits to creating a 6.65 USDT resource (surplus minus 5% [hypothetical for this example] fee).
  • The PA verifies the proof and calls the SwapForwarder. The SwapForwarder sends 0.35 USDT to the “Anoma treasury” (some account we control) and 6.65 USDT to the ERC20Forwarder. The PA creates a commitment for the new 6.65 USDT resource.

This post is the verbose answer to @cwgoes’s question:

If I want to swap A for B, can’t I just unshield my A-resource [e.g., 10 wrapped USDC], withdraw the corresponding ERC20 from the forwarder contract, execute a swap (we could use a “SwapForwarder” contract to abstract this, perhaps), and deposit + shield again (all in one tx)?[1]

The short (approximate) answer is yes, if we accept that we’re faking the swap with a limit order. The main design decision concerns the atomicity of the Ethereum transaction that performs the unwrapping, swapping, and reshielding atomically. I want to keep this post short. However, let us discuss requirements and design decisions, before we come to a the TL;DR of the current simple design.

Requirements

One point that I have added to the list is simplicity. Another one is that the user is not required to ever submit ethereum transactions.[2] Now, here is the list, with lower priority items on the bottom.

  • a single user interaction for issuing the request for a shielded swap limit order
  • no funds at risk
  • minimal trust in Heliax
  • no direct interaction with Ethereum
    • no need to hold ether
    • no need to submit Ethereum transactions
  • simple
  • fast settlement
  • "OK price"

The last requirement can be phrased more precisely as the following requirement:

ratio of output relative to quote99.x% on average ("OK price")[3]

If you wonder where the quote comes from and why there is an RFQ phase, please read on.

Design decisions

There are two major design decisions, namely atomicity and replacing the post-swap surplus settlement phase with a pre-swap RFQ phase—essentially guessing the surplus in advance.[4] However, the first design decision is whether we want to perform an atomic unwrap-swap-rewrap ethereum transaction (AUSRET).[5]

Atomicity: on chain via EIP-7702

There are probably several ways to achieve atomicity. One of them is EIP-7702. It may even be a natural choice, given that CoW DAO writes that one of

the most practical benefits of EIP-7702 is transaction bundling.

It turns out that they even follow up with a use case that the shielded swap expands upon.

Consider a user who wants to approve a token spending limit and then immediately use those tokens in a decentralized exchange swap. Traditionally, this requires two separate transactions, each paying gas fees and waiting for confirmation.

With EIP-7702, the user can authorize their EOA to use a batching contract, then execute both the approval and swap in a single transaction. This reduces gas costs, eliminates the need for multiple confirmations, and provides a smoother user experience.

Now, we only add the rewrap into the shielded pool and we are essentially done.[6]

Interestingly, the design decision for atomicity via EIP-7702 provides the base for some of the requirements, namely

  • atomicity of the shielded limit order
  • no need to hold ether.

How to handle the surplus

Surplus settlement was a separate phase in @apriori’s write up. Some time ago, Artem pointed out that—at that point in time—the owner of the EOA could just take all the funds. Moreover, earlier this week, Chris pointed out the funds at risk. That was the last bit of the contract that needed refinement. The current design still has two phases:

  1. pre-swap RFQ
  2. shielded limit order.

The historic trigger for this change of the design were the additional complications, in particular, the post-swap signature of the EOA (see here for more details). Thus, instead, we guess the fees in advance and adjust the quote; then the user has the option to take it. This may even be advertised as putting users in the driver’s seat.[7]

Current Design / RFC

In one phrase, in the current design, we provide the user with a quote that 1. likely will still be executable after proof generation and 2. has the fees factored in.[8]

We assume the user to hold wrapped ERC20 tokens in the shielded pool, corresponding to commitments in the Merkle tree of the protocol adapter. Thus, users are expected to produce authorization signatures for spending resources (or have them prefabricated), e.g., the setup of AnomaPay. Moreover, on the user end, as part of the swap request, nullifier keys must be stored (and generated) whose commitments will be used for the resources that will be created when wrapping the output tokens. There will be an ephemeral ethereum throwaway key, but it will be very short lived. In fact, it can be thrown away even before the swap request is sent off![9]

The following message sequence diagram illustrates the flow.

sequenceDiagram
    participant User
    participant Bundler
    participant Ethereum

    User->>Bundler: 1. Request quote (token, quantity)
    Bundler-->>User: 2. Quote (price incl. fees)
    User->>Bundler: 3. Swap request (or request new quote)
    Bundler->>Ethereum: 4. Submit AUSRET (unwrap → swap → rewrap)
    Ethereum-->>Bundler: tx confirmation

Single user interaction

The user goes through the following steps within seconds.

  1. The user chooses to swap some wrapped ERC20, e.g. 10 USDC.
  2. They will choose the output ERC20 token, e.g., USDT.
  3. They will request a quote.
  4. The user sends off a swap request.

This should be simple enough.[10] The most important action is the last one. A power user could provide their own price, leaving the bundler to refuse the request.

No funds at risk

The AUSRET goes through or not. If it does, the specified minimal amount goes directly back into the shielded pool; otherwise, there are never any funds outside of the shielded pool. If there is leftover surplus, either the user has to entrust us with it or it will be at risk. So, we simply take it out of the throwaway EOA that is used to make sure that nobody has to put too much trust into us.

Minimal trust in Heliax

We are using the same proving service as for AnomaPay. That could be put into a TEE for good measure. The one thing that we could be tempted to do is to give tempting RFQs such that we expect the price to move favorably in the next seconds. Given that the swaps are in the open, we are at least accountable.

No direct interaction with Ethereum

The only datum that is connected to ethereum is the key of the throwaway EOA. It does not even need to leave the front-end. Gas fees are paid by the bundler, which also submits the ethereum transaction.

Simplicity

The main argument for simplicity is the code for the swap delegate contract. The only non-trivial part concerns the signature function; however, we simply can re-use ecrecover from openzeppelin.

ShieldedSwapDelegate.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {IERC20} from "@openzeppelin-contracts-5.5.0/token/ERC20/IERC20.sol";
import {IERC1271} from "@openzeppelin-contracts-5.5.0/interfaces/IERC1271.sol";
import {ECDSA} from "@openzeppelin-contracts-5.5.0/utils/cryptography/ECDSA.sol";
import {IProtocolAdapter} from "pa-evm/interfaces/IProtocolAdapter.sol";
import {Transaction} from "pa-evm/Types.sol";

/// @title ShieldedSwapDelegate
/// @notice EIP-7702 delegation target for throwaway EOAs. Orchestrates
///         unwrap → DEX swap → wrap in a single atomic transaction.
contract ShieldedSwapDelegate is IERC1271 {
    /// @notice Canonical Permit2 deployment address (same on all EVM chains).
    address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    address public immutable PROTOCOL_ADAPTER;
    address public immutable DEX_ROUTER;

    error InvalidSigner();

    constructor(address protocolAdapter_, address dexRouter_) {
        PROTOCOL_ADAPTER = protocolAdapter_;
        DEX_ROUTER = dexRouter_;
    }

    /// @notice EIP-1271 signature validation for Permit2 compatibility with EIP-7702.
    /// Uses OZ ECDSA.recover — a pure ecrecover wrapper with no EIP-1271 dispatch,
    /// avoiding the infinite recursion that Permit2's SignatureVerification.verify()
    /// would cause on an EIP-7702 account (whose code.length > 0).
    function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4) {
        address signer = ECDSA.recover(hash, signature);
        if (signer != address(this)) revert InvalidSigner();
        return IERC1271.isValidSignature.selector;
    }

    /// @notice Execute a full shielded swap: unwrap → DEX swap → wrap.
    ///         Any surplus (swap output above minAmountOut) is sent to surplusRecipient.
    function executeShieldedSwap(
        Transaction calldata unwrapTx,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 minAmountOut,
        bytes calldata dexCalldata,
        Transaction calldata wrapTx,
        address surplusRecipient,
        bytes calldata signature
    ) external {
        // Verify the throwaway EOA authorized the user-chosen swap parameters.
        // ARM transactions are proof-verified by PA.execute(); dexCalldata is
        // protected by the minAmountOut slippage check below.
        bytes32 paramsHash = keccak256(
            abi.encode(tokenIn, tokenOut, amountIn, minAmountOut, surplusRecipient)
        );
        address signer = ECDSA.recover(paramsHash, signature);
        if (signer != address(this)) revert InvalidSigner();

        // Step 1: Unwrap — release tokenX from the shielded pool to this throwaway.
        IProtocolAdapter(PROTOCOL_ADAPTER).execute(unwrapTx);

        // Step 2: Swap tokenX → tokenY on the DEX.
        uint256 balanceBefore = IERC20(tokenOut).balanceOf(address(this));
        IERC20(tokenIn).approve(DEX_ROUTER, amountIn);
        (bool swapOk,) = DEX_ROUTER.call(dexCalldata);
        require(swapOk, "swap failed");
        uint256 balanceAfter = IERC20(tokenOut).balanceOf(address(this));
        require(balanceAfter - balanceBefore >= minAmountOut, "slippage");

        // Approve Permit2 to pull tokenOut from this throwaway for the wrap step.
        IERC20(tokenOut).approve(PERMIT2, minAmountOut);

        // Step 3: Wrap — wrap tokenY back into the shielded pool.
        IProtocolAdapter(PROTOCOL_ADAPTER).execute(wrapTx);
        uint256 balanceAfterWrap = IERC20(tokenOut).balanceOf(address(this));
        require(balanceAfter - balanceAfterWrap >= minAmountOut, "wrap amount mismatch");

        // Step 4: Transfer surplus to the designated recipient (covers gas + income).
        if (balanceAfterWrap > 0) {
            IERC20(tokenOut).transfer(surplusRecipient, balanceAfterWrap);
        }
    }
}

Fast settlement

This is the main weakness. The time between accepting the RFQ and swap execution will be at least as long as the proving time of the wrap transaction.[11]

"OK price"

We essentially trade proving time for privacy, because the market price may change between RFQ and AUSRET submission.[12]

TL;DR

It seems possible to offer a shielded limit order via AUSRETs and learn over time how to generate revenue by playing with the quoting mechanism. This design should generalize to any EVM chain with EIP-7702 and uses a generic DEX / routing contract.

Simple as that?


  1. I will bracket the question of why I use the word SwapDelegate and not SwapForwarder. ↩︎

  2. If you don’t like it, please pause reading and reach out to me or comment below; in this case, it is probably best to pretend that the corresponding bullet point below is moved to the section about design choices. In other words, we could assume the user wants to touch ethereum directly, but let us grow the set of potential users and not assume it. ↩︎

  3. The fun part is figuring out how large we can grow x in 99.x% and be profitable. ↩︎

  4. Thus, the fees apply in expectation/mean—probably something we do not need to start our elevator pitch with. ↩︎

  5. There is a hidden first design decision, namely how to batch transactions. As historical fact, EIP-7702 was the choice of the first experiment—which then was opening the road to atomicity. I have left it out, because we can take @cwgoes’s parenthesis as a secondary requirement. ↩︎

  6. There is a bunch of technicalities that make the re-wrap non-trivial, because we need to make Permit2 signatures work. However, the isValidSignature function is a necessity if we want atomicity via EIP-7702 delegation. ↩︎

  7. In fact, the user may adjust the quote if they want to play a game and they provide a route for how this could happen, i.e., they do the solving themselves. ↩︎

  8. As the bundler pays the gas, it makes sense to have a minimal swap volume, which raises the chances that we at least get the gas fees back. Over time, we may also dynamically adjust the fees. ↩︎

  9. This would require however to trust the bundler/relayer/solver with the surplus of the trade or—even simpler—the user would give all fees to Heliax. ↩︎

  10. Probably, we want to take a page out of Monero and use only resources with a quantity from a short list, like 1, 2, 5, 10, 20, 50, 100, \ldots. ↩︎

  11. This may be one more reason to switch the protocol adapter to use the MASP instead of the resource machine. ↩︎

  12. We may want to do some experiments using the Tycho indexer and executor. ↩︎

1 Like

Just to briefly mention it here - I spoke with https://orda.network yesterday. Originally, I thought we could primarily use them for direct on/offramping from/to ACH/SEPA/PIX. However, turns out that they are also going to ship ‘Binding Quotes’ to their staging environment next week. We will thus be able to request a binding quote from their system of connected solvers/aggregators and know exactly what price/fx we can expect.

Of course, we will have to await actual benchmarks on how competitive these prices will be but in terms of the surplus/remainder question, this should be one high-potential solution.

I will share more information about the actual integration prototype with orda once we get access to the binding quotes feature, presumably as early as next week.

1 Like

Let me write up a simple obvious observation: this is fantastic, because we would have a fall-back option if we do not find any better price (e.g., via a tycho solution).