Skip to content

Commit

Permalink
Add TestToken without init checks for testing purposes
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino committed Mar 4, 2024
1 parent b7ce0c5 commit 521a258
Show file tree
Hide file tree
Showing 8 changed files with 663 additions and 4 deletions.
1 change: 1 addition & 0 deletions noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ members = [
"contracts/slow_tree_contract",
"contracts/stateful_test_contract",
"contracts/test_contract",
"contracts/test_token_contract",
"contracts/token_contract",
"contracts/token_blacklist_contract",
"contracts/token_bridge_contract",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "test_token_contract"
authors = [""]
compiler_version = ">=0.18.0"
type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
compressed_string = { path = "../../../aztec-nr/compressed-string" }
authwit = { path = "../../../aztec-nr/authwit" }
314 changes: 314 additions & 0 deletions noir-projects/noir-contracts/contracts/test_token_contract/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
mod types;

// Copy of the TokenContract that skips initializer checks for all public functions.
// Meant to be used for public simulator tests at simulator/src/public/index.test.ts.

contract TestToken {
// Libs
use dep::std::option::Option;

use dep::compressed_string::FieldCompressedString;

use dep::aztec::{
note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils},
hash::{compute_secret_hash}, state_vars::{Map, PublicMutable, SharedImmutable, PrivateSet},
protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}
};

use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}};

use crate::types::{transparent_note::TransparentNote, token_note::{TokenNote, TOKEN_NOTE_LEN}, balances_map::BalancesMap};

struct Storage {
admin: PublicMutable<AztecAddress>,
minters: Map<AztecAddress, PublicMutable<bool>>,
balances: BalancesMap<TokenNote>,
total_supply: PublicMutable<U128>,
pending_shields: PrivateSet<TransparentNote>,
public_balances: Map<AztecAddress, PublicMutable<U128>>,
symbol: SharedImmutable<FieldCompressedString>,
name: SharedImmutable<FieldCompressedString>,
decimals: SharedImmutable<u8>,
}

#[aztec(private)]
#[aztec(initializer)]
fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) {
let selector = FunctionSelector::from_signature("_initialize((Field),(Field),(Field),u8)");
let name_s = FieldCompressedString::from_string(name);
let symbol_s = FieldCompressedString::from_string(symbol);
context.call_public_function(
context.this_address(),
selector,
[admin.to_field(), name_s.serialize()[0], symbol_s.serialize()[0], decimals as Field]
);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn set_admin(new_admin: AztecAddress) {
assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin");
storage.admin.write(new_admin);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn public_get_name() -> pub FieldCompressedString {
storage.name.read_public()
}

#[aztec(private)]
fn private_get_name() -> pub FieldCompressedString {
storage.name.read_private()
}

unconstrained fn un_get_name() -> pub [u8; 31] {
storage.name.read_public().to_bytes()
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn public_get_symbol() -> pub FieldCompressedString {
storage.symbol.read_public()
}

#[aztec(private)]
fn private_get_symbol() -> pub FieldCompressedString {
storage.symbol.read_private()
}

unconstrained fn un_get_symbol() -> pub [u8; 31] {
storage.symbol.read_public().to_bytes()
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn public_get_decimals() -> pub u8 {
storage.decimals.read_public()
}

#[aztec(private)]
fn private_get_decimals() -> pub u8 {
storage.decimals.read_private()
}

unconstrained fn un_get_decimals() -> pub u8 {
storage.decimals.read_public()
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn set_minter(minter: AztecAddress, approve: bool) {
assert(storage.admin.read().eq(context.msg_sender()), "caller is not admin");
storage.minters.at(minter).write(approve);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn mint_public(to: AztecAddress, amount: Field) {
assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter");
let amount = U128::from_integer(amount);
let new_balance = storage.public_balances.at(to).read().add(amount);
let supply = storage.total_supply.read().add(amount);

storage.public_balances.at(to).write(new_balance);
storage.total_supply.write(supply);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn mint_private(amount: Field, secret_hash: Field) {
assert(storage.minters.at(context.msg_sender()).read(), "caller is not minter");
let pending_shields = storage.pending_shields;
let mut note = TransparentNote::new(amount, secret_hash);
let supply = storage.total_supply.read().add(U128::from_integer(amount));

storage.total_supply.write(supply);
pending_shields.insert_from_public(&mut note);
}

#[aztec(private)]
fn privately_mint_private_note(amount: Field) {
storage.balances.add(context.msg_sender(), U128::from_integer(amount));
let selector = FunctionSelector::from_signature("assert_minter_and_mint((Field),Field)");
let _void = context.call_public_function(
context.this_address(),
selector,
[context.msg_sender().to_field(), amount]
);
}

#[aztec(public)]
#[aztec(noinitcheck)]
internal fn assert_minter_and_mint(minter: AztecAddress, amount: Field) {
assert(storage.minters.at(minter).read(), "caller is not minter");
let supply = storage.total_supply.read() + U128::from_integer(amount);
storage.total_supply.write(supply);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
// The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message.
assert_current_call_valid_authwit_public(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

let amount = U128::from_integer(amount);
let from_balance = storage.public_balances.at(from).read().sub(amount);

let pending_shields = storage.pending_shields;
let mut note = TransparentNote::new(amount.to_integer(), secret_hash);

storage.public_balances.at(from).write(from_balance);
pending_shields.insert_from_public(&mut note);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
assert_current_call_valid_authwit_public(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

let amount = U128::from_integer(amount);
let from_balance = storage.public_balances.at(from).read().sub(amount);
storage.public_balances.at(from).write(from_balance);

let to_balance = storage.public_balances.at(to).read().add(amount);
storage.public_balances.at(to).write(to_balance);
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn burn_public(from: AztecAddress, amount: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
assert_current_call_valid_authwit_public(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

let amount = U128::from_integer(amount);
let from_balance = storage.public_balances.at(from).read().sub(amount);
storage.public_balances.at(from).write(from_balance);

let new_supply = storage.total_supply.read().sub(amount);
storage.total_supply.write(new_supply);
}

#[aztec(private)]
fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) {
let pending_shields = storage.pending_shields;
let secret_hash = compute_secret_hash(secret);
// Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash
// stored in field with index 1 (select(1, secret_hash)).
let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1);
let notes = pending_shields.get_notes(options);
let note = notes[0].unwrap_unchecked();
// Remove the note from the pending shields set
pending_shields.remove(note);

// Add the token note to user's balances set
storage.balances.add(to, U128::from_integer(amount));
}

#[aztec(private)]
fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
assert_current_call_valid_authwit(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

storage.balances.sub(from, U128::from_integer(amount));

let selector = FunctionSelector::from_signature("_increase_public_balance((Field),Field)");
let _void = context.call_public_function(context.this_address(), selector, [to.to_field(), amount]);
}

#[aztec(private)]
fn transfer(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
assert_current_call_valid_authwit(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

let amount = U128::from_integer(amount);
storage.balances.sub(from, amount);
storage.balances.add(to, amount);
}

#[aztec(private)]
fn burn(from: AztecAddress, amount: Field, nonce: Field) {
if (!from.eq(context.msg_sender())) {
assert_current_call_valid_authwit(&mut context, from);
} else {
assert(nonce == 0, "invalid nonce");
}

storage.balances.sub(from, U128::from_integer(amount));

let selector = FunctionSelector::from_signature("_reduce_total_supply(Field)");
let _void = context.call_public_function(context.this_address(), selector, [amount]);
}

#[aztec(public)]
#[aztec(noinitcheck)]
internal fn _initialize(
new_admin: AztecAddress,
name: FieldCompressedString,
symbol: FieldCompressedString,
decimals: u8
) {
assert(!new_admin.is_zero(), "invalid admin");
storage.admin.write(new_admin);
storage.minters.at(new_admin).write(true);
storage.name.initialize(name);
storage.symbol.initialize(symbol);
storage.decimals.initialize(decimals);
}

/// Internal ///

#[aztec(public)]
#[aztec(noinitcheck)]
internal fn _increase_public_balance(to: AztecAddress, amount: Field) {
let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount));
storage.public_balances.at(to).write(new_balance);
}

#[aztec(public)]
#[aztec(noinitcheck)]
internal fn _reduce_total_supply(amount: Field) {
// Only to be called from burn.
let new_supply = storage.total_supply.read().sub(U128::from_integer(amount));
storage.total_supply.write(new_supply);
}

/// Unconstrained ///

unconstrained fn admin() -> pub Field {
storage.admin.read().to_field()
}

unconstrained fn is_minter(minter: AztecAddress) -> pub bool {
storage.minters.at(minter).read()
}

unconstrained fn total_supply() -> pub Field {
storage.total_supply.read().to_integer()
}

unconstrained fn balance_of_private(owner: AztecAddress) -> pub Field {
storage.balances.balance_of(owner).to_integer()
}

unconstrained fn balance_of_public(owner: AztecAddress) -> pub Field {
storage.public_balances.at(owner).read().to_integer()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod transparent_note;
mod balances_map;
mod token_note;
Loading

0 comments on commit 521a258

Please sign in to comment.