diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md index 18f05ea24..64042af57 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md @@ -11,9 +11,10 @@ The application keeps a dedicated region of machine memory called the **accounts An application supports emergency withdrawal only if: -1. It maintains an accounts drive, and -2. The drive's layout matches the [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md) the application was deployed with. -3. The WithdrawalOutputBuilder contract configured in the application can decode the account and build a valid output to withdraw the assets +1. It maintains an accounts drive. +2. The drive's layout matches the [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md) used when the application was deployed. +3. Every account record stores its owner address in the final 20 bytes. +4. The configured withdrawal output builder can decode each account and produce a valid withdrawal output. If the layout the guest writes and the config the contract was given disagree, proofs will not validate and funds cannot be withdrawn. @@ -25,19 +26,15 @@ The [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md) describes - `log2MaxNumOfAccounts` sets how many accounts fit (the tree depth); - `log2LeavesPerAccount` sets each record's size, which is `2^(5 + log2LeavesPerAccount)` bytes. -For the single-token case (see [`UsdWithdrawalOutputBuilder`](../contracts/withdrawal/usd-withdrawal-output-builder.md)), each record is 32 bytes: an 8-byte little-endian balance, followed by the 20-byte owner address, followed by padding. +For the single-token case, each record is exactly 32 bytes. The [`UsdWithdrawalOutputBuilder`](../contracts/withdrawal/usd-withdrawal-output-builder.md) reads the first 12 bytes as a little-endian `uint96` balance and the final 20 bytes as the owner's address. There is no padding between these fields. ## Creating the accounts drive The accounts drive is a standard Cartesi Machine drive, declared in your project's `cartesi.toml` alongside every other drive. The [Advanced configuration](../../development/advanced-configuration.md#drives) guide covers how drives are defined and built in general; the accounts drive is distinctive only in that it is left raw, so the guest can write balance records into it directly. -Declare it next to the root drive as an empty, raw, unmounted flash drive, and set `final_hash = true` so the build produces the machine hash that on-chain deployment requires: +Declare it next to the root drive as an empty, raw, unmounted flash drive. `cartesi build` computes and stores the final machine hash automatically: ```toml -[machine] -# ...your existing machine settings... -final_hash = true - # The application and OS, built from your Dockerfile. [drives.root] builder = "docker" @@ -53,7 +50,7 @@ mount = false user = "dapp" ``` -Leaving the drive raw and unmounted is deliberate. Rather than layering a filesystem on top, the guest opens the block device directly (for example `/dev/pmem1`) and writes fixed-size records at deterministic offsets. That predictable layout is precisely what allows the drive to be Merkle-proven against the machine state after foreclosure. The [Common drive options](../../development/advanced-configuration.md#common-drive-options) reference explains each field used above. +Leaving the drive raw and unmounted allows the guest to open the block device directly, for example `/dev/pmem1`, and write fixed-size records at deterministic offsets. This predictable layout allows the drive to be proven against the machine state after foreclosure. The [Common drive options](../../development/advanced-configuration.md#common-drive-options) reference explains each field used above. Two properties of the drive must agree with the [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md): @@ -68,7 +65,7 @@ You rarely need to write the drive by hand. A ledger library maintains the accou ## The account encoding must round-trip -The bytes the guest writes for an account must be the same bytes the on-chain [withdrawal output builder](../contracts/withdrawal/iwithdrawal-output-builder.md) decodes at withdrawal time. For the USD builder, that means the `(owner, balance)` encoding the guest produces must match what the builder reads back to build the transfer. +The bytes written by the guest must match the account format decoded by the on-chain [withdrawal output builder](../contracts/withdrawal/iwithdrawal-output-builder.md). For the USD builder, write the balance into bytes 0 through 11 in little-endian order and the owner address into bytes 12 through 31. The builder reads those same bytes when it creates the token-transfer output. :::note Emergency withdrawal relies on four descriptions of the accounts drive agreeing: the layout the **guest** writes, the **`WithdrawalConfig`** on-chain, the parameters used to **generate proofs** off-chain, and the account encoding the **output builder** decodes. Choose these together at deploy time. See [Withdrawal Contracts Overview](../contracts/withdrawal/overview.md#the-four-way-agreement). diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application-factory.md index 164950726..9daf5e1a2 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application-factory.md @@ -2,152 +2,146 @@ id: application-factory title: ApplicationFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/ApplicationFactory.sol - title: Application Factory contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/ApplicationFactory.sol + title: ApplicationFactory contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/IApplicationFactory.sol + title: IApplicationFactory interface --- -The **ApplicationFactory** contract is a tool for reliably deploying new instances of the [`Application`](../contracts/application.md) contract with or without a specified salt value for address derivation. +The **ApplicationFactory** deploys [`Application`](./application.md) contracts directly or at deterministic `CREATE2` addresses. -Additionally, it provides a function to calculate the address of a potential new `CartesiDApp` contract based on input parameters. +Every Application created by one factory uses the same immutable [refund output builder](./refund/overview.md). The caller still chooses the validator, owner, template hash, input box, and withdrawal configuration for each deployment. -This contract ensures efficient and secure deployment of `Application` contracts within the Cartesi Rollups framework. +## `constructor()` -## Functions +```solidity +constructor(IRefundOutputBuilder refundOutputBuilder) +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `refundOutputBuilder` | `IRefundOutputBuilder` | Builder assigned to every Application deployed by this factory | -### `newApplication()` +## `newApplication()` ```solidity function newApplication( IOutputsMerkleRootValidator outputsMerkleRootValidator, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IInputBox inputBox, WithdrawalConfig calldata withdrawalConfig -) external override returns (IApplication) +) external returns (IApplication appContract) ``` -Deploys a new Application contract without a salt value for address derivation. +Deploys an Application with the standard `CREATE` opcode. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Initial output validator | +| `appOwner` | `address` | Nonzero initial Application owner | +| `templateHash` | `bytes32` | Initial machine state hash | +| `inputBox` | `IInputBox` | Input box used by the Application and its portals | +| `withdrawalConfig` | `WithdrawalConfig` | Guardian, accounts-drive geometry, and withdrawal builder; use a zero-valued config to disable recovery | -| Name | Type | Description | -|------|------|-------------| -| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The initial outputs Merkle root validator contract | -| `appOwner` | `address` | Address of the owner of the application | -| `templateHash` | `bytes32` | Hash of the template for the application | -| `dataAvailability` | `bytes` | The data availability solution | -| `withdrawalConfig` | `WithdrawalConfig` | The withdrawal configuration (see [WithdrawalConfig](./withdrawal/withdrawal-config.md)). Pass a zero-valued config to deploy without emergency withdrawal | +Returns the deployed Application and emits `ApplicationCreated`. -**Return Values** +| Return value | Type | Description | +| --- | --- | --- | +| `appContract` | `IApplication` | Deployed Application contract | -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `IApplication` | The deployed Application contract | - -### `newApplication()` (with salt) +## `newApplication()` with salt ```solidity function newApplication( IOutputsMerkleRootValidator outputsMerkleRootValidator, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IInputBox inputBox, WithdrawalConfig calldata withdrawalConfig, bytes32 salt -) external override returns (IApplication) +) external returns (IApplication appContract) ``` -Deploys a new `Application` contract with a specified salt value for address derivation. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The initial outputs Merkle root validator contract | -| `appOwner` | `address` | Address of the owner of the application | -| `templateHash` | `bytes32` | Hash of the template for the application | -| `dataAvailability` | `bytes` | The data availability solution | -| `withdrawalConfig` | `WithdrawalConfig` | The withdrawal configuration (see [WithdrawalConfig](./withdrawal/withdrawal-config.md)). Pass a zero-valued config to deploy without emergency withdrawal | -| `salt` | `bytes32` | Salt value for address derivation | +Deploys the same configuration with `CREATE2`. The address depends on every constructor value, the factory's immutable refund builder, and `salt`. -**Return Values** +| Parameter | Type | Description | +| --- | --- | --- | +| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Initial output validator | +| `appOwner` | `address` | Nonzero initial Application owner | +| `templateHash` | `bytes32` | Initial machine state hash | +| `inputBox` | `IInputBox` | Input box used by the Application and its portals | +| `withdrawalConfig` | `WithdrawalConfig` | Guardian, accounts-drive geometry, and withdrawal builder; use a zero-valued config to disable recovery | +| `salt` | `bytes32` | Value used to derive the deterministic deployment address | -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `IApplication` | The deployed Application contract | +| Return value | Type | Description | +| --- | --- | --- | +| `appContract` | `IApplication` | Deployed Application contract | -### `calculateApplicationAddress()` +## `calculateApplicationAddress()` ```solidity function calculateApplicationAddress( IOutputsMerkleRootValidator outputsMerkleRootValidator, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IInputBox inputBox, WithdrawalConfig calldata withdrawalConfig, bytes32 salt -) external view override returns (address) +) external view returns (address appContract) ``` -Calculates the address of a potential new Application contract based on input parameters. +Returns the address at which the salted `newApplication` overload would deploy the Application. It does not deploy a contract. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Initial output validator | +| `appOwner` | `address` | Nonzero initial Application owner | +| `templateHash` | `bytes32` | Initial machine state hash | +| `inputBox` | `IInputBox` | Input box used by the Application and its portals | +| `withdrawalConfig` | `WithdrawalConfig` | Guardian, accounts-drive geometry, and withdrawal builder; use a zero-valued config to disable recovery | +| `salt` | `bytes32` | Value used to derive the deterministic deployment address | -| Name | Type | Description | -|------|------|-------------| -| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The initial outputs Merkle root validator contract | -| `appOwner` | `address` | Address of the owner of the application | -| `templateHash` | `bytes32` | Hash of the template for the application | -| `dataAvailability` | `bytes` | The data availability solution | -| `withdrawalConfig` | `WithdrawalConfig` | The withdrawal configuration (see [WithdrawalConfig](./withdrawal/withdrawal-config.md)). Pass a zero-valued config to deploy without emergency withdrawal | -| `salt` | `bytes32` | Salt value for address derivation | +| Return value | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Address calculated for the Application | -**Return Values** +Use exactly the same factory and arguments for calculation and deployment. Changing the input box, validator, withdrawal configuration, or any other constructor value changes the resulting address. -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `address` | Address of the potential new Application contract | - -## Events - -### `ApplicationCreated()` +## `ApplicationCreated` ```solidity event ApplicationCreated( - IOutputsMerkleRootValidator outputsMerkleRootValidator, + IOutputsMerkleRootValidator indexed outputsMerkleRootValidator, address appOwner, bytes32 templateHash, - bytes dataAvailability, + IInputBox inputBox, WithdrawalConfig withdrawalConfig, IApplication appContract ) ``` -A new Application contract was deployed. +Emitted after either deployment method succeeds. -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The outputs Merkle root validator contract | -| `appOwner` | `address` | The owner of the application | -| `templateHash` | `bytes32` | The template hash | -| `dataAvailability` | `bytes` | The data availability solution | -| `withdrawalConfig` | `WithdrawalConfig` | The withdrawal configuration (see [WithdrawalConfig](./withdrawal/withdrawal-config.md)). Pass a zero-valued config to deploy without emergency withdrawal | -| `appContract` | `IApplication` | The deployed Application contract | +| Parameter | Type | Description | +| --- | --- | --- | +| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Initial output validator assigned to the Application | +| `appOwner` | `address` | Initial Application owner | +| `templateHash` | `bytes32` | Initial machine state hash | +| `inputBox` | `IInputBox` | Input box assigned to the Application | +| `withdrawalConfig` | `WithdrawalConfig` | Withdrawal configuration assigned to the Application | +| `appContract` | `IApplication` | Deployed Application contract | ## Errors -### `InvalidWithdrawalConfig()` +### `InvalidWithdrawalConfig` ```solidity error InvalidWithdrawalConfig(WithdrawalConfig withdrawalConfig) ``` -Raised at deployment when the provided [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) is invalid, meaning its accounts-drive layout does not fit inside the machine memory (see [`LibWithdrawalConfig.isValid`](./withdrawal/withdrawal-config.md#validation)). Checking the config in the factory means users and the node do not have to check it themselves. - -**Parameters** +Raised when the accounts-drive layout in `withdrawalConfig` does not fit within the Cartesi Machine memory. See [`WithdrawalConfig` validation](./withdrawal/withdrawal-config.md#validation). -| Name | Type | Description | -|------|------|-------------| -| `withdrawalConfig` | `WithdrawalConfig` | The invalid withdrawal configuration | +| Parameter | Type | Description | +| --- | --- | --- | +| `withdrawalConfig` | `WithdrawalConfig` | Invalid withdrawal configuration supplied for deployment | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application.md index 385821a0e..4d0619e85 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/application.md @@ -2,19 +2,25 @@ id: application title: Application resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/Application.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/Application.sol title: Application contract - - url: https://docs.openzeppelin.com/contracts/5.x/ - title: OpenZeppelin Contracts + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/IApplication.sol + title: IApplication interface --- -The **Application** contract serves as the base layer representation of the application running on the execution layer. The application can interact with other smart contracts through the execution and validation of outputs. These outputs, generated by the application backend on the execution layer, can be proven in the base layer through claims submitted by a consensus contract. +The **Application** contract is the base-layer representation of an application running inside a Cartesi Machine. Inputs advance the machine off-chain, while accepted claims allow the contract to validate and execute outputs on-chain. -Every Application is subscribed to a consensus contract and governed by a single address (owner). The consensus has the authority to submit claims, which are then used to validate outputs. The owner has complete control over the Application and can replace the consensus at any time. Consequently, users of an Application must trust both the consensus and the application owner. Depending on centralization or ownership concerns, the ownership model can be modified. This process is managed by the consensus contract. For more information about different ownership and consensus models, refer to the [consensus contracts](./consensus/overview.md). +Each Application stores the contracts and values that define its lifecycle: -An Application may optionally be deployed with a [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) that turns on **foreclosure and emergency withdrawal**. A chosen **guardian** can foreclose the application. Once it is foreclosed, users can withdraw their in-app balances straight from this contract by proving their accounts against the last-finalized machine state, without a running node. See [Foreclosure & Emergency Withdrawal](../../development/emergency-withdrawal/overview.md) for the full flow. These functions are documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). +- an [`IInputBox`](./input-box.md) containing the application's inputs; +- an [`IOutputsMerkleRootValidator`](./consensus/ioutputs-merkle-root-validator.md) that determines which outputs are valid; +- the initial machine state hash, called the template hash; +- a [refund output builder](./refund/overview.md) for returning assets from unprocessed deposits; and +- an optional [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) for foreclosure and emergency withdrawal. -## Functions +An Application can have an owner, but consensus migration is restricted to the block in which the Application is deployed. The owner cannot replace the validator later. Self-hosted factory deployments renounce ownership before the deployment transaction finishes. + +## Deployment ### `constructor()` @@ -23,24 +29,24 @@ constructor( IOutputsMerkleRootValidator outputsMerkleRootValidator, address initialOwner, bytes32 templateHash, - bytes memory dataAvailability, + IInputBox inputBox, + IRefundOutputBuilder refundOutputBuilder, WithdrawalConfig memory withdrawalConfig -) Ownable(initialOwner) +) ``` -Creates an Application contract. - -*Reverts with `InvalidWithdrawalConfig` if `withdrawalConfig` is invalid (see [`WithdrawalConfig`](./withdrawal/withdrawal-config.md)). A zero-valued `withdrawalConfig` is valid and deploys an application without the foreclosure / emergency-withdrawal feature.* +Creates an Application and stores its immutable input, refund, machine, and withdrawal configuration. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Initial contract that validates accepted outputs | +| `initialOwner` | `address` | Nonzero initial owner; ownership can be renounced after deployment | +| `templateHash` | `bytes32` | Merkle root of the initial machine state | +| `inputBox` | `IInputBox` | Contract containing this application's input stream | +| `refundOutputBuilder` | `IRefundOutputBuilder` | Builder used to create deposit-refund outputs | +| `withdrawalConfig` | `WithdrawalConfig` | Guardian, accounts-drive geometry, and withdrawal output builder | -| Name | Type | Description | -|------|------|-------------| -| `outputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The initial outputs Merkle root validator contract | -| `initialOwner` | `address` | The initial application owner | -| `templateHash` | `bytes32` | The initial machine state hash | -| `dataAvailability` | `bytes` | The data availability solution | -| `withdrawalConfig` | `WithdrawalConfig` | The withdrawal configuration (guardian, accounts-drive layout, and output builder). See [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) | +The constructor reverts when `initialOwner` is zero or when the accounts-drive layout does not fit in machine memory. A zero-valued withdrawal configuration disables foreclosure recovery. ### `receive()` @@ -48,288 +54,233 @@ Creates an Application contract. receive() external payable ``` -Accept Ether transfers. +Accepts Ether. Use the [`EtherPortal`](./portals/EtherPortal.md) when the backend must also receive an input describing the transfer. -*If you wish to transfer Ether to an application while informing the backend of it, then please do so through the Ether portal contract.* +## Output execution ### `executeOutput()` ```solidity -function executeOutput(bytes calldata output, OutputValidityProof calldata proof) external override nonReentrant +function executeOutput(bytes calldata output, OutputValidityProof calldata proof) external ``` -Execute an output. +Validates an output against the current outputs Merkle root validator, prevents the same output index from being executed twice, records the execution, emits `OutputExecuted`, and executes the output. -*On a successful execution, emits an OutputExecuted event.* +| Parameter | Type | Description | +| --- | --- | --- | +| `output` | `bytes` | Encoded output to validate and execute | +| `proof` | `OutputValidityProof` | Merkle proof that locates the output in an accepted outputs tree | -**Parameters** +The state flag and event are updated before the external interaction. During that interaction, `wasOutputExecuted(outputIndex)` already returns `true`. -| Name | Type | Description | -|------|------|-------------| -| `output` | `bytes` | The output | -| `proof` | `OutputValidityProof` | The proof used to validate the output against a claim accepted to the current outputs Merkle root validator contract | +Executable outputs currently include vouchers and delegate-call vouchers. Execution can revert when the output encoding is unsupported, the output was already executed, the target has no deployed code where code is required, the Application lacks enough Ether, or the target call fails. -### `migrateToOutputsMerkleRootValidator()` +### `wasOutputExecuted()` ```solidity -function migrateToOutputsMerkleRootValidator(IOutputsMerkleRootValidator newOutputsMerkleRootValidator) external override onlyOwner +function wasOutputExecuted(uint256 outputIndex) external view returns (bool) ``` -Migrate the application to a new outputs Merkle root validator. - -*Can only be called by the application owner.* +Returns whether the output was executed previously or is being executed in the current transaction. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `outputIndex` | `uint256` | Global index of the output | -| Name | Type | Description | -|------|------|-------------| -| `newOutputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The new outputs Merkle root validator | +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `bool` | `true` if the output was already executed or is being executed | -### `wasOutputExecuted()` +### `getNumberOfExecutedOutputs()` ```solidity -function wasOutputExecuted(uint256 outputIndex) external view override returns (bool) +function getNumberOfExecutedOutputs() external view returns (uint256) ``` -Check whether an output has been executed. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `outputIndex` | `uint256` | The index of output | +Returns the number of outputs the Application has executed. Indexers can use this count when synchronizing `OutputExecuted` events. -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bool` | Whether the output has been executed before | +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `uint256` | Number of outputs executed by the Application | ### `validateOutput()` ```solidity -function validateOutput(bytes calldata output, OutputValidityProof calldata proof) public view override +function validateOutput(bytes calldata output, OutputValidityProof calldata proof) + external + view ``` -Validate an output. - -*May raise any of the errors raised by validateOutputHash.* +Hashes `output` and calls `validateOutputHash`. -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `output` | `bytes` | The output | -| `proof` | `OutputValidityProof` | The proof used to validate the output against a claim accepted to the current outputs Merkle root validator contract | +| Parameter | Type | Description | +| --- | --- | --- | +| `output` | `bytes` | Encoded output to validate | +| `proof` | `OutputValidityProof` | Merkle proof that locates the output in an accepted outputs tree | ### `validateOutputHash()` ```solidity -function validateOutputHash(bytes32 outputHash, OutputValidityProof calldata proof) public view override +function validateOutputHash(bytes32 outputHash, OutputValidityProof calldata proof) + external + view ``` -Validate an output hash. - -*May raise InvalidOutputHashesSiblingsArrayLength or InvalidOutputsMerkleRoot.* - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `outputHash` | `bytes32` | The output hash | -| `proof` | `OutputValidityProof` | The proof used to validate the output against a claim accepted to the current outputs Merkle root validator contract | - -### `getTemplateHash()` +Reconstructs the outputs Merkle root from `outputHash` and `proof`, then checks that root with the current validator. -```solidity -function getTemplateHash() external view override returns (bytes32) -``` +| Parameter | Type | Description | +| --- | --- | --- | +| `outputHash` | `bytes32` | Hash of the encoded output | +| `proof` | `OutputValidityProof` | Merkle proof that reconstructs the outputs root | -Get the application's template hash. +It can revert with `InvalidOutputHashesSiblingsArrayLength` or `InvalidOutputsMerkleRoot`. -**Return Values** +## Deposit refunds -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bytes32` | The application's template hash | +Deposit refunds recover assets from deposit inputs that were not finalized before foreclosure. See [Deposit refunds](./refund/overview.md) for the complete lifecycle and supported asset types. -### `getOutputsMerkleRootValidator()` +### `issueRefund()` ```solidity -function getOutputsMerkleRootValidator() external view override returns (IOutputsMerkleRootValidator) +function issueRefund(uint256 inputIndex, bytes calldata input) external ``` -Get the current outputs Merkle root validator. - -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `IOutputsMerkleRootValidator` | The current outputs Merkle root validator | - -### `getDataAvailability()` +Issues a refund after the Application has been foreclosed. Anyone can call it. -```solidity -function getDataAvailability() external view override returns (bytes memory) -``` +| Parameter | Type | Description | +| --- | --- | --- | +| `inputIndex` | `uint256` | Index of the deposit input in the Application's input box | +| `input` | `bytes` | Complete encoded input stored at `inputIndex` | -Get the data availability solution used by application. +The function: -**Return Values** +1. verifies that the input has not already been refunded; +2. validates the complete encoded input against the Application's input box; +3. asks the outputs Merkle root validator whether the input was finalized; +4. asks the refund output builder to construct the asset transfer; +5. records the refund and emits `RefundIssued`; and +6. executes the refund output. -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bytes` | Solidity ABI-encoded function call that describes the source of inputs that should be fed to the application. | +It reverts for a finalized input, a repeated refund, an invalid input, a non-deposit input, or a deposit sent through an unsupported portal. -### `getDeploymentBlockNumber()` +### `wasRefundForInputIssued()` ```solidity -function getDeploymentBlockNumber() external view override returns (uint256) +function wasRefundForInputIssued(uint256 inputIndex) external view returns (bool) ``` -Get number of block in which contract was deployed. +Returns whether a refund for `inputIndex` was issued previously or is being issued in the current transaction. -**Return Values** +| Parameter | Type | Description | +| --- | --- | --- | +| `inputIndex` | `uint256` | Index of the input to check | -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `uint256` | The deployment block number | +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `bool` | `true` if the input was already refunded or is being refunded | -### `owner()` +### `getNumberOfIssuedRefunds()` ```solidity -function owner() public view override(IOwnable, Ownable) returns (address) +function getNumberOfIssuedRefunds() external view returns (uint256) ``` -Returns the address of the current owner. - -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `address` | The address of the current owner | - -### `renounceOwnership()` +Returns the number of issued refunds. Indexers can compare this count with synchronized `RefundIssued` events. -```solidity -function renounceOwnership() public override(IOwnable, Ownable) -``` - -Leaves the contract without owner. It will not be possible to call onlyOwner functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner. +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `uint256` | Number of refunds issued by the Application | -### `transferOwnership()` +### `getRefundOutputBuilder()` ```solidity -function transferOwnership(address newOwner) public override(IOwnable, Ownable) +function getRefundOutputBuilder() external view returns (IRefundOutputBuilder) ``` -Transfers ownership of the contract to a new account (newOwner). Can only be called by the current owner. +Returns the immutable builder used for deposit refunds. -**Parameters** +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `IRefundOutputBuilder` | Refund output builder assigned at deployment | -| Name | Type | Description | -|------|------|-------------| -| `newOwner` | `address` | The new owner address | - -## Events +## Input validation -### `OutputExecuted()` +### `validateInput()` ```solidity -event OutputExecuted(uint64 outputIndex, bytes output) +function validateInput(uint256 inputIndex, bytes calldata input) + external + view + returns (uint256 blockNumber, address inputSender, bytes memory inputPayload) ``` -An output was executed from the Application. +Checks that `keccak256(input)` matches the hash stored at `inputIndex`, then decodes an EVM advance input. It also verifies the chain ID, Application address, block number, timestamp, and embedded input index. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `inputIndex` | `uint256` | Index of the input in the Application's input box | +| `input` | `bytes` | Complete encoded input to validate and decode | -| Name | Type | Description | -|------|------|-------------| -| `outputIndex` | `uint64` | The index of the output | -| `output` | `bytes` | The output | +| Return value | Type | Description | +| --- | --- | --- | +| `blockNumber` | `uint256` | Base-layer block in which the input was added | +| `inputSender` | `address` | Direct sender to the input box, such as a portal contract | +| `inputPayload` | `bytes` | Application payload encoded in the input | -### `OutputsMerkleRootValidatorChanged()` +### `validateInputHash()` ```solidity -event OutputsMerkleRootValidatorChanged(IOutputsMerkleRootValidator newOutputsMerkleRootValidator) +function validateInputHash(uint256 inputIndex, bytes32 inputHash) external view ``` -The outputs Merkle root validator was changed. +Checks that `inputIndex` exists in the Application's input box and that its stored hash equals `inputHash`. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `inputIndex` | `uint256` | Index of the input in the Application's input box | +| `inputHash` | `bytes32` | Hash expected at `inputIndex` | -| Name | Type | Description | -|------|------|-------------| -| `newOutputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The new outputs Merkle root validator | +It reverts with `InvalidInputIndex` or `InvalidInputHash`. -## Guardian & Foreclosure - -These members come from the [`IApplicationForeclosure`](https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/IApplicationForeclosure.sol) interface. They are only meaningful when the application was deployed with a non-empty [`WithdrawalConfig`](./withdrawal/withdrawal-config.md); the guardian is the address set in that configuration. +## Guardian and foreclosure ### `foreclose()` ```solidity -function foreclose() external override onlyGuardian -``` - -Forecloses the application, allowing users to withdraw their funds by providing Merkle proofs of their in-app accounts. - -*Can only be called by the application guardian. On success, emits a `Foreclosure` event. An application that has been foreclosed remains so.* - -**Errors** - -| Error | Condition | -|-------|-----------| -| `NotGuardian` | Called by an account other than the guardian | - -### `getGuardian()` - -```solidity -function getGuardian() external view override returns (address) +function foreclose() external ``` -Get the address of the guardian, which has the power to foreclose the application. +Permanently forecloses the Application. Only the configured guardian can call it. Foreclosure prevents new claims from being submitted or accepted and enables deposit refunds and emergency withdrawals. -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `address` | The guardian address | +A second call reverts with `Foreclosed`, so the Application emits `Foreclosure` at most once. ### `isForeclosed()` ```solidity -function isForeclosed() external view override returns (bool) +function isForeclosed() external view returns (bool) ``` -Check whether the application has been foreclosed. An application that has been foreclosed will remain so. - -**Return Values** +Returns whether the Application has been foreclosed. -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bool` | Whether the application has been foreclosed | +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `bool` | `true` if the Application is foreclosed | -### `Foreclosure()` +### `getGuardian()` ```solidity -event Foreclosure() +function getGuardian() external view returns (address) ``` -Triggered when the application is foreclosed. - -## Emergency Withdrawal +Returns the address allowed to foreclose the Application. -These members come from the [`IApplicationWithdrawal`](https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/IApplicationWithdrawal.sol) interface. After the application is foreclosed, its **accounts drive** (the in-app balance ledger) is proved on-chain once, and then each account's funds can be withdrawn permissionlessly. For the end-to-end procedure see the [recovery guide](../../development/emergency-withdrawal/recovery-guide.md); for the output-building contracts see the [Withdrawal](./withdrawal/overview.md) subsection. +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `address` | Configured guardian address | -Withdrawal-related functions take an `AccountValidityProof`: +## Emergency withdrawal -```solidity -struct AccountValidityProof { - uint64 accountIndex; // the account's index in the accounts drive - bytes32[] accountRootSiblings; // Merkle siblings of the account root -} -``` +After foreclosure, users can recover balances recorded in the accounts drive. The canonical procedure is documented in [Foreclosure and emergency withdrawal](../../development/emergency-withdrawal/overview.md). ### `proveAccountsDriveMerkleRoot()` @@ -337,186 +288,222 @@ struct AccountValidityProof { function proveAccountsDriveMerkleRoot( bytes32 accountsDriveMerkleRoot, bytes32[] calldata proof -) external override +) external ``` -Prove the accounts drive Merkle root against the last-finalized machine state provided by the application's outputs Merkle root validator. Callable by anyone after the application is foreclosed, so that accounts can be validated and their funds withdrawn. - -*On success, stores the proved accounts drive Merkle root and emits an `AccountsDriveMerkleRootProved` event.* - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `accountsDriveMerkleRoot` | `bytes32` | The accounts drive Merkle root | -| `proof` | `bytes32[]` | Siblings of the accounts drive Merkle root in the machine state tree | +Proves and stores the accounts-drive Merkle root. Anyone can call it after foreclosure, but it can succeed only once. -**Errors** +| Parameter | Type | Description | +| --- | --- | --- | +| `accountsDriveMerkleRoot` | `bytes32` | Merkle root of the configured accounts drive | +| `proof` | `bytes32[]` | Sibling hashes connecting the accounts-drive root to the finalized machine root | -| Error | Condition | -|-------|-----------| -| `NotForeclosed` | The application has not been foreclosed | -| `AccountsDriveMerkleRootAlreadyProved` | The root has already been proved | -| `InvalidAccountsDriveMerkleRootProofSize` | The proof array length is wrong | -| `InvalidMachineMerkleRoot(bytes32)` | The computed machine root differs from the last-finalized one (argument is the computed root) | +The proof is checked against the last finalized machine state. If no machine state was ever finalized, the constructor's `templateHash` is used. This allows recovery even when the Application has no accepted claim. ### `withdraw()` ```solidity -function withdraw(bytes calldata account, AccountValidityProof calldata proof) external override +function withdraw(bytes calldata account, AccountValidityProof calldata proof) external ``` -Withdraw the funds of an account from the foreclosed application. First the account is validated against the proved accounts drive Merkle root; then a withdrawal output is built from the account and executed. +Validates an account against the proved accounts-drive root, builds a withdrawal output, records the withdrawal, emits `Withdrawal`, and executes the output. Anyone can submit a valid withdrawal after foreclosure. -*On success, marks the account funds as withdrawn and emits a `Withdrawal` event.* +| Parameter | Type | Description | +| --- | --- | --- | +| `account` | `bytes` | Complete encoded accounts-drive record | +| `proof` | `AccountValidityProof` | Proof that locates the account in the proved accounts drive | -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `account` | `bytes` | The account, as encoded in the accounts drive | -| `proof` | `AccountValidityProof` | The proof used to validate the account | - -**Errors** - -| Error | Condition | -|-------|-----------| -| `NotForeclosed` | The application has not been foreclosed | -| `AccountFundsAlreadyWithdrawn(uint64)` | The account's funds were already withdrawn (argument is the account index) | -| Errors from `validateAccount()` | The account fails validation (see [`validateAccount()`](#validateaccount)) | - -### `getWithdrawalConfig()` - -```solidity -function getWithdrawalConfig() external view override returns (WithdrawalConfig memory withdrawalConfig) -``` - -Get the [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) set upon construction. +The state flag and event are updated before the output interaction. During that interaction, `wereAccountFundsWithdrawn(accountIndex)` already returns `true`. ### `getAccountsDriveMerkleRoot()` ```solidity function getAccountsDriveMerkleRoot() - external view override - returns (bool wasAccountsDriveMerkleRootProved, bytes32 accountsDriveMerkleRoot) + external + view + returns (bool wasProved, bytes32 accountsDriveMerkleRoot) ``` -Check whether the accounts drive Merkle root was proved, and its value. +Returns whether the root was proved and, when available, its value. -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `wasAccountsDriveMerkleRootProved` | `bool` | Whether the accounts drive Merkle root was proved | -| `accountsDriveMerkleRoot` | `bytes32` | The accounts drive Merkle root (if proved) | +| Return value | Type | Description | +| --- | --- | --- | +| `wasProved` | `bool` | Whether the accounts-drive root has been proved and stored | +| `accountsDriveMerkleRoot` | `bytes32` | Stored accounts-drive root, or zero before it is proved | ### `getNumberOfWithdrawals()` ```solidity -function getNumberOfWithdrawals() external view override returns (uint256) +function getNumberOfWithdrawals() external view returns (uint256) ``` -Get the number of withdrawals. Useful for fast-syncing `Withdrawal` events. +Returns the number of completed withdrawals. + +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `uint256` | Number of completed withdrawals | ### `wereAccountFundsWithdrawn()` ```solidity -function wereAccountFundsWithdrawn(uint256 accountIndex) external view override returns (bool) +function wereAccountFundsWithdrawn(uint256 accountIndex) external view returns (bool) ``` -Check whether an account had its funds withdrawn. +Returns whether the account's funds were withdrawn previously or are being withdrawn in the current transaction. -**Parameters** +| Parameter | Type | Description | +| --- | --- | --- | +| `accountIndex` | `uint256` | Index of the account in the accounts drive | -| Name | Type | Description | -|------|------|-------------| -| `accountIndex` | `uint256` | The index of the account in the accounts drive | +| Return value | Type | Description | +| --- | --- | --- | +| unnamed | `bool` | `true` if the account was already withdrawn or is being withdrawn | -### `getLog2LeavesPerAccount()` +### `validateAccount()` ```solidity -function getLog2LeavesPerAccount() external view override returns (uint8) +function validateAccount(bytes calldata account, AccountValidityProof calldata proof) + external + view ``` -Get the log (base 2) of the number of machine-state-tree leaves reserved for each account in the accounts drive. +Hashes an encoded account and calls `validateAccountMerkleRoot`. + +| Parameter | Type | Description | +| --- | --- | --- | +| `account` | `bytes` | Complete encoded accounts-drive record | +| `proof` | `AccountValidityProof` | Proof that locates the account in the accounts drive | -### `getLog2MaxNumOfAccounts()` +### `validateAccountMerkleRoot()` ```solidity -function getLog2MaxNumOfAccounts() external view override returns (uint8) +function validateAccountMerkleRoot( + bytes32 accountMerkleRoot, + AccountValidityProof calldata proof +) external view ``` -Get the log (base 2) of the maximum number of accounts the accounts drive can store (the depth of the accounts drive tree). +Checks an account root at `proof.accountIndex` against the proved accounts-drive root. -### `getAccountsDriveStartIndex()` +| Parameter | Type | Description | +| --- | --- | --- | +| `accountMerkleRoot` | `bytes32` | Merkle root of the encoded account record | +| `proof` | `AccountValidityProof` | Proof that locates the account root in the accounts drive | + +### Accounts-drive configuration views ```solidity -function getAccountsDriveStartIndex() external view override returns (uint64) +function getWithdrawalConfig() external view returns (WithdrawalConfig memory) +function getLog2LeavesPerAccount() external view returns (uint8) +function getLog2MaxNumOfAccounts() external view returns (uint8) +function getAccountsDriveStartIndex() external view returns (uint64) +function getWithdrawalOutputBuilder() external view returns (IWithdrawalOutputBuilder) ``` -Get the start-index factor of the accounts drive. With `a = getLog2LeavesPerAccount()`, `b = getLog2MaxNumOfAccounts()`, and `c = getAccountsDriveStartIndex()`, the accounts drive starts at memory address `c * 2^(a+b+5)` and is `2^(a+b+5)` bytes in size. - -### `getWithdrawalOutputBuilder()` +These functions expose the immutable [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) and its builder. -```solidity -function getWithdrawalOutputBuilder() external view override returns (IWithdrawalOutputBuilder) -``` +| Function | Return type | Description | +| --- | --- | --- | +| `getWithdrawalConfig()` | `WithdrawalConfig` | Complete withdrawal configuration | +| `getLog2LeavesPerAccount()` | `uint8` | Base-2 logarithm of the number of Merkle leaves in each account | +| `getLog2MaxNumOfAccounts()` | `uint8` | Base-2 logarithm of the maximum number of accounts | +| `getAccountsDriveStartIndex()` | `uint64` | Machine-memory leaf index at which the accounts drive begins | +| `getWithdrawalOutputBuilder()` | `IWithdrawalOutputBuilder` | Builder used to turn an account record into a withdrawal output | -Get the [withdrawal output builder](./withdrawal/iwithdrawal-output-builder.md), which is static-called whenever an account's funds are to be withdrawn. +## General configuration and ownership -### `validateAccount()` +### Configuration views ```solidity -function validateAccount(bytes calldata account, AccountValidityProof calldata proof) external view override +function getTemplateHash() external view returns (bytes32) +function getOutputsMerkleRootValidator() + external + view + returns (IOutputsMerkleRootValidator) +function getInputBox() external view returns (IInputBox) +function getDeploymentBlockNumber() external view returns (uint256) ``` -Validate the existence of an account at a given index in the accounts drive, against the accounts drive Merkle root proved through `proveAccountsDriveMerkleRoot()`. +`getInputBox()` is also used by the portal contracts to discover where each Application receives inputs. -*May raise any error raised by [`validateAccountMerkleRoot()`](#validateaccountmerkleroot), as well as `DriveSmallerThanData` (if the provided account is too large).* +| Function | Return type | Description | +| --- | --- | --- | +| `getTemplateHash()` | `bytes32` | Initial machine state hash | +| `getOutputsMerkleRootValidator()` | `IOutputsMerkleRootValidator` | Current output validator | +| `getInputBox()` | `IInputBox` | Input box assigned at deployment | +| `getDeploymentBlockNumber()` | `uint256` | Base-layer block in which the Application was deployed | -### `validateAccountMerkleRoot()` +### `migrateToOutputsMerkleRootValidator()` ```solidity -function validateAccountMerkleRoot(bytes32 accountMerkleRoot, AccountValidityProof calldata proof) external view override +function migrateToOutputsMerkleRootValidator( + IOutputsMerkleRootValidator newOutputsMerkleRootValidator +) external ``` -Validate the existence of an account root at a given index in the accounts drive. +Changes the validator only when called by the owner in the Application's deployment block and before foreclosure. Calls in later blocks revert with `NotDeploymentBlock`. -**Errors** +| Parameter | Type | Description | +| --- | --- | --- | +| `newOutputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | Validator to assign to the Application | -| Error | Condition | -|-------|-----------| -| `InvalidAccountRootSiblingsArrayLength` | The siblings array length is wrong | -| `InvalidNodeIndex` | The account index is outside the accounts drive | -| `AccountsDriveMerkleRootNotProved` | The accounts drive root has not been proved yet | -| `InvalidAccountsDriveMerkleRoot(bytes32)` | The computed accounts drive root differs from the proved one (argument is the computed root) | - -### `AccountsDriveMerkleRootProved()` +### Ownership functions ```solidity -event AccountsDriveMerkleRootProved(bytes32 accountsDriveMerkleRoot) +function owner() external view returns (address) +function renounceOwnership() external +function transferOwnership(address newOwner) external ``` -Triggered when the accounts drive Merkle root is proved. - -**Parameters** +These functions implement OpenZeppelin ownership. Because validator migration is limited to the deployment block, ownership after deployment does not grant an ongoing ability to change consensus. -| Name | Type | Description | -|------|------|-------------| -| `accountsDriveMerkleRoot` | `bytes32` | The accounts drive Merkle root | +| Function | Parameter or return value | Type | Description | +| --- | --- | --- | --- | +| `owner()` | Return value | `address` | Current owner address | +| `transferOwnership()` | `newOwner` | `address` | Address that will become the owner | -### `Withdrawal()` +## Events ```solidity -event Withdrawal(uint64 accountIndex, bytes account, bytes output) -``` - -Triggered when the funds of an account are withdrawn. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `accountIndex` | `uint64` | The account index in the accounts drive | -| `account` | `bytes` | The account as encoded in the accounts drive | -| `output` | `bytes` | The withdrawal output | +event OutputsMerkleRootValidatorChanged( + IOutputsMerkleRootValidator newOutputsMerkleRootValidator +) +event OutputExecuted(uint64 indexed outputIndex, bytes output) +event Foreclosure() +event RefundIssued(uint256 indexed inputIndex, bytes input, bytes output) +event AccountsDriveMerkleRootProved(bytes32 accountsDriveMerkleRoot) +event Withdrawal(uint64 indexed accountIndex, bytes account, bytes output) +``` + +The output, refund, and withdrawal indexes are indexed event parameters, so clients can filter them by topic. + +## Errors + +| Error | Meaning | +| --- | --- | +| `OutputNotExecutable` | The output selector is not an executable output type | +| `OutputNotReexecutable` | The output index was already executed | +| `InvalidOutputHashesSiblingsArrayLength` | The output proof has the wrong number of siblings | +| `InvalidOutputsMerkleRoot` | The reconstructed outputs root is not accepted | +| `NotGuardian` | A non-guardian called a guardian-only function | +| `NotForeclosed` | A recovery action was attempted before foreclosure | +| `Foreclosed` | An action requires an active Application, or foreclosure was repeated | +| `InvalidInputIndex` | The requested input index does not exist | +| `InvalidInputHash` | The provided input does not match the stored hash | +| `IllFormedInput` | The encoded input is not a valid EVM advance for this Application | +| `CannotRefundFinalizedInput` | The input was finalized and cannot be refunded | +| `RefundAlreadyIssued` | The input was already refunded | +| `UnknownInputSender` | The refund builder does not recognize the input sender as a supported portal | +| `InvalidAccountsDriveMerkleRootProofSize` | The accounts-drive proof has the wrong size | +| `AccountsDriveMerkleRootAlreadyProved` | The accounts-drive root was already stored | +| `AccountsDriveMerkleRootNotProved` | Account validation was attempted before proving the drive root | +| `InvalidAccountRootSiblingsArrayLength` | The account proof has the wrong number of siblings | +| `InvalidMachineMerkleRoot` | The drive proof does not reconstruct the finalized or template machine root | +| `InvalidAccountsDriveMerkleRoot` | The account proof does not reconstruct the stored drive root | +| `AccountFundsAlreadyWithdrawn` | The account was already withdrawn | +| `InvalidAccountSize` | A withdrawal builder received an account with an unexpected size | +| `NotDeploymentBlock` | Validator migration was attempted after deployment | +| `InsufficientFunds` | A voucher requires more Ether than the Application owns | +| `TargetHasNoCode` | An executable output targets an address without deployed code | + +Merkle-tree validation can also raise the errors inherited from `BinaryMerkleTreeErrors`. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/abstract-consensus.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/abstract-consensus.md index 7b586a402..98848963f 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/abstract-consensus.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/abstract-consensus.md @@ -2,65 +2,69 @@ id: abstract-consensus title: AbstractConsensus resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/AbstractConsensus.sol - title: AbstractConsensus Contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/AbstractConsensus.sol + title: AbstractConsensus contract --- -The **AbstractConsensus** contract provides an abstract implementation of `IConsensus` with common consensus functionality. +**`AbstractConsensus`** implements the claim lifecycle shared by Authority and Quorum consensus. Concrete contracts provide the rule that stages a submitted claim. -## Functions - -### `isOutputsMerkleRootValid()` +## Validation and finalization ```solidity -function isOutputsMerkleRootValid(address appContract, bytes32 outputsMerkleRoot) public view override returns (bool) +function isOutputsMerkleRootValid( + address appContract, + bytes32 outputsMerkleRoot +) public view returns (bool) + +function getLastFinalizedMachineMerkleRoot(address appContract) + public view returns (bytes32) + +function wasInputFinalized( + address appContract, + uint256 inputIndex, + uint256 blockNumber +) public view returns (bool) ``` -Check whether an outputs Merkle root is valid. - -**Parameters** +An outputs root becomes valid only when its staged claim is accepted. The last finalized machine root is updated at the same time. -| Name | Type | Description | -|------|------|-------------| -| `appContract` | `address` | The application contract address | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +`wasInputFinalized` returns whether the input's block is earlier than the first unprocessed block recorded for the Application. The standard implementation does not otherwise use `inputIndex`. -**Return Values** +## Claim information -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bool` | True if the outputs Merkle root is valid | +```solidity +function getEpochLength() public view returns (uint256) +function getClaimStagingPeriod() public view returns (uint256) +function getNumberOfAcceptedClaims(address appContract) external view returns (uint256) +function getNumberOfStagedClaims(address appContract) external view returns (uint256) +function getNumberOfSubmittedClaims(address appContract) external view returns (uint256) +function getClaim( + address appContract, + uint256 lastProcessedBlockNumber, + bytes32 machineMerkleRoot +) public view returns (IConsensus.Claim memory) +``` -### `getEpochLength()` +## `acceptClaim()` ```solidity -function getEpochLength() public view override returns (uint256) +function acceptClaim( + address appContract, + uint256 lastProcessedBlockNumber, + bytes32 machineMerkleRoot +) external ``` -Get the epoch length. +Accepts a staged claim after the configured staging period. The function is permissionless, but it rejects a missing claim, an incomplete staging period, an invalid block boundary, or a foreclosed Application. -**Return Values** +## Machine validation -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `uint256` | The epoch length | +The internal `_validateMachine` routine checks a [`MachineValidityProof`](./iconsensus.md#machine-validity-proof) and returns the outputs Merkle root stored in the proved transmit-buffer block. Authority and Quorum call it before registering a claim. -### `supportsInterface()` +## ERC-165 support ```solidity -function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) +function supportsInterface(bytes4 interfaceId) public view returns (bool) ``` -Check if the contract supports a specific interface. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `interfaceId` | `bytes4` | The interface identifier | - -**Return Values** - -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `bool` | True if the interface is supported | \ No newline at end of file +The base implementation reports support for both `IConsensus` and `IOutputsMerkleRootValidator`. Concrete consensus contracts also report their specialized interface. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority-factory.md index 48ec68eee..9ff6c9994 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority-factory.md @@ -2,7 +2,7 @@ id: authority-factory title: AuthorityFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/AuthorityFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/authority/AuthorityFactory.sol title: AuthorityFactory Contract --- @@ -13,7 +13,11 @@ The **AuthorityFactory** contract allows anyone to reliably deploy new `IAuthori ### `newAuthority()` ```solidity -function newAuthority(address authorityOwner, uint256 epochLength) external override returns (IAuthority) +function newAuthority( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod +) external override returns (IAuthority) ``` Deploy a new authority contract. @@ -24,6 +28,7 @@ Deploy a new authority contract. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | **Return Values** @@ -34,7 +39,12 @@ Deploy a new authority contract. ### `newAuthority()` (with salt) ```solidity -function newAuthority(address authorityOwner, uint256 epochLength, bytes32 salt) external override returns (IAuthority) +function newAuthority( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 salt +) external override returns (IAuthority) ``` Deploy a new authority contract deterministically using CREATE2. @@ -45,6 +55,7 @@ Deploy a new authority contract deterministically using CREATE2. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the authority address | **Return Values** @@ -59,6 +70,7 @@ Deploy a new authority contract deterministically using CREATE2. function calculateAuthorityAddress( address authorityOwner, uint256 epochLength, + uint256 claimStagingPeriod, bytes32 salt ) external view override returns (address) ``` @@ -71,10 +83,11 @@ Calculate the address of an authority to be deployed deterministically. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the authority address | **Return Values** | Name | Type | Description | |------|------|-------------| -| `[0]` | `address` | The deterministic authority address | \ No newline at end of file +| `[0]` | `address` | The deterministic authority address | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority.md index 48c604567..f5f8bdb62 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/authority.md @@ -2,11 +2,11 @@ id: authority title: Authority resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/Authority.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/authority/Authority.sol title: Authority Contract --- -The **Authority** contract implements a single-owner consensus mechanism where only the contract owner can submit and accept claims. +The **Authority** contract implements a single-owner consensus mechanism. Only the owner can submit a claim. A valid submission is staged immediately, and anyone can accept it after the claim-staging period through the inherited `acceptClaim()` function. ## Functions @@ -16,11 +16,12 @@ The **Authority** contract implements a single-owner consensus mechanism where o function submitClaim( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot + bytes32 machineMerkleRoot, + MachineValidityProof calldata proof ) external onlyOwner ``` -Submit a claim to the consensus. Only the contract owner can call this function. +Submit a claim to the consensus. Only the contract owner can call this function. A valid claim is submitted and staged in the same transaction, then waits for the configured claim staging period before acceptance. **Parameters** @@ -28,7 +29,8 @@ Submit a claim to the consensus. Only the contract owner can call this function. |------|------|-------------| | `appContract` | `address` | The application contract address | | `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| `machineMerkleRoot` | `bytes32` | The post-epoch machine Merkle root | +| `proof` | `MachineValidityProof` | Proof of a valid `rx accepted` yield and the outputs Merkle root | ### `owner()` @@ -84,4 +86,4 @@ Check if the contract supports a specific interface. | Name | Type | Description | |------|------|-------------| -| `[0]` | `bool` | True if the interface is supported | \ No newline at end of file +| `[0]` | `bool` | True if the interface is supported | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority-factory.md index c9c91f50d..4b712cb94 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority-factory.md @@ -2,7 +2,7 @@ id: iauthority-factory title: IAuthorityFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/IAuthorityFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/authority/IAuthorityFactory.sol title: IAuthorityFactory Interface --- @@ -29,7 +29,11 @@ A new authority was deployed. ### `newAuthority()` ```solidity -function newAuthority(address authorityOwner, uint256 epochLength) external returns (IAuthority) +function newAuthority( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod +) external returns (IAuthority) ``` Deploy a new authority. @@ -40,6 +44,7 @@ Deploy a new authority. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | **Return Values** @@ -50,7 +55,12 @@ Deploy a new authority. ### `newAuthority()` (with salt) ```solidity -function newAuthority(address authorityOwner, uint256 epochLength, bytes32 salt) external returns (IAuthority) +function newAuthority( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 salt +) external returns (IAuthority) ``` Deploy a new authority deterministically. @@ -61,6 +71,7 @@ Deploy a new authority deterministically. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the authority address | **Return Values** @@ -75,6 +86,7 @@ Deploy a new authority deterministically. function calculateAuthorityAddress( address authorityOwner, uint256 epochLength, + uint256 claimStagingPeriod, bytes32 salt ) external view returns (address) ``` @@ -87,10 +99,11 @@ Calculate the address of an authority to be deployed deterministically. |------|------|-------------| | `authorityOwner` | `address` | The initial authority owner | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the authority address | **Return Values** | Name | Type | Description | |------|------|-------------| -| `[0]` | `address` | The deterministic authority address | \ No newline at end of file +| `[0]` | `address` | The deterministic authority address | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority.md index 3e04fd366..be096e2ed 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/authority/iauthority.md @@ -2,7 +2,7 @@ id: iauthority title: IAuthority resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/IAuthority.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/authority/IAuthority.sol title: IAuthority Interface --- @@ -16,4 +16,4 @@ A consensus contract controlled by a single address, the owner. This interface c - [`Authority`](./authority.md): Implementation of this interface - [`IConsensus`](../iconsensus.md): Base consensus interface -- [`IOwnable`](https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/access/IOwnable.sol): Ownership management interface \ No newline at end of file +- [`IOwnable`](https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/access/IOwnable.sol): Ownership management interface diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/iconsensus.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/iconsensus.md index 660022646..88e2830b8 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/iconsensus.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/iconsensus.md @@ -2,27 +2,48 @@ id: iconsensus title: IConsensus resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/IConsensus.sol - title: IConsensus Interface + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/IConsensus.sol + title: IConsensus interface + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/common/MachineValidityProof.sol + title: MachineValidityProof structure --- -The `IConsensus` interface defines the main consensus contract behavior for validating and accepting claims submitted by validators. +**`IConsensus`** defines how validators submit, stage, and accept claims about an Application's post-epoch state. -## Description +Each Application has its own input stream, divided into epochs by base-layer block number. After processing an epoch, a validator can submit the resulting machine Merkle root together with a proof that the machine stopped at a valid manual yield. The proof also reveals the cumulative outputs Merkle root stored in the machine's transmit buffer. -Each application has its own stream of inputs. When an input is fed to the application, it may yield several outputs. Since genesis, a Merkle tree of all outputs ever produced is maintained both inside and outside the Cartesi Machine. +## Claim lifecycle -The claim that validators may submit to the consensus contract is the root of this Merkle tree after processing all base layer blocks until some height. +1. A validator submits a claim for an epoch. +2. The consensus model stages the claim when its own criteria are satisfied. Authority stages the owner's claim immediately. Quorum stages a claim after a majority supports it. +3. The claim remains staged for `getClaimStagingPeriod()` base-layer blocks. +4. Anyone can call `acceptClaim` after the staging period. +5. The accepted outputs Merkle root becomes valid for on-chain output execution. -A validator should be able to save transaction fees by not submitting a claim if it was: -- Already submitted by the validator (see the `ClaimSubmitted` event) or -- Already accepted by the consensus (see the `ClaimAccepted` event) +If the Application is foreclosed before acceptance, the consensus cannot submit or accept further claims. -The acceptance criteria for claims may depend on the type of consensus, and is not specified by this interface. For example, a claim may be accepted if it was: -- Submitted by an authority or -- Submitted by the majority of a quorum or -- Submitted and not proven wrong after some period of time or -- Submitted and proven correct through an on-chain tournament +## Machine validity proof + +```solidity +struct LeafProof { + bytes32 dataBlock; + bytes32[] siblings; +} + +struct MachineValidityProof { + LeafProof iflagsYProof; + LeafProof htifTohostProof; + LeafProof txBufferProof; +} +``` + +The three leaf proofs establish that: + +- the machine's `iflags_Y` register is set; +- the HTIF `tohost` register signals a manual yield with the `rx accepted` reason; and +- the first data block of the CMIO transmit buffer contains the outputs Merkle root. + +All three proofs must reconstruct the submitted `machineMerkleRoot`. ## Functions @@ -32,134 +53,150 @@ The acceptance criteria for claims may depend on the type of consensus, and is n function submitClaim( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot + bytes32 machineMerkleRoot, + MachineValidityProof calldata proof ) external ``` -Submit a claim to the consensus. - -**Parameters** +Submits a claim. The concrete consensus contract decides who may call the function and when the claim becomes staged. -| Name | Type | Description | -|------|------|-------------| -| `appContract` | `address` | The application contract address | -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| Parameter | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Application whose state was computed | +| `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `machineMerkleRoot` | `bytes32` | Post-epoch machine state root | +| `proof` | `MachineValidityProof` | Proof of a valid accepted yield and the outputs root | -**Events:** -- `ClaimSubmitted`: Must be fired -- `ClaimAccepted`: MAY be fired, if the acceptance criteria is met +Every successful call emits `ClaimSubmitted`. It may also emit `ClaimStaged` when the staging criteria are met. -### `getEpochLength()` +### `acceptClaim()` ```solidity -function getEpochLength() external view returns (uint256) +function acceptClaim( + address appContract, + uint256 lastProcessedBlockNumber, + bytes32 machineMerkleRoot +) external ``` -Get the epoch length, in number of base layer blocks. +Accepts a staged claim after its staging period. A successful call emits `ClaimAccepted` and makes the claim's outputs root valid. -**Return Values** +| Parameter | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Application whose claim will be accepted | +| `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `machineMerkleRoot` | `bytes32` | Post-epoch machine state root submitted with the claim | -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `uint256` | The epoch length | - -**Note:** The epoch number of a block is defined as the integer division of the block number by the epoch length. - -## Events - -### `ClaimSubmitted()` +### Configuration and counters ```solidity -event ClaimSubmitted( - address indexed submitter, - address indexed appContract, - uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot -) +function getEpochLength() external view returns (uint256) +function getClaimStagingPeriod() external view returns (uint256) +function getNumberOfAcceptedClaims(address appContract) external view returns (uint256) +function getNumberOfStagedClaims(address appContract) external view returns (uint256) +function getNumberOfSubmittedClaims(address appContract) external view returns (uint256) ``` -Must trigger when a claim is submitted. +The epoch number of a block is its integer division by `getEpochLength()`. -**Parameters** +| Function | Parameter | Type | Return type | Description | +| --- | --- | --- | --- | --- | +| `getEpochLength()` | None | None | `uint256` | Number of base-layer blocks in an epoch | +| `getClaimStagingPeriod()` | None | None | `uint256` | Number of blocks a staged claim must wait before acceptance | +| `getNumberOfAcceptedClaims()` | `appContract` | `address` | `uint256` | Number of claims accepted for the Application | +| `getNumberOfStagedClaims()` | `appContract` | `address` | `uint256` | Number of claims staged for the Application | +| `getNumberOfSubmittedClaims()` | `appContract` | `address` | `uint256` | Number of claims submitted for the Application | -| Name | Type | Description | -|------|------|-------------| -| `submitter` | `address` | The submitter address | -| `appContract` | `address` | The application contract address | -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | - -### `ClaimAccepted()` +### `getClaim()` ```solidity -event ClaimAccepted( - address indexed appContract, +function getClaim( + address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot -) + bytes32 machineMerkleRoot +) external view returns (Claim memory claim) ``` -Must trigger when a claim is accepted. - -**Parameters** +Returns the status, staging block, and staged outputs Merkle root for one claim. -| Name | Type | Description | -|------|------|-------------| -| `appContract` | `address` | The application contract address | -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| Parameter | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Application associated with the claim | +| `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `machineMerkleRoot` | `bytes32` | Post-epoch machine state root submitted with the claim | -**Note:** For each application and lastProcessedBlockNumber, there can be at most one accepted claim. - -## Errors - -### `NotEpochFinalBlock()` +| Return value | Type | Description | +| --- | --- | --- | +| `claim` | `Claim` | Stored claim status and staging data | ```solidity -error NotEpochFinalBlock(uint256 lastProcessedBlockNumber, uint256 epochLength) -``` - -The claim contains the number of a block that is not at the end of an epoch (its modulo epoch length is not epoch length - 1). - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `epochLength` | `uint256` | The epoch length | +enum ClaimStatus { UNSTAGED, STAGED, ACCEPTED } -### `NotPastBlock()` - -```solidity -error NotPastBlock(uint256 lastProcessedBlockNumber, uint256 currentBlockNumber) +struct Claim { + ClaimStatus status; + uint256 stagingBlockNumber; + bytes32 stagedOutputsMerkleRoot; +} ``` -The claim contains the number of a block in the future (it is greater or equal to the current block number). - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `currentBlockNumber` | `uint256` | The number of the current block | +The staging fields are meaningful only for staged or accepted claims. -### `NotFirstClaim()` +## Events ```solidity -error NotFirstClaim(address appContract, uint256 lastProcessedBlockNumber) -``` +event ClaimSubmitted( + address indexed submitter, + address indexed appContract, + uint256 lastProcessedBlockNumber, + bytes32 outputsMerkleRoot, + bytes32 machineMerkleRoot +) -A claim for that application and epoch was already submitted by the validator. +event ClaimStaged( + address indexed appContract, + uint256 lastProcessedBlockNumber, + bytes32 outputsMerkleRoot, + bytes32 machineMerkleRoot +) -**Parameters** +event ClaimAccepted( + address indexed appContract, + uint256 lastProcessedBlockNumber, + bytes32 outputsMerkleRoot, + bytes32 machineMerkleRoot +) +``` -| Name | Type | Description | -|------|------|-------------| -| `appContract` | `address` | The application contract address | -| `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | +At most one claim can be staged for an Application and `lastProcessedBlockNumber` pair. + +| Event | Parameter | Type | Description | +| --- | --- | --- | --- | +| `ClaimSubmitted` | `submitter` | `address` | Validator that submitted the claim | +| `ClaimSubmitted` | `appContract` | `address` | Application associated with the claim | +| `ClaimSubmitted` | `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `ClaimSubmitted` | `outputsMerkleRoot` | `bytes32` | Cumulative outputs root extracted from the machine proof | +| `ClaimSubmitted` | `machineMerkleRoot` | `bytes32` | Post-epoch machine state root | +| `ClaimStaged` | `appContract` | `address` | Application associated with the staged claim | +| `ClaimStaged` | `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `ClaimStaged` | `outputsMerkleRoot` | `bytes32` | Cumulative outputs root staged for acceptance | +| `ClaimStaged` | `machineMerkleRoot` | `bytes32` | Post-epoch machine state root | +| `ClaimAccepted` | `appContract` | `address` | Application associated with the accepted claim | +| `ClaimAccepted` | `lastProcessedBlockNumber` | `uint256` | Final base-layer block covered by the claim | +| `ClaimAccepted` | `outputsMerkleRoot` | `bytes32` | Cumulative outputs root accepted for validation | +| `ClaimAccepted` | `machineMerkleRoot` | `bytes32` | Post-epoch machine state root | -## Related Contracts +## Errors -- [`AbstractConsensus`](./abstract-consensus.md): Abstract implementation of this interface -- [`IOutputsMerkleRootValidator`](./ioutputs-merkle-root-validator.md): Interface for validating outputs Merkle roots \ No newline at end of file +| Error | Meaning | +| --- | --- | +| `NotEpochFinalBlock` | The claim does not end at an epoch boundary | +| `NotPastBlock` | The claimed block is not strictly in the past | +| `NotFirstClaim` | The validator already submitted a claim for that Application epoch | +| `ClaimNotStaged` | Acceptance was requested for a claim that is not staged | +| `ClaimStagingPeriodNotOverYet` | The required number of blocks has not elapsed | +| `InvalidSiblingsArrayLength` | A machine leaf proof has the wrong number of siblings | +| `InvalidMachineMerkleProof` | A leaf proof does not reconstruct the submitted machine root | +| `InvalidPostEpochMachineIflagsYRegister` | The machine did not finish in a finalizable yielded state | +| `InvalidPostEpochMachineHtifTohostRegister` | The machine did not yield with the `rx accepted` reason | + +Application-check errors can also be raised when the target Application is missing, malformed, reverting, or foreclosed. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/ioutputs-merkle-root-validator.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/ioutputs-merkle-root-validator.md index 50381952d..fffa21fe3 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/ioutputs-merkle-root-validator.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/ioutputs-merkle-root-validator.md @@ -2,33 +2,48 @@ id: ioutputs-merkle-root-validator title: IOutputsMerkleRootValidator resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/IOutputsMerkleRootValidator.sol - title: IOutputsMerkleRootValidator Interface + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/IOutputsMerkleRootValidator.sol + title: IOutputsMerkleRootValidator interface --- -The `IOutputsMerkleRootValidator` interface provides valid outputs Merkle roots for validation. +**`IOutputsMerkleRootValidator`** is the interface an [`Application`](../application.md) uses to validate outputs, locate its last finalized machine state, and determine whether an input was finalized. -## Description +It extends ERC-165. Clients can use `supportsInterface` to detect additional behavior, such as the claim-submission API in [`IConsensus`](./iconsensus.md). -This interface provides functionality to check whether an outputs Merkle root is valid. ERC-165 can be used to determine whether this contract also supports any other interface (e.g. for submitting claims). +## `isOutputsMerkleRootValid()` -## Functions +```solidity +function isOutputsMerkleRootValid( + address appContract, + bytes32 outputsMerkleRoot +) external view returns (bool) +``` + +Returns whether `outputsMerkleRoot` was accepted for `appContract`. + +## `getLastFinalizedMachineMerkleRoot()` -### `isOutputsMerkleRootValid` ```solidity -function isOutputsMerkleRootValid(address appContract, bytes32 outputsMerkleRoot) external view returns (bool) +function getLastFinalizedMachineMerkleRoot(address appContract) + external + view + returns (bytes32) ``` -Check whether an outputs Merkle root is valid. +Returns the most recently finalized machine state root for the Application. It returns zero when no state has been finalized. -**Parameters:** -- `appContract` (address): The application contract address -- `outputsMerkleRoot` (bytes32): The outputs Merkle root +During emergency recovery, the Application uses its template hash when this function returns zero. This makes the initial machine state the recovery source when no claim was ever accepted. -**Returns:** -- (bool): True if the outputs Merkle root is valid +## `wasInputFinalized()` + +```solidity +function wasInputFinalized( + address appContract, + uint256 inputIndex, + uint256 blockNumber +) external view returns (bool) +``` -## Related Contracts +Returns whether the specified input was covered by the finalized state. The standard `AbstractConsensus` implementation compares `blockNumber` with the Application's first unprocessed block number. -- [`IConsensus`](./iconsensus.md): Interface that inherits from this interface -- [`AbstractConsensus`](./abstract-consensus.md): Abstract implementation that implements this interface \ No newline at end of file +The caller must supply the real index and base-layer block for an existing input. [`Application.issueRefund`](../application.md#issuerefund) obtains those values from a validated encoded input before calling this function. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/overview.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/overview.md index dff5dd066..b18839574 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/overview.md @@ -2,18 +2,18 @@ id: overview title: Overview resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.9/src/consensus title: Consensus Smart Contracts --- -The consensus mechanism in Cartesi Rollups is responsible for validating and accepting claims submitted by validators. These contracts ensure the integrity of the rollup by validating outputs Merkle roots. +The consensus contracts receive claims about an Application's post-epoch machine state. A claim proves both the machine Merkle root and the cumulative outputs Merkle root stored inside that machine. After the claim is staged and accepted, the Application can validate and execute outputs from the accepted outputs root. ## Consensus Contracts The framework supports different consensus mechanisms: -- **[Authority](./authority/authority.md)**: Single-owner consensus controlled by one address -- **[Quorum](./quorum/quorum.md)**: Multi-validator consensus requiring majority approval +- **[Authority](./authority/authority.md)**: One owner submits claims, which are staged immediately +- **[Quorum](./quorum/quorum.md)**: An immutable validator set stages a claim after a strict-majority vote ## Core Interfaces @@ -23,17 +23,14 @@ The framework supports different consensus mechanisms: ## Consensus Mechanism -A claim consists of: +A claim submission identifies: -- Application Contract Address: The address of the dApp being validated -- Last Processed Block Number: The block number up to which inputs have been processed -- Outputs Merkle Root: The root hash of the Merkle tree containing all outputs produced by the application +- the Application contract; +- the final base-layer block processed in the epoch; +- the post-epoch machine Merkle root; and +- a machine-validity proof showing a valid `rx accepted` yield and the outputs Merkle root in the transmit buffer. -The consensus contract validates that: -- The block number is at the end of an epoch (modulo epoch length equals epoch length - 1) -- The block number is in the past (not future) -- No duplicate claim has been submitted for the same application and epoch - -Once a claim is accepted, the outputs Merkle root becomes valid and can be used to validate individual outputs in the application contract. +The consensus verifies that the processed block is in the past and falls at an epoch boundary. Its concrete staging rule then applies. Staged claims remain pending for the configured claim-staging period, giving the guardian time to foreclose an Application if a bad claim is detected. After that period, anyone can accept the claim. +Acceptance makes the outputs Merkle root valid, records the latest finalized machine root, and advances the first unprocessed block for that Application. See [`IConsensus`](./iconsensus.md) for the proof, lifecycle, events, and errors. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum-factory.md index 1cf78eb89..42a4d4112 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum-factory.md @@ -2,7 +2,7 @@ id: iquorum-factory title: IQuorumFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/IQuorumFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/quorum/IQuorumFactory.sol title: IQuorumFactory Interface --- @@ -29,7 +29,11 @@ A new quorum was deployed. ### `newQuorum()` ```solidity -function newQuorum(address[] calldata validators, uint256 epochLength) external returns (IQuorum) +function newQuorum( + address[] calldata validators, + uint256 epochLength, + uint256 claimStagingPeriod +) external returns (IQuorum) ``` Deploy a new quorum. @@ -40,6 +44,7 @@ Deploy a new quorum. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | **Return Values** @@ -50,7 +55,12 @@ Deploy a new quorum. ### `newQuorum()` (with salt) ```solidity -function newQuorum(address[] calldata validators, uint256 epochLength, bytes32 salt) external returns (IQuorum) +function newQuorum( + address[] calldata validators, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 salt +) external returns (IQuorum) ``` Deploy a new quorum deterministically. @@ -61,6 +71,7 @@ Deploy a new quorum deterministically. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the quorum address | **Return Values** @@ -75,6 +86,7 @@ Deploy a new quorum deterministically. function calculateQuorumAddress( address[] calldata validators, uint256 epochLength, + uint256 claimStagingPeriod, bytes32 salt ) external view returns (address) ``` @@ -87,10 +99,11 @@ Calculate the address of a quorum to be deployed deterministically. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the quorum address | **Return Values** | Name | Type | Description | |------|------|-------------| -| `[0]` | `address` | The deterministic quorum address | \ No newline at end of file +| `[0]` | `address` | The deterministic quorum address | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum.md index a179662a0..c44dfea83 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/iquorum.md @@ -2,7 +2,7 @@ id: iquorum title: IQuorum resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/IQuorum.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/quorum/IQuorum.sol title: IQuorum Interface --- @@ -97,7 +97,7 @@ Check whether a validator is in favor of any claim in a given epoch. function numOfValidatorsInFavorOf( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot + bytes32 machineMerkleRoot ) external view returns (uint256) ``` @@ -106,7 +106,7 @@ Get the number of validators in favor of a claim. **Parameters:** - `appContract` (address): The application contract address - `lastProcessedBlockNumber` (uint256): The number of the last processed block -- `outputsMerkleRoot` (bytes32): The outputs Merkle root +- `machineMerkleRoot` (bytes32): The machine Merkle root **Returns:** - (uint256): Number of validators in favor of claim @@ -116,7 +116,7 @@ Get the number of validators in favor of a claim. function isValidatorInFavorOf( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot, + bytes32 machineMerkleRoot, uint256 id ) external view returns (bool) ``` @@ -126,7 +126,7 @@ Check whether a validator is in favor of a claim. **Parameters:** - `appContract` (address): The application contract address - `lastProcessedBlockNumber` (uint256): The number of the last processed block -- `outputsMerkleRoot` (bytes32): The outputs Merkle root +- `machineMerkleRoot` (bytes32): The machine Merkle root - `id` (uint256): The ID of the validator **Returns:** @@ -137,4 +137,4 @@ Check whether a validator is in favor of a claim. ## Related Contracts - [`Quorum`](./quorum.md): Implementation of this interface -- [`IConsensus`](../iconsensus.md): Base consensus interface \ No newline at end of file +- [`IConsensus`](../iconsensus.md): Base consensus interface diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum-factory.md index 176f177b1..2a39b4c64 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum-factory.md @@ -2,7 +2,7 @@ id: quorum-factory title: QuorumFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/QuorumFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/quorum/QuorumFactory.sol title: QuorumFactory Contract --- @@ -13,7 +13,11 @@ The **QuorumFactory** contract allows anyone to reliably deploy new `IQuorum` co ### `newQuorum()` ```solidity -function newQuorum(address[] calldata validators, uint256 epochLength) external override returns (IQuorum) +function newQuorum( + address[] calldata validators, + uint256 epochLength, + uint256 claimStagingPeriod +) external override returns (IQuorum) ``` Deploy a new quorum contract. @@ -24,6 +28,7 @@ Deploy a new quorum contract. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | **Return Values** @@ -34,7 +39,12 @@ Deploy a new quorum contract. ### `newQuorum()` (with salt) ```solidity -function newQuorum(address[] calldata validators, uint256 epochLength, bytes32 salt) external override returns (IQuorum) +function newQuorum( + address[] calldata validators, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 salt +) external override returns (IQuorum) ``` Deploy a new quorum contract deterministically using CREATE2. @@ -45,6 +55,7 @@ Deploy a new quorum contract deterministically using CREATE2. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the quorum address | **Return Values** @@ -59,6 +70,7 @@ Deploy a new quorum contract deterministically using CREATE2. function calculateQuorumAddress( address[] calldata validators, uint256 epochLength, + uint256 claimStagingPeriod, bytes32 salt ) external view override returns (address) ``` @@ -71,10 +83,11 @@ Calculate the address of a quorum to be deployed deterministically. |------|------|-------------| | `validators` | `address[]` | The list of validators | | `epochLength` | `uint256` | The epoch length | +| `claimStagingPeriod` | `uint256` | Blocks that must pass between claim staging and acceptance | | `salt` | `bytes32` | The salt used to deterministically generate the quorum address | **Return Values** | Name | Type | Description | |------|------|-------------| -| `[0]` | `address` | The deterministic quorum address | \ No newline at end of file +| `[0]` | `address` | The deterministic quorum address | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum.md index 629339719..4fc667d84 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/consensus/quorum/quorum.md @@ -2,11 +2,11 @@ id: quorum title: Quorum resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/Quorum.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/consensus/quorum/Quorum.sol title: Quorum Contract --- -The **Quorum** contract implements a multi-validator consensus mechanism where claims are accepted when a majority of validators vote in favor. +The **Quorum** contract implements a multi-validator consensus mechanism. A claim is staged when a strict majority of validators vote for it. Anyone can accept the staged claim after its claim-staging period through the inherited `acceptClaim()` function. ## Functions @@ -16,11 +16,12 @@ The **Quorum** contract implements a multi-validator consensus mechanism where c function submitClaim( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot + bytes32 machineMerkleRoot, + MachineValidityProof calldata proof ) external override ``` -Submit a claim to the consensus. Only validators can call this function. +Submit a claim and cast the caller's vote for it. Only validators can call this function, and each validator can vote for only one claim in an Application epoch. The claim is staged when it reaches a strict majority. **Parameters** @@ -28,7 +29,8 @@ Submit a claim to the consensus. Only validators can call this function. |------|------|-------------| | `appContract` | `address` | The application contract address | | `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| `machineMerkleRoot` | `bytes32` | The post-epoch machine Merkle root | +| `proof` | `MachineValidityProof` | Proof of a valid `rx accepted` yield and the outputs Merkle root stored in the machine | ### `numOfValidators()` @@ -140,7 +142,7 @@ Check whether a validator is in favor of any claim in a given epoch. function numOfValidatorsInFavorOf( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot + bytes32 machineMerkleRoot ) external view override returns (uint256) ``` @@ -152,7 +154,7 @@ Get the number of validators in favor of a claim. |------|------|-------------| | `appContract` | `address` | The application contract address | | `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| `machineMerkleRoot` | `bytes32` | The machine Merkle root | **Return Values** @@ -166,7 +168,7 @@ Get the number of validators in favor of a claim. function isValidatorInFavorOf( address appContract, uint256 lastProcessedBlockNumber, - bytes32 outputsMerkleRoot, + bytes32 machineMerkleRoot, uint256 id ) external view override returns (bool) ``` @@ -179,7 +181,7 @@ Check whether a validator is in favor of a claim. |------|------|-------------| | `appContract` | `address` | The application contract address | | `lastProcessedBlockNumber` | `uint256` | The number of the last processed block | -| `outputsMerkleRoot` | `bytes32` | The outputs Merkle root | +| `machineMerkleRoot` | `bytes32` | The machine Merkle root | | `id` | `uint256` | The ID of the validator | **Return Values** @@ -206,4 +208,4 @@ Check if the contract supports a specific interface. | Name | Type | Description | |------|------|-------------| -| `[0]` | `bool` | True if the interface is supported | \ No newline at end of file +| `[0]` | `bool` | True if the interface is supported | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/devnet-test-tokens.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/devnet-test-tokens.md new file mode 100644 index 000000000..3c6a041f5 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/devnet-test-tokens.md @@ -0,0 +1,118 @@ +--- +id: devnet-test-tokens +title: Devnet test tokens +resources: + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.9/src/devnet + title: Devnet contract source +--- + +Running `make devnet` in the Rollups Contracts repository deploys a set of test assets to Anvil chain ID `31337`. These contracts are intended only for local development. Their unrestricted mint functions make them unsuitable for public networks or production use. + +## Deployed token contracts + +| Contract | Standard | Name | Symbol | Decimals or URI | +| --- | --- | --- | --- | --- | +| `TestFungibleToken` | ERC-20 | Fungible | FUN | 18 decimals | +| `TestUsdc` | ERC-20 | USD Coin | USDC | 6 decimals | +| `TestNonFungibleToken` | ERC-721 | Non-fungible | NFT | Not applicable | +| `TestMultiToken` | ERC-1155 | Not applicable | Not applicable | `https://test-multi-token.com/{id}.json` | + +The deployment script also creates `TestUsdWithdrawalOutputBuilder`. This contract is not a token. It is configured to build emergency-withdrawal outputs that transfer `TestUsdc`. + +## ERC-20 test tokens + +### `TestFungibleToken` + +`TestFungibleToken` is an 18-decimal ERC-20 token named `Fungible` with the symbol `FUN`. Use it to test standard ERC-20 deposits, transfers, vouchers, and refunds. + +### `TestUsdc` + +`TestUsdc` is a six-decimal ERC-20 token named `USD Coin` with the symbol `USDC`. Its decimal precision matches USDC-style frontend and accounting flows. One whole token is represented by `1_000_000` base units. + +Both ERC-20 contracts inherit the following development helpers from `BaseTestFungibleToken`: + +```solidity +function mint(uint256 value) external +function mint(address to, uint256 value) external +function burn(uint256 value) external +``` + +| Function | Description | +| --- | --- | +| `mint(value)` | Mints `value` base units to the caller | +| `mint(to, value)` | Mints `value` base units to `to` | +| `burn(value)` | Burns `value` base units from the caller's balance | + +The functions are permissionless. Any account can create tokens for itself or another address, while `burn` only reduces the caller's balance. + +For example, mint ten `TestUsdc` tokens to an account with: + +```shell +cast send \ + "mint(address,uint256)" \ + 10000000 \ + --rpc-url http://127.0.0.1:8545 \ + --private-key +``` + +## ERC-721 test token + +`TestNonFungibleToken` is an ERC-721 collection named `Non-fungible` with the symbol `NFT`. It exposes two permissionless mint functions: + +```solidity +function mint(uint256 tokenId) external +function mint(address to, uint256 tokenId) external +``` + +| Function | Description | +| --- | --- | +| `mint(tokenId)` | Creates `tokenId` and assigns it to the caller | +| `mint(to, tokenId)` | Creates `tokenId` and assigns it to `to` | + +Each token ID can be minted only once. A call reverts if the selected ID already exists. + +For example: + +```shell +cast send \ + "mint(address,uint256)" \ + 1 \ + --rpc-url http://127.0.0.1:8545 \ + --private-key +``` + +## ERC-1155 test token + +`TestMultiToken` is an ERC-1155 contract for testing individual and batched token transfers. It uses `https://test-multi-token.com/{id}.json` as its metadata URI template. + +```solidity +function mint(uint256 tokenId, uint256 value) external +function mint(address to, uint256 tokenId, uint256 value) external +function mintBatch(uint256[] calldata tokenIds, uint256[] calldata values) external +function mintBatch( + address to, + uint256[] calldata tokenIds, + uint256[] calldata values +) external +``` + +| Function | Description | +| --- | --- | +| `mint(tokenId, value)` | Mints `value` units of `tokenId` to the caller | +| `mint(to, tokenId, value)` | Mints `value` units of `tokenId` to `to` | +| `mintBatch(tokenIds, values)` | Mints several token IDs and amounts to the caller | +| `mintBatch(to, tokenIds, values)` | Mints several token IDs and amounts to `to` | + +For batch minting, `tokenIds` and `values` must have the same length. Each value at position `n` is the amount minted for the token ID at position `n`. + +For example: + +```shell +cast send \ + "mint(address,uint256,uint256)" \ + 1 25 \ + --rpc-url http://127.0.0.1:8545 \ + --private-key +``` + + diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/input-box.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/input-box.md index 2bffa0cb4..c3d80674f 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/input-box.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/input-box.md @@ -2,7 +2,7 @@ id: input-box title: InputBox resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/inputs/InputBox.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/inputs/InputBox.sol title: InputBox contract --- diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/overview.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/overview.md index 27f21b165..3c1fdc9c7 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/overview.md @@ -2,7 +2,7 @@ id: overview title: Overview resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6 + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.9 title: Smart Contracts for Cartesi Rollups --- @@ -26,6 +26,14 @@ Clients can interact with Ethereum-compatible nodes using the JSON-RPC API in tw - [`ApplicationFactory`](../contracts/application-factory.md): This contract enables anyone to deploy [`Application`](../contracts/application.md) contracts with a simple function call. It provides greater convenience to the deployer and security to users and validators, as they can verify that the bytecode has not been maliciously altered. -- [`Portals`](../contracts/portals/): These contracts are used to safely transfer assets from the base layer to the execution environment of your application. Currently, Portal contracts are available for the following types of assets: [Ether (ETH)](../contracts/portals/EtherPortal.md), [ERC-20 (Fungible tokens)](../contracts/portals/ERC20Portal.md), [ERC-721 (Non-fungible tokens)](../contracts/portals/ERC721Portal.md), [ERC-1155 single transfer](../contracts/portals/ERC1155SinglePortal.md), and [ERC-1155 batch token transfers](../contracts/portals/ERC1155BatchPortal.md). +- [`SelfHostedApplicationFactory`](../contracts/self-hosted-application-factory.md): This contract deploys an Authority and ownerless Application together at deterministic addresses for self-hosted operation. -- [`Consensus`](../contracts/consensus/overview.md): These contracts are crucial for the framework's security and integrity. They validate and accept claims submitted by validators, ensuring the rollup's integrity by validating outputs Merkle roots. The framework supports different consensus mechanisms including [Authority-based consensus](../contracts/consensus/authority/authority.md) for single-owner control and [Quorum-based consensus](../contracts/consensus/quorum/quorum.md) for multi-validator approval. \ No newline at end of file +- [`Devnet test tokens`](../contracts/devnet-test-tokens.md): These development-only assets include mintable fungible tokens, the six-decimal `TestUsdc`, and the local USD withdrawal builder. + +- [`Deposit refunds`](../contracts/refund/overview.md): The refund builder and Application refund API return assets from canonical portal deposits that were not finalized before foreclosure. + +- [`Portals`](../contracts/portals/overview.md): These contracts safely transfer assets from the base layer to the execution environment. The available portals support [Ether](../contracts/portals/EtherPortal.md), [ERC-20](../contracts/portals/Erc20Portal.md), [ERC-721](../contracts/portals/Erc721Portal.md), [ERC-1155 single transfers](../contracts/portals/Erc1155SinglePortal.md), and [ERC-1155 batch transfers](../contracts/portals/Erc1155BatchPortal.md). + +- [`Consensus`](../contracts/consensus/overview.md): These contracts are crucial for the framework's security and integrity. They validate and accept claims submitted by validators, ensuring the rollup's integrity by validating outputs Merkle roots. The framework supports different consensus mechanisms including [Authority-based consensus](../contracts/consensus/authority/authority.md) for single-owner control and [Quorum-based consensus](../contracts/consensus/quorum/quorum.md) for multi-validator approval. + +- [`Emergency withdrawal`](../contracts/withdrawal/overview.md): These contracts define the accounts-drive layout and build outputs that recover finalized balances after foreclosure. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155BatchPortal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155BatchPortal.md deleted file mode 100644 index b9445c683..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155BatchPortal.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC1155BatchPortal.sol - title: ERC1155BatchPortal contract ---- - -The **ERC1155BatchPortal** allows anyone to perform batch transfers of -ERC-1155 tokens to a dApp while informing the off-chain machine. - -## `depositBatchERC1155Token()` - -```solidity -function depositBatchERC1155Token( IERC1155 token, address appContract, uint256[] calldata tokenIds, uint256[] calldata values, bytes calldata baseLayerData, bytes calldata execLayerData) external; -``` - -Transfer a batch of ERC-1155 tokens to a dApp and add an input to -the dApp's input box to signal such operation. - -The caller must enable approval for the portal to manage all of their tokens -beforehand, by calling the `setApprovalForAll` function in the token contract. - -_Please make sure `tokenIds` and `values` have the same length._ - -#### Parameters - -| Name | Type | Description | -| ------------- | --------- | -------------------------------------------------------- | -| token | IERC1155 | The ERC-1155 token contract | -| appContract | address | The address of the dApp | -| tokenIds | uint256[] | The identifiers of the tokens being transferred | -| values | uint256[] | Transfer amounts per token type | -| baseLayerData | bytes | Additional data to be interpreted by the base layer | -| execLayerData | bytes | Additional data to be interpreted by the execution layer | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155SinglePortal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155SinglePortal.md deleted file mode 100644 index a85c7ee7b..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC1155SinglePortal.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC1155SinglePortal.sol - title: ERC1155SinglePortal contract ---- - -The **ERC1155SinglePortal** allows anyone to perform single transfers of ERC-1155 tokens to a dApp while informing the off-chain machine. - -### `depositSingleERC1155Token()` - -```solidity -function depositSingleERC1155Token( IERC1155 token, address appContract, uint256 tokenId, uint256 value, bytes calldata baseLayerData, bytes calldata execLayerData) external; - -``` - -Transfer an ERC-1155 token to a dApp and add an input to -the dApp's input box to signal such operation. - -The caller must enable approval for the portal to manage all of their tokens -beforehand, by calling the `setApprovalForAll` function in the token contract. - -#### Parameters - -| Name | Type | Description | -| ------------- | -------- | -------------------------------------------------------- | -| token | IERC1155 | The ERC-1155 token contract | -| appContract | address | The address of the dApp | -| tokenId | uint256 | The identifier of the token being transferred | -| value | uint256 | Transfer amount | -| baseLayerData | bytes | Additional data to be interpreted by the base layer | -| execLayerData | bytes | Additional data to be interpreted by the execution layer | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC20Portal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC20Portal.md deleted file mode 100644 index 08261f225..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC20Portal.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC20Portal.sol - title: ERC20Portal contract ---- - -The **ERC20Portal** allows anyone to perform transfers of -ERC-20 tokens to a dApp while informing the off-chain machine. - -## `depositERC20Tokens()` - -```solidity -function depositERC20Tokens(IERC20 token, address appContract, uint256 value, bytes calldata execLayerData) external; -``` - -Transfer ERC-20 tokens to a dApp and add an input to -the dApp's input box to signal such operation. - -The caller must allow the portal to withdraw at least `_amount` tokens -from their account beforehand, by calling the `approve` function in the -token contract. - -#### Parameters - -| Name | Type | Description | -| ------------- | ------- | -------------------------------------------------------- | -| token | IERC20 | The ERC-20 token contract address | -| appContract | address | The address of the dApp | -| value | uint256 | The amount of tokens to be transferred | -| execLayerData | bytes | Additional data to be interpreted by the execution layer | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC721Portal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC721Portal.md deleted file mode 100644 index 7719e399f..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/ERC721Portal.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC721Portal.sol - title: ERC721Portal contract ---- - -The **ERC721Portal** allows anyone to perform transfers of -ERC-721 tokens to a dApp while informing the off-chain machine. - -## `depositERC721Token()` - -```solidity -function depositERC721Token( IERC721 token, address appContract, uint256 tokenId, bytes baseLayerData, bytes execLayerData) external -``` - -Transfer an ERC-721 token to a dApp and add an input to -the dApp's input box to signal such operation. - -The caller must change the approved address for the ERC-721 token -to the portal address beforehand, by calling the `approve` function in the -token contract. - -#### Parameters - -| Name | Type | Description | -| ------------- | ------- | -------------------------------------------------------- | -| token | IERC721 | The ERC-721 token contract address | -| appContract | address | The address of the dApp | -| tokenId | uint256 | The identifier of the token being transferred | -| baseLayerData | bytes | Additional data to be interpreted by the base layer | -| execLayerData | bytes | Additional data to be interpreted by the execution layer | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155BatchPortal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155BatchPortal.md new file mode 100644 index 000000000..02d980e10 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155BatchPortal.md @@ -0,0 +1,37 @@ +--- +id: Erc1155BatchPortal +title: Erc1155BatchPortal +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/Erc1155BatchPortal.sol + title: Erc1155BatchPortal contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/IErc1155BatchPortal.sol + title: IErc1155BatchPortal interface +--- + +The **`Erc1155BatchPortal`** transfers multiple ERC-1155 token types to an Application and adds one input describing the batch. See the [portal overview](./overview.md) for input-box discovery and common errors. + +## `depositBatchErc1155Token()` + +```solidity +function depositBatchErc1155Token( + IERC1155 token, + address appContract, + uint256[] calldata tokenIds, + uint256[] calldata values, + bytes calldata baseLayerData, + bytes calldata execLayerData +) external +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `token` | `IERC1155` | ERC-1155 token contract | +| `appContract` | `address` | Application receiving the tokens and input | +| `tokenIds` | `uint256[]` | Token-type identifiers | +| `values` | `uint256[]` | Amount corresponding to each token identifier | +| `baseLayerData` | `bytes` | Data passed to the Application's ERC-1155 receiver hook | +| `execLayerData` | `bytes` | Additional data for the execution layer | + +`tokenIds` and `values` must have the same length. Before depositing, the owner must authorize the portal with `setApprovalForAll`. + +If an unfinalized deposit is later refunded to a contract depositor, that contract must implement the appropriate ERC-1155 receiver hook. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155SinglePortal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155SinglePortal.md new file mode 100644 index 000000000..27509a394 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc1155SinglePortal.md @@ -0,0 +1,37 @@ +--- +id: Erc1155SinglePortal +title: Erc1155SinglePortal +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/Erc1155SinglePortal.sol + title: Erc1155SinglePortal contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/IErc1155SinglePortal.sol + title: IErc1155SinglePortal interface +--- + +The **`Erc1155SinglePortal`** transfers an amount of one ERC-1155 token type to an Application and adds an input describing the deposit. See the [portal overview](./overview.md) for input-box discovery and common errors. + +## `depositSingleErc1155Token()` + +```solidity +function depositSingleErc1155Token( + IERC1155 token, + address appContract, + uint256 tokenId, + uint256 value, + bytes calldata baseLayerData, + bytes calldata execLayerData +) external +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `token` | `IERC1155` | ERC-1155 token contract | +| `appContract` | `address` | Application receiving the tokens and input | +| `tokenId` | `uint256` | Token-type identifier | +| `value` | `uint256` | Amount to transfer | +| `baseLayerData` | `bytes` | Data passed to the Application's ERC-1155 receiver hook | +| `execLayerData` | `bytes` | Additional data for the execution layer | + +Before depositing, the owner must authorize the portal with `setApprovalForAll`. + +If an unfinalized deposit is later refunded to a contract depositor, that contract must implement the appropriate ERC-1155 receiver hook. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc20Portal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc20Portal.md new file mode 100644 index 000000000..cc3365407 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc20Portal.md @@ -0,0 +1,43 @@ +--- +id: Erc20Portal +title: Erc20Portal +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/Erc20Portal.sol + title: Erc20Portal contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/IErc20Portal.sol + title: IErc20Portal interface +--- + +The **`Erc20Portal`** transfers ERC-20 tokens to an Application and adds an input describing the deposit. See the [portal overview](./overview.md) for input-box discovery and common errors. + +## `depositErc20Tokens()` + +```solidity +function depositErc20Tokens( + IERC20 token, + address appContract, + uint256 value, + bytes calldata execLayerData +) external +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `token` | `IERC20` | ERC-20 token contract | +| `appContract` | `address` | Application receiving the tokens and input | +| `value` | `uint256` | Number of token base units to transfer | +| `execLayerData` | `bytes` | Additional data for the execution layer | + +Before calling the portal, the depositor must approve it to spend at least `value` tokens. + +The portal measures the Application's token balance before and after `transferFrom`. It accepts the deposit only when the balance increases by exactly `value` and the token returns `true`. Fee-on-transfer tokens and other non-compliant ERC-20 implementations are rejected to prevent the backend from recording more assets than the Application received. + +## Errors + +| Error | Meaning | +| --- | --- | +| `Erc20TransferFailed` | `transferFrom` returned `false` | +| `Erc20TransferDecreasedApplicationBalance` | The Application's balance decreased during the transfer | +| `Erc20TransferValueIsNotBalanceDelta` | The balance increase differs from `value` | + +Malformed or missing ERC-20 return data can also produce a low-level revert. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc721Portal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc721Portal.md new file mode 100644 index 000000000..f517786a9 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/Erc721Portal.md @@ -0,0 +1,35 @@ +--- +id: Erc721Portal +title: Erc721Portal +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/Erc721Portal.sol + title: Erc721Portal contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/IErc721Portal.sol + title: IErc721Portal interface +--- + +The **`Erc721Portal`** transfers one ERC-721 token to an Application and adds an input describing the deposit. See the [portal overview](./overview.md) for input-box discovery and common errors. + +## `depositErc721Token()` + +```solidity +function depositErc721Token( + IERC721 token, + address appContract, + uint256 tokenId, + bytes calldata baseLayerData, + bytes calldata execLayerData +) external +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `token` | `IERC721` | ERC-721 token contract | +| `appContract` | `address` | Application receiving the token and input | +| `tokenId` | `uint256` | Token identifier | +| `baseLayerData` | `bytes` | Data passed to the Application's ERC-721 receiver hook | +| `execLayerData` | `bytes` | Additional data for the execution layer | + +Before depositing, the owner must approve the portal for `tokenId` or grant it operator approval with `setApprovalForAll`. + +If an unfinalized deposit is later refunded to a contract depositor, that contract must accept the token through `onERC721Received`. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/EtherPortal.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/EtherPortal.md index edf46329e..c0d9074cd 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/EtherPortal.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/EtherPortal.md @@ -1,12 +1,16 @@ --- +id: EtherPortal +title: EtherPortal resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/EtherPortal.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/portals/EtherPortal.sol title: EtherPortal contract --- The **EtherPortal** allows anyone to perform transfers of Ether to a dApp while informing the off-chain machine. +The portal obtains the input-box address from the target Application for every deposit. See the [portal overview](./overview.md) for the shared validation flow and errors. + ## `depositEther()` ```solidity @@ -18,6 +22,8 @@ the dApp's input box to signal such operation. All the value sent through this function is forwarded to the dApp. +If an unfinalized deposit is later refunded to a contract depositor, that contract must accept the returned Ether through a payable message call. + #### Parameters | Name | Type | Description | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/overview.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/overview.md new file mode 100644 index 000000000..07b8efe08 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/portals/overview.md @@ -0,0 +1,48 @@ +--- +id: overview +title: Portals +resources: + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.9/src/portals + title: Portal contracts +--- + +Portal contracts transfer assets to an [`Application`](../application.md) and add an input describing the deposit to that Application's [`InputBox`](../input-box.md). + +Portals do not store one global input-box address. For each deposit, the portal calls `Application.getInputBox()` and sends the input to the address returned by that Application. This allows different Applications to use different input boxes. + +## Deposit sequence + +1. The depositor grants the required token approval, when applicable. +2. The portal transfers the asset to the Application contract. +3. The portal encodes the depositor, asset information, amount, and optional data. +4. The portal obtains the Application's input box. +5. The portal adds the encoded deposit as an Application input. + +Both the asset transfer and input submission occur in the same transaction. If either action reverts, the entire deposit reverts. + +## Application and input-box checks + +A portal can raise these errors before adding the input: + +| Error | Meaning | +| --- | --- | +| `ApplicationNotDeployed` | The supplied Application address has no code | +| `ApplicationReverted` | Calling `getInputBox()` on the Application reverted | +| `IllformedApplicationReturnData` | `getInputBox()` did not return a valid address | +| `InputBoxNotDeployed` | The advertised input-box address has no code | + +## Available portals + +| Portal | Asset | +| --- | --- | +| [`EtherPortal`](./EtherPortal.md) | Ether | +| [`Erc20Portal`](./Erc20Portal.md) | ERC-20 tokens | +| [`Erc721Portal`](./Erc721Portal.md) | ERC-721 tokens | +| [`Erc1155SinglePortal`](./Erc1155SinglePortal.md) | One ERC-1155 token type | +| [`Erc1155BatchPortal`](./Erc1155BatchPortal.md) | Multiple ERC-1155 token types | + +## Refunds after foreclosure + +If a deposit input was not finalized before foreclosure, anyone can ask the Application to return the asset through the [deposit-refund flow](../refund/overview.md). + +Contract depositors must be able to receive the refunded asset. Ether refunds require a payable receive path. ERC-721 and ERC-1155 refunds require the corresponding token-receiver hooks. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/overview.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/overview.md new file mode 100644 index 000000000..149a8f49a --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/overview.md @@ -0,0 +1,64 @@ +--- +id: overview +title: Deposit refunds +resources: + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.9/src/refund + title: Refund contracts +--- + +Deposit refunds let users recover assets from deposits that were not finalized before an Application was [foreclosed](../application.md#guardian-and-foreclosure). + +A portal deposit performs two base-layer actions in one transaction: + +1. it transfers the asset to the Application contract; and +2. it adds an input describing the deposit to the Application's input box. + +The backend normally processes that input and records the asset in its application state. If the Application is foreclosed first, an unfinalized deposit may exist on the base layer without being reflected in the last finalized machine state. Refunding returns that asset to its original depositor. + +## Refund lifecycle + +1. The guardian forecloses the Application. +2. A caller obtains the complete encoded input and its index from the Application's input box events. +3. The caller submits both values to [`Application.issueRefund`](../application.md#issuerefund). +4. The Application verifies the input hash and encoding. +5. The outputs Merkle root validator confirms that the input was not finalized. +6. The [`RefundOutputBuilder`](./refund-output-builder.md) decodes the portal payload and builds an output returning the asset. +7. The Application records the refund, emits `RefundIssued`, and executes the output. + +Anyone can submit the refund transaction. The asset always returns to the depositor encoded by the canonical portal, not to the transaction sender. + +## Supported deposits + +The standard refund builder supports deposits made through the following portals: + +| Portal | Refunded asset | Output form | +| --- | --- | --- | +| `EtherPortal` | Ether | Voucher transferring Ether to the depositor | +| `Erc20Portal` | ERC-20 tokens | Delegate-call voucher using `SafeErc20Transfer` | +| `Erc721Portal` | One ERC-721 token | Voucher transferring the token from the Application | +| `Erc1155SinglePortal` | One ERC-1155 token type | Voucher transferring the deposited amount | +| `Erc1155BatchPortal` | A batch of ERC-1155 token types | Voucher transferring the deposited amounts | + +Direct inputs and deposits from non-canonical portals cannot be refunded by the standard builder. They revert with `UnknownInputSender`. + +## When a refund is unavailable + +A refund fails when: + +- the Application has not been foreclosed; +- the input was finalized; +- the same input was already refunded; +- the supplied input or index does not match the input box; +- the input is malformed or was not sent by a supported portal; or +- the generated asset transfer reverts. + +Refunds to contract depositors require the contract to accept the returned asset. For example, a contract receiving Ether needs a payable receive path, and a contract receiving ERC-721 or ERC-1155 tokens needs the corresponding receiver hook. Without that support, the refund output can revert and the funds may remain unrecoverable. + +## Refunds compared with emergency withdrawals + +Refunds and emergency withdrawals address different balances: + +- **Refunds** return deposits that were never included in finalized application state. +- **Emergency withdrawals** recover balances that were already recorded in the finalized [accounts drive](../withdrawal/overview.md). + +An operator should reconcile input finalization and the accounts drive before directing a user to either path. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/refund-output-builder.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/refund-output-builder.md new file mode 100644 index 000000000..12e537bc3 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/refund/refund-output-builder.md @@ -0,0 +1,56 @@ +--- +id: refund-output-builder +title: RefundOutputBuilder +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/refund/RefundOutputBuilder.sol + title: RefundOutputBuilder contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/refund/IRefundOutputBuilder.sol + title: IRefundOutputBuilder interface + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/refund/IRefundOutputBuilderErrors.sol + title: IRefundOutputBuilderErrors interface +--- + +**`RefundOutputBuilder`** decodes a canonical portal deposit and builds an executable output that returns the asset to its original depositor. + +The [`Application`](../application.md) calls the builder with `STATICCALL`. The builder cannot write storage, emit events, create contracts, transfer Ether, or perform another state-changing action while constructing the output. The Application executes the returned output separately. + +## `constructor()` + +```solidity +constructor( + IEtherPortal etherPortal, + IErc20Portal erc20Portal, + IErc721Portal erc721Portal, + IErc1155SinglePortal erc1155SinglePortal, + IErc1155BatchPortal erc1155BatchPortal, + ISafeErc20Transfer safeTransfer +) +``` + +The constructor fixes the canonical portal addresses recognized by this builder and the safe-transfer helper used for ERC-20 refunds. + +## `buildRefundOutput()` + +```solidity +function buildRefundOutput( + address appContract, + address inputSender, + bytes calldata inputPayload +) external view returns (bytes memory output) +``` + +| Parameter | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Application holding the deposited asset | +| `inputSender` | `address` | Direct input sender, expected to be a canonical portal | +| `inputPayload` | `bytes` | Portal-encoded deposit payload | + +The function identifies the deposit format from `inputSender`, decodes `inputPayload`, and returns an encoded voucher or delegate-call voucher. It assumes the Application has already verified that the input exists in its input box. + +## `UnknownInputSender` + +```solidity +error UnknownInputSender(address inputSender) +``` + +Raised when `inputSender` is not one of the five canonical portal addresses configured in the constructor. This normally means the input is not a deposit or came through a custom portal unsupported by the standard builder. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/self-hosted-application-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/self-hosted-application-factory.md new file mode 100644 index 000000000..24cd3d253 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/self-hosted-application-factory.md @@ -0,0 +1,75 @@ +--- +id: self-hosted-application-factory +title: SelfHostedApplicationFactory +resources: + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/SelfHostedApplicationFactory.sol + title: SelfHostedApplicationFactory contract + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/dapp/ISelfHostedApplicationFactory.sol + title: ISelfHostedApplicationFactory interface +--- + +`SelfHostedApplicationFactory` deploys an Authority and its Application together at deterministic addresses. The Application is configured to use the new Authority as its outputs Merkle root validator. + +The factory temporarily owns the Application during deployment, then renounces ownership. This makes the Application ownerless after the transaction completes and prevents later validator migration through ownership. + +## Constructor + +```solidity +constructor( + IAuthorityFactory authorityFactory, + IApplicationFactory applicationFactory +) +``` + +The constructor stores the two factories used by every deployment. + +## `deployContracts()` + +```solidity +function deployContracts( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 templateHash, + IInputBox inputBox, + WithdrawalConfig calldata withdrawalConfig, + bytes32 salt +) external returns (IApplication application, IAuthority authority) +``` + +The function performs three steps in one transaction: + +1. It deploys an Authority for `authorityOwner` with the requested epoch and claim-staging periods. +2. It deploys an Application that uses that Authority, the selected input box, and the supplied withdrawal configuration. +3. It renounces the Application's ownership. + +The `salt` participates in both CREATE2 addresses. Reusing every deployment parameter and the same salt produces the same calculated addresses and cannot deploy a second copy at those addresses. + +## `calculateAddresses()` + +```solidity +function calculateAddresses( + address authorityOwner, + uint256 epochLength, + uint256 claimStagingPeriod, + bytes32 templateHash, + IInputBox inputBox, + WithdrawalConfig calldata withdrawalConfig, + bytes32 salt +) external view returns (address application, address authority) +``` + +Returns the addresses that `deployContracts()` will use without deploying either contract. Every parameter must match the later deployment call. + +## Factory views + +```solidity +function getAuthorityFactory() external view returns (IAuthorityFactory) +function getApplicationFactory() external view returns (IApplicationFactory) +``` + +These functions expose the immutable factory dependencies. + +:::note Deployment ownership +The function signatures accept an `IInputBox` directly. The factory owns the Application while it completes the deployment setup, then renounces ownership before the transaction finishes. +::: diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md index 40574ffaa..f65348ece 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md @@ -2,21 +2,19 @@ id: iwithdrawal-output-builder title: IWithdrawalOutputBuilder resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IWithdrawalOutputBuilder.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/IWithdrawalOutputBuilder.sol title: IWithdrawalOutputBuilder interface - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IWithdrawalOutputBuilderErrors.sol - title: IWithdrawalOutputBuilderErrors + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/IWithdrawalOutputBuilderErrors.sol + title: IWithdrawalOutputBuilderErrors interface --- -A **withdrawal output builder** turns an account (as encoded in the application's [accounts drive](./withdrawal-config.md#drive-geometry)) into an [output](../../backend/vouchers.md) that, when executed by the [`Application`](../application.md) contract, transfers that account's funds to its owner. +A **withdrawal output builder** converts one encoded accounts-drive record into an output that transfers the account's funds to its owner. -During [`withdraw()`](../application.md#withdraw), the Application **static-calls** the builder set in its [`WithdrawalConfig`](./withdrawal-config.md) and runs the returned output. Because the call is a `STATICCALL`, `buildWithdrawalOutput` must not change any state (it is `view`/`pure`). Any state change, such as contract creation, log emission, storage write, self-destruct, or Ether transfer, reverts the call and aborts the withdrawal. +The [`Application`](../application.md#withdraw) calls the builder with `STATICCALL`. Building the output cannot change state, emit events, create contracts, transfer Ether, or self-destruct. The Application executes the returned output separately. -The account encoding is **application-specific**. See [UsdWithdrawalOutputBuilder](./usd-withdrawal-output-builder.md) for the single-ERC-20 implementation. +Account contents remain application-specific, but every account must end with its owner's 20-byte address. The builder must interpret the complete account exactly as the guest application wrote it. -## Functions - -### `buildWithdrawalOutput()` +## `buildWithdrawalOutput()` ```solidity function buildWithdrawalOutput(address appContract, bytes calldata account) @@ -25,34 +23,22 @@ function buildWithdrawalOutput(address appContract, bytes calldata account) returns (bytes memory output) ``` -Build an output that, when executed by the application contract, transfers the funds of an account to its owner. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `appContract` | `address` | The application contract address. May be needed for outputs that move assets from the application's own account to the account owner (e.g. ERC-721 / ERC-1155 transfers). | -| `account` | `bytes` | The account, as encoded in the accounts drive | +| Parameter | Type | Description | +| --- | --- | --- | +| `appContract` | `address` | Application holding the base-layer assets | +| `account` | `bytes` | Complete encoded accounts-drive record | -**Return Values** +Returns an executable output that transfers the encoded funds to the account owner. -| Name | Type | Description | -|------|------|-------------| -| `output` | `bytes` | The withdrawal output | - -## Errors - -### `AccountTooShort()` +## `InvalidAccountSize` ```solidity -error AccountTooShort(uint64 attemptedAccountSize, uint64 minAccountSize) +error InvalidAccountSize(uint256 attemptedAccountSize, uint64 accountSize) ``` -Raised when the provided account is too short for the builder to decode on-chain. - -**Parameters** +Raised when the supplied record length differs from the exact size expected by the builder. -| Name | Type | Description | -|------|------|-------------| -| `attemptedAccountSize` | `uint64` | The attempted account size, in bytes | -| `minAccountSize` | `uint64` | The minimum expected account size, in bytes | +| Parameter | Description | +| --- | --- | +| `attemptedAccountSize` | Number of bytes supplied by the caller | +| `accountSize` | Exact number of bytes required by the builder | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md index ef0ac50f3..1d2d77cfd 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md @@ -3,7 +3,7 @@ id: overview title: Overview --- -These contracts power **emergency withdrawal**: the ability for users to recover their in-app balances straight from the base layer after an application is [foreclosed](../application.md#guardian--foreclosure), without a running node. For the concept and the operator procedure, see [Foreclosure & Emergency Withdrawal](../../../development/emergency-withdrawal/overview.md). +These contracts power **emergency withdrawal**: the ability for users to recover finalized in-app balances from the base layer after an Application is [foreclosed](../application.md#guardian-and-foreclosure), without a running node. For the concept and operator procedure, see [Foreclosure and emergency withdrawal](../../../development/emergency-withdrawal/overview.md). ## How the pieces fit together @@ -11,24 +11,26 @@ The withdrawal machinery lives partly on the [`Application`](../application.md) | Piece | Where | Role | |-------|-------|------| -| Foreclosure + withdrawal logic | [`Application`](../application.md) (`IApplicationForeclosure`, `IApplicationWithdrawal`) | `foreclose`, `proveAccountsDriveMerkleRoot`, `withdraw`, and the account/getter views | +| Foreclosure and withdrawal logic | [`IApplication`](../application.md) | `foreclose`, `proveAccountsDriveMerkleRoot`, `withdraw`, and the account views | | [`WithdrawalConfig`](./withdrawal-config.md) | passed to the `Application` constructor | Guardian, accounts-drive geometry, and the output builder to use | | [`IWithdrawalOutputBuilder`](./iwithdrawal-output-builder.md) | referenced by the config | Turns an account into a withdrawal output (static-called during `withdraw`) | -| [`UsdWithdrawalOutputBuilder`](./usd-withdrawal-output-builder.md) (+ [factory](./usd-withdrawal-output-builder-factory.md)) | one per ERC-20 token | The single-ERC-20 builder; emits a `DelegateCallVoucher` to a shared `SafeERC20Transfer` | +| [`UsdWithdrawalOutputBuilder`](./usd-withdrawal-output-builder.md) and [factory](./usd-withdrawal-output-builder-factory.md) | one per ERC-20 token | The single-ERC-20 builder; emits a `DelegateCallVoucher` to a shared `SafeErc20Transfer` | ## The withdrawal flow, on-chain -1. The guardian calls [`foreclose()`](../application.md#foreclose) → the application is frozen at its last-finalized state. -2. Anyone calls [`proveAccountsDriveMerkleRoot()`](../application.md#proveaccountsdrivemerkleroot) once, anchoring the accounts-drive root against the finalized machine state. +1. The guardian calls [`foreclose()`](../application.md#foreclose), freezing the Application against further claim submission or acceptance. +2. Anyone calls [`proveAccountsDriveMerkleRoot()`](../application.md#proveaccountsdrivemerkleroot) once, anchoring the accounts-drive root against the last finalized machine state. If no claim was accepted, the initial template state is used. 3. Each user calls [`withdraw(account, proof)`](../application.md#withdraw). The Application validates the account against the anchored root, **static-calls** the configured output builder to build the transfer output, executes it, and marks the account withdrawn (single-use). ## The four-way agreement Emergency withdrawal only works if four descriptions of the **accounts drive** agree: -1. the **guest application** actually writes account records with the layout it claims; +1. the **guest application** writes account records with the expected size and places the owner address in the final 20 bytes; 2. the [`WithdrawalConfig`](./withdrawal-config.md) (`log2LeavesPerAccount`, `log2MaxNumOfAccounts`, `accountsDriveStartIndex`) matches that layout; 3. the **proofs** generated off-chain (via the machine tool) use those same parameters; and 4. the **output builder** decodes the account encoding the guest produced. If any of the four disagree, proofs fail to validate or funds cannot be built, so these values must be chosen together at deploy time. See [drive geometry](./withdrawal-config.md#drive-geometry). + +Deposit refunds cover a separate case: assets transferred by inputs that were never finalized. See [Deposit refunds](../refund/overview.md) for that recovery path. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md index b0df75c82..d100aae0c 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md @@ -2,15 +2,15 @@ id: usd-withdrawal-output-builder-factory title: UsdWithdrawalOutputBuilderFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/UsdWithdrawalOutputBuilderFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/UsdWithdrawalOutputBuilderFactory.sol title: UsdWithdrawalOutputBuilderFactory contract - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IUsdWithdrawalOutputBuilderFactory.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/IUsdWithdrawalOutputBuilderFactory.sol title: IUsdWithdrawalOutputBuilderFactory interface --- **`UsdWithdrawalOutputBuilderFactory`** lets anyone deploy a [`UsdWithdrawalOutputBuilder`](./usd-withdrawal-output-builder.md) for a given ERC-20 token at a predictable address. Because these builders are **stateless**, it does not matter whether you deploy one yourself or reuse an existing one for the same token. The address is derived deterministically from the token and salt (using `CREATE2`). -The factory is constructed with a shared `SafeERC20Transfer` contract, which it passes to every builder it deploys (used as the delegate-call voucher destination). +The factory is constructed with a shared `SafeErc20Transfer` contract, which it passes to every builder it deploys as the delegate-call voucher destination. ## Functions @@ -64,7 +64,7 @@ Compute the deterministic address a builder for `token`/`salt` would have, wheth ### `getSafeErc20Transfer()` ```solidity -function getSafeErc20Transfer() external view returns (ISafeERC20Transfer safeErc20Transfer) +function getSafeErc20Transfer() external view returns (ISafeErc20Transfer safeErc20Transfer) ``` Get the shared safe ERC-20 transfer contract passed down to the builders (used as the delegate-call voucher destination). diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md index 3405ed945..94b2f5e9f 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md @@ -2,67 +2,63 @@ id: usd-withdrawal-output-builder title: UsdWithdrawalOutputBuilder resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/UsdWithdrawalOutputBuilder.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/UsdWithdrawalOutputBuilder.sol title: UsdWithdrawalOutputBuilder contract - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IUsdWithdrawalOutputBuilder.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/withdrawal/IUsdWithdrawalOutputBuilder.sol title: IUsdWithdrawalOutputBuilder interface + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/library/LibUsdAccount.sol + title: LibUsdAccount encoding --- -**`UsdWithdrawalOutputBuilder`** is a concrete [`IWithdrawalOutputBuilder`](./iwithdrawal-output-builder.md) for applications whose accounts drive denominates a **single ERC-20 token**. It is a stateless contract fixed to one token at construction; deploy one per token with the [factory](./usd-withdrawal-output-builder-factory.md). +**`UsdWithdrawalOutputBuilder`** implements [`IWithdrawalOutputBuilder`](./iwithdrawal-output-builder.md) for an accounts drive denominated in one ERC-20 token. -For each account it produces a **`DelegateCallVoucher`** that delegate-calls a shared `SafeERC20Transfer` contract to move `balance` of the token to the account owner. +The contract is stateless and fixed to a token at construction. Its output is a delegate-call voucher that invokes the shared `SafeErc20Transfer` helper from the Application's context. -## Functions +## USD account encoding -### `constructor()` +The builder accepts exactly 32 bytes: -```solidity -constructor(ISafeERC20Transfer safeErc20Transfer, IERC20 usd) -``` - -**Parameters** +| Byte range | Value | +| --- | --- | +| `0..11` | `uint96` token balance in little-endian byte order | +| `12..31` | 20-byte account-owner address | -| Name | Type | Description | -|------|------|-------------| -| `safeErc20Transfer` | `ISafeERC20Transfer` | The shared safe-transfer contract used as the delegate-call destination | -| `usd` | `IERC20` | The ERC-20 token this builder denominates withdrawals in | +This layout places the owner in the final 20 bytes, as required for accounts-drive records. The balance is measured in the token's base units. For a six-decimal token such as USDC, one token is represented as `1_000_000`. -### `token()` +## `constructor()` ```solidity -function token() external view override returns (IERC20) +constructor(ISafeErc20Transfer safeErc20Transfer, IERC20 usd) ``` -Get the ERC-20 token used to generate withdrawal outputs. +| Parameter | Type | Description | +| --- | --- | --- | +| `safeErc20Transfer` | `ISafeErc20Transfer` | Delegate-call target that performs the ERC-20 transfer | +| `usd` | `IERC20` | Token held and withdrawn by the Application | -**Return Values** +## `token()` + +```solidity +function token() external view returns (IERC20) +``` -| Name | Type | Description | -|------|------|-------------| -| `[0]` | `IERC20` | The configured token | +Returns the configured ERC-20 token. -### `buildWithdrawalOutput()` +## `buildWithdrawalOutput()` ```solidity -function buildWithdrawalOutput(address, bytes calldata account) +function buildWithdrawalOutput(address appContract, bytes calldata account) external view - override returns (bytes memory output) ``` -Decode `account` as `(address user, uint256 balance)` and return a `DelegateCallVoucher` that, when executed by the application, calls `SafeERC20Transfer.safeTransfer(token, user, balance)`. - -**Parameters** - -| Name | Type | Description | -|------|------|-------------| -| `account` | `bytes` | The account, decoded via `LibUsdAccount.decode` into `(user, balance)` | +Decodes the 32-byte account and returns a `DelegateCallVoucher` whose payload calls: -**Return Values** +```solidity +SafeErc20Transfer.safeTransfer(token, owner, balance) +``` -| Name | Type | Description | -|------|------|-------------| -| `output` | `bytes` | An ABI-encoded `DelegateCallVoucher(destination, payload)` where `destination` is the `SafeERC20Transfer` contract and `payload` is `safeTransfer(token, user, balance)` | +The `appContract` parameter is unused because the voucher executes from the calling Application's context. -*Raises [`AccountTooShort`](./iwithdrawal-output-builder.md#accounttooshort) if the account cannot be decoded.* +The function reverts with [`InvalidAccountSize`](./iwithdrawal-output-builder.md#invalidaccountsize) unless `account` is exactly 32 bytes. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md index 079421295..7e272d1de 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md @@ -2,9 +2,9 @@ id: withdrawal-config title: WithdrawalConfig resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/common/WithdrawalConfig.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/common/WithdrawalConfig.sol title: WithdrawalConfig struct - - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/library/LibWithdrawalConfig.sol + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/src/library/LibWithdrawalConfig.sol title: LibWithdrawalConfig library --- @@ -40,7 +40,7 @@ Let `a = log2LeavesPerAccount`, `b = log2MaxNumOfAccounts`, and `c = accountsDri - **starts** at machine memory address `c * 2^(a + b + 5)`; - holds up to `2^b` accounts, each occupying `2^(a + 5)` bytes. -These same three values are returned on-chain by [`getLog2LeavesPerAccount()`](../application.md#getlog2leavesperaccount), [`getLog2MaxNumOfAccounts()`](../application.md#getlog2maxnumofaccounts), and [`getAccountsDriveStartIndex()`](../application.md#getaccountsdrivestartindex), and must match the layout the guest application actually writes. +These same three values are returned by the Application's [accounts-drive configuration views](../application.md#accounts-drive-configuration-views) and must match the layout written by the guest application. ## Validation diff --git a/cartesi-rollups_versioned_docs/version-2.0/build-with-ai/prompting.md b/cartesi-rollups_versioned_docs/version-2.0/build-with-ai/prompting.md index 6818bda2a..1ee7f9f27 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/build-with-ai/prompting.md +++ b/cartesi-rollups_versioned_docs/version-2.0/build-with-ai/prompting.md @@ -25,7 +25,7 @@ Build a Cartesi Rollups v2 JavaScript app called "order-book". Use cartesi-scaffold, cartesi-backend-core, cartesi-backend-js-ts, and cartesi-contracts. Stack: JS template, Foundry for any L1 contracts, vanilla CSS -for any harness. Pin Cartesi alpha packages explicitly. +for any harness. Use the Cartesi package versions documented for this release. Deliverables: - Folder structure: handlers/, validation/, inspect/, assets/. @@ -79,7 +79,7 @@ What to do instead: - Stay on **testnets** with **dev keys** while iterating. - Ask the assistant to **print** CLI / `cast` / `forge` commands; you run them. - Have it **diff and explain** changes before any commit. -- Read [Overview → Exercise caution](./overview.md#exercise-caution) before widening the agent's access. +- Read [Overview: Agent access and sandboxing](./overview.md#agent-access-and-sandboxing) before widening the agent's access. ## Prompt patterns @@ -131,7 +131,7 @@ Step 4 — Verify (I run locally): - Summarize expected outcomes per user story ID after each command group. Constraints: -- Cartesi Rollups v2 only. Pin alpha packages explicitly. +- Cartesi Rollups v2 only. Use the Cartesi package versions documented for this release. - Every test and code change must trace to a user story ID in SPEC.md. - Print CLI commands for me to run; do not execute them. diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md index 4460f0066..de70b7cc0 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md @@ -2,8 +2,12 @@ id: introduction title: Introduction resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v1.4.0/onchain/rollups/deployments - title: Supported networks + - url: https://github.com/cartesi/rollups-contracts/releases/tag/v3.0.0-alpha.9 + title: Rollups Contracts v3.0.0 + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/docs/deployment.md + title: Contract deployment guide + - url: https://github.com/cartesi/rollups-contracts/blob/v3.0.0-alpha.9/docs/verification.md + title: Contract verification guide --- @@ -36,19 +40,21 @@ There are two methods to deploy an application: Deployment with a third-party service provider is under development and will be available soon. ::: -## Supported networks +## Use published contract addresses -As stated above, the first step in deploying a new Cartesi dApp to a blockchain requires creating a smart contract on that network that uses the Cartesi Rollups smart contracts. Cartesi has already deployed the Rollups smart contracts to several networks for convenience. +The contract reference in this documentation targets Rollups Contracts `v3.0.0`. Use the deployment addresses published with that release when following its interfaces. -The table below shows the list of all [networks that are currently supported](https://usecannon.com/packages/cartesi-rollups) in the latest release: +The contracts can be deployed to any EVM-compatible chain that supports the required EVM version. The Cartesi Foundation commonly deploys releases to Ethereum, Arbitrum, Optimism, Base, and their testnets, but availability depends on the release and network. -| Network Name | Chain ID | -| ---------------- | -------- | -| Ethereum Mainnet | 1 | -| Sepolia | 11155111 | -| Optimism | 10 | -| Optimism Sepolia | 11155420 | -| Arbitrum | 42161 | -| Arbitrum Sepolia | 421614 | -| Base | 8453 | -| Base Sepolia | 84532 | +Before deploying an Application: + +1. obtain `cartesi-rollups-contracts-3.0.0-deployment-addresses.tar.gz` from the GitHub release, or deploy the suite from the tagged source; +2. verify the chain ID and bytecode for each address; +3. keep that artifact with the Application deployment record; and +4. configure every client and node component with addresses from the same release. + +The repository uses Foundry deployment scripts and stores results under `deployments/`. Each contract has a plain-text `.txt` address file. Integrations should read the plain-text address files. + +Follow the linked contract deployment guide to simulate and broadcast a deployment. Verification can be retried independently with `make verify-` or for one contract with `make verify--`. + +Contract source is distributed through the Soldeer package `cartesi-rollups-contracts~3.0.0`. Compiled artifacts and the Anvil state are available as separate assets on the GitHub release. diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md index e1ebc58f8..70ac07f22 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md @@ -83,11 +83,12 @@ Ensure to follow best practices when handling private keys during local developm docker compose --project-name cartesi-rollups-node \ exec advancer cartesi-rollups-cli deploy application /var/lib/cartesi-rollups-node/snapshot \ --epoch-length 10 \ + --claim-staging-period \ --salt \ --register ``` - Replace `` with your application name and `` with a unique identifier. The salt must be unique for each deployment and cannot be repeated. You can generate a unique salt using: + Replace `` with your application name, `` with the required claim-staging period, and `` with a unique identifier. The salt must be unique for each deployment and cannot be repeated. You can generate a unique salt using: ```shell cast keccak256 "your-unique-string" @@ -102,12 +103,12 @@ Ensure to follow best practices when handling private keys during local developm 1. Deploy an authority contract with `cast`. Replace each placeholder with the expected value, and grab the returned address from the command output (the final `sed` call normalizes the address). ```shell - cast send "newAuthority(address,uint256)" \ - 10 --private-key --rpc-url \ + cast send "newAuthority(address,uint256,uint256)" \ + 10 --private-key --rpc-url \ --json | jq -r '.logs[-1].data' | sed 's/^0x000000000000000000000000/0x/' ``` - You can find the AuthorityFactory, portals and inputbox addresses for your target chain in the **Deployed Contracts** section below; Replace `` with the appropriate address. + You can find the AuthorityFactory, portal, and InputBox addresses for your target chain in the **Deployed contracts** section below. Replace `` with the appropriate address. 2. Use the address you got above as the `` in the deploy command below. This command re-runs the snapshot registration using the specified authority and epoch values. @@ -119,17 +120,11 @@ Ensure to follow best practices when handling private keys during local developm --json ``` - On success this command deploys, registers and returns the address of the deployed application contract, this should be notted for further interaction with your applciation. + On success, this command deploys and registers the Application, then returns its contract address. Record the address for later interactions. -## Deployed Contracts: +## Deployed contracts -Depending on your intended deployment chain, you can find the list of required contracts like the Inputbox, Portals, Authority Factory etc, below: - -- [Cannon Devnet](https://usecannon.com/packages/cartesi-rollups/2.2.0/13370-main/deployment/contracts) -- [Ethereum Sepolia](https://usecannon.com/packages/cartesi-rollups/2.2.0/11155111-main/deployment/contracts) -- [Arbitrum Sepolia](https://usecannon.com/packages/cartesi-rollups/2.2.0/421614-main/deployment/contracts) -- [OP Sepolia](https://usecannon.com/packages/cartesi-rollups/2.2.0/11155420-main/deployment/contracts) -- [Base Sepolia](https://usecannon.com/packages/cartesi-rollups/2.2.0/84532-main/deployment/contracts) +The commands require addresses for the InputBox, portals, Application factory, and Authority factory from one contract deployment. Use the verified `deployments/` artifact published with the Rollups Contracts release. See [Use published contract addresses](../introduction.md#use-published-contract-addresses). ## Accessing the node diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md index 46eb6d9ad..2f75907da 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md @@ -19,7 +19,7 @@ In addition to the [standard prerequisites](./standard.md#prerequisites) (Cartes ## Configure the machine and ledger (`cartesi.toml`) -For an application to support emergency withdrawal, its Cartesi Machine must include a dedicated **accounts drive**: a raw, unmounted flash drive that holds the balance ledger. You declare it in `cartesi.toml` alongside the root drive, size it to fit the account tree, and enable `final_hash` so the machine hash is produced for deployment. The guest then writes balances into that drive using a ledger library, in a layout that matches the application's `WithdrawalConfig`. +For an application to support emergency withdrawal, its Cartesi Machine must include a dedicated **accounts drive**: a raw, unmounted flash drive that holds the balance ledger. You declare it in `cartesi.toml` alongside the root drive and size it to fit the account tree. `cartesi build` produces the final machine hash automatically. The guest writes balances into the drive using a ledger library, in a layout that matches the application's `WithdrawalConfig`. Because those choices (the drive declaration, its size and position, and the record layout) belong to the guest application, they are documented once, in full, on the guest-requirements page. Set the drive up as described in [Creating the accounts drive](../../api-reference/backend/emergency-withdrawal.md#creating-the-accounts-drive) before continuing, and see [Keeping the balances](../../api-reference/backend/emergency-withdrawal.md#keeping-the-balances) for the ledger library. @@ -97,12 +97,13 @@ Create a `withdrawal.json` describing the guardian and the accounts-drive layout docker compose --project-name cartesi-rollups-node \ exec advancer cartesi-rollups-cli deploy application /var/lib/cartesi-rollups-node/snapshot \ --epoch-length 10 \ + --claim-staging-period \ --withdrawal-config-file /tmp/withdrawal.json \ --salt \ --register ``` - Replace `` with your application name and `` with a unique identifier (generate one with `cast keccak256 "your-unique-string"`). The deployment is rejected if the config is invalid, meaning its accounts-drive layout does not fit the machine memory. A zero-valued config would deploy an application without emergency withdrawal, which is the standard case. + Replace `` with your application name, `` with the required claim-staging period, and `` with a unique identifier. You can generate a salt with `cast keccak256 "your-unique-string"`. The deployment is rejected if the config is invalid, meaning its accounts-drive layout does not fit the machine memory. A zero-valued config deploys an Application without emergency withdrawal. After this, your application is deployed and registered, and a guardian can foreclose it when needed. diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/snapshot.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/snapshot.md index 2b79b0c08..f70b9e18c 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/snapshot.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/snapshot.md @@ -143,7 +143,6 @@ jobs: uses: softprops/action-gh-release@v2 with: files: release-assets/* - prerelease: ${{ contains(github.ref, '-rc') }} fail_on_unmatched_files: true ``` @@ -163,7 +162,7 @@ The build job sets up the environment with Docker Buildx, QEMU, and Node.js, ins ### Release Job -The release job downloads the build artifacts, prepares the release assets, and creates a GitHub release with the tag. It attaches the snapshot files and checksums, marking the release as prerelease if the tag contains `-rc`. +The release job downloads the build artifacts, prepares the release assets, and creates a GitHub release with the tag. It attaches the snapshot files and checksums to the release. ## Release Management @@ -176,9 +175,7 @@ The release job downloads the build artifacts, prepares the release assets, and git push origin v1.0.0 ``` -2. **Prereleases**: Use tags like `v1.0.0-rc` for release candidates - -3. **Release artifacts** will include: +2. **Release artifacts** will include: - `snapshot.tar.gz` - Compressed snapshot - - `snapshot.tar.gz.sha256` - Checksum file \ No newline at end of file + - `snapshot.tar.gz.sha256` - Checksum file diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/advanced-configuration.md b/cartesi-rollups_versioned_docs/version-2.0/development/advanced-configuration.md index 47d208292..e9c77196a 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/development/advanced-configuration.md +++ b/cartesi-rollups_versioned_docs/version-2.0/development/advanced-configuration.md @@ -15,6 +15,8 @@ Here is what the file controls at a high level: - **SDK version**: Which version of the Cartesi SDK to use when building your machine. - **Machine settings**: How the machine boots, how much RAM it has, what program it runs, and how it behaves. - **Drives**: The file systems attached to your machine, including your application code and any additional data. +- **NVRAMs**: Raw byte ranges that the application accesses directly through Linux UIO devices. +- **Withdrawal configuration**: How an application exposes its accounts drive for emergency withdrawal. It is important to note that `cartesi.toml` is only read when you run `cartesi build` or `cartesi shell`. By default, the CLI looks for a `cartesi.toml` in the project root, unless you point it to a different path using the `-c` or `--config` flag with a relative path to the configuration file. If no config file is found, the CLI applies sensible defaults, most of which are covered in the sections below. The default Cartesi templates do not include a `cartesi.toml` in the project root hence you manually create a configuration file when you have an explicit need for it. @@ -40,7 +42,7 @@ format = "ext2" This means that by default, the CLI will: -1. Use SDK version specified i.e `0.12.0`. +1. Use the SDK version specified by ``. 2. Give your machine 128 megabytes of RAM. 3. Build your root drive from a `Dockerfile` in your project directory. 4. Pull environment variables and the working directory from that Docker image. @@ -51,7 +53,7 @@ If those defaults work for you, all you need is a `Dockerfile` and you are ready ## SDK Version ```toml -sdk = "cartesi/" +sdk = "cartesi/sdk:" ``` The `sdk` field tells the CLI which version of the Cartesi SDK image to use when building your machine. This is a docker image containing the Linux kernel, the RISC‑V toolchain, Cartesi Node and everything else needed to assemble your Cartesi Machine. @@ -116,12 +118,10 @@ A value of `2305843009213693952` is the default machine cycle the Cartesi machin ### Rollup Behavior ```toml -assert_rolling_update = true +assert_rolling_template = true ``` -Set this to `true` when you are building a standalone application that does not need to interact with the blockchain's input/output system. This is useful during early development or for tools that run inside the machine but do not need the rollup lifecycle. - -**`assert_rolling_update`** is related to rolling template assertions. When set to `true`, the CLI will verify that your machine is compatible with rolling updates. This is important for production deployments where you want to ensure your application can be updated without breaking the existing state. +**`assert_rolling_template`** asks `cartesi-machine` to verify the rolling-template invariants while building the machine. Enable it when you need the build to fail if the resulting machine cannot serve as a valid rolling template. ### Docker Integration @@ -139,16 +139,6 @@ These fields control how the CLI uses information from your Docker image when bu **`user`** sets the user that your application runs as inside the machine. The default value `"dapp"` is a non root user, which is a good security practice. You can change this if your application needs to run as a different user. -### Final Hash - -```toml -final_hash = true -``` - -When `final_hash` is set to `true`, the CLI computes a hash of the machine after it finishes building. This hash uniquely identifies the exact state of your Cartesi Machine, including all its drives, memory, and configuration. - -This is important for on chain verification. The hash is what gets registered on the blockchain, and it allows anyone to verify that the machine running off chain is exactly the same one that was agreed upon. If you are deploying to production, you will want this enabled. - ## Drives Drives are the file systems attached to your Cartesi Machine. Since the machine is a virtual computer, drives are its hard disks. Every machine has at least one drive (the root drive), and you can attach upto 6 different drives. @@ -290,13 +280,111 @@ A few options are shared across all builder types: **`extra_size`** adds free space beyond the actual content size. Useful for drives when you intend to convert to an ext2 format, it takes the actual size of the existing directory contents then adds the specified `extra_size` to it, allowing for future additions. Specified as a string like `"100Mb"` or `"50Mi"`. +## NVRAM Configuration + +An NVRAM is a raw range of bytes that the guest application accesses through a Linux UIO device such as `/dev/uio0`. It has no file system and no mount point. This makes NVRAM suitable for applications that need direct, memory-mapped access without a page cache between the guest and the emulator. + +Define each NVRAM under `[nvrams.