Skip to main content

Overview

Your Nyx private account follows one simple rule:
The only way to authorize anything from your Nyx private account is to sign a message with your connected Ethereum wallet, and what you sign is exactly what gets executed.
No one, including the Nyx team, the Nyx app, or a malicious website, can get you to sign one thing and then run something else from your account. This page explains how that works and how to read the signing requests your wallet shows you.

Your account is a smart contract

On Aztec, every account is a smart contract (see Account overview). That contract decides what counts as a valid authorization. Nyx private accounts run a contract called Eip712SignedMessageAccount. It has three key properties:
  • One key, set at creation. When your private account is created, your Ethereum wallet’s public key is written into the contract as an immutable private note. No function exists to change it, add another key, or bypass it.
  • No admin, no backdoor. The contract has no owner, guardian, or recovery key. The Nyx backend has no way to authorize a transaction for you.
  • Your wallet does the signing. Authorization uses standard EIP-712 typed data signatures, the same kind used across Ethereum for permits and off-chain orders. Any Ethereum EOA wallet (non-smart contract wallet) works, including hardware wallets, and your private key never leaves it.
Your passkey and account secret, covered in Account overview, let you see your private account. Only your Ethereum wallet can act on it.

What you sign

Each time you send a private transaction, your wallet shows a structured EIP-712 message instead of an unreadable hex blob. Here is a simplified example of a private send of 1 USDC:
The fields mean the following:
Token amounts in args are in the token’s smallest unit, with no decimal point. USDC has 6 decimals, so 1000000 means 1 USDC. WETH has 18 decimals, so 1000000000000000000 means 1 WETH.

Why what you sign is what gets executed

A typical Ethereum transaction signature covers raw calldata, and your wallet has to decode it to show you something readable. If the wallet decodes it wrong, or a site tricks it, what you see can differ from what you sign. Nyx works the other way around. The human-readable message is what gets signed, and the account contract checks it against the transaction it is about to run. When your transaction executes, the account contract:
  1. Receives the list of function calls to execute.
  2. Rebuilds the full EIP-712 message from those exact calls: their target addresses, function signatures, and arguments as text.
  3. Verifies your wallet’s signature against that rebuilt message, using the public key stored at account creation.
  4. Executes the calls only if the signature is valid. Otherwise the transaction fails.
The contract doesn’t take any displayed value on trust. It ties each one to what runs:
  • Function signature → function. The function that gets called is computed from the signature text you saw. You can’t sign transfer(...) and have the account call withdraw_everything(...).
  • Args → argsHash → execution. The contract re-encodes the displayed arguments and checks that they hash to argsHash, which is the exact input passed to the call. You can’t sign “send 1 USDC” and have the account send 1,000. Numeric text such as 1000000 is parsed back into a number inside the contract, so the text can’t be faked either.
  • Target address → target. The call goes to exactly the targetAddress you saw.
  • Account, network, and transaction binding. outerHash combines your account address, the network’s chain ID and rollup version, and a hash of the whole payload including a random nonce. A signature for one transaction can’t be reused for a different account, a different network, or different calls.
All of this happens inside the account contract’s private function, so it’s covered by the zero-knowledge proof that every Aztec transaction carries. The network accepts the transaction only if the proof shows these checks passed.

The description is a non-verified comment

The description field is a plain-language summary written by the app, such as “Privately send 1 USDC to Alice.” It’s part of the signed message, so it can’t be changed after you sign, but the contract does not check that it matches the function calls. That’s impossible in general: the description is free text. Treat the description as a helpful comment and the functionCalls as the truth. If the two disagree, trust functionCalls, and don’t sign.

Reading the caution line

The caution line comes from a fixed set built into the account contract. An app can’t choose its own caution text, and the contract checks that the right one was shown.

Letting a contract act for you

Some actions need another contract to do something on your behalf. For example, when you send funds from your private account to Ethereum, the token bridge contract has to burn tokens from your private balance. In Aztec, that permission is called an authentication witness. Nyx shows it as a separate signing request with primary type AztecCallIntent:
The same guarantees apply, with one more field:
  • caller is the only contract allowed to use this permission.
  • functionCall is the only call it may make with it, with exactly these arguments.
When the token contract asks your account “did you authorize this?”, your account rebuilds the call intent from the actual call and verifies your signature against it. A different caller, function, or amount doesn’t pass verification. Clear-signed call intents are limited to private calls.

Blind signing

Clear signing has fixed size limits, because every displayed value must be processed inside a zero-knowledge circuit. Currently, a transaction is clear-signed when:
  • It has at most 2 function calls.
  • Each call has at most 6 arguments (call intents: at most 6).
  • Each function signature fits in 93 bytes, and each text argument fits in 31 bytes.
  • All arguments are field elements, unsigned integers, booleans, or short strings.
If a transaction exceeds these limits, Nyx falls back to blind signing. The message type becomes AztecOpaqueTransactionRequest (or AztecOpaqueCallIntent). It shows the caution, description, account address, and network, plus an outerHash in place of the readable calls. Blind signatures are still bound to one account, one network, and one exact set of calls. The outerHash commits to all of that, so the signature can’t be reused for anything else. What you lose is the ability to see the calls in your wallet. You’re relying on the app to have built the transaction honestly.
A blind signing request always starts with Blind signing. in its caution line. Only sign one if you started the action yourself and you trust the app that prepared the transaction. All Nyx actions such as sending, receiving, depositing, and redeeming are designed to be clear-signed.

Checklist before you sign

  1. Make sure you started the action. Only sign a request that comes right after something you did in the app, such as clicking Send. If a signing request appears out of nowhere, reject it.
  2. Check the site. Make sure you’re on nyx.money, especially if the caution line asks you to.
  3. Check the caution line. If it starts with Blind signing., take extra care.
  4. Check the account. accountAddress should be your own private account.
  5. Check the calls, not just the description. Look at targetAddress, functionSignature, and args for each call. Expect a small sponsor() call to Nyx’s JuiceBar contract, which pays your network fees.
  6. Check the amounts in smallest units, and check recipient addresses.
  7. For call intents, check caller. It should be the contract you expect, such as the token bridge for a withdrawal.
If anything looks off, reject the request in your wallet. Nothing can happen in your private account without your signature.

Source code

Nyx is still under active development, and the details on this page may change as it evolves. The behavior described here is implemented in two places:
  • The on-chain account contract, which verifies signatures and executes calls.
  • The client-side code in the Nyx app, which builds the EIP-712 messages your wallet shows.
Both, along with the rest of Nyx’s smart contracts, will be open-sourced and publicly auditable when Nyx reaches GA (general availability). See Nyx smart contracts for more on our plans.