Skip to content

Commit

Permalink
refactor: purging portal addresses from noir contracts step 1
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Apr 18, 2024
1 parent d7adbdb commit 2d8a867
Show file tree
Hide file tree
Showing 30 changed files with 107 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ title: How to deploy a contract with a Portal
---

- Deploy to L1 using Viem, Foundry or your preferred tool;
- Deploy to L2 passing in the address of the L1 portal as its portal contract;
- Deploy to L2 passing in the address of the L1 portal as an argument;
```typescript
const deploymentTx = Contract.deploy(wallet).send({
portalContract: tokenPortalAddress,
});
const deploymentTx = Contract.deploy(wallet, tokenPortalAddress).send();
```
- Initialize l1 with l2 address for access control.

Expand Down
3 changes: 0 additions & 3 deletions noir-projects/aztec-nr/aztec/src/context/avm_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,6 @@ impl ContextInterface for AvmContext {
fn this_address(self) -> AztecAddress {
address()
}
fn this_portal_address(self) -> EthAddress {
portal()
}
fn chain_id(self) -> Field {
chain_id()
}
Expand Down
1 change: 0 additions & 1 deletion noir-projects/aztec-nr/aztec/src/context/interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ trait ContextInterface {
fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field);
fn msg_sender(self) -> AztecAddress;
fn this_address(self) -> AztecAddress;
fn this_portal_address(self) -> EthAddress;
fn chain_id(self) -> Field;
fn version(self) -> Field;
fn selector(self) -> FunctionSelector;
Expand Down
4 changes: 0 additions & 4 deletions noir-projects/aztec-nr/aztec/src/context/private_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ impl ContextInterface for PrivateContext {
self.inputs.call_context.storage_contract_address
}

fn this_portal_address(self) -> EthAddress {
self.inputs.call_context.portal_contract_address
}

fn chain_id(self) -> Field {
self.inputs.private_global_variables.chain_id
}
Expand Down
4 changes: 0 additions & 4 deletions noir-projects/aztec-nr/aztec/src/context/public_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,6 @@ impl ContextInterface for PublicContext {
self.inputs.call_context.storage_contract_address
}

fn this_portal_address(self) -> EthAddress {
self.inputs.call_context.portal_contract_address
}

fn chain_id(self) -> Field {
self.inputs.public_global_variables.chain_id
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,6 @@ contract AvmTest {
context.msg_sender()
}

#[aztec(public-vm)]
fn get_portal() -> pub EthAddress {
context.this_portal_address()
}

#[aztec(public-vm)]
fn get_fee_per_l1_gas() -> pub Field {
context.fee_per_l1_gas()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ mod lib;

contract GasToken {
use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}};
use dep::aztec::{hash::compute_secret_hash, state_vars::{PublicMutable, Map}};
use dep::aztec::{hash::compute_secret_hash, state_vars::{SharedImmutable, PublicMutable, Map}};

use crate::lib::{calculate_fee, get_bridge_gas_msg_hash};

#[aztec(storage)]
struct Storage {
balances: Map<AztecAddress, PublicMutable<U128>>,
portal_address: SharedImmutable<EthAddress>,
}

#[aztec(public)]
#[aztec(initializer)]
fn constructor(portal_address: EthAddress) {
storage.portal_address.initialize(portal_address);
}

#[aztec(public)]
fn claim_public(to: AztecAddress, amount: Field, secret: Field, leaf_index: Field) {
let content_hash = get_bridge_gas_msg_hash(to, amount);

// Consume message and emit nullifier
context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address(), leaf_index);
context.consume_l1_to_l2_message(
content_hash,
secret,
storage.portal_address.read_public(),
leaf_index
);

let new_balance = storage.balances.at(to).read() + U128::from_integer(amount);
storage.balances.at(to).write(new_balance);
Expand Down
57 changes: 22 additions & 35 deletions noir-projects/noir-contracts/contracts/test_contract/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
contract Test {
use dep::aztec::prelude::{
AztecAddress, EthAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions,
PrivateContext, PrivateImmutable, PrivateSet
PrivateContext, PrivateImmutable, PrivateSet, SharedImmutable
};

use dep::aztec::protocol_types::{
Expand All @@ -24,10 +24,7 @@ contract Test {
note_getter_options::NoteStatus
},
deploy::deploy_contract as aztec_deploy_contract,
oracle::{
get_public_key::get_public_key as get_public_key_oracle,
unsafe_rand::unsafe_rand
},
oracle::{get_public_key::get_public_key as get_public_key_oracle, unsafe_rand::unsafe_rand},
log::emit_unencrypted_log_from_private
};
use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash};
Expand All @@ -52,17 +49,6 @@ contract Test {
[pub_key.x, pub_key.y]
}

#[aztec(private)]
fn get_portal_contract_address() -> EthAddress {
context.this_portal_address()
}

// Get the address of the l1 portal for this contract (taken from the input context)
#[aztec(private)]
fn get_this_portal_address() -> EthAddress {
context.this_portal_address()
}

// Get the address of this contract (taken from the input context)
#[aztec(private)]
fn get_this_address() -> AztecAddress {
Expand Down Expand Up @@ -206,12 +192,12 @@ contract Test {

// Purely exists for testing
#[aztec(public)]
fn create_l2_to_l1_message_public(amount: Field, secret_hash: Field) {
fn create_l2_to_l1_message_public(amount: Field, secret_hash: Field, portal_address: EthAddress) {
// Create a commitment to the amount
let note = DummyNote::new(amount, secret_hash);

// Public oracle call to emit new commitment.
context.message_portal(context.this_portal_address(), note.get_commitment());
context.message_portal(portal_address, note.get_commitment());
}

#[aztec(public)]
Expand Down Expand Up @@ -274,30 +260,27 @@ contract Test {
to: AztecAddress,
amount: Field,
secret: Field,
message_leaf_index: Field
message_leaf_index: Field,
portal_address: EthAddress
) {
let content_hash = get_mint_public_content_hash(to, amount);
// Consume message and emit nullifier
context.consume_l1_to_l2_message(
content_hash,
secret,
context.this_portal_address(),
message_leaf_index
);
context.consume_l1_to_l2_message(content_hash, secret, portal_address, message_leaf_index);
}

#[aztec(private)]
fn consume_mint_private_message(
secret_hash_for_redeeming_minted_notes: Field,
amount: Field,
secret_for_L1_to_L2_message_consumption: Field
secret_for_L1_to_L2_message_consumption: Field,
portal_address: EthAddress
) {
// Consume L1 to L2 message and emit nullifier
let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount);
context.consume_l1_to_l2_message(
content_hash,
secret_for_L1_to_L2_message_consumption,
context.this_portal_address()
portal_address
);
}

Expand Down Expand Up @@ -393,10 +376,13 @@ contract Test {
fn test_shared_mutable_private_getter_for_registry_contract(
contract_address_to_read: AztecAddress,
storage_slot_of_shared_mutable: Field,
address_to_get_in_registry: AztecAddress,
address_to_get_in_registry: AztecAddress
) {
// We have to derive this slot to get the location of the shared mutable inside the Map
let derived_slot = dep::aztec::hash::pedersen_hash([storage_slot_of_shared_mutable, address_to_get_in_registry.to_field()], 0);
let derived_slot = dep::aztec::hash::pedersen_hash(
[storage_slot_of_shared_mutable, address_to_get_in_registry.to_field()],
0
);
// It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly
let registry_private_getter: SharedMutablePrivateGetter<AztecAddress, 5> = SharedMutablePrivateGetter::new(context, contract_address_to_read, derived_slot);
let nullifier_public_key = registry_private_getter.get_current_value_in_private();
Expand All @@ -407,10 +393,14 @@ contract Test {
#[aztec(private)]
fn test_shared_mutable_private_getter(
contract_address_to_read: AztecAddress,
storage_slot_of_shared_mutable: Field,
storage_slot_of_shared_mutable: Field
) {
// It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly
let test: SharedMutablePrivateGetter<AztecAddress, 5> = SharedMutablePrivateGetter::new(context, contract_address_to_read, storage_slot_of_shared_mutable);
let test: SharedMutablePrivateGetter<AztecAddress, 5> = SharedMutablePrivateGetter::new(
context,
contract_address_to_read,
storage_slot_of_shared_mutable
);
let authorized = test.get_current_value_in_private();

emit_unencrypted_log_from_private(&mut context, authorized);
Expand All @@ -419,10 +409,7 @@ contract Test {
#[aztec(public)]
fn delay() {
// We use this as a util function to "mine a block"
dep::aztec::log::emit_unencrypted_log(
&mut context,
"dummy"
);
dep::aztec::log::emit_unencrypted_log(&mut context, "dummy");
}

// Purely exists for testing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Bridge has to be set as a minter on the token before it can be used

contract TokenBridge {
use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PublicMutable};
use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PublicMutable, SharedImmutable};

use dep::aztec::{context::Context, hash::compute_secret_hash};

Expand All @@ -20,25 +20,26 @@ contract TokenBridge {
#[aztec(storage)]
struct Storage {
token: PublicMutable<AztecAddress>,
portal_address: SharedImmutable<EthAddress>,
}

// Constructs the contract.
#[aztec(private)]
#[aztec(public)]
#[aztec(initializer)]
fn constructor(token: AztecAddress) {
let selector = FunctionSelector::from_signature("_initialize((Field))");
context.call_public_function(context.this_address(), selector, [token.to_field()]);
fn constructor(token: AztecAddress, portal_address: EthAddress) {
storage.token.write(token);
storage.portal_address.initialize(portal_address);
}
// docs:end:token_bridge_storage_and_constructor

#[aztec(private)]
fn get_portal_address() -> EthAddress {
context.this_portal_address()
storage.portal_address.read_private()
}

#[aztec(public)]
fn get_portal_address_public() -> EthAddress {
context.this_portal_address()
storage.portal_address.read_public()
}

// docs:start:claim_public
Expand All @@ -51,7 +52,7 @@ contract TokenBridge {
context.consume_l1_to_l2_message(
content_hash,
secret,
context.this_portal_address(),
storage.portal_address.read_public(),
message_leaf_index
);

Expand All @@ -72,7 +73,7 @@ contract TokenBridge {
) {
// Send an L2 to L1 message
let content = get_withdraw_content_hash(recipient, amount, caller_on_l1);
context.message_portal(context.this_portal_address(), content);
context.message_portal(storage.portal_address.read_public(), content);

// Burn tokens
Token::at(storage.token.read()).burn_public(context.msg_sender(), amount, nonce).call(&mut context);
Expand All @@ -92,7 +93,7 @@ contract TokenBridge {
context.consume_l1_to_l2_message(
content_hash,
secret_for_L1_to_L2_message_consumption,
context.this_portal_address()
storage.portal_address.read_private()
);

// Mint tokens on L2
Expand Down Expand Up @@ -120,7 +121,7 @@ contract TokenBridge {
) {
// Send an L2 to L1 message
let content = get_withdraw_content_hash(recipient, amount, caller_on_l1);
context.message_portal(context.this_portal_address(), content);
context.message_portal(storage.portal_address.read_private(), content);

// docs:start:call_assert_token_is_same
// Assert that user provided token address is same as seen in storage.
Expand All @@ -143,21 +144,6 @@ contract TokenBridge {
storage.token.read()
}

// /// Unconstrained ///

// docs:start:read_token
unconstrained fn token() -> pub AztecAddress {
storage.token.read()
}
// docs:end:read_token

#[aztec(public)]
#[aztec(internal)]
#[aztec(noinitcheck)]
fn _initialize(token: AztecAddress) {
storage.token.write(token);
}

// docs:start:call_mint_on_token
// This is a public call as we need to read from public storage.
// Also, note that user hashes their secret in private and only sends the hash in public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod util;
// Has two separate flows for private and public respectively
// Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1
contract Uniswap {
use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, Map, PublicMutable};
use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, Map, PublicMutable, SharedImmutable};
use dep::aztec::context::gas::GasOpts;

use dep::authwit::auth::{
Expand All @@ -24,9 +24,16 @@ contract Uniswap {
// tracks the nonce used to create the approval message for burning funds
// gets incremented each time after use to prevent replay attacks
nonce_for_burn_approval: PublicMutable<Field>,
portal_address: SharedImmutable<EthAddress>,
}
// docs:end:uniswap_setup

#[aztec(public)]
#[aztec(initializer)]
fn constructor(portal_address: EthAddress) {
storage.portal_address.initialize(portal_address);
}

// docs:start:swap_public
#[aztec(public)]
fn swap_public(
Expand Down Expand Up @@ -84,7 +91,7 @@ contract Uniswap {
secret_hash_for_L1_to_l2_message,
caller_on_L1
);
context.message_portal(context.this_portal_address(), content_hash);
context.message_portal(storage.portal_address.read_public(), content_hash);
}
// docs:end:swap_public

Expand Down Expand Up @@ -142,7 +149,7 @@ contract Uniswap {
secret_hash_for_L1_to_l2_message,
caller_on_L1
);
context.message_portal(context.this_portal_address(), content_hash);
context.message_portal(storage.portal_address.read_private(), content_hash);
}
// docs:end:swap_private

Expand Down Expand Up @@ -197,11 +204,12 @@ contract Uniswap {
// increment nonce_for_burn_approval so it won't be used again
storage.nonce_for_burn_approval.write(nonce_for_burn_approval + 1);

let this_portal_address = storage.portal_address.read_public();
// Exit to L1 Uniswap Portal !
TokenBridge::at(token_bridge).exit_to_l1_public(
context.this_portal_address(),
this_portal_address,
amount,
context.this_portal_address(),
this_portal_address,
nonce_for_burn_approval
).call(&mut context)
}
Expand Down
Loading

0 comments on commit 2d8a867

Please sign in to comment.