From 6905fb906199ab1a69c4c263029f9a0b8708ee4d Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:03:55 +0200 Subject: [PATCH] fix(docs): use code snippet macros in bridge docs (#2205) fixes: https://github.com/AztecProtocol/aztec-packages/issues/2193 Updates the bridge docs code such that it uses code snippets (which can change) rather than having static code --- .../contracts/portals/data_structures.md | 51 +----- docs/dev_docs/contracts/portals/inbox.md | 43 +---- docs/dev_docs/contracts/portals/main.md | 168 ++---------------- docs/dev_docs/contracts/portals/outbox.md | 28 +-- docs/dev_docs/contracts/portals/registry.md | 44 +---- 5 files changed, 41 insertions(+), 293 deletions(-) diff --git a/docs/dev_docs/contracts/portals/data_structures.md b/docs/dev_docs/contracts/portals/data_structures.md index b8e21de..96ead1a 100644 --- a/docs/dev_docs/contracts/portals/data_structures.md +++ b/docs/dev_docs/contracts/portals/data_structures.md @@ -10,14 +10,7 @@ The `DataStructures` are structs that we are using throughout the message infras An entry for the messageboxes multi-sets. -```solidity title="DataStructures.sol" - struct Entry { - uint64 fee; - uint32 count; - uint32 version; - uint32 deadline; - } -``` +#include_code data_structure_entry l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -31,12 +24,7 @@ An entry for the messageboxes multi-sets. An entity on L1, specifying the address and the chainId for the entity. Used when specifying sender/recipient with an entity that is on L1. -```solidity title="DataStructures.sol" - struct L1Actor { - address actor; - uint256 chainId; - } -``` +#include_code l1_actor l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -48,12 +36,7 @@ An entity on L1, specifying the address and the chainId for the entity. Used whe An entity on L2, specifying the address and the version for the entity. Used when specifying sender/recipient with an entity that is on L2. -```solidity title="DataStructures.sol" - struct L2Actor { - bytes32 actor; - uint256 version; - } -``` +#include_code l2_actor l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -64,16 +47,7 @@ An entity on L2, specifying the address and the version for the entity. Used whe A message that is sent from L1 to L2. -```solidity title="DataStructures.sol" - struct L1ToL2Msg { - L1Actor sender; - L2Actor recipient; - bytes32 content; - bytes32 secretHash; - uint32 deadline; - uint64 fee; - } -``` +#include_code l1_to_l2_msg l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -88,13 +62,7 @@ A message that is sent from L1 to L2. A message that is sent from L2 to L1. -```solidity title="DataStructures.sol" - struct L2ToL1Msg { - DataStructures.L2Actor sender; - DataStructures.L1Actor recipient; - bytes32 content; - } -``` +#include_code l2_to_l1_msg l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -106,14 +74,7 @@ A message that is sent from L2 to L1. A snapshot of the registry values. -```solidity title="DataStructures.sol" - struct RegistrySnapshot { - address rollup; - address inbox; - address outbox; - uint256 blockNumber; - } -``` +#include_code registry_snapshot l1-contracts/src/core/libraries/DataStructures.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | diff --git a/docs/dev_docs/contracts/portals/inbox.md b/docs/dev_docs/contracts/portals/inbox.md index 41551ea..ba47e4b 100644 --- a/docs/dev_docs/contracts/portals/inbox.md +++ b/docs/dev_docs/contracts/portals/inbox.md @@ -10,14 +10,8 @@ The `Inbox` is a contract deployed on L1 that handles message passing from L1 to Sends a message from L1 to L2. -```solidity -function sendL2Message( - DataStructures.L2Actor memory _recipient, - uint32 _deadline, - bytes32 _content, - bytes32 _secretHash -) external payable returns (bytes32); -``` +#include_code send_l1_to_l2_message l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity + | Name | Type | Description | | -------------- | ------- | ----------- | @@ -40,12 +34,7 @@ function sendL2Message( ## `cancelL2Message()` Cancels a message that has not yet been consumed. -```solidity -function cancelL2Message( - DataStructures.L1ToL2Msg memory _message, - address _feeCollector -) external returns (bytes32 entryKey); -``` +#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -63,9 +52,8 @@ function cancelL2Message( Allows the `Rollup` to consume multiple messages in a single transaction. -```solidity -function batchConsume(bytes32[] memory _entryKeys, address _feeCollector) external; -``` +#include_code inbox_batch_consume l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity + | Name | Type | Description | | -------------- | ------- | ----------- | | `_entryKeys` | `bytes32[]` | The entry keys (message hashs) to consume | @@ -84,9 +72,7 @@ Will claim the fees that has accrued to the `msg.sender` from consuming messages Let the sequencer withdraw fees from the inbox. -```solidity -function withdrawFees() external; -``` +#include_code inbox_withdraw_fees l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity #### Edge cases @@ -95,10 +81,7 @@ function withdrawFees() external; ## `get()` Retrieves the `entry` for a given message. The entry contains fee, number of occurrences, deadline and version information. -```solidity -function get(bytes32 _entryKey) - external view returns (DataStructures.Entry memory); -``` +#include_code inbox_get l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -112,11 +95,7 @@ function get(bytes32 _entryKey) ## `contains()` Returns whether the key exists in the inbox. -```solidity -function contains( - bytes32 _entryKey -) external view returns (bool); -``` +#include_code inbox_contains l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -126,11 +105,7 @@ function contains( ## `computeEntryKey()` Computes the hash of a message. -```solidity -function computeEntryKey( - DataStructures.L1ToL2Msg memory _message -) external pure returns (bytes32 entryKey); -``` +#include_code inbox_compute_entry_key l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | diff --git a/docs/dev_docs/contracts/portals/main.md b/docs/dev_docs/contracts/portals/main.md index 4af8dcd..b1ead86 100644 --- a/docs/dev_docs/contracts/portals/main.md +++ b/docs/dev_docs/contracts/portals/main.md @@ -30,29 +30,14 @@ Should we discard the use of the L2Actor struct and use the individual fields in With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. -```solidity title="IInbox.sol" - function sendL2Message( - DataStructures.L2Actor memory _recipient, - uint32 _deadline, - bytes32 _content, - bytes32 _secretHash - ) external payable returns (bytes32); -``` +#include_code send_l1_to_l2_message l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity As time passes, a sequencer will see your tx, the juicy fee provided and include it in a rollup block. Upon inclusion, it is removed from L1, and made available to be consumed on L2. To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. The `msg_key` is the hash of the message produced from the `sendL2Message` call, the `content` is the content of the message, and the `secret` is the pre-image hashed to compute the `secretHash`. -```rust title="context.nr" - fn consume_l1_to_l2_message( - &mut self, - inputs: abi::PrivateContextInputs, - msg_key: Field, - content: Field, - secret: Field - ) -``` +#include_code context_consume_l1_to_l2_message /yarn-project/noir-libs/aztec-noir/src/context.nr rust Computing the `content` might be a little clunky in its current form, as we are still adding a number of bytes utilities. A good example exists within the [Non-native token example](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/hash.nr). @@ -62,27 +47,7 @@ The `inputs` that is passed into `consume_l1_to_l2_message` are only temporary, An example usage of this flow is a token bridge, in the Aztec contract a `mint` function consumes a message from L1 and mints tokens to a user. Note that we are using a private function, as we don't want to expose the user that is receiving the tokens publicly. -```rust title="NonNativeTokenContract.nr" -// mints token upon consuming valid messages from portal -fn mint( - ... - amount: Field, - owner: Field, - msg_key: Field, - secret: Field, -) -> distinct pub abi::PrivateCircuitPublicInputs { - ... - let content_hash = get_mint_content_hash(amount, owner, canceller); - - // Consume the message from L1 - context.consume_l1_to_l2_message(inputs, msg_key, content_hash, secret); - - // Mint the tokens to the owner - let balance = storage.balances.at(owner); - send_note(&mut context, balance, amount, owner); - ... -} -``` +#include_code non_native_token_mint yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr rust After the transaction has been mined, the message is consumed, and the tokens have been minted on Aztec and are ready for use by the user. A consumed message cannot be consumed again. @@ -98,9 +63,7 @@ The portal must ensure that the sender is as expected. One way to do this, is to To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as field). -```rust title="context.nr" - fn message_portal(&mut self, content: Field) -``` +#include_code context_message_portal /yarn-project/noir-libs/aztec-noir/src/context.nr rust When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). @@ -110,68 +73,17 @@ Access control on the L1 portal contract is essential to prevent consumption of As earlier, we can use a token bridge as an example. In this case, we are burning tokens on L2 and sending a message to the portal to free them on L1. -```rust title="NonNativeTokenContract.nr" -// burns token and sends a message to the portal -fn withdraw( - amount: Field, - sender: Field, - recipient: Field, - callerOnL1: Field, -) -> distinct pub abi::PrivateCircuitPublicInputs { - ... - let sender_balance = storage.balances.at(sender); - spend_notes(&mut context, sender_balance, amount, sender); - - let content = get_withdraw_content_hash(amount, recipient, callerOnL1); - context.message_portal(content); - ... -} -``` +#include_code non_native_token_withdraw yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr rust When the transaction is included in a rollup block the message will be inserted into the `Outbox`, where the recipient portal can consume it from. When consuming, the `msg.sender` must match the `recipient` meaning that only portal can actually consume the message. -```solidity title="IOutbox.sol" -struct L2ToL1Msg { - DataStructures.L2Actor sender; - DataStructures.L1Actor recipient; - bytes32 content; -} +#include_code l2_to_l1_msg l1-contracts/src/core/libraries/DataStructures.sol solidity -function consume(DataStructures.L2ToL1Msg memory _message) - external - returns (bytes32 entryKey); -``` +#include_code outbox_consume l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity As noted earlier, the portal contract should check that the sender is as expected. In the example below, we support only one sender contract (stored in `l2TokenAddress`) so we can just pass it as the sender, that way we will only be able to consume messages from that contract. If multiple senders are supported, you could use a have `mapping(address => bool) allowed` and check that `allowed[msg.sender]` is `true`. -```solidity title="TokenPortal.sol" -function withdraw(uint256 _amount, address _recipient, bool _withCaller) - external - returns (bytes32) - { - // Create the message structure - DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2TokenAddress, version), - recipient: DataStructures.L1Actor(address(this), block.chainid), - content: Hash.sha256ToField( - abi.encodeWithSignature( - "withdraw(uint256,address,address)", - _amount, - _recipient, - _withCaller ? msg.sender : address(0) - ) - ) - }); - - // Consume the message - bytes32 entryKey = registry.getOutbox().consume(message); - - // Transfer the tokens to the user - underlying.transfer(_recipient, _amount); - - return entryKey; - } -``` +#include_code token_portal_withdraw l1-contracts/test/portals/TokenPortal.sol solidity ## How to deploy a contract with a portal @@ -227,42 +139,11 @@ As this requires logic on the portal itself, it is not something that the protoc The portal can call the `cancelL2Message` at the `Inbox` when `block.timestamp > deadline` for the message. -```solidity title="IInbox.sol" -function cancelL2Message( - DataStructures.L1ToL2Msg memory _message, - address _feeCollector -) external returns (bytes32 entryKey); -``` +#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity Building on our token example from earlier, this can be called like: -```solidity title="TokenPortal.sol" -function cancelL1ToAztecMessage( - bytes32 _to, - uint256 _amount, - uint32 _deadline, - bytes32 _secretHash, - uint64 _fee - ) external returns (bytes32) { - IInbox inbox = registry.getInbox(); - DataStructures.L1Actor memory l1Actor = DataStructures.L1Actor(address(this), block.chainid); - DataStructures.L2Actor memory l2Actor = DataStructures.L2Actor(l2TokenAddress, 1); - DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ - sender: l1Actor, - recipient: l2Actor, - content: Hash.sha256ToField( - abi.encodeWithSignature("mint(uint256,bytes32,address)", _amount, _to, msg.sender) - ), - secretHash: _secretHash, - deadline: _deadline, - fee: _fee - }); - bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // Ensures that `msg.sender == canceller` by using `msg.sender` in the hash computation. - underlying.transfer(msg.sender, _amount); - return entryKey; - } -``` +#include_code token_portal_cancel l1-contracts/test/portals/TokenPortal.sol solidity The example above ensure that the user can cancel their message if it is underpriced. @@ -286,34 +167,7 @@ bytes memory message = abi.encodeWithSignature( This way, the message can be consumed by the portal contract, but only if the caller is the designated caller. By being a bit clever when specifying the designated caller, we can ensure that the calls are done in the correct order. For the Uniswap example, say that we have token portals implemented as we have done throughout this page, and n Uniswap portal implementing the designated caller: -```solidity title="UniswapPortal.sol" - function swap( - address _inputTokenPortal, - uint256 _inAmount, - uint24 _uniswapFeeTier, - address _outputTokenPortal, - uint256 _amountOutMinimum, - bytes32 _aztecRecipient, - bytes32 _secretHash, - uint32 _deadlineForL1ToL2Message, - address _canceller, - bool _withCaller - ) public payable returns (bytes32) { - // Withdraw the input asset from the portal with designated caller - TokenPortal(_inputTokenPortal).withdraw(_inAmount, address(this), true); - - // Consume message to Uniswap portal (self) - registry.getOutbox().consume(...); - - // swap... - uint256 amountOut = ROUTER.exactInputSingle(swapParams); - - // Deposit the output asset to the L2 via its portal - return TokenPortal(_outputTokenPortal).depositToAztec{value: msg.value}( - _aztecRecipient, amountOut, _deadlineForL1ToL2Message, _secretHash, _canceller - ); - } -``` +#include_code solidity_uniswap_swap l1-contracts/test/portals/UniswapPortal.sol solidity We could then have withdraw transactions (on L2) where we are specifying the `UniswapPortal` as the caller. Because the order of the calls are specified in the contract, and that it reverts if any of them fail, we can be sure that it will execute the withdraw first, then the swap and then the deposit. Since only the `UniswapPortal` is able to execute the withdraw, we can be sure that the ordering is ensured. However, note that this means that if it for some reason is impossible to execute the batch (say prices moved greatly), the user will be stuck with the funds on L1 unless the `UniswapPortal` implements proper error handling! diff --git a/docs/dev_docs/contracts/portals/outbox.md b/docs/dev_docs/contracts/portals/outbox.md index bf33f06..bbc1289 100644 --- a/docs/dev_docs/contracts/portals/outbox.md +++ b/docs/dev_docs/contracts/portals/outbox.md @@ -10,9 +10,7 @@ The `Outbox` is a contract deployed on L1 that handles message passing from the Inserts multiple messages from the `Rollup`. -```solidity -function sendL1Messages(bytes32[] memory _entryKey) external; -``` +#include_code outbox_send_l1_msg l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -27,11 +25,8 @@ function sendL1Messages(bytes32[] memory _entryKey) external; Allows a recipient to consume a message from the `Outbox`. -```solidity -function consume( - DataStructures.L2ToL1Msg memory _message -) external returns (bytes32 entryKey); -``` +#include_code outbox_consume l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity + | Name | Type | Description | | -------------- | ------- | ----------- | @@ -48,10 +43,7 @@ function consume( ## `get()` Retrieves the `entry` for a given message. The entry contains fee, occurrences, deadline and version information. -```solidity -function get(bytes32 _entryKey) - external view returns (DataStructures.Entry memory); -``` +#include_code outbox_get l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -64,11 +56,7 @@ function get(bytes32 _entryKey) ## `contains()` Returns whether the key is found in the inbox. -```solidity -function contains( - bytes32 _entryKey -) external view returns (bool); -``` +#include_code outbox_contains l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | @@ -78,11 +66,7 @@ function contains( ## `computeEntryKey()` Computes the hash of a message. -```solidity -function computeEntryKey( - DataStructures.L2ToL1Msg memory _message -) external pure returns (bytes32 entryKey); -``` +#include_code outbox_compute_entry_key l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | diff --git a/docs/dev_docs/contracts/portals/registry.md b/docs/dev_docs/contracts/portals/registry.md index ddcf34c..2c1b561 100644 --- a/docs/dev_docs/contracts/portals/registry.md +++ b/docs/dev_docs/contracts/portals/registry.md @@ -10,9 +10,7 @@ The registry is a contract deployed on L1, that contains addresses for the `Roll Retrieves the number of versions that have been deployed. -```solidity -function numberOfVersions() external view returns (uint256); -``` +#include_code registry_number_of_versions l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -21,9 +19,7 @@ function numberOfVersions() external view returns (uint256); ## `getRollup()` Retrieves the current rollup contract. -```solidity -function getRollup() external view returns (IRollup); -``` +#include_code registry_get_rollup l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -33,9 +29,7 @@ function getRollup() external view returns (IRollup); Retrieves the current inbox contract. -```solidity -function getInbox() external view returns (IInbox); -``` +#include_code registry_get_inbox l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -45,9 +39,7 @@ function getInbox() external view returns (IInbox); Retrieves the current inbox contract. -```solidity -function getOutbox() external view returns (IOutbox); -``` +#include_code registry_get_outbox l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -56,9 +48,8 @@ function getOutbox() external view returns (IOutbox); ## `getVersionFor(address _rollup)` Retrieve the version of a specific rollup contract. -```solidity -function getVersionFor(address _rollup) external view returns (uint256); -``` + +#include_code registry_get_version_for l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -72,20 +63,8 @@ Will revert with `Registry__RollupNotRegistered(_rollup)` if the rollup have not Retrieve the snapshot of a specific version. -```solidity -// Snippet from DataStructures.sol -struct RegistrySnapshot { - address rollup; - address inbox; - address outbox; - uint256 blockNumber; - } - -function getSnapshot(uint256 _version) - external - view - returns (DataStructures.RegistrySnapshot memory); -``` +#include_code registry_snapshot l1-contracts/src/core/libraries/DataStructures.sol solidity +#include_code registry_get_snapshot l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- | @@ -100,12 +79,7 @@ function getSnapshot(uint256 _version) Retrieves the snapshot for the current version. -```solidity -function getCurrentSnapshot() - external - view - returns (DataStructures.RegistrySnapshot memory); -``` +#include_code registry_get_current_snapshot l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol solidity | Name | Description | | -------------- | ----------- |