Reward Swap
Reward claim
Account tsree
Anonymity Points claimed as rewards for anonymity mining are stored in "shielded" accounts within a Merkle Tree, using many of the same patterns as in the core deposit contract and Tornado Trees.
Shielded balance
The special property that the accounts tree brings to the table is that only the owner of the account knows its balance. Each time that an account's balance is updated by claiming additional rewards, or withdrawing from it, a new account is created, and the old account is nullified.
The balance of an account is stored as a component of the commitment hash that is inserted into the tree. The balance of an account can only by known by having the private key used to produce an encrypted backup of its commitment inputs.
Account commitment
An account commitment consists of three components:
The 31-byte amount of AP in the account
A 31-byte random secret
A 31-byte random nullifier
An account commitment hash is the Poseidon hash of these three components
Claiming a reward
Inputs to a reward proof
The total set of public inputs for a reward proof are:
The block reward rate for the claim
The fee that you're paying the relayer (or zero)
The Tornado instance address associated with the note
The reward nullifier (Poseidon hash of the note nullifier)
The args hash
The root of the account tree pre-claim (input)
The nullifier of the existing account being added to
The root of the account tree after updating it (output)
The path indices to the new account, as an integer, left-padded with zeroes
The commitment for the new account
The root of the deposit tree
The root of the withdrawal tree
The total set of private inputs for a reward proof are:
The secret of the note being claimed
The nullifier of the note being claimed
The amount coming from an existing account
An array of path elements to the existing account commitment in the tree
The path indices to the existing account, as an integer, left-padded with zeroes
The balance of the new account
The secret of the new account
The nullifier of the new account
An array of path elements to the new account
The block number when the claimed note was deposited
The path indices to the deposit in the Tornado Trees deposit tree, as an integer, left-padded with zeroes
An array of path elements to the deposit in the Tornado Trees deposit tree
The block number when the claimed note was withdrawn
The path indices to the withdrawal in the Tornado Trees withdrawal tree, as an integer, left-padded with zeroes
An array of path elements to the withdrawal in the Tornado Trees withdrawal tree
Proven claims
Rewards are claimed by proving that:
You know the path to a deposit and withdrawal event pair
The deposit and withdrawal correspond to the same note whose secret and nullifier you know
The withdrawal event's block number is a specified duration after the deposit event's block number
The amount you're claiming is then a multiple of the agreed-upon reward rate, times the specified block duration
The disclosed "reward nullifier" is the Poseidon hash of the original note nullifier
Sanity checks
An invariant constraint is first created showing that the amount that is coming from an existing account, plus the block reward rate times the block duration, is equal to the new account's balance plus the relayer fee.
An overflow check is then performed on the input, output, and block duration values to ensure that they fit within 248 bits, 248 bits, and 32 bits, respectively, without overflowing.
Input account validation
The input account balance, secret, and nullifier are hashed to obtain the input account commitment, and then the path elements and path indices are used to verify that such a commitment exists within the specified input root, but in such a way that if the input account balance is 0, the check passes regardless.
This scheme allows for new accounts to be created without publicly disclosing that they are new.
The public input nullifier hash is checked against the input account's nullifier component.
Output account validation
The output account balance, secret, and nullifier are hashed to obtain the output account commitment, and are checked against the public output commitment hash.
The account tree update is validated using the input root, output root, output commitment as a new leaf, and the specified output path elements and indices.
Tornado trees validation
The Tornado Commitment used for the note being claimed is computed using the note secret and nullifier, and then the corresponding commitment in the Tornado Trees deposit tree is computed using the Tornado instance address, note commitment, and deposit block number as components.
The deposit commitment is then verified to exist at the specified deposit path beneath the deposit tree root.
The withdrawal commitment in the Tornado Trees withdrawal tree is then computed using the Tornado instance address, note nullifier hash, and withdrawal block number as components. The withdrawal commitment is verified to exist at the specified withdrawal path beneat the withdrawal tree root.
Reward nullifier
The reward nullifier for the provided note is then computed by generating the Poseidon hash of the note's nullifier. This is compared to the reward nullifier specified as a public input.
Args hash square
As a last step, the args hash is squared into a public output, to ensure that the reward transaction parameters cannot be tampered with relative to the proof.
Completing the reward transaction
Using the generated proof, we can now call the reward
method of the Miner contract.
The reward method takes the proof, and the public inputs to the proof, and verifies:
The input account nullifier has not already been used
The output account path corresponds to the input root leaf index
The deposit and withdrawal roots are the current or previous roots of the Tornado Trees contract (are known roots)
The args hash is correct with respect to the extData args
The relayer fee is within a valid 248-bit integer range
The reward rate equals what is expected for the Tornado instance specified
The reward has not already been claimed according to the reward nullifier
The proof is valid according to the Reward verifier, using the public inputs provided
If these preconditions are met, then:
The input account is nullified
The reward is nullified
The account tree root is updated to the specified output account root
If applicable, the relayer is rewarded TORN using the fee AP at the current AMM rate
A New Account event is emitted
Batch bewards
There is an alternate method in the Miner contract which deals with "batch rewards". While most transactions claim rewards individually, batch reward transactions claim multiple rewards at once. This avoids having to wait for the next block for each reward claim, since each claim has to insert a new leaf from the last account root.
A batch reward transaction specifies a sequence of reward
method parameter sets, which are executed incrementally.
Last updated
Was this helpful?