Inside ShieldTX: The Architecture Enabling Shielded Trading Onchain

Explore the architecture behind ShieldTX: how Nightshade uses private notes, zero-knowledge proofs and solver-funded accounts to separate deposited capital from native Hyperliquid trading, plus its current trust assumptions and path toward stronger privacy.

By Prabal Banerjee 11 min read
Inside ShieldTX: The Architecture Enabling Shielded Trading Onchain

ShieldTX provides a shielded perp trading experience on Hyperliquid. For the sake of a good user experience (UX), no one sees how we shield user actions on a public blockchain. In this article we discuss some of the choices made when building the foundation on which ShieldTX stands. This foundation is generic enough that it can support various customer needs without leaking information on-chain - from running a custom trading setup with the ShieldTX API to an instant-settlement private stablecoin payment platform, shielded DeFi and many more.

At a high level, ShieldTX does not make Hyperliquid itself private. Positions opened on Hyperliquid are still publicly visible from the account that owns them. What ShieldTX is designed to break is the obvious public link between the capital a user deposits and the positions they later open. Underneath the trading interface is a zkAppchain, known  as Nightshade.

Avail Nightshade: A Privacy First ZK Appchain on Avail

Nightshade as a zero-knowledge (ZK) appchain implementing a “commit-first, prove-later” architecture. Transactions on the appchain execute with sub-second latency, while proofs of correct execution of state transitions are generated asynchronously and settled on Arbitrum later. 

Nightshade represents its state using a well-understood model: commitment and nullifier sparse merkle trees (SMTs). The commitment tree keeps track of all notes that have ever existed inside the system. While the nullifier tree keeps track of notes that have already been spent, i.e., preventing double spend. 

For every state transition, (submitted appchain transactions), Nightshade captures the before and after state roots, along with the Merkle path witnesses required to later prove that the transition was valid. These transitions are committed into an ordered proving queue at execution time. Later, multiple queued state transitions are proven together inside the SP1 zkVM. Multiple compressed STARK proofs are then aggregated and wrapped into a Groth16 proof that the Arbitrum settlement contract verifies before updating its compact representation of Nightshade’s state.

This separation between execution and proving is important. A user does not need to wait for a proof to be generated before sending a note to another user or performing another Nightshade operation. Execution happens immediately inside the appchain. Settlement finality on Arbitrum comes later, once the corresponding transitions have been proven.

Shielding USDC into Nightshade

To use ShieldTX, a user deposits USDC into the Arbitrum settlement contract and receives a note of equal value inside Nightshade.

One limitation we want to be explicit about - note management is sequencer-side today. The sequencer currently has visibility into note preimages and user state. This is primarily due to the lack of mature tooling for sub-second latency client-side proving that gives us the UX we want. We are closely watching the exciting progress happening on this front. We ultimately want Nightshade to operate in a model where the sequencer does not need to see note preimages at all. It should operate on opaque commitment and nullifier hashes while users locally prove ownership and correctness of transactions.

Today, however, the privacy model is different: Nightshade state is hidden from public observers, but not from the sequencer. When a user deposits USDC into the Arbitrum settlement contract, the recipient inside Nightshade is visible publicly. The recipient needs to be explicit because Nightshade identifies participants using Ed25519 keypairs. Receiving the note at an ephemeral Nightshade address helps prevent the deposit itself from becoming a long-lived identifier for everything the user later does with their shielded funds.

The settlement contract keeps track of deposits, which we also refer to as shields, using a cumulative Keccak256 hash chain. This serves an important purpose. Nightshade must process deposits in the exact order in which the settlement contract observed them. When a batch is proven, the zkVM proves that the sequencer consumed the corresponding deposit sequence correctly. In other words, a valid Nightshade batch cannot silently skip deposit i, process deposit i+1 ahead of it, or mint a note which does not have a corresponding settlement-layer deposit. Every note minted from the shield path therefore corresponds to a real USDC deposit recorded by the Arbitrum settlement contract.

Notes inside Nightshade

Once a user has a note inside Nightshade, actions taken on them are not published to the outside world. A public-chain observer does not see individual note transfers, note balances, or any other state transitions that users perform. The sequencer does. Today the sequencer has plaintext visibility into note state. It does not, however, expose arbitrary user state through its API. To retrieve user-specific state, the client must prove control of the corresponding Nightshade identity by signing a fresh randomly sampled challenge from the sequencer.

So there are two separate properties here. The first is privacy from the public: Nightshade state is not published. The second is access control over user-specific state returned by the sequencer.

Spending notes

A simple Nightshade transaction requires moving a note received at an ephemeral address to a user's static Ed25519 identity maintained inside Nightshade. The ephemeral owner signs authorization to spend the note, and the resulting note belongs to the user's static Nightshade identity. Because Nightshade is commit-first and prove-later, this transfer can happen with sub-second appchain latency. It does not need to wait for Arbitrum settlement. The recipient can discover and spend further almost instantly.

The ZK circuit enforces the usual unspent transaction output (UTXO) rules. For a note to be spendable, the prover must show that its commitment exists in the commitment SMT. It must also show that its corresponding nullifier does not already exist in the nullifier SMT. After the spend, that nullifier is inserted into the tree, preventing the same note from being spent twice. For any spend-type operations, the circuit additionally enforces properties such as asset type consistency, authorization by the note owner, and value conservation across inputs and outputs. A sequencer can never spend a user-owned note. Spending requires authorization from the corresponding Ed25519 owner key.

Opening a Hyperliquid position

Opening a perp position is where things become more interesting because the action crosses the boundary of the Nightshade appchain, and reaches Hyperliquid.

Suppose a user wants to open a “$2,500 20x long on ETH”. The first step is that the user escrows the required Nightshade notes with the protocol. An escrowed note is a special note type owned by the protocol. It contains an expiry represented in terms of Arbitrum block height and retains enough information for the protocol to return the value to the original owner if the intent expires. The user also designates a solver. Only that solver discovers the user's intent.

The flow looks like following:

1. The user escrows Nightshade notes and creates an intent with expiry.

2. The intent designates a solver and a position-specific Hyperliquid address.

3. The solver supplies USDC liquidity to that address.

4. The solver presents evidence that the funding occurred.

5. Nightshade verifies that evidence and releases the escrowed note to the solver.

6. The user trades natively from the funded Hyperliquid account.

The solver is effectively putting its own liquidity on the line. It does so because the protocol guarantees that if the solver can prove that it fulfilled the funding obligation, the corresponding escrowed Nightshade note can be released to it. If the solver does not fulfil the intent before expiry, the escrowed value can automatically be refunded to the original note owner. Expiry is executed with the trigger of Arbitrum reaching a certain block-height. It is enforced by both the ZK circuit and the settlement contract on Arbitrum. At the time of proving it takes the current Arbitrum block-height as input. The settlement layer contract can reject a ZK proof if it finds the input block-height was invalid, i.e., block-height not yet reached or block-height older than the previous batch it saw.

For proving that the Hyperliquid-side USDC transfer actually happened, the solver today relies on what is, essentially, an oracle model. An attestation tells Nightshade that the required transfer occurred. We are eager to make this part more robust. The end state we want is a cryptographic guarantee of correct execution on Hyperliquid rather than trusting an external attestation mechanism. This oracle is therefore an explicit trust assumption in the current protocol.

Once execution attestation is accepted, the solver gets the Nightshade note and the user's position-specific Hyperliquid address receives USDC. The solver periodically rebalances liquidity across chains as part of its normal operation. From this point onward, trading is entirely native Hyperliquid.

What is actually private here?

ShieldTX does not hide a Hyperliquid trade from Hyperliquid. If an ephemeral account opens a position, that position is still visible publicly from that account. What ShieldTX changes is the funding graph around that account. Each position can use a fresh Hyperliquid address. That address is funded by a designated solver rather than directly by the user's publicly known deposit wallet.

A passive public observer looking at the user's original deposit on Arbitrum therefore does not get a trivial on-chain path from the deposit to the Hyperliquid account that later opens the position. Similarly, activity within one position-specific Hyperliquid wallet is still linkable to itself. That is unavoidable if the trading venue itself is public.

The privacy goal is not to hide Hyperliquid's ledger. The goal is to make it difficult for a public observer to correlate the user's settlement-layer funding identity with their various trading identities. There are still actors with more information than a passive public observer. The Nightshade sequencer sees note state today. The designated solver learns the funding destination it is asked to fulfil. The protocol therefore does not currently claim privacy against a colluding sequencer and solver. That is an important distinction.

Native Hyperliquid once funded

ShieldTX offers a familiar user interface and existing Hyperliquid users should feel at home. Once funds land in the position-specific ephemeral Hyperliquid address, the experience is 100% native. Users can open market and limit orders. Take Profit (TP) and Stop Loss (SL) work as expected. The actual position lifecycle is handled by Hyperliquid rather than by some custom synthetic trading system inside ShieldTX.

That was an important product decision for us. We are not recreating Hyperliquid. We are changing how users get capital into and out of Hyperliquid accounts.

Closing a position

When a position is closed, either manually or automatically, the user's proceeds move from the ephemeral position wallet back toward Nightshade. For this path we use Circle's Cross-Chain Transfer Protocol (CCTP) together with the Arbitrum settlement contract's shield path.

The proceeds eventually arrive on Arbitrum and are shielded back into Nightshade. Again, using a fresh ephemeral Nightshade recipient prevents the returning capital from trivially reconnecting the Hyperliquid position wallet with the user's original Nightshade identity or their original Arbitrum deposit. The result is the user instantly receives a new Nightshade note for opening future positions, internal transfers, or eventual withdrawal.

Unshielding back to Arbitrum

When a user wants to unshield their USDC notes, whether those notes came from deposits or Hyperliquid trading proceeds, they burn the corresponding notes inside Nightshade and specify an Arbitrum recipient address. The burn is explicitly authorized by the note owner and cryptographically binds the intended Arbitrum recipient. Once the batch containing that burn is proven and accepted by the Arbitrum settlement contract, the withdrawal can be claimed by anyone on behalf of the recipient, presenting the corresponding Merkle inclusion proof against the withdrawal commitment hash published by the batch. Because the authorized Nightshade burn already binds the recipient, the Arbitrum transaction relayer does not gain custody of the funds and cannot redirect the withdrawal to itself. Claims are therefore conveniently relayed by third-parties.

What can the sequencer do?

Our adversary model treats the sequencer as an actor that sees the full Nightshade state, but whose ability to change that state is constrained by the ZK proof system. For user-owned notes, the sequencer cannot create a valid spend transaction without an authorization (EdDSA signature) from the owner. It cannot arbitrarily withdraw a user's notes to an address of its choosing. Again a withdrawal requires a user-authorized note burn that binds the Arbitrum recipient. It cannot mint arbitrary shielded assets because every note entering through the deposit path must correspond to an ordered settlement-layer deposit. For escrow notes, the circuit restricts what can happen to them. They can be released to the designated solver only if the required execution evidence is presented, or returned to the original owner once the intent expires.

That said, it would be inaccurate to say that the sequencer can *only* ever attack liveness without stating the assumptions behind that claim. The safety properties depend on the correct implementation and use of the proving system, ZK circuits, settlement contract on Arbitrum, digital signature scheme, cryptographic hash functions, and other protocol components. Today they also depend on the correctness of the Hyperliquid execution attestation mechanism. If that attestator incorrectly certifies that a solver funded an account when it did not, the Nightshade circuit cannot independently discover that the external-world statement was false. This is why replacing the current oracle model with cryptographic verification is important to us. Under those assumptions, a malicious sequencer cannot forge transactions.

Its unilateral power is primarily over liveness. It can refuse to process a user's transaction. It can delay proving. It can stop producing batches which it submits to the settlement contract, required for withdrawing funds. It can withhold user state from its API. What it should not be able to do is produce a valid proof that violates the Nightshade state-transition rules.

Why did we choose this architecture?

When starting out, we explored trusted execution environments (TEEs) as a way to prevent the sequencer from seeing note preimages. We ultimately decided to build around only zero-knowledge cryptography, even though we were very aware that the first version would temporarily lack sequencer-obliviousness. SP1 compressed STARK proofs aggregated into an EVM-verifiable Groth16 proof gives the settlement layer a succinct way to verify Nightshade transactions without seeing and replaying them.

Privacy from public observers comes largely from the fact that detailed Nightshade state is not published on-chain. What we do not yet have is the stronger property where even the sequencer can execute transactions without learning note preimages. We are still confident that building Nightshade as a zkAppchain puts us on the right path toward that model. As client-side proving becomes faster on mobile devices, in future users should be able to prove ownership of Nightshade notes and spend them toward Hyperliquid positions without revealing those notes to the sequencer.

At that point, the sequencer would operate primarily on opaque commitments, nullifiers, and proofs rather than plaintext user state. That is the architecture we ultimately want Nightshade to become.

What hasn't ShieldTX solved yet?

The Nightshade sequencer currently sees note preimages and user state. The sequencer can censor users or halt the appchain, even if it cannot forge valid user-authorized spends under the protocol's security assumptions. Availability of data in case the sequencer stops submitting batch proofs, is yet to be integrated. Hyperliquid positions themselves remain public. The designated solver learns the position-specific address it is asked to fund. Hyperliquid funding verification currently depends on an attestation mechanism rather than a fully cryptographic proof of external-chain execution.

All of these are areas where the architecture can become stronger. But we believe the foundation matters. Today Nightshade already gives us a private note ledger from the perspective of public observers, instant transaction execution, and deferred settlement on Arbitrum, and a way to break the obvious funding link between a user's deposited capital and their Hyperliquid trading actions.

The next step is progressively reducing what every intermediary needs to know. Eventually, the sequencer should not see note preimages. External execution should be proven rather than attested. And opening a Hyperliquid position from Nightshade should require revealing as little information as possible to everyone involved. That is the direction in which we are building ShieldTX.