diff --git a/docs/docs/dev_docs/contracts/portals/data_structures.md b/docs/docs/dev_docs/contracts/portals/data_structures.md index b8e21dea115..96ead1a06c0 100644 --- a/docs/docs/dev_docs/contracts/portals/data_structures.md +++ b/docs/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/docs/dev_docs/contracts/portals/inbox.md b/docs/docs/dev_docs/contracts/portals/inbox.md index 41551eabe0e..ba47e4b8ddc 100644 --- a/docs/docs/dev_docs/contracts/portals/inbox.md +++ b/docs/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/docs/dev_docs/contracts/portals/main.md b/docs/docs/dev_docs/contracts/portals/main.md index 4af8dcdb944..b1ead86a80e 100644 --- a/docs/docs/dev_docs/contracts/portals/main.md +++ b/docs/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/docs/dev_docs/contracts/portals/outbox.md b/docs/docs/dev_docs/contracts/portals/outbox.md index bf33f06a38b..bbc1289c35d 100644 --- a/docs/docs/dev_docs/contracts/portals/outbox.md +++ b/docs/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/docs/dev_docs/contracts/portals/registry.md b/docs/docs/dev_docs/contracts/portals/registry.md index ddcf34c3959..2c1b561ba7a 100644 --- a/docs/docs/dev_docs/contracts/portals/registry.md +++ b/docs/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 | | -------------- | ----------- | diff --git a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol index fb5de27ae26..da3fba36088 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol @@ -24,6 +24,7 @@ interface IInbox { event L1ToL2MessageCancelled(bytes32 indexed entryKey); + // docs:start:send_l1_to_l2_message /** * @notice Inserts an entry into the Inbox * @dev Will emit `MessageAdded` with data for easy access by the sequencer @@ -40,7 +41,9 @@ interface IInbox { bytes32 _content, bytes32 _secretHash ) external payable returns (bytes32); + // docs:end:send_l1_to_l2_message + // docs:start:pending_l2_cancel /** * @notice Cancel a pending L2 message * @dev Will revert if the deadline have not been crossed - message only cancellable past the deadline @@ -53,7 +56,9 @@ interface IInbox { function cancelL2Message(DataStructures.L1ToL2Msg memory _message, address _feeCollector) external returns (bytes32 entryKey); + // docs:end:pending_l2_cancel + // docs:start:inbox_batch_consume /** * @notice Batch consumes entries from the Inbox * @dev Only callable by the rollup contract @@ -62,29 +67,38 @@ interface IInbox { * @param _feeCollector - The address to receive the "fee" */ function batchConsume(bytes32[] memory _entryKeys, address _feeCollector) external; + // docs:end:inbox_batch_consume + // docs:start:inbox_withdraw_fees /** * @notice Withdraws fees accrued by the sequencer */ function withdrawFees() external; + // docs:end:inbox_withdraw_fees + // docs:start:inbox_get /** * @notice Fetch an entry * @param _entryKey - The key to lookup * @return The entry matching the provided key */ function get(bytes32 _entryKey) external view returns (DataStructures.Entry memory); + // docs:end:inbox_get + // docs:start:inbox_contains /** * @notice Check if entry exists * @param _entryKey - The key to lookup * @return True if entry exists, false otherwise */ function contains(bytes32 _entryKey) external view returns (bool); + // docs:end:inbox_contains + // docs:start:inbox_compute_entry_key /// @notice Given a message, computes an entry key for the Inbox function computeEntryKey(DataStructures.L1ToL2Msg memory _message) external pure returns (bytes32); + // docs:end:inbox_compute_entry_key } diff --git a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol index 3c822b2823e..ecbfcfd98de 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol @@ -16,20 +16,25 @@ interface IOutbox { event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); + // docs:start:outbox_compute_entry_key /** * @notice Computes an entry key for the Outbox * @param _message - The L2 to L1 message * @return The key of the entry in the set */ function computeEntryKey(DataStructures.L2ToL1Msg memory _message) external returns (bytes32); + // docs:end:outbox_compute_entry_key + // docs:start:outbox_send_l1_msg /** * @notice Inserts an array of entries into the Outbox * @dev Only callable by the rollup contract * @param _entryKeys - Array of entry keys (hash of the message) - computed by the L2 counterpart and sent to L1 via rollup block */ function sendL1Messages(bytes32[] memory _entryKeys) external; + // docs:end:outbox_send_l1_msg + // docs:start:outbox_consume /** * @notice Consumes an entry from the Outbox * @dev Only meaningfully callable by portals, otherwise should never hit an entry @@ -38,18 +43,23 @@ interface IOutbox { * @return entryKey - The key of the entry removed */ function consume(DataStructures.L2ToL1Msg memory _message) external returns (bytes32 entryKey); + // docs:end:outbox_consume + // docs:start:outbox_get /** * @notice Fetch an entry * @param _entryKey - The key to lookup * @return The entry matching the provided key */ function get(bytes32 _entryKey) external view returns (DataStructures.Entry memory); + // docs:end:outbox_get + // docs:start:outbox_contains /** * @notice Check if entry exists * @param _entryKey - The key to lookup * @return True if entry exists, false otherwise */ function contains(bytes32 _entryKey) external view returns (bool); + // docs:end:outbox_contains } diff --git a/l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol b/l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol index 580d92a309f..0d184a521f2 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IRegistry.sol @@ -7,22 +7,38 @@ import {IInbox} from "./IInbox.sol"; import {IOutbox} from "./IOutbox.sol"; interface IRegistry { + // docs:start:registry_upgrade function upgrade(address _rollup, address _inbox, address _outbox) external returns (uint256); + // docs:end:registry_upgrade + // docs:start:registry_get_rollup function getRollup() external view returns (IRollup); + // docs:end:registry_get_rollup + // docs:start:registry_get_version_for function getVersionFor(address _rollup) external view returns (uint256); + // docs:end:registry_get_version_for + // docs:start:registry_get_inbox function getInbox() external view returns (IInbox); + // docs:end:registry_get_inbox + // docs:start:registry_get_outbox function getOutbox() external view returns (IOutbox); + // docs:end:registry_get_outbox + // docs:start:registry_get_snapshot function getSnapshot(uint256 _version) external view returns (DataStructures.RegistrySnapshot memory); + // docs:end:registry_get_snapshot + // docs:start:registry_get_current_snapshot function getCurrentSnapshot() external view returns (DataStructures.RegistrySnapshot memory); + // docs:end:registry_get_current_snapshot + // docs:start:registry_number_of_versions function numberOfVersions() external view returns (uint256); + // docs:end:registry_number_of_versions } diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index 251a8147643..f588c7c1d4d 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -8,6 +8,7 @@ pragma solidity >=0.8.18; * @notice Library that contains data structures used throughout the Aztec protocol */ library DataStructures { + // docs:start:data_structure_entry /** * @notice Entry struct - Done as struct to easily support extensions if needed * @param fee - The fee provided to sequencer for including in the inbox. 0 if Outbox (as not applicable). @@ -21,7 +22,9 @@ library DataStructures { uint32 version; uint32 deadline; } + // docs:end:data_structure_entry + // docs:start:l1_actor /** * @notice Actor on L1. * @param actor - The address of the actor @@ -31,7 +34,9 @@ library DataStructures { address actor; uint256 chainId; } + // docs:end:l1_actor + // docs:start:l2_actor /** * @notice Actor on L2. * @param actor - The aztec address of the actor @@ -41,7 +46,9 @@ library DataStructures { bytes32 actor; uint256 version; } + // docs:end:l2_actor + // docs:start:l1_to_l2_msg /** * @notice Struct containing a message from L1 to L2 * @param sender - The sender of the message @@ -59,7 +66,9 @@ library DataStructures { uint32 deadline; uint64 fee; } + // docs:end:l1_to_l2_msg + // docs:start:l2_to_l1_msg /** * @notice Struct containing a message from L2 to L1 * @param sender - The sender of the message @@ -71,7 +80,9 @@ library DataStructures { DataStructures.L1Actor recipient; bytes32 content; } + // docs:end:l2_to_l1_msg + // docs:start:registry_snapshot /** * @notice Struct for storing address of cross communication components and the block number when it was updated * @param rollup - The address of the rollup contract @@ -85,4 +96,5 @@ library DataStructures { address outbox; uint256 blockNumber; } + // docs:end:registry_snapshot } diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index 4188e380b07..40bdada2423 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -55,6 +55,7 @@ contract TokenPortal { return inbox.sendL2Message{value: msg.value}(actor, _deadline, contentHash, _secretHash); } + // docs:start:token_portal_cancel /** * @notice Cancel the L1 to L2 message * @dev only callable by the `canceller` of the message @@ -92,7 +93,9 @@ contract TokenPortal { underlying.transfer(msg.sender, _amount); return entryKey; } + // docs:end:token_portal_cancel + // docs:start:token_portal_withdraw /** * @notice Withdraw funds from the portal * @dev Second part of withdraw, must be initiated from L2 first as it will consume a message from outbox @@ -126,4 +129,5 @@ contract TokenPortal { return entryKey; } + // docs:end:token_portal_withdraw } diff --git a/l1-contracts/test/portals/UniswapPortal.sol b/l1-contracts/test/portals/UniswapPortal.sol index 048eeeeb739..8d68ff8861a 100644 --- a/l1-contracts/test/portals/UniswapPortal.sol +++ b/l1-contracts/test/portals/UniswapPortal.sol @@ -34,6 +34,7 @@ contract UniswapPortal { bytes32 contentHash; } + // docs:start:solidity_uniswap_swap /** * @notice Exit with funds from L2, perform swap on L1 and deposit output asset to L2 again * @dev `msg.value` indicates fee to submit message to inbox. Currently, anyone can call this method on your behalf. @@ -125,4 +126,5 @@ contract UniswapPortal { _aztecRecipient, amountOut, _deadlineForL1ToL2Message, _secretHash, _canceller ); } + // docs:end:solidity_uniswap_swap } diff --git a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr index 75aca44a9f7..a9fb5b021ba 100644 --- a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr @@ -91,6 +91,7 @@ contract NonNativeToken { // Mint Private Function // This mint function differs to the typical token mint function as it only allows minting // upon consuming valid messages from a token portal contract + // docs:start:non_native_token_mint #[aztec(private)] fn mint( amount: Field, @@ -110,10 +111,12 @@ contract NonNativeToken { let balance = storage.balances.at(owner); increment(balance, amount, owner); } + // docs:end:non_native_token_mint // Withdraws using user's private balance. // @dev Destroys 2 of user's notes and sends a message to the L1 portal contract. That message can then be consumed // by calling the `withdraw` function on the L1 portal contract (assuming the args are set correctly). + // docs:start:non_native_token_withdraw #[aztec(private)] fn withdraw( amount: Field, @@ -129,6 +132,7 @@ contract NonNativeToken { let content = get_withdraw_content_hash(amount, recipient, callerOnL1); context.message_portal(content); } + // docs:end:non_native_token_withdraw // Mint Public Function // This mint function differs to the typical token mint function as it only allows minting diff --git a/yarn-project/noir-libs/aztec-noir/src/context.nr b/yarn-project/noir-libs/aztec-noir/src/context.nr index 7043ec87b76..250853c2eab 100644 --- a/yarn-project/noir-libs/aztec-noir/src/context.nr +++ b/yarn-project/noir-libs/aztec-noir/src/context.nr @@ -162,13 +162,25 @@ impl PrivateContext { self.nullified_commitments.push(nullified_commitment); } - fn message_portal(&mut self, content: Field) { + // docs:start:context_message_portal + fn message_portal(&mut self, content: Field) + // docs:end:context_message_portal + { self.new_l2_to_l1_msgs.push(content); } // PrivateContextInputs must be temporarily passed in to prevent too many unknowns // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned - fn consume_l1_to_l2_message(&mut self, inputs: abi::PrivateContextInputs, msg_key: Field, content: Field, secret: Field) { + // docs:start:context_consume_l1_to_l2_message + fn consume_l1_to_l2_message( + &mut self, + inputs: abi::PrivateContextInputs, + msg_key: Field, + content: Field, + secret: Field + ) + // docs:end:context_consume_l1_to_l2_message + { let nullifier = process_l1_to_l2_message(inputs.block_data.l1_to_l2_messages_tree_root, inputs.call_context.storage_contract_address, msg_key, content, secret); // Push nullifier (and the "commitment" corresponding to this can be "empty")