Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions note-send-proof/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
target
codegenCache.json
artifacts
dist
9 changes: 9 additions & 0 deletions note-send-proof/circuits/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "circuits"
type = "bin"
authors = [""]

[dependencies]
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v2.0.3", directory = "noir-projects/aztec-nr/aztec" }
poseidon = { tag = "v0.1.1", git = "https://github.com/noir-lang/poseidon" }
uint_note = { path = "../uint-note" }
7 changes: 7 additions & 0 deletions note-send-proof/circuits/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
settled_note_hash: "0x109ebaffd4e6aa4e4c305606addd352dd432d37fd5541b67e86e7310cdf80053"
contract_address: "0x0f140443f51fe2a1b9ca04b279cda12e2bbdd073efb6b09aed79a6a4315957d0"
recipient: "0x116586dbcc81434e8b0727cbe282be01271886275e347489947af5d1b94618a4"
randomness: "0x0000000000000000000000000000000000000000000000000000000000001b39",
value: 69,
storage_slot: "0x134f661dca40dad62341c230269bbed01da64b506e8a0e6e0a452a9262023012"
note_nonce: "0x0fe225cdf1421a3266faf50f46025b73bb57858d10f7cd62875b47e988c64edd"
27 changes: 27 additions & 0 deletions note-send-proof/circuits/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use dep::aztec::protocol_types::{
address::AztecAddress,
constants::{GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__UNIQUE_NOTE_HASH},
traits::FromField,
};
use dep::aztec::note::note_interface::NoteHash;
use dep::poseidon;

use dep::uint_note::uint_note::UintNote;

fn main(
settled_note_hash: pub Field,
contract_address: pub Field,
recipient: pub Field,
randomness: Field,
value: pub u128,
storage_slot: Field,
note_nonce: Field,
) {
let note = UintNote::new_with_randomness(value, AztecAddress::from_field(recipient), randomness);
let note_hash = note.compute_note_hash(storage_slot);

let siloed_note_hash = poseidon::poseidon2::Poseidon2::hash([GENERATOR_INDEX__SILOED_NOTE_HASH as Field, contract_address, note_hash], 3);
let unique_note_hash = poseidon::poseidon2::Poseidon2::hash([GENERATOR_INDEX__UNIQUE_NOTE_HASH as Field, note_nonce, siloed_note_hash], 3);

assert_eq(settled_note_hash, unique_note_hash);
}
16 changes: 16 additions & 0 deletions note-send-proof/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
This proves note hash delivery

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some more context. Why would someone want to do this? It might be helpful to explain the question that instigated the development of this example.


Prerequisites:
aztec-up @ 2.0.3

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a link to the docs on how to install aztec-up


Steps:
1. aztec-nargo compile in circuits/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you wrap the commands in backticks (`) so that they show up as code blocks? it makes it more clear

2. aztec-nargo compile in sample-contract
3. aztec-postprocess-contract in sample-contract
4. yarn codegen in scripts

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
4. yarn codegen in scripts
4. `yarn && yarn codegen` in ./scripts

4. yarn copy-target in scripts
5. aztec start --sandbox in terminal 2
6. yarn start in scripts
7. copy details outputted by step 6

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where am i supposed to copy this? continuing through, I see its meant to be copy pasted in the web app, but that isnt clear at this point

Also i see the output in my terminal like this:

image

Can you log it in a way that makes it easier to copy-paste? as is, when i double click on the value it highlights this whole line
image

8. yarn dev in vite

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
8. yarn dev in vite
8. `yarn && yarn dev` in ./vite

9. paste details copied in step 7 to the frontend started by step 8
9 changes: 9 additions & 0 deletions note-send-proof/sample-contract/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "getting_started_contract"
authors = [""]
compiler_version = ">=1.0.0"
type = "contract"

[dependencies]
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "v2.0.3", directory = "noir-projects/aztec-nr/aztec" }
uint_note = { path = "../uint-note" }
79 changes: 79 additions & 0 deletions note-send-proof/sample-contract/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use aztec::macros::aztec;

#[aztec]
pub contract GettingStarted {
use aztec::{
state_vars::{private_mutable::PrivateMutable, private_set::PrivateSet, public_mutable::PublicMutable, map::Map},
messages::logs::note::encode_and_encrypt_note_unconstrained,
note::{constants::MAX_NOTES_PER_PAGE, note_viewer_options::NoteViewerOptions},

macros::{
functions::{initializer, private, public, utility, internal},
storage::storage,
},
protocol_types::{
address::AztecAddress,
},
};

use dep::uint_note::uint_note::UintNote;

#[storage]
struct Storage<Context> {
contract_private_state: PrivateMutable<UintNote, Context>,
user_private_state: Map<AztecAddress, PrivateSet<UintNote, Context>, Context>,
contract_public_state: PublicMutable<u128, Context>,
user_public_state: Map<AztecAddress, PublicMutable<u128, Context>, Context>,
owner: PublicMutable<AztecAddress, Context>,
}

#[initializer]
#[public]
fn setup() {
storage.owner.write(context.msg_sender());
}

#[private]
fn create_note_for_user(value: u128) {
let note_owner = context.msg_sender();
storage.user_private_state.at(note_owner)
// randomness should actually be random, but is a workaround because we can't recover it now
.insert(UintNote::new_with_randomness(value, note_owner, 6969))
.emit(encode_and_encrypt_note_unconstrained(&mut context, note_owner));
}

#[public]
fn modify_public_state_for_user(value: u128) {
storage.user_public_state.at(context.msg_sender()).write(value);
}

#[private]
fn modify_private_state_for_contract(value: u128) {
let maybe_contract_owner = context.msg_sender();

storage.contract_private_state.initialize_or_replace(UintNote::new(value, maybe_contract_owner))
.emit(encode_and_encrypt_note_unconstrained(&mut context, maybe_contract_owner));

GettingStarted::at(context.this_address())._assert_is_owner(maybe_contract_owner).enqueue(&mut context);
}

#[public]
#[internal]
fn _assert_is_owner(maybe_owner: AztecAddress) {
assert_eq(maybe_owner, storage.owner.read());
}

#[public]
fn modify_public_state_for_contract(value: u128) {
let maybe_contract_owner = context.msg_sender();

GettingStarted::at(context.this_address())._assert_is_owner(maybe_contract_owner).call(&mut context);

storage.user_public_state.at(context.msg_sender()).write(value);
}

#[utility]
unconstrained fn view_created_notes(owner: AztecAddress) -> BoundedVec<UintNote, MAX_NOTES_PER_PAGE> {
storage.user_private_state.at(owner).view_notes(NoteViewerOptions::new())
}
}
28 changes: 28 additions & 0 deletions note-send-proof/scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "scripts",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"build": "npx tsc && npm run copy-target-after-build",
"clean": "rimraf dist",
"start": "npm run clean && npm run build && node dist/src/index.js",
"lint": "eslint .",
"codegen": "aztec codegen -f ../sample-contract/target/getting_started_contract-GettingStarted.json && npm run copy-target",
"copy-target": "mkdir -p ./artifacts && cp -r ../sample-contract/target ./artifacts",
"copy-target-after-build": "cp -r ../sample-contract/target ./dist/artifacts"
},
"dependencies": {
"@aztec/accounts": "2.0.3",
"@aztec/aztec.js": "2.0.3",
"@aztec/foundation": "2.0.3",
"@aztec/stdlib": "2.0.3"
},
"devDependencies": {
"@eslint/js": "^9.29.0",
"eslint": "^9.29.0",
"rimraf": "^6.0.1",
"typescript": "~5.8.3",
"typescript-eslint": "^8.34.1"
}
}
85 changes: 85 additions & 0 deletions note-send-proof/scripts/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { GettingStartedContract } from '../artifacts/target/GettingStarted.js';
import {
createPXEClient,
waitForPXE,
createAztecNodeClient,
Fr,
} from '@aztec/aztec.js';
import { getInitialTestAccountsWallets } from '@aztec/accounts/testing';
import { computeNoteHashNonce, computeUniqueNoteHash, deriveStorageSlotInMap, siloNoteHash } from '@aztec/stdlib/hash';
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';

const NOTE_HASH_SEPARATOR = 1;

export const SANDBOX_URL = 'http://localhost:8080';

const pxe = createPXEClient('http://localhost:8080');
await waitForPXE(pxe);

const wallets = await getInitialTestAccountsWallets(pxe);
const deployerWallet = wallets[0];
const deployerAddress = deployerWallet.getAddress();

const gettingStarted = await GettingStartedContract.deploy(deployerWallet).send({
from: deployerAddress,
}).wait();

console.log('CONTRACT DEPLOYED AT', gettingStarted.contract.address);

const NOTE_VALUE = 69;

const tx = gettingStarted.contract.methods.create_note_for_user(NOTE_VALUE);

const txExecutionRequest = await tx.create();

const txRequestHash = await txExecutionRequest.toTxRequest().hash();

console.log('TX REQUEST HASH', txRequestHash);

const sentTx = await tx.send({ from: deployerAddress }).wait();

const node = createAztecNodeClient(SANDBOX_URL);

const txEffect = await node.getTxEffect(sentTx.txHash);

if (txEffect === undefined) {
throw new Error('Cannot find txEffect from tx hash');
}

const storageSlot = await deriveStorageSlotInMap(GettingStartedContract.storage.user_private_state.slot, deployerAddress);

const NOTE_RANDOMNESS = new Fr(6969);

const commitment = await poseidon2HashWithSeparator([deployerAddress.toField(), NOTE_RANDOMNESS, storageSlot], NOTE_HASH_SEPARATOR);

const noteHash = await poseidon2HashWithSeparator([commitment, new Fr(NOTE_VALUE)], NOTE_HASH_SEPARATOR);

const INDEX_OF_NOTE_HASH_IN_TRANSACTION = 0;

const nonceGenerator = txEffect?.data.nullifiers[0] ?? txRequestHash;

const noteHashNonce = await computeNoteHashNonce(nonceGenerator, INDEX_OF_NOTE_HASH_IN_TRANSACTION);

const siloedNoteHash = await siloNoteHash(gettingStarted.contract.address, noteHash);

const computedUniqueNoteHash = await computeUniqueNoteHash(
noteHashNonce,
siloedNoteHash,
);

console.log('NOTE HASH', noteHash)
console.log('NONCE GENERATOR', nonceGenerator);
console.log('NONCE', noteHashNonce);
console.log('SILOED NOTE HASH', siloedNoteHash);
console.log('COMPUTED UNIQUE NOTE HASH', computedUniqueNoteHash);
console.log('ACTUAL UNIQUE NOTE HASH', txEffect.data.noteHashes[0]);

console.log('REQUIRED INPUT', {
settled_note_hash: txEffect.data.noteHashes[0],
contract_address: gettingStarted.contract.address,
recipient: deployerAddress,
randomness: NOTE_RANDOMNESS,
value: NOTE_VALUE,
storage_slot: storageSlot,
note_nonce: noteHashNonce,
})
14 changes: 14 additions & 0 deletions note-send-proof/scripts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"module": "nodenext", /* Specify what module code is generated. */
"moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */
"resolveJsonModule": true, /* Enable importing .json files. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"outDir": "dist"
},
"include": [ "src/**/*", "artifacts/**/*"]
}
Loading
Loading