Skip to content
Merged
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
30 changes: 10 additions & 20 deletions l1-contracts/test/portals/TokenPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ contract TokenPortal {
);

event DepositToAztecPrivate(
bytes32 secretHashForRedeemingMintedNotes,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This ^ was the hash in the transparent note. It's no longer there (and neither is L2 address) meaning that only the message secret "owns" the bridged tokens.

uint256 amount,
bytes32 secretHashForL2MessageConsumption,
bytes32 key,
uint256 index
uint256 amount, bytes32 secretHashForL2MessageConsumption, bytes32 key, uint256 index
);

IRegistry public registry;
Expand Down Expand Up @@ -76,26 +72,22 @@ contract TokenPortal {
// docs:start:deposit_private
/**
* @notice Deposit funds into the portal and adds an L2 message which can only be consumed privately on Aztec
* @param _secretHashForRedeemingMintedNotes - The hash of the secret to redeem minted notes privately on Aztec. The hash should be 254 bits (so it can fit in a Field element)
* @param _amount - The amount to deposit
* @param _secretHashForL2MessageConsumption - The hash of the secret consumable L1 to L2 message. The hash should be 254 bits (so it can fit in a Field element)
* @return The key of the entry in the Inbox and its leaf index
*/
function depositToAztecPrivate(
bytes32 _secretHashForRedeemingMintedNotes,
uint256 _amount,
bytes32 _secretHashForL2MessageConsumption
) external returns (bytes32, uint256) {
function depositToAztecPrivate(uint256 _amount, bytes32 _secretHashForL2MessageConsumption)
external
returns (bytes32, uint256)
{
// Preamble
IInbox inbox = IRollup(registry.getRollup()).INBOX();
DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, 1);

// Hash the message content to be reconstructed in the receiving contract
bytes32 contentHash = Hash.sha256ToField(
abi.encodeWithSignature(
"mint_private(bytes32,uint256)", _secretHashForRedeemingMintedNotes, _amount
)
);
// Hash the message content to be reconstructed in the receiving contract - the signature below does not correspond
// to a real function. It's just an identifier of an action.
bytes32 contentHash =
Hash.sha256ToField(abi.encodeWithSignature("mint_private(uint256)", _amount));

// Hold the tokens in the portal
underlying.safeTransferFrom(msg.sender, address(this), _amount);
Expand All @@ -105,9 +97,7 @@ contract TokenPortal {
inbox.sendL2Message(actor, contentHash, _secretHashForL2MessageConsumption);

// Emit event
emit DepositToAztecPrivate(
_secretHashForRedeemingMintedNotes, _amount, _secretHashForL2MessageConsumption, key, index
);
emit DepositToAztecPrivate(_amount, _secretHashForL2MessageConsumption, key, index);

return (key, index);
}
Expand Down
14 changes: 3 additions & 11 deletions l1-contracts/test/portals/TokenPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ contract TokenPortalTest is Test {
// this hash is just a random 32 byte string
bytes32 internal secretHashForL2MessageConsumption =
0x147e4fec49805c924e28150fc4b36824679bc17ecb1d7d9f6a9effb7fde6b6a0;
// this hash is just a random 32 byte string
bytes32 internal secretHashForRedeemingMintedNotes =
0x157e4fec49805c924e28150fc4b36824679bc17ecb1d7d9f6a9effb7fde6b6a0;

// params for withdraw:
address internal recipient = address(0xdead);
Expand Down Expand Up @@ -94,11 +91,7 @@ contract TokenPortalTest is Test {
return DataStructures.L1ToL2Msg({
sender: DataStructures.L1Actor(address(tokenPortal), block.chainid),
recipient: DataStructures.L2Actor(l2TokenAddress, 1),
content: Hash.sha256ToField(
abi.encodeWithSignature(
"mint_private(bytes32,uint256)", secretHashForRedeemingMintedNotes, amount
)
),
content: Hash.sha256ToField(abi.encodeWithSignature("mint_private(uint256)", amount)),
secretHash: secretHashForL2MessageConsumption,
index: _index
});
Expand Down Expand Up @@ -137,9 +130,8 @@ contract TokenPortalTest is Test {
// event we will get

// Perform op
(bytes32 leaf, uint256 index) = tokenPortal.depositToAztecPrivate(
secretHashForRedeemingMintedNotes, amount, secretHashForL2MessageConsumption
);
(bytes32 leaf, uint256 index) =
tokenPortal.depositToAztecPrivate(amount, secretHashForL2MessageConsumption);

assertEq(leaf, expectedLeaf, "returned leaf and calculated leaf should match");
assertEq(index, expectedIndex, "returned index and calculated index should match");
Expand Down
10 changes: 3 additions & 7 deletions l1-contracts/test/portals/UniswapPortal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ contract UniswapPortal {
* @param _uniswapFeeTier - The fee tier for the swap on UniswapV3
* @param _outputTokenPortal - The ethereum address of the output token portal
* @param _amountOutMinimum - The minimum amount of output assets to receive from the swap (slippage protection)
* @param _secretHashForRedeemingMintedNotes - The hash of the secret to redeem minted notes privately on Aztec. The hash should be 254 bits (so it can fit in a Field element)
* @param _secretHashForL1ToL2Message - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element)
* @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0)
* @return A hash of the L1 to L2 message inserted in the Inbox
Expand All @@ -169,7 +168,6 @@ contract UniswapPortal {
uint24 _uniswapFeeTier,
address _outputTokenPortal,
uint256 _amountOutMinimum,
bytes32 _secretHashForRedeemingMintedNotes,
bytes32 _secretHashForL1ToL2Message,
bool _withCaller,
// Avoiding stack too deep
Expand All @@ -195,13 +193,12 @@ contract UniswapPortal {
// prevent stack too deep errors
vars.contentHash = Hash.sha256ToField(
abi.encodeWithSignature(
"swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)",
"swap_private(address,uint256,uint24,address,uint256,bytes32,address)",
_inputTokenPortal,
_inAmount,
_uniswapFeeTier,
_outputTokenPortal,
_amountOutMinimum,
_secretHashForRedeemingMintedNotes,
_secretHashForL1ToL2Message,
_withCaller ? msg.sender : address(0)
)
Expand Down Expand Up @@ -247,9 +244,8 @@ contract UniswapPortal {
vars.outputAsset.approve(address(_outputTokenPortal), amountOut);

// Deposit the output asset to the L2 via its portal
return TokenPortal(_outputTokenPortal).depositToAztecPrivate(
_secretHashForRedeemingMintedNotes, amountOut, _secretHashForL1ToL2Message
);
return
TokenPortal(_outputTokenPortal).depositToAztecPrivate(amountOut, _secretHashForL1ToL2Message);
}
}
// docs:end:solidity_uniswap_swap_private
14 changes: 3 additions & 11 deletions l1-contracts/test/portals/UniswapPortal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ contract UniswapPortalTest is Test {
uint24 internal uniswapFeePool = 3000; // 0.3% fee
uint256 internal amountOutMinimum = 0;
bytes32 internal aztecRecipient = bytes32(uint256(0x3));
bytes32 internal secretHashForRedeemingMintedNotes = bytes32(uint256(0x4));

uint256 internal l2BlockNumber = 69;

Expand Down Expand Up @@ -140,26 +139,21 @@ contract UniswapPortalTest is Test {

/**
* L2 to L1 message to be added to the outbox -
* @param _secretHashForRedeemingMintedNotes - The hash of the secret to redeem minted notes privately on Aztec
* @param _caller - designated caller on L1 that will call the swap function - typically address(this)
* Set to address(0) if anyone can call.
*/
function _createUniswapSwapMessagePrivate(
bytes32 _secretHashForRedeemingMintedNotes,
address _caller
) internal view returns (bytes32) {
function _createUniswapSwapMessagePrivate(address _caller) internal view returns (bytes32) {
DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({
sender: DataStructures.L2Actor(l2UniswapAddress, 1),
recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid),
content: Hash.sha256ToField(
abi.encodeWithSignature(
"swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)",
"swap_private(address,uint256,uint24,address,uint256,bytes32,address)",
address(daiTokenPortal),
amount,
uniswapFeePool,
address(wethTokenPortal),
amountOutMinimum,
_secretHashForRedeemingMintedNotes,
secretHash,
_caller
)
Expand Down Expand Up @@ -572,8 +566,7 @@ contract UniswapPortalTest is Test {
})
];

bytes32 messageHashPortalChecksAgainst =
_createUniswapSwapMessagePrivate(secretHashForRedeemingMintedNotes, address(this));
bytes32 messageHashPortalChecksAgainst = _createUniswapSwapMessagePrivate(address(this));

bytes32 actualRoot;
bytes32 consumedRoot;
Expand Down Expand Up @@ -607,7 +600,6 @@ contract UniswapPortalTest is Test {
uniswapFeePool,
address(wethTokenPortal),
amountOutMinimum,
secretHashForRedeemingMintedNotes,
secretHash,
true,
outboxMessageMetadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,15 +386,13 @@ contract Test {

#[private]
fn consume_mint_private_message(
secret_hash_for_redeeming_minted_notes: Field,
amount: Field,
secret_for_L1_to_L2_message_consumption: Field,
portal_address: EthAddress,
message_leaf_index: Field,
) {
// Consume L1 to L2 message and emit nullifier
let content_hash =
get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount);
let content_hash = get_mint_private_content_hash(amount);
context.consume_l1_to_l2_message(
content_hash,
secret_for_L1_to_L2_message_consumption,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use dep::aztec::macros::aztec;

#[aztec]
contract TokenBridge {
use dep::aztec::prelude::{AztecAddress, EthAddress, PublicMutable, SharedImmutable};
use dep::aztec::prelude::{AztecAddress, EthAddress, SharedImmutable};

use dep::token_portal_content_hash_lib::{
get_mint_private_content_hash, get_mint_public_content_hash, get_withdraw_content_hash,
Expand All @@ -27,15 +27,15 @@ contract TokenBridge {
// Storage structure, containing all storage, and specifying what slots they use.
#[storage]
struct Storage<Context> {
token: PublicMutable<AztecAddress, Context>,
token: SharedImmutable<AztecAddress, Context>,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We now need to read this in private as well so changed PublicMutable to Shared.

portal_address: SharedImmutable<EthAddress, Context>,
}

// Constructs the contract.
#[public]
#[initializer]
fn constructor(token: AztecAddress, portal_address: EthAddress) {
storage.token.write(token);
storage.token.initialize(token);
storage.portal_address.initialize(portal_address);
}
// docs:end:token_bridge_storage_and_constructor
Expand Down Expand Up @@ -65,7 +65,7 @@ contract TokenBridge {
);

// Mint tokens
Token::at(storage.token.read()).mint_public(to, amount).call(&mut context);
Token::at(storage.token.read_public()).mint_public(to, amount).call(&mut context);
}
// docs:end:claim_public

Expand All @@ -84,39 +84,42 @@ contract TokenBridge {
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,
);
Token::at(storage.token.read_public())
.burn_public(context.msg_sender(), amount, nonce)
.call(&mut context);
}
// docs:end:exit_to_l1_public

// docs:start:claim_private
// Consumes a L1->L2 message and calls the token contract to mint the appropriate amount in private assets
// User needs to call token.redeem_shield() to get the private assets
// TODO(#8416): Consider creating a truly private claim flow.
/// Claims the bridged tokens and makes them accessible in private. Note that recipient's address is not revealed
/// but the amount is. Hence it's most likely possible to determine to which L1 deposit this claim corresponds to
/// (unless there are multiple pending deposits of the same amount).
/// TODO(#8416): Consider creating a truly private claim flow.
#[private]
fn claim_private(
secret_hash_for_redeeming_minted_notes: Field, // secret hash used to redeem minted notes at a later time. This enables anyone to call this function and mint tokens to a user on their behalf
recipient: AztecAddress, // recipient of the bridged tokens
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We are no longer redeeming "to" a TransparentNote and instead we just mint a real ValueNote to a recipient.

amount: Field,
secret_for_L1_to_L2_message_consumption: Field, // secret used to consume the L1 to L2 message
message_leaf_index: Field,
) {
// Consume L1 to L2 message and emit nullifier
let content_hash =
get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount);
let content_hash = get_mint_private_content_hash(amount);
context.consume_l1_to_l2_message(
content_hash,
secret_for_L1_to_L2_message_consumption,
storage.portal_address.read_private(),
message_leaf_index,
);

// Mint tokens on L2
// `mint_private` on token is public. So we call an internal public function
// which then calls the public method on the token contract.
// Since the secret_hash is passed, no secret is leaked.
TokenBridge::at(context.this_address())
._call_mint_on_token(amount, secret_hash_for_redeeming_minted_notes)
.enqueue(&mut context);
// Read the token address from storage
let token_address = storage.token.read_private();

// At last we mint the tokens
// docs:start:call_mint_on_token
Token::at(token_address).mint_to_private(context.msg_sender(), recipient, amount).call(
&mut context,
);
// docs:end:call_mint_on_token
}
// docs:end:claim_private

Expand Down Expand Up @@ -147,26 +150,18 @@ contract TokenBridge {
#[public]
#[view]
fn get_token() -> AztecAddress {
storage.token.read()
storage.token.read_public()
}
// docs:end:get_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
// meaning only user can `redeem_shield` at a later time with their secret.
#[public]
#[internal]
fn _call_mint_on_token(amount: Field, secret_hash: Field) {
Token::at(storage.token.read()).mint_private_old(amount, secret_hash).call(&mut context);
}
// docs:end:call_mint_on_token

// docs:start:assert_token_is_same
#[public]
#[internal]
fn _assert_token_is_same(token: AztecAddress) {
assert(storage.token.read().eq(token), "Token address is not the same as seen in storage");
assert(
storage.token.read_public().eq(token),
"Token address is not the same as seen in storage",
);
}
// docs:end:assert_token_is_same
}
Loading