Comment on page
High-level overview of the operation flow
Within the Nocturne protocol, users carry out actions with their private funds through operations. Abstractly, an operation consists of two pieces of information: A list of JoinSplits and a list of actions.
An action consists of a contract address and some ABI-encoded calldata specifying a method call to make on that contract.
At a high level, an easy way to interpret an operation is:
- 1.The list of JoinSplits specifies what assets to spend and how much of it to use for actions, all without revealing the owner of the assets
- 2.The list of actions specifies what to do with said assets
Concretely operations contain other important fields for security, including:
- A stealth address
refundAddrthat specifies an
ownerfor any new notes created at the end of the operation (step 7 below)
- Gas price / limit
- Chain id / deadline to protect against replay attacks
Once submitted, operations are processed on-chain with the following procedure:
- 1.The JoinSplit proofs are verified by the Teller against the committment tree.
- 3.The old note nullifiers from the JoinSplits are added to the nullifier set.
- 4.The new note commitments produced by the JoinSplits are queued for insertion into the commitment tree.
publicSpendin the JoinSplits is sent from the Teller to the Handler (unwrapped).
- 6.The actions are executed by the Handler using the unwrapped funds.
- 7.Any new refund notes resulting from the actions are queued for insertion into the commitment tree.
- 8.The underlying assets for the refund notes are sent back to the Teller contract.
To better understand what this means, let's consider some practical examples.
A "confidential payment" is a payment where the amount and recipient are hidden. We can represent a confidential payment via an operation with no actions and one or more JoinSplits where there is a publicSpend of 0 and the owner of one of the new notes is set to the payment recipient.
Since publicSpend equals 0, the underlying assets are never unwrapped and thus are never revealed, making the payment fully confidential. All that is seen on chain is that some unknown notes for unknown assets and amounts were spent and new unknown notes of that same unknown asset were created.
Suppose we have some USDC inside Nocturne and we wanted to unwrap it and pay an Ethereum address $100. In this interaction, the sender is anonymous but the recipient is not.
We can express this transfer via an operation with one or more JoinSplits for USDC, where the public JoinSplits' spends total to $100. The operation would have one action encoding a call to transfer $100 USDC to the recipient.
When submitted, this operation will unwrap the desired amount of USDC from Nocturne, then transfer it to the recipient.
Suppose we have 3 WETH inside Nocturne and we wanted to swap 1 WETH for DAI. We can create an operation with one or more JoinSplits for WETH, where the JoinSplits' public spends total to 1 WETH. The operation would have one action encoding a call to Uniswap to swap 1 WETH for DAI.
When submitted, this operation will unwrap 1 WETH from Nocturne, call Uniswap to swap it for DAI, create a refund note for the resultant DAI, and send the DAI back to the Teller.