From fadea4d81607ca87843db01da31fe3913f5c8629 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 00:29:50 +0100 Subject: [PATCH 01/11] docs(v2): nest Foreclosure & Emergency Withdrawal under Development Move the category from a top-level sidebar entry to inside the Development section, right after Advanced-configuration. Files stay in foreclosure/. `yarn build` passes. --- .../backend/emergency-withdrawal.md | 10 ++++ .../withdrawal/iwithdrawal-output-builder.md | 10 ++++ .../contracts/withdrawal/overview.md | 10 ++++ .../usd-withdrawal-output-builder-factory.md | 10 ++++ .../usd-withdrawal-output-builder.md | 10 ++++ .../contracts/withdrawal/withdrawal-config.md | 10 ++++ .../jsonrpc/methods/withdrawals/get.md | 10 ++++ .../jsonrpc/methods/withdrawals/list.md | 10 ++++ .../version-2.0/deployment/introduction.md | 2 +- .../deployment/self-hosted/overview.md | 11 +++++ .../standard.md} | 6 +-- .../self-hosted/with-emergency-withdrawal.md | 10 ++++ .../version-2.0/foreclosure/lifecycle.md | 10 ++++ .../version-2.0/foreclosure/overview.md | 10 ++++ .../version-2.0/foreclosure/recovery-guide.md | 10 ++++ .../version-2.0-sidebars.json | 48 +++++++++++++++++-- 16 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md rename cartesi-rollups_versioned_docs/version-2.0/deployment/{self-hosted.md => self-hosted/standard.md} (97%) create mode 100644 cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md 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 new file mode 100644 index 000000000..f1e2a551c --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/backend/emergency-withdrawal.md @@ -0,0 +1,10 @@ +--- +id: emergency-withdrawal +title: Emergency Withdrawal (guest requirements) +--- + +# Emergency Withdrawal (guest requirements) + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 3 of the emergency-withdrawal docs plan. + +Guest-side responsibility: maintaining the accounts drive (withdrawable-balance ledger) whose layout matches the app's WithdrawalConfig. Cross-links to the Asset Management Library (libcma). 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 new file mode 100644 index 000000000..b3d8c95b0 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md @@ -0,0 +1,10 @@ +--- +id: iwithdrawal-output-builder +title: IWithdrawalOutputBuilder +--- + +# IWithdrawalOutputBuilder + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +Interface every withdrawal output builder implements. 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 new file mode 100644 index 000000000..21ee76eb5 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/overview.md @@ -0,0 +1,10 @@ +--- +id: overview +title: Withdrawal Contracts Overview +--- + +# Withdrawal Contracts Overview + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +How foreclosure/withdrawal on the Application contract composes with the Withdrawal Output Builder and WithdrawalConfig. 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 new file mode 100644 index 000000000..cf24b0d5e --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md @@ -0,0 +1,10 @@ +--- +id: usd-withdrawal-output-builder-factory +title: UsdWithdrawalOutputBuilderFactory +--- + +# UsdWithdrawalOutputBuilderFactory + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +Deterministic (CREATE2) factory: newUsdWithdrawalOutputBuilder / calculateUsdWithdrawalOutputBuilderAddress. 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 new file mode 100644 index 000000000..f81be3bc8 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md @@ -0,0 +1,10 @@ +--- +id: usd-withdrawal-output-builder +title: UsdWithdrawalOutputBuilder +--- + +# UsdWithdrawalOutputBuilder + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +Single-ERC-20 output builder; token() getter; the DelegateCallVoucher it produces. 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 new file mode 100644 index 000000000..4a1d4e98b --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/contracts/withdrawal/withdrawal-config.md @@ -0,0 +1,10 @@ +--- +id: withdrawal-config +title: WithdrawalConfig +--- + +# WithdrawalConfig + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +The WithdrawalConfig struct (guardian, log2LeavesPerAccount, log2MaxNumOfAccounts, accountsDriveStartIndex, withdrawalOutputBuilder) and LibWithdrawalConfig.isValid drive-size/offset rules. diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md new file mode 100644 index 000000000..53ad73c0c --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md @@ -0,0 +1,10 @@ +--- +id: withdrawals-get +title: Get Withdrawal +--- + +# Get Withdrawal + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +cartesi_getWithdrawal — a single withdrawal by (application, account_index). diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md new file mode 100644 index 000000000..9fe1d1ac2 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md @@ -0,0 +1,10 @@ +--- +id: withdrawals-list +title: List Withdrawals +--- + +# List Withdrawals + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. + +cartesi_listWithdrawals — paginated withdrawals for an application. 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 ac584e03b..4460f0066 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/introduction.md @@ -29,7 +29,7 @@ After deployment, any changes to the application code will generate a different There are two methods to deploy an application: -1. [Self-hosted deployment](./self-hosted.md): Deploy the application node using your infrastructure +1. [Self-hosted deployment](./self-hosted/overview.md): Deploy the application node using your infrastructure 2. Third-party service provider: Outsource running the application node to a service provider :::caution important diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md new file mode 100644 index 000000000..50a7a368d --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md @@ -0,0 +1,11 @@ +--- +id: overview +title: Self-hosted deployment +slug: /deployment/self-hosted +--- + +# Self-hosted deployment + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 4 of the emergency-withdrawal docs plan. + +Chooser between the standard self-hosted deployment and the emergency-withdrawal-enabled one. diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md similarity index 97% rename from cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted.md rename to cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md index e904e6b9e..e1ebc58f8 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/standard.md @@ -1,6 +1,6 @@ --- -id: self-hosted -title: Self-hosted deployment +id: standard +title: Self-hosted deployment (standard) --- This guide explains how to run a Cartesi Rollups node locally on your machine for development and testing purposes on **testnet**. @@ -23,7 +23,7 @@ Before starting, ensure you have the following installed: - Docker Desktop 4.x: The required tool to distribute the Cartesi Rollups framework and its dependencies. -For more details about the installation process for each of these tools, please refer to the [this section](../development/installation.md). +For more details about the installation process for each of these tools, please refer to the [this section](../../development/installation.md). ## Configuration 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 new file mode 100644 index 000000000..924d1c152 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/with-emergency-withdrawal.md @@ -0,0 +1,10 @@ +--- +id: with-emergency-withdrawal +title: Self-hosted with Emergency Withdrawal +--- + +# Self-hosted with Emergency Withdrawal + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 4 of the emergency-withdrawal docs plan. + +Deploy with a WithdrawalConfig (guardian, drive layout, output builder) and the recovery preconditions. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md new file mode 100644 index 000000000..fdaf7e704 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md @@ -0,0 +1,10 @@ +--- +id: lifecycle +title: Claim & Foreclosure Lifecycle +--- + +# Claim & Foreclosure Lifecycle + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 2 of the emergency-withdrawal docs plan. + +The epoch → claim → stage → accept → foreclose → prove → withdraw flow, including CLAIM_FORECLOSED terminalization. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md new file mode 100644 index 000000000..fdf68bac1 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md @@ -0,0 +1,10 @@ +--- +id: overview +title: Foreclosure & Emergency Withdrawal +--- + +# Foreclosure & Emergency Withdrawal + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; prose is authored in Phase 2 of the emergency-withdrawal docs plan. + +What foreclosure and emergency withdrawal are, the operator trust model, and when application funds are recoverable directly from the base-layer contracts without a live node. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md new file mode 100644 index 000000000..f85adff9b --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md @@ -0,0 +1,10 @@ +--- +id: recovery-guide +title: Emergency Withdrawal Recovery Guide +--- + +# Emergency Withdrawal Recovery Guide + +> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 2 of the emergency-withdrawal docs plan. + +Operational how-to: machine-tool replay → prove accounts-drive → prove-drive-root → withdraw. Includes the public-chain gas-limit caveat. diff --git a/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json b/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json index e0da3dff9..909c3a276 100644 --- a/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json +++ b/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json @@ -68,6 +68,18 @@ ] } ] + }, + { + "type": "category", + "label": "Withdrawal", + "collapsed": true, + "items": [ + "api-reference/contracts/withdrawal/overview", + "api-reference/contracts/withdrawal/withdrawal-config", + "api-reference/contracts/withdrawal/iwithdrawal-output-builder", + "api-reference/contracts/withdrawal/usd-withdrawal-output-builder", + "api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory" + ] } ] }, @@ -81,7 +93,8 @@ "api-reference/backend/reports", "api-reference/backend/vouchers", "api-reference/backend/exception", - "api-reference/backend/finish" + "api-reference/backend/finish", + "api-reference/backend/emergency-withdrawal" ] }, { @@ -141,6 +154,14 @@ "api-reference/jsonrpc/methods/node/node-version" ] }, + { + "type": "category", + "label": "Withdrawals", + "items": [ + "api-reference/jsonrpc/methods/withdrawals/withdrawals-list", + "api-reference/jsonrpc/methods/withdrawals/withdrawals-get" + ] + }, "api-reference/jsonrpc/types" ] } @@ -158,7 +179,17 @@ "development/send-inputs-and-assets", "development/query-outputs", "development/asset-handling", - "development/Advanced-configuration" + "development/Advanced-configuration", + { + "type": "category", + "label": "Foreclosure & Emergency Withdrawal", + "collapsed": true, + "items": [ + "foreclosure/overview", + "foreclosure/lifecycle", + "foreclosure/recovery-guide" + ] + } ] }, { @@ -168,7 +199,16 @@ "items": [ "deployment/introduction", "deployment/snapshot", - "deployment/self-hosted" + { + "type": "category", + "label": "Self-hosted deployment", + "collapsed": true, + "items": [ + "deployment/self-hosted/overview", + "deployment/self-hosted/standard", + "deployment/self-hosted/with-emergency-withdrawal" + ] + } ] }, { @@ -256,4 +296,4 @@ ] } ] -} \ No newline at end of file +} From 8600f2e2115aabd4c1c1c48b92654a5f611d9cf4 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 10:25:31 +0100 Subject: [PATCH 02/11] docs(v2): bump contract refs to v3.0.0-alpha.6 + document foreclosure/withdrawal on Application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump all Base Layer Contracts source refs v2.0.1 -> v3.0.0-alpha.6 (21 pages); fix EtherPortal src path typo. - application.md: 5-param constructor (adds WithdrawalConfig), intro paragraph, and full "Guardian & Foreclosure" (IApplicationForeclosure) and "Emergency Withdrawal" (IApplicationWithdrawal) sections — functions, getters, events, errors, and the AccountValidityProof struct. `yarn build` passes. --- .../contracts/application-factory.md | 2 +- .../api-reference/contracts/application.md | 269 +++++++++++++++++- .../contracts/consensus/abstract-consensus.md | 2 +- .../consensus/authority/authority-factory.md | 2 +- .../consensus/authority/authority.md | 2 +- .../consensus/authority/iauthority-factory.md | 2 +- .../consensus/authority/iauthority.md | 4 +- .../contracts/consensus/iconsensus.md | 2 +- .../ioutputs-merkle-root-validator.md | 2 +- .../contracts/consensus/overview.md | 2 +- .../consensus/quorum/iquorum-factory.md | 2 +- .../contracts/consensus/quorum/iquorum.md | 2 +- .../consensus/quorum/quorum-factory.md | 2 +- .../contracts/consensus/quorum/quorum.md | 2 +- .../api-reference/contracts/input-box.md | 2 +- .../api-reference/contracts/overview.md | 2 +- .../contracts/portals/ERC1155BatchPortal.md | 2 +- .../contracts/portals/ERC1155SinglePortal.md | 2 +- .../contracts/portals/ERC20Portal.md | 2 +- .../contracts/portals/ERC721Portal.md | 2 +- .../contracts/portals/EtherPortal.md | 2 +- 21 files changed, 288 insertions(+), 23 deletions(-) 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 e9ca2feff..63a90a30a 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,7 +2,7 @@ id: application-factory title: ApplicationFactory resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/dapp/ApplicationFactory.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/ApplicationFactory.sol title: Application Factory contract --- 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 8b8c8c7e6..45fc9d1b6 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,7 +2,7 @@ id: application title: Application resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/dapp/Application.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/dapp/Application.sol title: Application contract - url: https://docs.openzeppelin.com/contracts/5.x/ title: OpenZeppelin Contracts @@ -12,6 +12,8 @@ The **Application** contract serves as the base layer representation of the appl 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). +An Application may optionally be deployed with a [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) that enables **foreclosure and emergency withdrawal**. A designated **guardian** can foreclose the application; once foreclosed, users can withdraw their in-app balances directly from this contract by proving their accounts against the last-finalized machine state — without a live node. See [Foreclosure & Emergency Withdrawal](../../foreclosure/overview.md) for the end-to-end flow. The relevant surface is documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). + ## Functions ### `constructor()` @@ -21,12 +23,15 @@ constructor( IOutputsMerkleRootValidator outputsMerkleRootValidator, address initialOwner, bytes32 templateHash, - bytes memory dataAvailability + bytes memory dataAvailability, + 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.* + **Parameters** | Name | Type | Description | @@ -35,6 +40,7 @@ Creates an Application 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) | ### `receive()` @@ -255,3 +261,262 @@ The outputs Merkle root validator was changed. | Name | Type | Description | |------|------|-------------| | `newOutputsMerkleRootValidator` | `IOutputsMerkleRootValidator` | The new outputs Merkle root validator | + +## 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. + +### `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) +``` + +Get the address of the guardian, which has the power to foreclose the application. + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `[0]` | `address` | The guardian address | + +### `isForeclosed()` + +```solidity +function isForeclosed() external view override returns (bool) +``` + +Check whether the application has been foreclosed. An application that has been foreclosed will remain so. + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `[0]` | `bool` | Whether the application has been foreclosed | + +### `Foreclosure()` + +```solidity +event Foreclosure() +``` + +Triggered when the application is foreclosed. + +## Emergency Withdrawal + +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](../../foreclosure/recovery-guide.md); for the output-building contracts see the [Withdrawal](./withdrawal/overview.md) subsection. + +Withdrawal-related functions take an `AccountValidityProof`: + +```solidity +struct AccountValidityProof { + uint64 accountIndex; // the account's index in the accounts drive + bytes32[] accountRootSiblings; // Merkle siblings of the account root +} +``` + +### `proveAccountsDriveMerkleRoot()` + +```solidity +function proveAccountsDriveMerkleRoot( + bytes32 accountsDriveMerkleRoot, + bytes32[] calldata proof +) external override +``` + +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 | + +**Errors** + +| 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) | + +### `withdraw()` + +```solidity +function withdraw(bytes calldata account, AccountValidityProof calldata proof) external override +``` + +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. + +*On success, marks the account funds as withdrawn and emits a `Withdrawal` event.* + +**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) | +| — | Any error raised by [`validateAccount()`](#validateaccount) | + +### `getWithdrawalConfig()` + +```solidity +function getWithdrawalConfig() external view override returns (WithdrawalConfig memory withdrawalConfig) +``` + +Get the [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) set upon construction. + +### `getAccountsDriveMerkleRoot()` + +```solidity +function getAccountsDriveMerkleRoot() + external view override + returns (bool wasAccountsDriveMerkleRootProved, bytes32 accountsDriveMerkleRoot) +``` + +Check whether the accounts drive Merkle root was proved, and 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) | + +### `getNumberOfWithdrawals()` + +```solidity +function getNumberOfWithdrawals() external view override returns (uint256) +``` + +Get the number of withdrawals. Useful for fast-syncing `Withdrawal` events. + +### `wereAccountFundsWithdrawn()` + +```solidity +function wereAccountFundsWithdrawn(uint256 accountIndex) external view override returns (bool) +``` + +Check whether an account had its funds withdrawn. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `accountIndex` | `uint256` | The index of the account in the accounts drive | + +### `getLog2LeavesPerAccount()` + +```solidity +function getLog2LeavesPerAccount() external view override returns (uint8) +``` + +Get the log (base 2) of the number of machine-state-tree leaves reserved for each account in the accounts drive. + +### `getLog2MaxNumOfAccounts()` + +```solidity +function getLog2MaxNumOfAccounts() external view override returns (uint8) +``` + +Get the log (base 2) of the maximum number of accounts the accounts drive can store (the depth of the accounts drive tree). + +### `getAccountsDriveStartIndex()` + +```solidity +function getAccountsDriveStartIndex() external view override returns (uint64) +``` + +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()` + +```solidity +function getWithdrawalOutputBuilder() external view override returns (IWithdrawalOutputBuilder) +``` + +Get the [withdrawal output builder](./withdrawal/iwithdrawal-output-builder.md), which is static-called whenever an account's funds are to be withdrawn. + +### `validateAccount()` + +```solidity +function validateAccount(bytes calldata account, AccountValidityProof calldata proof) external view override +``` + +Validate the existence of an account at a given index in the accounts drive, against the accounts drive Merkle root proved through `proveAccountsDriveMerkleRoot()`. + +*May raise any error raised by [`validateAccountMerkleRoot()`](#validateaccountmerkleroot), as well as `DriveSmallerThanData` (if the provided account is too large).* + +### `validateAccountMerkleRoot()` + +```solidity +function validateAccountMerkleRoot(bytes32 accountMerkleRoot, AccountValidityProof calldata proof) external view override +``` + +Validate the existence of an account root at a given index in the accounts drive. + +**Errors** + +| 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()` + +```solidity +event AccountsDriveMerkleRootProved(bytes32 accountsDriveMerkleRoot) +``` + +Triggered when the accounts drive Merkle root is proved. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `accountsDriveMerkleRoot` | `bytes32` | The accounts drive Merkle root | + +### `Withdrawal()` + +```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 | 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 89a4624fd..7b586a402 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,7 +2,7 @@ id: abstract-consensus title: AbstractConsensus resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus/AbstractConsensus.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/AbstractConsensus.sol title: AbstractConsensus Contract --- 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 d09cfece2..48ec68eee 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/v2.0.1/src/consensus/authority/AuthorityFactory.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/AuthorityFactory.sol title: AuthorityFactory Contract --- 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 a2f8cf25b..48c604567 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,7 +2,7 @@ id: authority title: Authority resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus/authority/Authority.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/Authority.sol title: Authority Contract --- 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 11423631b..c9c91f50d 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/v2.0.1/src/consensus/authority/IAuthorityFactory.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/authority/IAuthorityFactory.sol title: IAuthorityFactory Interface --- 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 c9a2aad5c..3e04fd366 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/v2.0.1/src/consensus/authority/IAuthority.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/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/v2.0.1/src/access/IOwnable.sol): Ownership management interface \ No newline at end of file +- [`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 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 48348a664..660022646 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,7 +2,7 @@ id: iconsensus title: IConsensus resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus/IConsensus.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/IConsensus.sol title: IConsensus Interface --- 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 2fdadf48a..50381952d 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,7 +2,7 @@ id: ioutputs-merkle-root-validator title: IOutputsMerkleRootValidator resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus/IOutputsMerkleRootValidator.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/IOutputsMerkleRootValidator.sol title: IOutputsMerkleRootValidator Interface --- 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 c928237c5..dff5dd066 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,7 +2,7 @@ id: overview title: Overview resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus title: Consensus Smart Contracts --- 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 b4c12d3de..1cf78eb89 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/v2.0.1/src/consensus/quorum/IQuorumFactory.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/IQuorumFactory.sol title: IQuorumFactory Interface --- 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 660e317ec..a179662a0 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/v2.0.1/src/consensus/quorum/IQuorum.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/IQuorum.sol title: IQuorum 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 4f0d09e6d..176f177b1 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/v2.0.1/src/consensus/quorum/QuorumFactory.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/QuorumFactory.sol title: QuorumFactory Contract --- 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 0842e4f0d..629339719 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,7 +2,7 @@ id: quorum title: Quorum resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/consensus/quorum/Quorum.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/consensus/quorum/Quorum.sol title: Quorum Contract --- 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 6905bd840..2bffa0cb4 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/v2.0.1/src/inputs/InputBox.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/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 fcc5ba61c..27f21b165 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/v2.0.1 + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6 title: Smart Contracts for Cartesi Rollups --- 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 index 6426db559..b9445c683 100644 --- 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 @@ -1,6 +1,6 @@ --- resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/portals/ERC1155BatchPortal.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC1155BatchPortal.sol title: ERC1155BatchPortal contract --- 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 index 95dda15a8..a85c7ee7b 100644 --- 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 @@ -1,6 +1,6 @@ --- resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/portals/ERC1155SinglePortal.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC1155SinglePortal.sol title: ERC1155SinglePortal contract --- 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 index df75ab82a..08261f225 100644 --- 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 @@ -1,6 +1,6 @@ --- resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/portals/ERC20Portal.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC20Portal.sol title: ERC20Portal contract --- 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 index abf53dcbc..7719e399f 100644 --- 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 @@ -1,6 +1,6 @@ --- resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/portals/ERC721Portal.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/ERC721Portal.sol title: ERC721Portal contract --- 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 73b58ebf1..edf46329e 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,6 +1,6 @@ --- resources: - - url: https://github.com/cartesi/rollups-contracts/tree/v2.0.1/src/contracts/portals/EtherPortal.sol + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/portals/EtherPortal.sol title: EtherPortal contract --- From 7fe26c63890cb502771d449438015b5999231295 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 10:33:30 +0100 Subject: [PATCH 03/11] docs(v2): write Withdrawal contract reference pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fill the Base Layer Contracts → Withdrawal subsection from v3.0.0-alpha.6 sources: overview (how the pieces compose + four-way accounts-drive agreement), WithdrawalConfig (struct, drive geometry, LibWithdrawalConfig.isValid), IWithdrawalOutputBuilder, UsdWithdrawalOutputBuilder, and its factory. --- .../withdrawal/iwithdrawal-output-builder.md | 54 +++++++++++- .../contracts/withdrawal/overview.md | 30 ++++++- .../usd-withdrawal-output-builder-factory.md | 82 ++++++++++++++++++- .../usd-withdrawal-output-builder.md | 64 ++++++++++++++- .../contracts/withdrawal/withdrawal-config.md | 54 +++++++++++- 5 files changed, 269 insertions(+), 15 deletions(-) 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 b3d8c95b0..205322e8e 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 @@ -1,10 +1,58 @@ --- id: iwithdrawal-output-builder title: IWithdrawalOutputBuilder +resources: + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/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 --- -# IWithdrawalOutputBuilder +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. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +During [`withdraw()`](../application.md#withdraw), the Application **static-calls** the builder referenced by its [`WithdrawalConfig`](./withdrawal-config.md) and executes the returned output. Because the call is a `STATICCALL`, `buildWithdrawalOutput` must be side-effect free (`view`/`pure`): any state change — contract creation, log emission, storage write, self-destruct, or Ether transfer — reverts the call and aborts the withdrawal. -Interface every withdrawal output builder implements. +The account encoding is **application-specific**. See [UsdWithdrawalOutputBuilder](./usd-withdrawal-output-builder.md) for the single-ERC-20 implementation. + +## Functions + +### `buildWithdrawalOutput()` + +```solidity +function buildWithdrawalOutput(address appContract, bytes calldata account) + external + view + 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 | + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `output` | `bytes` | The withdrawal output | + +## Errors + +### `AccountTooShort()` + +```solidity +error AccountTooShort(uint64 attemptedAccountSize, uint64 minAccountSize) +``` + +Raised when the provided account is too short for the builder to decode on-chain. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `attemptedAccountSize` | `uint64` | The attempted account size, in bytes | +| `minAccountSize` | `uint64` | The minimum expected account size, in bytes | 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 21ee76eb5..94eb43c81 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,8 +3,32 @@ id: overview title: Withdrawal Contracts Overview --- -# Withdrawal Contracts Overview +These contracts implement **emergency withdrawal** — the ability for users to recover their in-app balances directly from the base layer after an application is [foreclosed](../application.md#guardian--foreclosure), without a live node. For the end-to-end concept and operator procedure, see [Foreclosure & Emergency Withdrawal](../../../foreclosure/overview.md). -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +## How the pieces fit together -How foreclosure/withdrawal on the Application contract composes with the Withdrawal Output Builder and WithdrawalConfig. +The withdrawal machinery lives partly on the [`Application`](../application.md) contract and partly in a small set of supporting contracts: + +| Piece | Where | Role | +|-------|-------|------| +| Foreclosure + withdrawal logic | [`Application`](../application.md) (`IApplicationForeclosure`, `IApplicationWithdrawal`) | `foreclose`, `proveAccountsDriveMerkleRoot`, `withdraw`, and the account/getter 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` | + +## 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. +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; +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. + +A mismatch on any of the four makes proofs fail to validate or funds impossible to build — so these values must be chosen together at deploy time. See [WithdrawalConfig — drive geometry](./withdrawal-config.md#drive-geometry). 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 cf24b0d5e..93dbaa17f 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 @@ -1,10 +1,86 @@ --- 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 + title: UsdWithdrawalOutputBuilderFactory contract + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IUsdWithdrawalOutputBuilderFactory.sol + title: IUsdWithdrawalOutputBuilderFactory interface --- -# UsdWithdrawalOutputBuilderFactory +**`UsdWithdrawalOutputBuilderFactory`** lets anyone deterministically deploy a [`UsdWithdrawalOutputBuilder`](./usd-withdrawal-output-builder.md) for a given ERC-20 token. 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 deterministic (`CREATE2`) from the token and salt. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +The factory is constructed with a shared `SafeERC20Transfer` contract, which it passes to every builder it deploys (used as the delegate-call voucher destination). -Deterministic (CREATE2) factory: newUsdWithdrawalOutputBuilder / calculateUsdWithdrawalOutputBuilderAddress. +## Functions + +### `newUsdWithdrawalOutputBuilder()` + +```solidity +function newUsdWithdrawalOutputBuilder(IERC20 token, bytes32 salt) + external + returns (IUsdWithdrawalOutputBuilder usdWithdrawalOutputBuilder) +``` + +Deploy a new USD withdrawal output builder deterministically. Emits `UsdWithdrawalOutputBuilderCreated`. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `token` | `IERC20` | The USD-like ERC-20 token | +| `salt` | `bytes32` | The salt used to deterministically generate the contract address | + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `usdWithdrawalOutputBuilder` | `IUsdWithdrawalOutputBuilder` | The deployed builder | + +### `calculateUsdWithdrawalOutputBuilderAddress()` + +```solidity +function calculateUsdWithdrawalOutputBuilderAddress(IERC20 token, bytes32 salt) + external + view + returns (address usdWithdrawalOutputBuilderAddress) +``` + +Compute the deterministic address a builder for `token`/`salt` would have, whether or not it is already deployed. Use this to obtain the builder address for a [`WithdrawalConfig`](./withdrawal-config.md) without deploying. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `token` | `IERC20` | The USD-like ERC-20 token | +| `salt` | `bytes32` | The salt used to deterministically generate the contract address | + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `usdWithdrawalOutputBuilderAddress` | `address` | The deterministic builder address | + +### `getSafeErc20Transfer()` + +```solidity +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). + +## Events + +### `UsdWithdrawalOutputBuilderCreated()` + +```solidity +event UsdWithdrawalOutputBuilderCreated(IUsdWithdrawalOutputBuilder usdWithdrawalOutputBuilder) +``` + +Triggered on a successful call to `newUsdWithdrawalOutputBuilder`. + +**Parameters** + +| Name | Type | Description | +|------|------|-------------| +| `usdWithdrawalOutputBuilder` | `IUsdWithdrawalOutputBuilder` | The newly deployed builder | 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 f81be3bc8..3405ed945 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 @@ -1,10 +1,68 @@ --- 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 + title: UsdWithdrawalOutputBuilder contract + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/withdrawal/IUsdWithdrawalOutputBuilder.sol + title: IUsdWithdrawalOutputBuilder interface --- -# UsdWithdrawalOutputBuilder +**`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). -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +For each account it produces a **`DelegateCallVoucher`** that delegate-calls a shared `SafeERC20Transfer` contract to move `balance` of the token to the account owner. -Single-ERC-20 output builder; token() getter; the DelegateCallVoucher it produces. +## Functions + +### `constructor()` + +```solidity +constructor(ISafeERC20Transfer safeErc20Transfer, IERC20 usd) +``` + +**Parameters** + +| 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 | + +### `token()` + +```solidity +function token() external view override returns (IERC20) +``` + +Get the ERC-20 token used to generate withdrawal outputs. + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `[0]` | `IERC20` | The configured token | + +### `buildWithdrawalOutput()` + +```solidity +function buildWithdrawalOutput(address, 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)` | + +**Return Values** + +| Name | Type | Description | +|------|------|-------------| +| `output` | `bytes` | An ABI-encoded `DelegateCallVoucher(destination, payload)` where `destination` is the `SafeERC20Transfer` contract and `payload` is `safeTransfer(token, user, balance)` | + +*Raises [`AccountTooShort`](./iwithdrawal-output-builder.md#accounttooshort) if the account cannot be decoded.* 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 4a1d4e98b..9ba61b884 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 @@ -1,10 +1,58 @@ --- id: withdrawal-config title: WithdrawalConfig +resources: + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/common/WithdrawalConfig.sol + title: WithdrawalConfig struct + - url: https://github.com/cartesi/rollups-contracts/tree/v3.0.0-alpha.6/src/library/LibWithdrawalConfig.sol + title: LibWithdrawalConfig library --- -# WithdrawalConfig +The **`WithdrawalConfig`** struct is passed to the [`Application`](../application.md#constructor) constructor to enable **foreclosure and emergency withdrawal**. It defines who may foreclose the application (the **guardian**), the geometry of the **accounts drive** (the in-app balance ledger held inside the machine state), and the contract that builds withdrawal outputs. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +A **zero-valued** `WithdrawalConfig` is valid and deploys an application **without** the feature. -The WithdrawalConfig struct (guardian, log2LeavesPerAccount, log2MaxNumOfAccounts, accountsDriveStartIndex, withdrawalOutputBuilder) and LibWithdrawalConfig.isValid drive-size/offset rules. +## Struct + +```solidity +struct WithdrawalConfig { + address guardian; + uint8 log2LeavesPerAccount; + uint8 log2MaxNumOfAccounts; + uint64 accountsDriveStartIndex; + IWithdrawalOutputBuilder withdrawalOutputBuilder; +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `guardian` | `address` | The account allowed to call [`foreclose()`](../application.md#foreclose). | +| `log2LeavesPerAccount` | `uint8` | Log2 of the machine-state-tree leaves reserved per account. Each account record occupies `2^(5 + log2LeavesPerAccount)` bytes. | +| `log2MaxNumOfAccounts` | `uint8` | Log2 of the maximum number of accounts — i.e. the depth of the accounts-drive tree. | +| `accountsDriveStartIndex` | `uint64` | Start-index factor that positions the accounts drive in machine memory (see [Drive geometry](#drive-geometry)). | +| `withdrawalOutputBuilder` | `IWithdrawalOutputBuilder` | The contract that builds the withdrawal output for an account. See [IWithdrawalOutputBuilder](./iwithdrawal-output-builder.md). | + +## Drive geometry + +Let `a = log2LeavesPerAccount`, `b = log2MaxNumOfAccounts`, and `c = accountsDriveStartIndex`. The accounts drive: + +- has **size** `2^(a + b + 5)` bytes — the `+5` is the log2 of the 32-byte data block (`CanonicalMachine.LOG2_DATA_BLOCK_SIZE`); +- **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. + +## Validation — `LibWithdrawalConfig.isValid()` + +```solidity +function isValid(WithdrawalConfig memory withdrawalConfig) internal pure returns (bool) +``` + +The `Application` constructor calls `isValid()` and reverts with `InvalidWithdrawalConfig` (see [ApplicationFactory](../application-factory.md)) if it returns `false`. `isValid()` enforces that the accounts drive fits inside the machine memory: + +- `log2(driveSize) = 5 + log2MaxNumOfAccounts + log2LeavesPerAccount` must not exceed `64` (the machine memory is `2^64` bytes); and +- the drive's end address `(accountsDriveStartIndex + 1) << log2(driveSize)` must not overflow and must not exceed `2^64`. + +:::note +`isValid()` validates only the **drive geometry**. It does **not** reject a zero `guardian` or a zero `withdrawalOutputBuilder` — a geometry-valid config with those zeroed will pass the constructor. Deployment tooling (for example the Cartesi Rollups CLI) additionally refuses a zero guardian or builder for an *enabled* config; a direct factory call would not. +::: From 7bd5251bd91f83acdc88b108dc8e9005b632ed6a Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 10:39:23 +0100 Subject: [PATCH 04/11] docs(v2): ApplicationFactory withdrawalConfig + JSON-RPC withdrawals reference - application-factory.md: add WithdrawalConfig to newApplication (x2), calculateApplicationAddress, and the ApplicationCreated event; document the InvalidWithdrawalConfig error. - JSON-RPC: fill cartesi_listWithdrawals and cartesi_getWithdrawal from the node model/handlers; add the Withdrawal interface + WithdrawalList/GetResult to types. --- .../contracts/application-factory.md | 26 +++++- .../api-reference/contracts/application.md | 4 +- .../withdrawal/iwithdrawal-output-builder.md | 2 +- .../contracts/withdrawal/overview.md | 4 +- .../usd-withdrawal-output-builder-factory.md | 2 +- .../contracts/withdrawal/withdrawal-config.md | 8 +- .../jsonrpc/methods/withdrawals/get.md | 68 ++++++++++++++- .../jsonrpc/methods/withdrawals/list.md | 87 ++++++++++++++++++- .../api-reference/jsonrpc/types.md | 35 ++++++++ 9 files changed, 221 insertions(+), 15 deletions(-) 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 63a90a30a..164950726 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 @@ -21,7 +21,8 @@ function newApplication( IOutputsMerkleRootValidator outputsMerkleRootValidator, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability + bytes calldata dataAvailability, + WithdrawalConfig calldata withdrawalConfig ) external override returns (IApplication) ``` @@ -35,6 +36,7 @@ Deploys a new Application contract without a salt value for address derivation. | `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 | **Return Values** @@ -50,6 +52,7 @@ function newApplication( address appOwner, bytes32 templateHash, bytes calldata dataAvailability, + WithdrawalConfig calldata withdrawalConfig, bytes32 salt ) external override returns (IApplication) ``` @@ -64,6 +67,7 @@ Deploys a new `Application` contract with a specified salt value for address der | `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 Values** @@ -80,6 +84,7 @@ function calculateApplicationAddress( address appOwner, bytes32 templateHash, bytes calldata dataAvailability, + WithdrawalConfig calldata withdrawalConfig, bytes32 salt ) external view override returns (address) ``` @@ -94,6 +99,7 @@ Calculates the address of a potential new Application contract based on input pa | `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 Values** @@ -112,6 +118,7 @@ event ApplicationCreated( address appOwner, bytes32 templateHash, bytes dataAvailability, + WithdrawalConfig withdrawalConfig, IApplication appContract ) ``` @@ -126,4 +133,21 @@ A new Application contract was deployed. | `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 | + +## Errors + +### `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** + +| Name | Type | Description | +|------|------|-------------| +| `withdrawalConfig` | `WithdrawalConfig` | The invalid withdrawal configuration | 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 45fc9d1b6..3636825c8 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 @@ -12,7 +12,7 @@ The **Application** contract serves as the base layer representation of the appl 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). -An Application may optionally be deployed with a [`WithdrawalConfig`](./withdrawal/withdrawal-config.md) that enables **foreclosure and emergency withdrawal**. A designated **guardian** can foreclose the application; once foreclosed, users can withdraw their in-app balances directly from this contract by proving their accounts against the last-finalized machine state — without a live node. See [Foreclosure & Emergency Withdrawal](../../foreclosure/overview.md) for the end-to-end flow. The relevant surface is documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). +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](../../foreclosure/overview.md) for the full flow. These functions are documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). ## Functions @@ -383,7 +383,7 @@ Withdraw the funds of an account from the foreclosed application. First the acco |-------|-----------| | `NotForeclosed` | The application has not been foreclosed | | `AccountFundsAlreadyWithdrawn(uint64)` | The account's funds were already withdrawn (argument is the account index) | -| — | Any error raised by [`validateAccount()`](#validateaccount) | +| Errors from `validateAccount()` | The account fails validation (see [`validateAccount()`](#validateaccount)) | ### `getWithdrawalConfig()` 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 205322e8e..40574ffaa 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 @@ -10,7 +10,7 @@ resources: 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. -During [`withdraw()`](../application.md#withdraw), the Application **static-calls** the builder referenced by its [`WithdrawalConfig`](./withdrawal-config.md) and executes the returned output. Because the call is a `STATICCALL`, `buildWithdrawalOutput` must be side-effect free (`view`/`pure`): any state change — contract creation, log emission, storage write, self-destruct, or Ether transfer — reverts the call and aborts the withdrawal. +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 account encoding is **application-specific**. See [UsdWithdrawalOutputBuilder](./usd-withdrawal-output-builder.md) for the single-ERC-20 implementation. 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 94eb43c81..b92796574 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: Withdrawal Contracts Overview --- -These contracts implement **emergency withdrawal** — the ability for users to recover their in-app balances directly from the base layer after an application is [foreclosed](../application.md#guardian--foreclosure), without a live node. For the end-to-end concept and operator procedure, see [Foreclosure & Emergency Withdrawal](../../../foreclosure/overview.md). +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](../../../foreclosure/overview.md). ## How the pieces fit together @@ -31,4 +31,4 @@ Emergency withdrawal only works if four descriptions of the **accounts drive** a 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. -A mismatch on any of the four makes proofs fail to validate or funds impossible to build — so these values must be chosen together at deploy time. See [WithdrawalConfig — drive geometry](./withdrawal-config.md#drive-geometry). +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). 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 93dbaa17f..b0df75c82 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 @@ -8,7 +8,7 @@ resources: title: IUsdWithdrawalOutputBuilderFactory interface --- -**`UsdWithdrawalOutputBuilderFactory`** lets anyone deterministically deploy a [`UsdWithdrawalOutputBuilder`](./usd-withdrawal-output-builder.md) for a given ERC-20 token. 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 deterministic (`CREATE2`) from the token and salt. +**`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). 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 9ba61b884..079421295 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 @@ -28,7 +28,7 @@ struct WithdrawalConfig { |-------|------|-------------| | `guardian` | `address` | The account allowed to call [`foreclose()`](../application.md#foreclose). | | `log2LeavesPerAccount` | `uint8` | Log2 of the machine-state-tree leaves reserved per account. Each account record occupies `2^(5 + log2LeavesPerAccount)` bytes. | -| `log2MaxNumOfAccounts` | `uint8` | Log2 of the maximum number of accounts — i.e. the depth of the accounts-drive tree. | +| `log2MaxNumOfAccounts` | `uint8` | Log2 of the maximum number of accounts. This is the depth of the accounts-drive tree. | | `accountsDriveStartIndex` | `uint64` | Start-index factor that positions the accounts drive in machine memory (see [Drive geometry](#drive-geometry)). | | `withdrawalOutputBuilder` | `IWithdrawalOutputBuilder` | The contract that builds the withdrawal output for an account. See [IWithdrawalOutputBuilder](./iwithdrawal-output-builder.md). | @@ -36,13 +36,13 @@ struct WithdrawalConfig { Let `a = log2LeavesPerAccount`, `b = log2MaxNumOfAccounts`, and `c = accountsDriveStartIndex`. The accounts drive: -- has **size** `2^(a + b + 5)` bytes — the `+5` is the log2 of the 32-byte data block (`CanonicalMachine.LOG2_DATA_BLOCK_SIZE`); +- has a **size** of `2^(a + b + 5)` bytes (the `+5` is the log2 of the 32-byte data block, `CanonicalMachine.LOG2_DATA_BLOCK_SIZE`); - **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. -## Validation — `LibWithdrawalConfig.isValid()` +## Validation ```solidity function isValid(WithdrawalConfig memory withdrawalConfig) internal pure returns (bool) @@ -54,5 +54,5 @@ The `Application` constructor calls `isValid()` and reverts with `InvalidWithdra - the drive's end address `(accountsDriveStartIndex + 1) << log2(driveSize)` must not overflow and must not exceed `2^64`. :::note -`isValid()` validates only the **drive geometry**. It does **not** reject a zero `guardian` or a zero `withdrawalOutputBuilder` — a geometry-valid config with those zeroed will pass the constructor. Deployment tooling (for example the Cartesi Rollups CLI) additionally refuses a zero guardian or builder for an *enabled* config; a direct factory call would not. +`isValid()` checks only the **drive geometry**. It does **not** reject a zero `guardian` or a zero `withdrawalOutputBuilder`. A config with those set to zero still passes the constructor, as long as its geometry is valid. Deployment tools such as the Cartesi Rollups CLI go further and refuse a zero guardian or builder for an *enabled* config, but a direct factory call would not. ::: diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md index 53ad73c0c..41364b2cf 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/get.md @@ -5,6 +5,70 @@ title: Get Withdrawal # Get Withdrawal -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +## Example Request -cartesi_getWithdrawal — a single withdrawal by (application, account_index). +```json +{ + "jsonrpc": "2.0", + "method": "cartesi_getWithdrawal", + "params": { + "application": "", + "account_index": "" + }, + "id": 1 +} +``` + +The `cartesi_getWithdrawal` method retrieves a single emergency withdrawal by its application and account index. + +## Parameters + +| Name | Type | Required | Description | +|---------------|--------|----------|--------------------------------------------------| +| application | string | Yes | The application's name or hex encoded address | +| account_index | string | Yes | The account index in the accounts drive (hex encoded) | + +## Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "data": { + "account_index": "0x0", + "account": "0xe803000000000000bd8eba8bf9e56ad92f4c4fc89d6cb8890253574900000000", + "output": "0x10321e8b...", + "block_number": "0xaac079", + "transaction_hash": "0xfe6c84b741624b237b6d09a9f71a174e81a59e5eedb7893a77f238b45e833656", + "log_index": "0x2b7", + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T00:00:00Z" + } + }, + "id": 1 +} +``` + +### Response Fields + +See the [`Withdrawal`](../../types.md#withdrawal) type. + +| Name | Type | Description | +|------------------|--------|--------------------------------------------------| +| account_index | string | The account index in the accounts drive (hex encoded) | +| account | string | The account as encoded in the accounts drive (hex) | +| output | string | The withdrawal output (hex encoded) | +| block_number | string | The block number of the `Withdrawal` event (hex encoded) | +| transaction_hash | string | The transaction hash of the withdrawal | +| log_index | string | The log index within the block (hex encoded) | +| created_at | string | Timestamp when the withdrawal was recorded | +| updated_at | string | Timestamp when the withdrawal was last updated | + +## Error Codes + +| Code | Message | Description | +|---------|------------------------|--------------------------------------------------| +| -32602 | Invalid params | Invalid parameter values | +| -32000 | Application not found | The specified application does not exist | +| -32003 | Withdrawal not found | The specified withdrawal does not exist | +| -32603 | Internal error | An internal error occurred | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md index 9fe1d1ac2..acc3bfd5d 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/methods/withdrawals/list.md @@ -5,6 +5,89 @@ title: List Withdrawals # List Withdrawals -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 1 of the emergency-withdrawal docs plan. +## Example Request -cartesi_listWithdrawals — paginated withdrawals for an application. +```json +{ + "jsonrpc": "2.0", + "method": "cartesi_listWithdrawals", + "params": { + "application": "", + "limit": 10, + "offset": 0 + }, + "id": 1 +} +``` + +The `cartesi_listWithdrawals` method returns a paginated list of emergency withdrawals observed on-chain for a specific application. Each entry corresponds to a `Withdrawal` event emitted by the application's [`withdraw()`](../../../contracts/application.md#withdraw) function after foreclosure. + +## Parameters + +| Name | Type | Required | Description | +|---------------|--------|----------|--------------------------------------------------| +| application | string | Yes | The application's name or hex encoded address | +| account_index | string | No | Filter by a specific account index (hex encoded) | +| limit | number | No | Maximum number of withdrawals to return (default: 50, minimum: 1) | +| offset | number | No | Starting point for the list (default: 0, minimum: 0) | + +## Response + +```json +{ + "jsonrpc": "2.0", + "result": { + "data": [ + { + "account_index": "0x0", + "account": "0xe803000000000000bd8eba8bf9e56ad92f4c4fc89d6cb8890253574900000000", + "output": "0x10321e8b...", + "block_number": "0xaac079", + "transaction_hash": "0xfe6c84b741624b237b6d09a9f71a174e81a59e5eedb7893a77f238b45e833656", + "log_index": "0x2b7", + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T00:00:00Z" + } + ], + "pagination": { + "total_count": 1, + "limit": 50, + "offset": 0 + } + }, + "id": 1 +} +``` + +### Response Fields + +#### Data + +See the [`Withdrawal`](../../types.md#withdrawal) type. + +| Name | Type | Description | +|------------------|--------|--------------------------------------------------| +| account_index | string | The account index in the accounts drive (hex encoded) | +| account | string | The account as encoded in the accounts drive (hex) | +| output | string | The withdrawal output (hex encoded) | +| block_number | string | The block number of the `Withdrawal` event (hex encoded) | +| transaction_hash | string | The transaction hash of the withdrawal | +| log_index | string | The log index within the block (hex encoded) | +| created_at | string | Timestamp when the withdrawal was recorded | +| updated_at | string | Timestamp when the withdrawal was last updated | + +#### Pagination + +| Name | Type | Description | +|-------------|--------|--------------------------------------------------| +| total_count | number | Total number of withdrawals available | +| limit | number | Number of withdrawals returned in this response | +| offset | number | Starting point of the returned withdrawals | + +## Error Codes + +| Code | Message | Description | +|---------|------------------------|--------------------------------------------------| +| -32602 | Invalid params | Invalid parameter values | +| -32000 | Application not found | The specified application does not exist | +| -32603 | Internal error | An internal error occurred | diff --git a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md index 5503698ad..83e13ed96 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md +++ b/cartesi-rollups_versioned_docs/version-2.0/api-reference/jsonrpc/types.md @@ -326,6 +326,22 @@ interface Report { } ``` +### Withdrawal +Represents an emergency withdrawal observed on-chain (a `Withdrawal` event emitted by the application after foreclosure). See [`Application.withdraw()`](../contracts/application.md#withdraw). + +```typescript +interface Withdrawal { + account_index: UnsignedInteger; + account: ByteArray; + output: ByteArray; + block_number: UnsignedInteger; + transaction_hash: Hash; + log_index: UnsignedInteger; + created_at: Timestamp; + updated_at: Timestamp; +} +``` + ### Pagination Represents pagination information for list responses. @@ -452,6 +468,25 @@ interface ReportGetResult { } ``` +### WithdrawalListResult +Result for listing withdrawals. + +```typescript +interface WithdrawalListResult { + data: Withdrawal[]; + pagination: Pagination; +} +``` + +### WithdrawalGetResult +Result for getting a single withdrawal. + +```typescript +interface WithdrawalGetResult { + data: Withdrawal; +} +``` + ### ChainIdResult Result for getting the chain ID. From 6b077f7e4742bda4b1bb69a7e1e116ca7fe7d80c Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 10:59:50 +0100 Subject: [PATCH 05/11] docs(v2): write Foreclosure & Emergency Withdrawal concept + guide (Phase 2) - overview: what foreclosure/emergency withdrawal are, the two parts, the operator trust model (protects against an operator who disappears, not one who lies), and when funds are recoverable. - lifecycle: inputs -> epochs -> claim -> submit/stage/accept, the epoch-status flow (with an ASCII state diagram), foreclosure effects, and prove+withdraw. - recovery-guide: step-by-step foreclose -> replay -> prove accounts-drive -> prove-drive-root -> withdraw -> verify, plus the public-chain 30M-gas caveat. Plain wording, no em-dashes. Build passes. --- .../version-2.0/foreclosure/lifecycle.md | 56 +++++++++++- .../version-2.0/foreclosure/overview.md | 37 +++++++- .../version-2.0/foreclosure/recovery-guide.md | 91 ++++++++++++++++++- 3 files changed, 175 insertions(+), 9 deletions(-) diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md index fdaf7e704..8fdcdcfc5 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md @@ -3,8 +3,58 @@ id: lifecycle title: Claim & Foreclosure Lifecycle --- -# Claim & Foreclosure Lifecycle +To understand foreclosure, it helps to first see how an application's inputs turn into settled state, and where foreclosure fits in. This page walks through that lifecycle. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 2 of the emergency-withdrawal docs plan. +## From inputs to a settled claim -The epoch → claim → stage → accept → foreclose → prove → withdraw flow, including CLAIM_FORECLOSED terminalization. +**Inputs.** A user action (a deposit through a portal, or a message sent to the app) becomes an **input**, recorded on-chain in the [`InputBox`](../api-reference/contracts/input-box.md). + +**Epochs.** Inputs are not settled one at a time. They are grouped into **epochs**, where an epoch is a fixed range of blocks (set by the consensus `epochLength`). Every input is assigned to an epoch by the block it arrived in. + +**Claims.** The application runs as a deterministic Cartesi Machine. Once an epoch's block range closes, the node feeds that epoch's inputs to the machine, which updates its state and produces outputs. The node then reduces the result to a single fingerprint, a **claim** (a Merkle root), and posts it on-chain so the consensus contract can trust the off-chain computation by checking one hash. + +Posting a claim happens in **two transactions**, both sent by the operator: + +1. **Submit** (`submitClaim`) posts the claim. The epoch becomes `CLAIM_STAGED`. +2. **Accept** (`acceptClaim`) finalizes it, once a waiting period has passed. The epoch becomes `CLAIM_ACCEPTED`. + +The waiting period between the two is the **claim staging period**, measured in blocks and fixed when the consensus is deployed. The consensus contract enforces it: `acceptClaim` reverts until enough blocks have passed. A staging period of `0` lets acceptance happen right away. + +## The epoch status flow + +An epoch moves through these statuses: + +```text +OPEN ──▶ INPUTS_PROCESSED ──▶ CLAIM_COMPUTED ──▶ CLAIM_STAGED ──▶ CLAIM_ACCEPTED + │ (machine ran (claim/root (submitted (finalized + │ the inputs) computed) on-chain, on-chain) + │ waiting) + │ │ + └─────────────────────── if the app is foreclosed ───┴──▶ CLAIM_FORECLOSED +``` + +- **OPEN**: the epoch's block range is still current and collecting inputs. +- **INPUTS_PROCESSED**: the range closed and the machine processed the inputs. +- **CLAIM_COMPUTED**: the node has the claim ready. +- **CLAIM_STAGED**: the claim was submitted on-chain and is in its staging window. +- **CLAIM_ACCEPTED**: the staging period elapsed and the claim was finalized. This is the settled state that outputs (and emergency withdrawal) rely on. +- **CLAIM_FORECLOSED**: a terminal status a claim reaches if the application is foreclosed before that claim finalizes (see below). + +## Foreclosure + +Everything above assumes the operator keeps running the node. Foreclosure is what happens when you no longer want to depend on that. + +The **guardian** calls [`foreclose()`](../api-reference/contracts/application.md#foreclose). This freezes the application: [`isForeclosed()`](../api-reference/contracts/application.md#isforeclosed) becomes `true` and stays `true`. Foreclosure has three effects on claims: + +- **Accepted history is kept.** An epoch that already reached `CLAIM_ACCEPTED` stays accepted. Foreclosure does not rewrite settled history. +- **In-flight claims are cancelled.** A claim that has not finalized cannot finalize once the operator's authority is frozen, so the node marks it terminal as `CLAIM_FORECLOSED` instead of leaving it stuck. This happens whether the claim was still pre-staging (`CLAIM_COMPUTED`) or already `CLAIM_STAGED`. +- **The state is frozen.** The application settles at its last accepted epoch, a final state that anyone can reproduce on their own. + +## After foreclosure: prove and withdraw + +Once frozen, the accounts drive (the in-app balance ledger inside the machine state) at the last settled epoch is the source of truth for balances. Turning that into on-chain payouts takes two on-chain steps: + +1. **Anchor the ledger.** Anyone calls [`proveAccountsDriveMerkleRoot()`](../api-reference/contracts/application.md#proveaccountsdrivemerkleroot) once, proving the accounts-drive root against the settled machine state. The contract stores it. +2. **Withdraw per account.** Each user calls [`withdraw()`](../api-reference/contracts/application.md#withdraw) with their account and a Merkle proof. The contract validates the account against the anchored root, builds a transfer output, runs it, and marks the account as withdrawn so it cannot be withdrawn twice. + +The [Emergency Withdrawal Recovery Guide](./recovery-guide.md) turns these steps into concrete commands. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md index fdf68bac1..b70e5ea58 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md @@ -3,8 +3,39 @@ id: overview title: Foreclosure & Emergency Withdrawal --- -# Foreclosure & Emergency Withdrawal +When users deposit assets into a Cartesi Rollups application, those assets are held by the application contract on the base layer, and the application's off-chain state (an in-app ledger of who owns what) decides how they can be spent. In normal operation the operator runs a node that keeps this state moving and settles it on-chain. But what happens to those funds if the operator stops running the node? -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; prose is authored in Phase 2 of the emergency-withdrawal docs plan. +**Foreclosure and emergency withdrawal** are the answer. They let a designated **guardian** freeze an application, after which any user can withdraw their in-app balance straight from the base-layer contracts by proving their account, with **no running node required**. -What foreclosure and emergency withdrawal are, the operator trust model, and when application funds are recoverable directly from the base-layer contracts without a live node. +The feature is opt-in: an application only supports it if it was deployed with a [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md). Applications deployed without one behave exactly as before. + +## The two parts + +**Foreclosure** freezes the application. A guardian address, set in the withdrawal config, calls [`foreclose()`](../api-reference/contracts/application.md#foreclose). From that moment the application is frozen at its last settled state, and it stays frozen forever. See [FOR-005](../api-reference/contracts/application.md#foreclose) for the guardian-only rule. + +**Emergency withdrawal** is the recovery path that foreclosure unlocks. The application's **accounts drive** (the in-app balance ledger, held inside the machine state) is proved on-chain once, and then each user withdraws their own balance by proving their account against that proved ledger. Everything happens directly against the contracts, so it keeps working even if the operator and its node are gone. + +## What you are trusting + +This is important to understand before relying on the feature. + +An application is settled by a **consensus** contract. With an [`Authority`](../api-reference/contracts/consensus/authority/authority.md) consensus (a single operator), the operator is **trusted to settle honest state**. The contracts do not re-run the machine, so they accept whatever state the operator finalizes. + +:::warning +Foreclosure protects you against an operator who **disappears**, not against one who **lies**. Emergency withdrawal faithfully pays out whatever state was finalized. If a dishonest Authority operator settles a state that omits a deposit, that deposit is not recoverable through this path. Trust-minimized consensus models (such as Quorum or dispute-based settlement) reduce this risk by not relying on a single operator's honesty. +::: + +## When funds are recoverable + +All of the following must hold: + +1. the application was deployed with a valid [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md) (a guardian, an accounts-drive layout, and a withdrawal output builder); +2. the guest application actually maintains the [accounts drive](../api-reference/backend/emergency-withdrawal.md) in the layout the config describes; +3. the application has been **foreclosed** by its guardian; and +4. the account's balance was part of the last settled state. + +## Where to go next + +- [Claim & Foreclosure Lifecycle](./lifecycle.md) explains how inputs become settled state, and how foreclosure fits into that lifecycle. +- [Emergency Withdrawal Recovery Guide](./recovery-guide.md) is the step-by-step procedure for foreclosing and withdrawing. +- The [Application](../api-reference/contracts/application.md#guardian--foreclosure) and [Withdrawal](../api-reference/contracts/withdrawal/overview.md) contract pages are the on-chain reference. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md index f85adff9b..2c4b49475 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md @@ -3,8 +3,93 @@ id: recovery-guide title: Emergency Withdrawal Recovery Guide --- -# Emergency Withdrawal Recovery Guide +This guide walks through foreclosing an application and withdrawing an account's funds directly from the base-layer contracts. For the concepts behind each step, see [Foreclosure & Emergency Withdrawal](./overview.md) and the [Claim & Foreclosure Lifecycle](./lifecycle.md). -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 2 of the emergency-withdrawal docs plan. +## Before you start -Operational how-to: machine-tool replay → prove accounts-drive → prove-drive-root → withdraw. Includes the public-chain gas-limit caveat. +You need: + +- an application that was deployed with a [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md), and that has reached at least one accepted epoch; +- the **guardian** key (only the guardian can foreclose); +- the [`cartesi-rollups-cli`](../development/installation.md) and the **machine tool** (`cartesi-rollups-machine-tool`), which reproduces the settled machine state and generates the proofs; +- the application's **accounts-drive parameters** from its withdrawal config: `accountsDriveStartIndex`, `log2MaxNumOfAccounts`, and `log2LeavesPerAccount`. These must match the values the application was deployed with. + +## Step 1: Foreclose the application + +Signed by the guardian, freeze the application: + +```sh +cartesi-rollups-cli foreclose --yes +``` + +After this, `isForeclosed()` returns `true` and the application is frozen at its last accepted epoch. + +## Step 2: Reproduce the settled machine state + +Find the last accepted epoch, then replay the node database into a machine snapshot up to that epoch: + +```sh +cartesi-rollups-machine-tool replay \ + --template \ + --application \ + --to-epoch \ + --store replay-snapshot +``` + +Replay is deterministic: running it again produces the same machine state, so anyone can reproduce this snapshot independently. + +## Step 3: Generate the proofs + +From that snapshot, generate the accounts-drive-root proof and the per-account proof for the account you want to withdraw. The `--accounts-drive-*` values **must match the withdrawal config**. + +```sh +cartesi-rollups-machine-tool prove accounts-drive \ + --snapshot replay-snapshot \ + --accounts-drive-start-index \ + --log2-max-num-of-accounts \ + --log2-leaves-per-account \ + --account \ + --out-drive-root-proof drive-root-proof.json \ + --out-withdraw-proof account-proof.json +``` + +This writes two files: `drive-root-proof.json` (used once, in step 4) and `account-proof.json` (used per account, in step 5). + +## Step 4: Anchor the accounts-drive root on-chain + +Record the accounts-drive root against the settled machine state. This is permissionless and only needs to happen once per foreclosed application: + +```sh +cartesi-rollups-cli prove-drive-root \ + --proof-file drive-root-proof.json --yes +``` + +On success the contract stores the root and emits `AccountsDriveMerkleRootProved`. Anchoring a root from the wrong epoch, or from a different application, is rejected. + +## Step 5: Withdraw the account's funds + +With the root anchored, withdraw the account: + +```sh +cartesi-rollups-cli withdraw \ + --proof-file account-proof.json --yes +``` + +The contract validates the account against the anchored root, builds and runs the transfer, marks the account as withdrawn, and emits a `Withdrawal` event. Withdrawing the same account again is rejected. + +## Step 6: Verify + +```sh +# the node indexes the on-chain Withdrawal event +cartesi-rollups-cli read withdrawals +``` + +You can also read the on-chain state directly: [`wereAccountFundsWithdrawn(accountIndex)`](../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. + +## Public-chain gas limit + +:::warning +On public chains, the transaction-sending `cartesi-rollups-cli` subcommands (`foreclose`, `prove-drive-root`, `withdraw`, and others) currently send transactions with a fixed 30,000,000 gas limit. Public networks reject a per-transaction gas limit that high (for example EIP-7825 caps a single transaction at `2^24` gas), so these commands fail there even though the calls themselves use far less gas. + +Until this is fixed, perform these calls on public chains with a **direct contract call** using an estimated or sane gas limit (for example with `cast send`), instead of the CLI subcommand. Read-only commands (`app register`, `read withdrawals`, and similar) are not affected. +::: From 6e4324167ba35bb919a339a75ec14ffb1f4e972d Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 11:11:06 +0100 Subject: [PATCH 06/11] docs(v2): backend accounts-drive page + self-hosted split content (Phases 3-4) - backend/emergency-withdrawal: the guest requirement to maintain the accounts drive matching the WithdrawalConfig, record layout, and the four-way agreement. - deployment/self-hosted split: overview chooser (keeps old URL via slug), standard (existing content), and with-emergency-withdrawal (same compose + a machine-tool service, deploy with --withdrawal-config-file, recovery link). Plain wording, no em-dashes. Build passes. --- .../backend/emergency-withdrawal.md | 35 ++++++++- .../deployment/self-hosted/overview.md | 9 ++- .../self-hosted/with-emergency-withdrawal.md | 74 ++++++++++++++++++- 3 files changed, 109 insertions(+), 9 deletions(-) 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 f1e2a551c..b2ad4006c 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 @@ -3,8 +3,37 @@ id: emergency-withdrawal title: Emergency Withdrawal (guest requirements) --- -# Emergency Withdrawal (guest requirements) +[Emergency withdrawal](../../foreclosure/overview.md) lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the **guest application** (the code running inside the Cartesi Machine) must do to support it. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 3 of the emergency-withdrawal docs plan. +## The accounts drive -Guest-side responsibility: maintaining the accounts drive (withdrawable-balance ledger) whose layout matches the app's WithdrawalConfig. Cross-links to the Asset Management Library (libcma). +The application keeps a dedicated region of machine memory called the **accounts drive**. It is the withdrawable-balance ledger: a list of account records, where each record holds an owner and that owner's balance. After foreclosure, the contracts prove this drive against the settled machine state and pay each account out from it. + +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. + +If the layout the guest writes and the config the contract was given disagree, proofs will not validate and funds cannot be withdrawn. + +## Matching the layout + +The [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md) describes the drive with three values, and the guest must write records that match them: + +- `accountsDriveStartIndex` positions the drive in machine memory; +- `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. + +## Keeping the balances + +You rarely need to write the drive by hand. A ledger library such as **libcma** (the Cartesi Machine accounts library used by asset-holding applications) maintains the accounts drive for you: it credits deposits, debits withdrawals and transfers, and stores every balance in the drive so it stays provable from the machine state. + +## 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. + +:::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/deployment/self-hosted/overview.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md index 50a7a368d..34e71e5cd 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md @@ -4,8 +4,11 @@ title: Self-hosted deployment slug: /deployment/self-hosted --- -# Self-hosted deployment +Self-hosting means running a Cartesi Rollups node yourself to deploy and operate your application, instead of using a third-party provider. This section covers two paths: -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 4 of the emergency-withdrawal docs plan. +- **[Standard deployment](./standard.md)** runs the node and deploys a regular application. Start here if you do not need emergency withdrawal. +- **[Deployment with emergency withdrawal](./with-emergency-withdrawal.md)** builds on the standard setup and deploys the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so a guardian can foreclose it and users can recover their funds directly from the contracts. Read the [Foreclosure & Emergency Withdrawal](../../foreclosure/overview.md) concept first. -Chooser between the standard self-hosted deployment and the emergency-withdrawal-enabled one. +:::warning Production Warning +**This self-hosted approach should NOT be used in _production_.** It is designed for development and testing on **testnet**. It lacks production requirements such as public snapshot verification, security hardening, and production-grade infrastructure. +::: 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 924d1c152..7a7053c18 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 @@ -3,8 +3,76 @@ id: with-emergency-withdrawal title: Self-hosted with Emergency Withdrawal --- -# Self-hosted with Emergency Withdrawal +This guide builds on the [standard self-hosted deployment](./standard.md) and adds what is needed to support [emergency withdrawal](../../foreclosure/overview.md): deploying the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), and adding the machine tool to your compose so you can generate withdrawal proofs later. -> 🚧 **Scaffold (Phase 0).** Placeholder wired into the sidebar; content is authored in Phase 4 of the emergency-withdrawal docs plan. +Follow the standard guide for the base setup (prerequisites, the `.env` file, downloading the compose file, and running the node). Only the differences are described here. -Deploy with a WithdrawalConfig (guardian, drive layout, output builder) and the recovery preconditions. +:::warning Production Warning +Like the standard setup, this is for development and testing on **testnet**, not production. +::: + +## What is different + +1. Your application must maintain an **accounts drive** so balances are provable from the machine state. See [Emergency Withdrawal (guest requirements)](../../api-reference/backend/emergency-withdrawal.md). +2. You deploy the application with a **withdrawal config** instead of a plain deploy. +3. You add a **machine-tool** service to the same compose file, used to generate proofs during recovery. + +## Extra prerequisites + +- A **guardian** address. This account, and only this account, can foreclose the application. +- A **withdrawal output builder** for your token. For a single ERC-20, deploy one with the [`UsdWithdrawalOutputBuilderFactory`](../../api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md), or reuse an existing one for the same token. Note its address. +- An application whose guest maintains the accounts drive in a known layout. + +## Step 1: Prepare the withdrawal config + +Create a `withdrawal.json` describing the guardian and the accounts-drive layout. These values must match what your guest application actually writes (see [WithdrawalConfig](../../api-reference/contracts/withdrawal/withdrawal-config.md#drive-geometry)): + +```json +{ + "guardian": "", + "log2_leaves_per_account": 0, + "log2_max_num_of_accounts": 12, + "accounts_drive_start_index": 309237645312, + "withdrawal_output_builder": "" +} +``` + +## Step 2: Deploy with the withdrawal config + +Deploy and register the application as in the standard guide, adding `--withdrawal-config-file`: + +```shell +docker compose --project-name cartesi-rollups-node \ + exec advancer cartesi-rollups-cli deploy application /var/lib/cartesi-rollups-node/snapshot \ + --epoch-length 10 \ + --withdrawal-config-file withdrawal.json \ + --salt \ + --register +``` + +The deployment is rejected if the config is invalid (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. + +## Step 3: Add the machine tool to your compose + +Recovery uses `cartesi-rollups-machine-tool` to reproduce the settled machine state and generate proofs. Add it as an extra service in the **same** `compose.local.yaml`, sharing the node's database and snapshot volumes, and run it on demand rather than keeping it up: + +```yaml + machine-tool: + image: + entrypoint: ["cartesi-rollups-machine-tool"] + depends_on: + database: + condition: service_healthy + volumes: + # share the node's snapshots and an output directory for the proofs + - ./node-snapshots:/var/lib/cartesi-rollups-node/snapshot + - ./artifacts:/artifacts + environment: + CARTESI_DATABASE_CONNECTION: +``` + +You then invoke it with `docker compose ... run --rm machine-tool replay ...` and `... prove accounts-drive ...` during recovery. + +## Step 4: Recovery + +When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../foreclosure/recovery-guide.md). From c12733cabc3f30884df4e342cd46e22073091bf8 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 11:26:29 +0100 Subject: [PATCH 07/11] docs(v2): revise self-hosted EW guide, rename overview pages, drop gas caveat - with-emergency-withdrawal: remove the manual machine-tool compose step (it is already in the standard compose file); add Configuration and full "Setting up the local node" steps (download compose, build, run, deploy with --withdrawal-config-file), mirroring the standard flow. Recovery stays last. - Rename both overview pages' title to "Overview" (foreclosure + self-hosted), so the sidebar entries read "Overview" under their categories. - recovery-guide: remove the public-chain gas-limit section (being fixed for the next alpha). Build passes. --- .../deployment/self-hosted/overview.md | 2 +- .../self-hosted/with-emergency-withdrawal.md | 113 +++++++++++------- .../version-2.0/foreclosure/overview.md | 2 +- .../version-2.0/foreclosure/recovery-guide.md | 8 -- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md index 34e71e5cd..bf014b665 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md @@ -1,6 +1,6 @@ --- id: overview -title: Self-hosted deployment +title: Overview slug: /deployment/self-hosted --- 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 7a7053c18..59fd74ffb 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 @@ -3,27 +3,47 @@ id: with-emergency-withdrawal title: Self-hosted with Emergency Withdrawal --- -This guide builds on the [standard self-hosted deployment](./standard.md) and adds what is needed to support [emergency withdrawal](../../foreclosure/overview.md): deploying the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), and adding the machine tool to your compose so you can generate withdrawal proofs later. - -Follow the standard guide for the base setup (prerequisites, the `.env` file, downloading the compose file, and running the node). Only the differences are described here. +This guide runs a self-hosted node and deploys an application that supports [emergency withdrawal](../../foreclosure/overview.md): a guardian can foreclose it, and users can then recover their funds directly from the contracts. It follows the same flow as the [standard deployment](./standard.md), with a few additions. Read the [Foreclosure & Emergency Withdrawal overview](../../foreclosure/overview.md) first for the concept. :::warning Production Warning Like the standard setup, this is for development and testing on **testnet**, not production. ::: -## What is different - -1. Your application must maintain an **accounts drive** so balances are provable from the machine state. See [Emergency Withdrawal (guest requirements)](../../api-reference/backend/emergency-withdrawal.md). -2. You deploy the application with a **withdrawal config** instead of a plain deploy. -3. You add a **machine-tool** service to the same compose file, used to generate proofs during recovery. +## Prerequisites -## Extra prerequisites +In addition to the [standard prerequisites](./standard.md#prerequisites) (Cartesi CLI and Docker Desktop), you need: - A **guardian** address. This account, and only this account, can foreclose the application. - A **withdrawal output builder** for your token. For a single ERC-20, deploy one with the [`UsdWithdrawalOutputBuilderFactory`](../../api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md), or reuse an existing one for the same token. Note its address. -- An application whose guest maintains the accounts drive in a known layout. +- An application whose guest maintains an **accounts drive** in a known layout. See [Emergency Withdrawal (guest requirements)](../../api-reference/backend/emergency-withdrawal.md). + +## Configuration -## Step 1: Prepare the withdrawal config +Configure your `.env` file exactly as in the standard flow: + +```shell +BLOCKCHAIN_ID= +AUTH_KIND="private_key" +CARTESI_AUTH_PRIVATE_KEY="" +BLOCKCHAIN_WS_ENDPOINT="" +BLOCKCHAIN_HTTP_ENDPOINT="" +CARTESI_BLOCKCHAIN_DEFAULT_BLOCK="" +``` + +| Variable | Description | +| ---------------------------------- | -------------------------------------------------------------------- | +| `BLOCKCHAIN_ID` | Your blockchain network ID | +| `BLOCKCHAIN_WS_ENDPOINT` | Your WebSocket endpoint | +| `BLOCKCHAIN_HTTP_ENDPOINT` | Your HTTP endpoint | +| `AUTH_KIND` | Set to `private_key` for local development | +| `CARTESI_AUTH_PRIVATE_KEY` | A funded private key for the selected chain | +| `CARTESI_BLOCKCHAIN_DEFAULT_BLOCK` | Set to either `latest` or `finalized` | + +:::danger Security +Follow best practices when handling private keys during local development and deployment. +::: + +## Prepare the withdrawal config Create a `withdrawal.json` describing the guardian and the accounts-drive layout. These values must match what your guest application actually writes (see [WithdrawalConfig](../../api-reference/contracts/withdrawal/withdrawal-config.md#drive-geometry)): @@ -37,42 +57,49 @@ Create a `withdrawal.json` describing the guardian and the accounts-drive layout } ``` -## Step 2: Deploy with the withdrawal config +## Setting up the local node -Deploy and register the application as in the standard guide, adding `--withdrawal-config-file`: +1. **Download the Cartesi Rollups Node docker compose file in your project root:** -```shell -docker compose --project-name cartesi-rollups-node \ - exec advancer cartesi-rollups-cli deploy application /var/lib/cartesi-rollups-node/snapshot \ - --epoch-length 10 \ - --withdrawal-config-file withdrawal.json \ - --salt \ - --register -``` + ```shell + curl -L https://raw.githubusercontent.com/Mugen-Builders/deployment-setup-v2.0/main/compose.local.yaml -o compose.local.yaml + ``` -The deployment is rejected if the config is invalid (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. - -## Step 3: Add the machine tool to your compose - -Recovery uses `cartesi-rollups-machine-tool` to reproduce the settled machine state and generate proofs. Add it as an extra service in the **same** `compose.local.yaml`, sharing the node's database and snapshot volumes, and run it on demand rather than keeping it up: - -```yaml - machine-tool: - image: - entrypoint: ["cartesi-rollups-machine-tool"] - depends_on: - database: - condition: service_healthy - volumes: - # share the node's snapshots and an output directory for the proofs - - ./node-snapshots:/var/lib/cartesi-rollups-node/snapshot - - ./artifacts:/artifacts - environment: - CARTESI_DATABASE_CONNECTION: -``` + This is the same compose file used by the standard flow. It already includes the machine-tool service used later for recovery, so there is nothing extra to add. + +2. **Build the application with the Cartesi CLI:** + + ```shell + cartesi build + ``` + + This compiles your application into RISC-V and creates a Cartesi machine snapshot locally. Make sure your application maintains its accounts drive in the layout described by `withdrawal.json`. + +3. **Run the Cartesi Rollups Node with the application's initial snapshot attached:** + + ```shell + docker compose -f compose.local.yaml --env-file .env up -d + ``` + +4. **Deploy and register the application with its withdrawal config:** + + Make the config file readable inside the `advancer` container, then deploy with `--withdrawal-config-file`: + + ```shell + docker compose --project-name cartesi-rollups-node cp withdrawal.json advancer:/tmp/withdrawal.json + + docker compose --project-name cartesi-rollups-node \ + exec advancer cartesi-rollups-cli deploy application /var/lib/cartesi-rollups-node/snapshot \ + --epoch-length 10 \ + --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. -You then invoke it with `docker compose ... run --rm machine-tool replay ...` and `... prove accounts-drive ...` during recovery. + After this, your application is deployed and registered, and a guardian can foreclose it when needed. -## Step 4: Recovery +## Recovery When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../foreclosure/recovery-guide.md). diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md index b70e5ea58..3da89dfbf 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md @@ -1,6 +1,6 @@ --- id: overview -title: Foreclosure & Emergency Withdrawal +title: Overview --- When users deposit assets into a Cartesi Rollups application, those assets are held by the application contract on the base layer, and the application's off-chain state (an in-app ledger of who owns what) decides how they can be spent. In normal operation the operator runs a node that keeps this state moving and settles it on-chain. But what happens to those funds if the operator stops running the node? diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md index 2c4b49475..b7938e1cc 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md +++ b/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md @@ -85,11 +85,3 @@ cartesi-rollups-cli read withdrawals ``` You can also read the on-chain state directly: [`wereAccountFundsWithdrawn(accountIndex)`](../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. - -## Public-chain gas limit - -:::warning -On public chains, the transaction-sending `cartesi-rollups-cli` subcommands (`foreclose`, `prove-drive-root`, `withdraw`, and others) currently send transactions with a fixed 30,000,000 gas limit. Public networks reject a per-transaction gas limit that high (for example EIP-7825 caps a single transaction at `2^24` gas), so these commands fail there even though the calls themselves use far less gas. - -Until this is fixed, perform these calls on public chains with a **direct contract call** using an estimated or sane gas limit (for example with `cast send`), instead of the CLI subcommand. Read-only commands (`app register`, `read withdrawals`, and similar) are not affected. -::: From 5af94e1a4567c0ec418107a484e889fcef59c831 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 11:35:29 +0100 Subject: [PATCH 08/11] docs(v2): document cartesi.toml accounts drive + ledger library for EW deploy - with-emergency-withdrawal: add a "Configure the machine and ledger" section covering the cartesi.toml accounts-drive block ([drives.accounts], raw/empty, final_hash) and the requirement that the app use a ledger library to write balances in a provable layout. - Link the Asset Management Library docs (temporarily via the PR-303 preview URL, since that page is not on this branch yet) from both the deploy guide and the backend guest-requirements page. Build passes. NOTE: the two Asset Management links use the pr-preview/pr-303 URL; swap them for the internal ../asset-management/overview.md once PR #303 merges to main. --- .../backend/emergency-withdrawal.md | 2 +- .../self-hosted/with-emergency-withdrawal.md | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) 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 b2ad4006c..c1f1a8b6a 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 @@ -28,7 +28,7 @@ For the single-token case (see [`UsdWithdrawalOutputBuilder`](../contracts/withd ## Keeping the balances -You rarely need to write the drive by hand. A ledger library such as **libcma** (the Cartesi Machine accounts library used by asset-holding applications) maintains the accounts drive for you: it credits deposits, debits withdrawals and transfers, and stores every balance in the drive so it stays provable from the machine state. +You rarely need to write the drive by hand. A ledger library maintains the accounts drive for you: it credits deposits, debits withdrawals and transfers, and stores every balance in the drive so it stays provable from the machine state. See the [Asset Management Library](https://cartesi.github.io/docs/pr-preview/pr-303/cartesi-rollups/2.0/api-reference/asset-management/overview/) for how to store and manage balances this way. ## The account encoding must round-trip 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 59fd74ffb..d0b7df9b3 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 @@ -17,6 +17,38 @@ In addition to the [standard prerequisites](./standard.md#prerequisites) (Cartes - A **withdrawal output builder** for your token. For a single ERC-20, deploy one with the [`UsdWithdrawalOutputBuilderFactory`](../../api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md), or reuse an existing one for the same token. Note its address. - An application whose guest maintains an **accounts drive** in a known layout. See [Emergency Withdrawal (guest requirements)](../../api-reference/backend/emergency-withdrawal.md). +## 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 flash drive that holds the balance ledger. Declare it in your `cartesi.toml` alongside the root drive, and enable `final_hash` so the machine hash is produced for on-chain deployment: + +```toml +[machine] +# ...your existing machine settings... +final_hash = true + +# The application and OS, built from your Dockerfile. +[drives.root] +builder = "docker" +dockerfile = "Dockerfile" +format = "ext2" + +# The accounts drive: a raw, unformatted flash drive for the balance ledger. +[drives.accounts] +builder = "empty" +format = "raw" +size = 4194304 # size in bytes +mount = false +user = "dapp" +``` + +The accounts drive is deliberately **raw and unmounted**: the application opens the block device directly (for example `/dev/pmem1`) and writes balance records into it, with no filesystem in between. + +**Your application must use a ledger library to write those balances in a recoverable (provable) layout.** The library keeps the record layout consistent with the [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so that after foreclosure the balances can be proved on-chain and withdrawn. For how to store and manage balances this way, see the [Asset Management Library](https://cartesi.github.io/docs/pr-preview/pr-303/cartesi-rollups/2.0/api-reference/asset-management/overview/). + +:::note +The drive's `size`, the ledger's record layout, and the `WithdrawalConfig` values (`log2_leaves_per_account`, `log2_max_num_of_accounts`, `accounts_drive_start_index`) must be chosen together. `accounts_drive_start_index` equals the drive's machine-memory start address divided by the proven-region size `2^(5 + log2_max_num_of_accounts + log2_leaves_per_account)`. You can read the built drive's position from `.cartesi/image/config.json`. +::: + ## Configuration Configure your `.env` file exactly as in the standard flow: From d3a9196fa7bbffe49e0dcfe8955f6a40afd78372 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Mon, 6 Jul 2026 16:59:46 +0100 Subject: [PATCH 09/11] docs(v2): minor page updates and add the Claim & Foreclosure lifecycle image - Rename the Withdrawal contracts overview page title to Overview. - Remove the "What you are trusting" section from the Foreclosure overview. - Move the foreclosure pages into the development/ folder to match the sidebar nesting, updating the sidebar and all inbound/outbound links. - Replace the epoch-status ASCII diagram with the epoch-flow.png image. --- .../backend/emergency-withdrawal.md | 2 +- .../api-reference/contracts/application.md | 4 ++-- .../contracts/withdrawal/overview.md | 4 ++-- .../deployment/self-hosted/overview.md | 2 +- .../self-hosted/with-emergency-withdrawal.md | 4 ++-- .../foreclosure/lifecycle.md | 17 +++++---------- .../{ => development}/foreclosure/overview.md | 20 +++++------------- .../foreclosure/recovery-guide.md | 6 +++--- .../version-2.0/epoch-flow.png | Bin 0 -> 62070 bytes .../version-2.0-sidebars.json | 6 +++--- 10 files changed, 24 insertions(+), 41 deletions(-) rename cartesi-rollups_versioned_docs/version-2.0/{ => development}/foreclosure/lifecycle.md (71%) rename cartesi-rollups_versioned_docs/version-2.0/{ => development}/foreclosure/overview.md (52%) rename cartesi-rollups_versioned_docs/version-2.0/{ => development}/foreclosure/recovery-guide.md (86%) create mode 100644 cartesi-rollups_versioned_docs/version-2.0/epoch-flow.png 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 c1f1a8b6a..af5855f37 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 @@ -3,7 +3,7 @@ id: emergency-withdrawal title: Emergency Withdrawal (guest requirements) --- -[Emergency withdrawal](../../foreclosure/overview.md) lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the **guest application** (the code running inside the Cartesi Machine) must do to support it. +[Emergency withdrawal](../../development/foreclosure/overview.md) lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the **guest application** (the code running inside the Cartesi Machine) must do to support it. ## The accounts drive 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 3636825c8..da8bd9556 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 @@ -12,7 +12,7 @@ The **Application** contract serves as the base layer representation of the appl 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). -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](../../foreclosure/overview.md) for the full flow. These functions are documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). +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/foreclosure/overview.md) for the full flow. These functions are documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). ## Functions @@ -320,7 +320,7 @@ Triggered when the application is foreclosed. ## Emergency Withdrawal -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](../../foreclosure/recovery-guide.md); for the output-building contracts see the [Withdrawal](./withdrawal/overview.md) subsection. +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/foreclosure/recovery-guide.md); for the output-building contracts see the [Withdrawal](./withdrawal/overview.md) subsection. Withdrawal-related functions take an `AccountValidityProof`: 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 b92796574..96b347dcd 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 @@ -1,9 +1,9 @@ --- id: overview -title: Withdrawal Contracts 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](../../../foreclosure/overview.md). +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/foreclosure/overview.md). ## How the pieces fit together diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md index bf014b665..5fced019d 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md @@ -7,7 +7,7 @@ slug: /deployment/self-hosted Self-hosting means running a Cartesi Rollups node yourself to deploy and operate your application, instead of using a third-party provider. This section covers two paths: - **[Standard deployment](./standard.md)** runs the node and deploys a regular application. Start here if you do not need emergency withdrawal. -- **[Deployment with emergency withdrawal](./with-emergency-withdrawal.md)** builds on the standard setup and deploys the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so a guardian can foreclose it and users can recover their funds directly from the contracts. Read the [Foreclosure & Emergency Withdrawal](../../foreclosure/overview.md) concept first. +- **[Deployment with emergency withdrawal](./with-emergency-withdrawal.md)** builds on the standard setup and deploys the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so a guardian can foreclose it and users can recover their funds directly from the contracts. Read the [Foreclosure & Emergency Withdrawal](../../development/foreclosure/overview.md) concept first. :::warning Production Warning **This self-hosted approach should NOT be used in _production_.** It is designed for development and testing on **testnet**. It lacks production requirements such as public snapshot verification, security hardening, and production-grade infrastructure. 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 d0b7df9b3..3bfde4d53 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 @@ -3,7 +3,7 @@ id: with-emergency-withdrawal title: Self-hosted with Emergency Withdrawal --- -This guide runs a self-hosted node and deploys an application that supports [emergency withdrawal](../../foreclosure/overview.md): a guardian can foreclose it, and users can then recover their funds directly from the contracts. It follows the same flow as the [standard deployment](./standard.md), with a few additions. Read the [Foreclosure & Emergency Withdrawal overview](../../foreclosure/overview.md) first for the concept. +This guide runs a self-hosted node and deploys an application that supports [emergency withdrawal](../../development/foreclosure/overview.md): a guardian can foreclose it, and users can then recover their funds directly from the contracts. It follows the same flow as the [standard deployment](./standard.md), with a few additions. Read the [Foreclosure & Emergency Withdrawal overview](../../development/foreclosure/overview.md) first for the concept. :::warning Production Warning Like the standard setup, this is for development and testing on **testnet**, not production. @@ -134,4 +134,4 @@ Create a `withdrawal.json` describing the guardian and the accounts-drive layout ## Recovery -When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../foreclosure/recovery-guide.md). +When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../development/foreclosure/recovery-guide.md). diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md similarity index 71% rename from cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md rename to cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md index 8fdcdcfc5..f8a01ea4a 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/lifecycle.md +++ b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md @@ -7,7 +7,7 @@ To understand foreclosure, it helps to first see how an application's inputs tur ## From inputs to a settled claim -**Inputs.** A user action (a deposit through a portal, or a message sent to the app) becomes an **input**, recorded on-chain in the [`InputBox`](../api-reference/contracts/input-box.md). +**Inputs.** A user action (a deposit through a portal, or a message sent to the app) becomes an **input**, recorded on-chain in the [`InputBox`](../../api-reference/contracts/input-box.md). **Epochs.** Inputs are not settled one at a time. They are grouped into **epochs**, where an epoch is a fixed range of blocks (set by the consensus `epochLength`). Every input is assigned to an epoch by the block it arrived in. @@ -24,14 +24,7 @@ The waiting period between the two is the **claim staging period**, measured in An epoch moves through these statuses: -```text -OPEN ──▶ INPUTS_PROCESSED ──▶ CLAIM_COMPUTED ──▶ CLAIM_STAGED ──▶ CLAIM_ACCEPTED - │ (machine ran (claim/root (submitted (finalized - │ the inputs) computed) on-chain, on-chain) - │ waiting) - │ │ - └─────────────────────── if the app is foreclosed ───┴──▶ CLAIM_FORECLOSED -``` +![Epoch status flow: OPEN to INPUTS_PROCESSED to CLAIM_COMPUTED to CLAIM_STAGED to CLAIM_ACCEPTED, with a foreclosure branch diverting an unfinalized claim to CLAIM_FORECLOSED](../../epoch-flow.png) - **OPEN**: the epoch's block range is still current and collecting inputs. - **INPUTS_PROCESSED**: the range closed and the machine processed the inputs. @@ -44,7 +37,7 @@ OPEN ──▶ INPUTS_PROCESSED ──▶ CLAIM_COMPUTED ──▶ CLAIM_STAGED Everything above assumes the operator keeps running the node. Foreclosure is what happens when you no longer want to depend on that. -The **guardian** calls [`foreclose()`](../api-reference/contracts/application.md#foreclose). This freezes the application: [`isForeclosed()`](../api-reference/contracts/application.md#isforeclosed) becomes `true` and stays `true`. Foreclosure has three effects on claims: +The **guardian** calls [`foreclose()`](../../api-reference/contracts/application.md#foreclose). This freezes the application: [`isForeclosed()`](../../api-reference/contracts/application.md#isforeclosed) becomes `true` and stays `true`. Foreclosure has three effects on claims: - **Accepted history is kept.** An epoch that already reached `CLAIM_ACCEPTED` stays accepted. Foreclosure does not rewrite settled history. - **In-flight claims are cancelled.** A claim that has not finalized cannot finalize once the operator's authority is frozen, so the node marks it terminal as `CLAIM_FORECLOSED` instead of leaving it stuck. This happens whether the claim was still pre-staging (`CLAIM_COMPUTED`) or already `CLAIM_STAGED`. @@ -54,7 +47,7 @@ The **guardian** calls [`foreclose()`](../api-reference/contracts/application.md Once frozen, the accounts drive (the in-app balance ledger inside the machine state) at the last settled epoch is the source of truth for balances. Turning that into on-chain payouts takes two on-chain steps: -1. **Anchor the ledger.** Anyone calls [`proveAccountsDriveMerkleRoot()`](../api-reference/contracts/application.md#proveaccountsdrivemerkleroot) once, proving the accounts-drive root against the settled machine state. The contract stores it. -2. **Withdraw per account.** Each user calls [`withdraw()`](../api-reference/contracts/application.md#withdraw) with their account and a Merkle proof. The contract validates the account against the anchored root, builds a transfer output, runs it, and marks the account as withdrawn so it cannot be withdrawn twice. +1. **Anchor the ledger.** Anyone calls [`proveAccountsDriveMerkleRoot()`](../../api-reference/contracts/application.md#proveaccountsdrivemerkleroot) once, proving the accounts-drive root against the settled machine state. The contract stores it. +2. **Withdraw per account.** Each user calls [`withdraw()`](../../api-reference/contracts/application.md#withdraw) with their account and a Merkle proof. The contract validates the account against the anchored root, builds a transfer output, runs it, and marks the account as withdrawn so it cannot be withdrawn twice. The [Emergency Withdrawal Recovery Guide](./recovery-guide.md) turns these steps into concrete commands. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md similarity index 52% rename from cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md rename to cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md index 3da89dfbf..2a8510e2f 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md @@ -7,30 +7,20 @@ When users deposit assets into a Cartesi Rollups application, those assets are h **Foreclosure and emergency withdrawal** are the answer. They let a designated **guardian** freeze an application, after which any user can withdraw their in-app balance straight from the base-layer contracts by proving their account, with **no running node required**. -The feature is opt-in: an application only supports it if it was deployed with a [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md). Applications deployed without one behave exactly as before. +The feature is opt-in: an application only supports it if it was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md). Applications deployed without one behave exactly as before. ## The two parts -**Foreclosure** freezes the application. A guardian address, set in the withdrawal config, calls [`foreclose()`](../api-reference/contracts/application.md#foreclose). From that moment the application is frozen at its last settled state, and it stays frozen forever. See [FOR-005](../api-reference/contracts/application.md#foreclose) for the guardian-only rule. +**Foreclosure** freezes the application. A guardian address, set in the withdrawal config, calls [`foreclose()`](../../api-reference/contracts/application.md#foreclose). From that moment the application is frozen at its last settled state, and it stays frozen forever. See [FOR-005](../../api-reference/contracts/application.md#foreclose) for the guardian-only rule. **Emergency withdrawal** is the recovery path that foreclosure unlocks. The application's **accounts drive** (the in-app balance ledger, held inside the machine state) is proved on-chain once, and then each user withdraws their own balance by proving their account against that proved ledger. Everything happens directly against the contracts, so it keeps working even if the operator and its node are gone. -## What you are trusting - -This is important to understand before relying on the feature. - -An application is settled by a **consensus** contract. With an [`Authority`](../api-reference/contracts/consensus/authority/authority.md) consensus (a single operator), the operator is **trusted to settle honest state**. The contracts do not re-run the machine, so they accept whatever state the operator finalizes. - -:::warning -Foreclosure protects you against an operator who **disappears**, not against one who **lies**. Emergency withdrawal faithfully pays out whatever state was finalized. If a dishonest Authority operator settles a state that omits a deposit, that deposit is not recoverable through this path. Trust-minimized consensus models (such as Quorum or dispute-based settlement) reduce this risk by not relying on a single operator's honesty. -::: - ## When funds are recoverable All of the following must hold: -1. the application was deployed with a valid [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md) (a guardian, an accounts-drive layout, and a withdrawal output builder); -2. the guest application actually maintains the [accounts drive](../api-reference/backend/emergency-withdrawal.md) in the layout the config describes; +1. the application was deployed with a valid [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md) (a guardian, an accounts-drive layout, and a withdrawal output builder); +2. the guest application actually maintains the [accounts drive](../../api-reference/backend/emergency-withdrawal.md) in the layout the config describes; 3. the application has been **foreclosed** by its guardian; and 4. the account's balance was part of the last settled state. @@ -38,4 +28,4 @@ All of the following must hold: - [Claim & Foreclosure Lifecycle](./lifecycle.md) explains how inputs become settled state, and how foreclosure fits into that lifecycle. - [Emergency Withdrawal Recovery Guide](./recovery-guide.md) is the step-by-step procedure for foreclosing and withdrawing. -- The [Application](../api-reference/contracts/application.md#guardian--foreclosure) and [Withdrawal](../api-reference/contracts/withdrawal/overview.md) contract pages are the on-chain reference. +- The [Application](../../api-reference/contracts/application.md#guardian--foreclosure) and [Withdrawal](../../api-reference/contracts/withdrawal/overview.md) contract pages are the on-chain reference. diff --git a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md similarity index 86% rename from cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md rename to cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md index b7938e1cc..7e14e4822 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/foreclosure/recovery-guide.md +++ b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md @@ -9,9 +9,9 @@ This guide walks through foreclosing an application and withdrawing an account's You need: -- an application that was deployed with a [`WithdrawalConfig`](../api-reference/contracts/withdrawal/withdrawal-config.md), and that has reached at least one accepted epoch; +- an application that was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), and that has reached at least one accepted epoch; - the **guardian** key (only the guardian can foreclose); -- the [`cartesi-rollups-cli`](../development/installation.md) and the **machine tool** (`cartesi-rollups-machine-tool`), which reproduces the settled machine state and generates the proofs; +- the [`cartesi-rollups-cli`](../installation.md) and the **machine tool** (`cartesi-rollups-machine-tool`), which reproduces the settled machine state and generates the proofs; - the application's **accounts-drive parameters** from its withdrawal config: `accountsDriveStartIndex`, `log2MaxNumOfAccounts`, and `log2LeavesPerAccount`. These must match the values the application was deployed with. ## Step 1: Foreclose the application @@ -84,4 +84,4 @@ The contract validates the account against the anchored root, builds and runs th cartesi-rollups-cli read withdrawals ``` -You can also read the on-chain state directly: [`wereAccountFundsWithdrawn(accountIndex)`](../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. +You can also read the on-chain state directly: [`wereAccountFundsWithdrawn(accountIndex)`](../../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. diff --git a/cartesi-rollups_versioned_docs/version-2.0/epoch-flow.png b/cartesi-rollups_versioned_docs/version-2.0/epoch-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..b8ec3246b2cb2e7f85156f29d0a87814f69fb7a5 GIT binary patch literal 62070 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 Date: Mon, 6 Jul 2026 16:59:46 +0100 Subject: [PATCH 10/11] docs(llms.txt): index the emergency-withdrawal pages Add the Foreclosure & Emergency Withdrawal guides (under Development), the Withdrawal contract pages, the backend accounts-drive page, the JSON-RPC withdrawals methods, and the self-hosted standard / with-emergency-withdrawal split. Update the Development documentation-map bullet. --- static/llms.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/static/llms.txt b/static/llms.txt index 1342fd355..a409e2140 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -17,7 +17,7 @@ Use this file to discover and navigate Cartesi's documentation. Each link below - **Cartesi Machine** — the off-chain RISC-V Linux VM; covers host CLI, Lua scripting, blockchain integration, and the verification game. - **Cartesi Rollups v2.0** — the current application framework. Sub-sections: - *Getting Started* — architecture, concepts, installation. - - *Development* — building, running, sending inputs, querying outputs, asset handling. + - *Development* — building, running, sending inputs, querying outputs, asset handling, and foreclosure & emergency withdrawal (recovering funds directly from the contracts after an app is foreclosed). - *API Reference* — HTTP backend API, inspect API, contract ABI, JSON-RPC node API. - *Deployment* — self-hosted node, public snapshot. - *Tutorials* — end-to-end worked examples (Counter, Calculator, Marketplace, wallets, React frontend). @@ -91,6 +91,9 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C - [Query outputs](https://docs.cartesi.io/cartesi-rollups/2.0/development/query-outputs.md): Vouchers, notices and reports - [Asset handling](https://docs.cartesi.io/cartesi-rollups/2.0/development/asset-handling.md): Deposits and withdrawals - [Advanced configuration](https://docs.cartesi.io/cartesi-rollups/2.0/development/Advanced-configuration.md): Configure the Cartesi Machine via cartesi.toml +- [Foreclosure & Emergency Withdrawal](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/overview.md): What foreclosure and emergency withdrawal are, and when application funds are recoverable directly from the contracts +- [Claim & Foreclosure Lifecycle](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/lifecycle.md): How inputs become settled claims, and how foreclosure fits the epoch and claim lifecycle +- [Emergency Withdrawal Recovery Guide](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/recovery-guide.md): Step-by-step foreclose, replay, prove the accounts drive, and withdraw ## Cartesi Rollups v2.0 — Development Snippets @@ -144,13 +147,19 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C - [Reports](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/reports.md): Application logs - [Exception](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/exception.md): Register exceptions - [Finish](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/finish.md): Complete request processing +- [Emergency Withdrawal (guest requirements)](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/emergency-withdrawal.md): Maintaining the accounts drive so balances are recoverable after foreclosure ## Cartesi Rollups v2.0 — Contracts API - [Contracts Overview](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/overview.md): All smart contracts in the framework - [InputBox](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/input-box.md): Entry point for user inputs - [Application](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/application.md): Per-dApp contract holding assets -- [ApplicationFactory](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/application-factory.md): Deploy Application contracts +- [ApplicationFactory](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/application-factory.md): Deploy Application contracts (with an optional WithdrawalConfig) +- [Withdrawal Contracts Overview](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/withdrawal/overview.md): How foreclosure/withdrawal on the Application composes with the WithdrawalConfig and output builder +- [WithdrawalConfig](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/withdrawal/withdrawal-config.md): The withdrawal configuration struct (guardian, accounts-drive layout, output builder) and its validation +- [IWithdrawalOutputBuilder](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/withdrawal/iwithdrawal-output-builder.md): Interface that turns an account into a withdrawal output +- [UsdWithdrawalOutputBuilder](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder.md): Single-ERC-20 withdrawal output builder +- [UsdWithdrawalOutputBuilderFactory](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/withdrawal/usd-withdrawal-output-builder-factory.md): Deterministic factory for USD withdrawal output builders - [EtherPortal](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/portals/EtherPortal.md): ETH deposits - [ERC20Portal](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/portals/ERC20Portal.md): ERC-20 token deposits - [ERC721Portal](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/contracts/portals/ERC721Portal.md): NFT deposits @@ -186,13 +195,17 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C - [Get Output](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/outputs/outputs-get.md): Get a specific output - [List Reports](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/reports/reports-list.md): List all reports - [Get Report](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/reports/reports-get.md): Get a specific report +- [List Withdrawals](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/withdrawals/withdrawals-list.md): List emergency withdrawals for an application +- [Get Withdrawal](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/withdrawals/withdrawals-get.md): Get a single withdrawal by account index - [Get Chain ID](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/node/node-chain-id.md): Get node chain ID - [Get Node Version](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/jsonrpc/methods/node/node-version.md): Get node version ## Cartesi Rollups v2.0 — Deployment - [Introduction](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/introduction.md): Overview of deployment options -- [Self-hosted deployment](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/self-hosted.md): Run your own node +- [Self-hosted deployment](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/self-hosted.md): Run your own node (overview and the two paths below) +- [Self-hosted (standard)](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/self-hosted/standard.md): Deploy a standard application without emergency withdrawal +- [Self-hosted with emergency withdrawal](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/self-hosted/with-emergency-withdrawal.md): Deploy with a WithdrawalConfig so the app can be foreclosed and funds recovered - [Public snapshot](https://docs.cartesi.io/cartesi-rollups/2.0/deployment/snapshot.md): Machine state management ## Cartesi Rollups v2.0 — Build with AI From c91bc3603033c54701330d1694916a10c42eeac9 Mon Sep 17 00:00:00 2001 From: Idogwu Chinonso Date: Sat, 11 Jul 2026 18:32:44 +0100 Subject: [PATCH 11/11] docs(v2): refine emergency-withdrawal guide and add recovery tooling - Rename the concept section to "Emergency Withdrawal" and update all sidebar, cross-page, and llms.txt references. - Add a standalone recovery-tools install guide (Cartesi Machine emulator, cartesi-rollups-cli, machine tool) with per-tool Linux and macOS steps. - Add a tabbed CLI/cast recovery walkthrough covering foreclose, replay, accounts-drive proving, root anchoring, and withdrawal. - Document how the guest creates and sizes the accounts drive against its WithdrawalConfig, and point the deployment guide to it to avoid duplication. - Expand the claim and foreclosure lifecycle for accuracy across Authority, Quorum, and PRT, including epoch definition, input-processing timing, and the three-step prove-and-withdraw flow. - Add foreclosure and accounts-drive withdrawal sequence diagrams and refresh the epoch-flow diagram. - Clarify that CLAIM_REJECTED is a node-level status, not an on-chain outcome. --- .../version-2.0/accounts-drive-withdrawal.png | Bin 0 -> 25131 bytes .../version-2.0/accounts-drive-withdrawal.svg | 57 +++++++ .../backend/emergency-withdrawal.md | 42 ++++- .../api-reference/contracts/application.md | 4 +- .../contracts/withdrawal/overview.md | 2 +- .../deployment/self-hosted/overview.md | 2 +- .../self-hosted/with-emergency-withdrawal.md | 34 +--- .../installation-guide.md | 85 ++++++++++ .../emergency-withdrawal/lifecycle.md | 73 ++++++++ .../overview.md | 7 +- .../emergency-withdrawal/recovery-guide.md | 160 ++++++++++++++++++ .../development/foreclosure/lifecycle.md | 53 ------ .../development/foreclosure/recovery-guide.md | 87 ---------- .../version-2.0/epoch-flow.png | Bin 62070 -> 65626 bytes .../version-2.0/foreclosure-sequence.png | Bin 0 -> 17816 bytes .../version-2.0-sidebars.json | 13 +- static/llms.txt | 9 +- 17 files changed, 439 insertions(+), 189 deletions(-) create mode 100644 cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.png create mode 100644 cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.svg create mode 100644 cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/installation-guide.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/lifecycle.md rename cartesi-rollups_versioned_docs/version-2.0/development/{foreclosure => emergency-withdrawal}/overview.md (58%) create mode 100644 cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/recovery-guide.md delete mode 100644 cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md delete mode 100644 cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md create mode 100644 cartesi-rollups_versioned_docs/version-2.0/foreclosure-sequence.png diff --git a/cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.png b/cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc9b00fb881fab44f325f7ca35195addb3e37ca GIT binary patch literal 25131 zcmdSBcTiJX*f$CmP!T~uK{__D(3BZg`^TM|877l$cF9_6KhLji!}WC37*BDYqM@N- z)KFJ_NJDcZi-v~w!wEWI3r7D31$aB@s{YuWhK7Ol;E$FjF_{C{NbCMkO_`>+n|l%X zaLiUoTZx9IG>U<2c^vqB#^c^24+F?^4{ysCHZ=F`ZJjMsOXIC+Xe@IyRFw>UXjdEL zow!YtuseDdCO9-r6{PxSeysB|{p#HZpzHURzg6Zv^FGQn_~1O(TczudtSz~oGH^g9 zPO8(6KW(Q?TE8C?-Rd+IR^*n6piPRrYTX&0@&)3GEr9IqNcUu%(HvWO9`V`dNh6hZo4+!|CBFM~YZDcesws1MymCj=>pm8*?hr-T8?8=fUM?eZL zI3_!32g-tYNj2O;(Zz)O6Uk3aoE-8UW14axgUd4)9baj%+bHZ#OtlCPcS z=R3v4+A4G~n|`;MffY+bv)*<0?GfPpoAgofgXK(vJ^laq3!CS&5VFt56gtzd7s`F# z%zJ>ZD$44_^>|9JhRXka8VFjMIC#N|7yQr>1%%mi1uEh3e;c)n$~O}k17W01eY zdyZN&))<-PswejyeW``eQtc^!5jZS$?`YWwW(&*Vnb*9Z*6wBZ4AfE9L2Z1#)i_>- zP!35ax8GacO~Y}{1oIAaadB)o%0ZBe^+*YFnh`A0M{1wES* zIO^oQD4sikiq9AdfLU2@h|YPB2y~^(W-C8*-eYH4)q9)Cx8Kq+iI-R2)5iQaaBg_9!}E>i+ci`Fd*R#+}sE zF4!58Zw?b|fC-jk;;BwpGnP+b$p~1!xYhH4n(NTc53wt>ZmhiK6djqDvor5*;SjsB zJr?lVKVnt4lc&*AZa=}feIMr8zHemR{?1F9Y$5G6Eu@7xm*Yq!68Bw$?R_h2rs-;| z6@yEBv^S`fO&3^p#74!Z)%b$-MzdWruV11A_?~%hJZek#`ECN$q-$)w5j$QQAV#@^ z+%(`}E8avJSx}J%!!srBEJ?n;US!Lydp_DEG-*G2)D6*xbli6xcSE3%Vr_W(A*2|I zOqeppzndI3tdz&zua|CGK8iGSd}_Smp-+8)a{Gha<>qF2V_xIZ zKnXtcsL3}7G4m*|&&&BH<$~GEwpGJwdu+Wf(>W4os&2=PN~1*sU*oh^DIsSvb>ekt zLa_ttx?DUTRrE8QwNtAl4l$Mgc5pm9I~#|JY=>_x>=f8OlO#7bjIUmjuksWTW==!E z_Nk~(V;(T6eK z$X;GzoTbjYr*)dhW%}<#P44ufWQje_5$(YFzxaroKY0$5cX&G}vWk+pE?9Y6GsU$$ zbKcd;kY@+N?hVP8HI-JA7VuiP5Dt)%@I=0yMqs=k%BQKFZRSTKq>-GB*Y9V!#{P)i zP|K)J!1lQemlxZo|s<~N=;4B=oDcD`gq5E{A@u6=PcoxVrNN`g-jWhUcbN4|Suyl>yI;U-ZV2BT{_iPt7^%O*8^qij|$Q0_}p;b zyb~*2OJC+)xW|esSTli9JuI%U35V7BhxyKc0X^;HMm#yu5ukz~IJnLCF zZoC1UObAVCjss7!M3?%%VO=f5QW?w(_V1R>P_@YK&n>f474sM!k|L+6tZf>d5tR4C z?oJ8a)@k3V-orP{X4OA0KeB11s)Sa1XKSCDR`4Z|i?%e`pkJo1!KKuiwwy5WzOS`< zpur^8ELeQIqyDx7Uy8QA%+dvl2fmEvUC*-6TZ7yW9dCC9&Y|?3j6Ls;e&*?WVVw-- zirq@vX-~TbExwQgbiKXC-0IP6E|vw zMF0iFewoM01XQ!%mezx-B?mWK`A8yu%y!o86_|L39kM%VbuTiHqsO4m{ z?liPFUcY)2Pj%XIH>+8Kx?R((bvdd?A;iEL6E$-MetCo`^g;40EXSVuKA2`|953BE zh54Noa(|lb2qVuM8EFw=&Gt8lNkewVhDxC*3ko%M>rHMwn{HB=yQ#H*V&?BI*r4sL zYWH~^NEnz@AZv*Da%qu*0`41KmH7?u@*}U`Q6C}PEG7!Qb8N--SKMH4D($R$<1hAl z#eydjkE9dwWAti03c44$2~_RHIEyEZ9K3t{@$6KKHrX61$qJNFZC_`l*t%~BiYxp2 zwNFk*TIMp^ayNi`Wxc26_X}=L-O$S5)JdwB8);{MUL{Apet5h~O=W8%_-fZ)|84V@ zncDV^J3K9tpG7L0^?YtBqR%40t2qXK&am&f0X^3BVZ$2+tDRd^^ydDxW2KR$=5MmR z98&W;qQ8groFJmWa&mQem1(obadBrb0a@&yuFj)$5>+-4oO>2X6C4m`}f(ZU1V+)^Q_+P*`j9?%dbAOgFl$HTgcuD*Vzs z$HIud1A)mbS?1DPzTpiTp5jIl?qv~XPiA9|;+q2L8&=oG>frN~ww>I>gnarX{;8w# z@t1riQhBGMn1(($iSF}FWnb~FW3HRRmyUia-^sa0)N(~sLi)DiMx5%aT;bvDV+ld2 zt&@r=i)lLD`2lry^cPFFfZ|NvZ;b1)QKz|2TWDL`d_{};7%sh%c1+(-lFV3m>R!ft zZMj-vPoo8|8GGEG1sHxoB;#7UQL(TPrE})8d?!Ek1$b` zn~rUl?&F$wdbs_ir^TG^q6)=33Qpa{tAa0lXeK;Qd5eRPmB>_)0IBts%p?-xyjOsY zkm7|Pe}U|&ZNBj#c(?{JcCs@jDP9y&yxAM^utUvC5@ycCQt9dtE^4!oab-i0;QBU| zMIg$E(6_)iYl2Xqp6ydHB(T0_dEa5e)F!B#O5laTl9#w*#z@FY``WTeM zyZ$DNz8buh$0GmeK>kq+cS3o0`$L9dNL?z9V7AQ)F>`w}M$d zs`rG4f#+=x{5f8T79st58b`74xZ$c}Qw2{;aPiMz#MfusMjqxH(}?It{*wNFM|Cj! z8^7i!Y0xEGw|U_w`s>f5mSGBF7wUf`TI!aqnG zQtp|RaOQqjxD?7E7;-Pl_K8kD?fqUZO6p>V$`OMj`lpIGbB8PaJ>Pz|$$_(>!t%tY z=F>9ieL&v_PC_H}Wi*(x1l7q}F+mG5;O|2B_n@FgR_3fr{JmFt`*HNT1f9q|`^z#c z%vsn=Kvl7+fq>`q+2@C z$Xwm`Y|%*$Xn2Zc0cD9@_qi`1xc;{J@=IH`7gkOwVs{{@qX0R%>&1Vc7I>dXdc|?T zm|sHZtk{5e8svpA{e$=I=YM~}O~T5fy_POUr~NAZis$Cy;7lNot^!XI+i!px@o>dt zoy{`%p735UDe{mZ9^H~1@>tnp&Klf!hAP$g3b3-zcq7@#ypTn{3tA#+PBX!=w`qM- zoUV3(>0j~aN|DEc{k9*ZxJuj*3&(mTia0kq=o`ocFJM;MzBo!jCEx&mWP(~;?FG~K zO04*>{0}9JTsxklY2Z1X(DO{(MtHC3y9GbR!$5k)v(N66c45PrOqaop&%IwYDh`;T zn<~IiL0Rvy-ltG}Kd#j|$QhSu%s@=DDfUBOHJ;^5|0Ks@>nct@iP+~qH3Cn!AUfY# z^-Soy>Rz;E?kib^`DtePtrH%$WxI zs!KWYX;rk`pcpromU_tOx90+CC8j@koH!!i0n9WLV5UN+`5~tc=9h-%qr}IfM{54P z&oA0n|KIGRa~6d{RhU+}2$Sl(@N-=u#at^bd(U>izvI%Zf?!4Z)-C*ZY~}#!nXSzm zOgp1yNdqL*1A*UJ}*@d zsYN^5_M|r4mX!2FUyX_c4$)4tnPV*$>rOYFeuv*=h3le{=RSGoF}sdp!1j8^>>jwf z9wt)0GTk0!V*aRTZ@)K58glu_G7j5l;aD|du50Qu{BZsOE8b0M1h%tjv;6WFLr6=+*`r;z#pbn&`Kq-Y?|dS_jqvk57`D0jGTy2+;?Nu7qKR=HWUo1x;kJJ* z1;7V_9eZM)Cw6`rEu|C6G8$#arT02Wegh4PzLw$^aX5PuD{gjFKFWhrM7Kb-ao2nn z3Qw|^*P+FZKBxUobGWF~XnGcW*tQr?TD?Fq*_ypXn|)km?A>!4JKmcQm)f^s*BI`p zElI+>3d+OHT|P$fQF;8}$2C5_wKP7%;=Y>S56O>HG-JQqL^tUou8E?BTaD^JMSJv4 zi!6Mb)(M4;mj*uG0$GjU7QhW#E=?$Vlv(hA;CJ%QEGeFRIy<@3;k)|;stR!#RO@kR z>C`jVvS+iPtl6&xZ>3#5b@WFRumW?$I8LSZZfxf?zIgp{1?jUfRop$sReS!}lV@EB zqH1$yFM_nX1Qr^)+n-Nj_)-oBR0D*uL;q(ta{ zK%lI*FnK~%oH3nujCssHB783FEs3Q^p|^_LmunO7mPN+PAqt!0hiLVV`#ZjuFEE&iJ&UO%h_#tIdKBU;J}g=aGa2p$U0*`9%W79HrC zP&Fnx%)=Jtnwer}+s7X8)MgDd?PZjlbrnbW`{Z3a&XU|n-S?G`#fC$Juh9+rpYrre z2}+ZarHkeR3QSUDlOA){^oDjLS58d|va5B{j{Q+tOW(0qAciEuIF`P+v zFatX$5{(jLU*ci>SzsaY86n_9Oo(_GC!GrmuBlD41Eu>m6mR1j@Tns!yo+?QW( zI<_1e%k$G#$PcZ|`ekzDp*>T_p3GAEo!nii`Fr zFAWOMoRK=+P6yVP=~54pdV41;TJg`e`<67h30AFQFHt&&74opofBW3T&HRJ$-xqY| z#0;Gj!=2Y-%4<(sT%FkB&q_nalQ*0Po(f63jOOJ!qSV-=tjF9CW^O=f^_BIf?o(iOV{1Nx<;VKk zqxcZDFL!sw>b$jsZ*;GYRCVg6Da7R$Fnme0K+Kuo$Zd7XnJ`9wox zG~eJ>g)U#dvJTqrPWL~tqo}UR zS>ePl%&CM&`1PHIV0^j7j7j{gB#H2|;0Y``$Z2w~7UGy%T;=hZp?fZk{4=dQU~jc5 zWWH*4@^+kSinm3*kDGK5;pm#X9jIL0S)$pSBf}`n4d<0@ z7aixk0n58%MuKSH<-Tl9j3LuWEvPR&F%aWCE}y*&7L6koI(m>inm!B z^4#*w@U}+uq}Y6|hqt8}`-pNi47Y$ug&3HEw|bEHch$0~*k)S(=zM z2}R!tb3*TYV>+hk=WxPoXV<=EnV8P0)@(GHI-k6BZmvfmHn)GdP(s(rw4Z6*B8rZ! zigUgpXUI{@T!eu1t$oU#V_ePRr3|V{YENMT={F6{?za)bv;dA9@*_noQDmYnCxxHo z=)PD3j;RkNMNcR>T|Q)qg&0*MZI+dt%?)_^AcG;e)+Nm|w?&Kxro3&47evMoguQ~q zH)q@8Tm`PCS(b^temsO41{ zGV%eBm9KT&@E?(8t6FCs$kQ%u9_#Zby$!`$Rp7^HnU-rI6h~2{MfM?4;7}-TKGFqW0ho z1tBfv{^<_Q`g6{$_d^>i0J^h&Ld@0!^dJxyVtCg^>&}8Q*}s6{EupS(w@(?jSCr`P z_>*KRKmNjJNNYnXu=*oqGL&ygT#>;&DKPBAQah_!d!)xo`|sk0&DqBU$_uBoP{dMFg~(HOtF+J^bf>sQ&wMGa7Tj}Ow~h_jQa5kO z*n(@ojpZ}Kk&eFEFQU#hY8~@Djr~23p7M6LR=8#vh9uo%e5cb2;Si)eyiAcq%`0f- zQef&20JzupR4A->W5VRj%y+S*)&1@1C~rv*F0gWeAl_m&B{|@r!$~aGc8?tuM3|pN zR+p?bU-y?+0(V?tY+0^V2)-hkGWA0x=fvjMMVoT|IpZmIzSrqx>*tQcZ)^?o?XQPE zf8_L3)XY<_y5qN|o&A_R;(JL=9gA;AdoWrhjtBHIU#-0%mFa`e=Ds9Bdq|15p(D3> z=4^c$jAKmhdXsrb+l~In)X>K*d$0{{UJb^^f*ymWf`o~F3;)%~Do0#!HNV|_i{|T1 ze+Sub z&f;6Ue!i8alr5*YZJzOU?Lp)*ai4pHr*(*`Pt06x=opw$Vg#a?2pgHO23@G$lP+ig@Y!*@sLFw5CnS~sQ#In zah*o&^$o*w_b16Njku~M*tT&YC{BLkv%vN?1-(vr#E7kI(W?(xkTe|c&+#MgIuVnK z5_<-5NtL`NDy@zgEA(--SQGO=6Su41`TF)#Wf-v7v6G7yKW}i(g^>TEgQ)q9$K{>#_3CIh&})_NYK#8d^9|W z3*6;hpZKqm^B*B;a!`noU-Ur|KjEr3`Q`p+=7G16)@evJFWEj*0-!96AOcGdkJ?Wh+B+24qOXxi|^R&LM=(}e}72akP(UF1eGm5AqC@VOOvbL z7(Eiuz@%Q@v0vTkq@zEWdHV~ej{_CaPx|x=Ybz(?PLDHB_WSNl##_|o3T#YN^q0VH z6wmX94oG_UdnXpuod4h;zjtvi3!02(PXysUZHLtP-t~1vm?Y4?TW;{(9p7Djk|p1Y z3$l4Q|Do3Y1kyS1eFD*B4><`rV5XoWKuh{-Q8JtLYpjngdv}EnNe1n!y5DOV?M-Bw zR6ND|fH8qM@S174Mp0`Z2@_p2V24;XYwunD^t)Gf?E#J#4KwqV&;IICj}#qTFEY`2 zG!57EM9Hqc30UmQ4wd>?fGip&0k;*@fb*L;fCIs?Qc89^522#;=6scv6eY)|PR9$4 zqzk<@3RE`K$cfW$ynolOY48wu(9VH}HyB69oj^Cc3xG)I^!hi0=9+y!*IJQ3#OvT`$f%(wxq=`H^_wugG(|?h1$1df6f4+Zk zw{w15yoYy-P?-Fy1klj9F1;tIi#m02(fE0nNKt%B25!!TIBkW~ChMI4Fdez-&!UO7 znf)`0et+KrG@Am&nMQ}0(^U&tq3qeT$zTaBL@*6!-1?tlK_f%7^UP1ArTO+_eN5~> zWPhU0@?Y96BOBtyp;H;i<*`w8N zS!*K%%f8WiXqmXYJbXcy_F7kwY1O*njLH~Lwp_&6jGuBwYQI-Ellh?0kS8V7j#6S9KZw;F)7PZ8N;t$n$4)t<*HP3YHN zDad_J3xlsuo=YfqMkIf1+#TPW^!yd@(VScSZ#V+Tvi(4nUh+~m`xPtlT*}P#W=MJn zL+m(nRcj}pgP2@-=vTMwCjENwecof@>YJ&ZihE3^jP07d5CaT(JGC!p{Z8DK_pErr z#3vaxT&C@%_-RZ1V4)0H z^`u|cf8jbTHsp?1qa2v$b&3EeH7EH=nmrmL;%j}EPo2EMepwp}*%=_XhKrrl$NT7x zCdu&0zY%%DE7ZVO?2{;L?k<|Nc|F$T<_{DpWK6#M25C;7@FL-II@!z=gZkzBNWLgJ zqV8VfRov`R>}7twot@OdP50oQ(65~jM&|rXHHZ0o@9=;!&4YcRnEpt9J5nGgSIInIwOi4C%3En$&w!C_&5}_OiExFGBr613jkYhveeo#8p*GnB37%uR zv#(MUN-%J|$BhhU;YLCIrvsy=Wd5Q?Ul+a|;-3HDR_#)%dC?qh1J_Q@G8cNcR*gVBzN)e*#}CmHqgp)-l^rH9f%>tX$tV+4RcIrKLb`XTBok$6MC*$HB$$3D0c}1As|V{=_tMflz`uRDQKt>%(crDrMe8QP+>*d=O3L}GSB_Lib4?Ggc(8#jd2OUm6nbK14|Je)KxhsX`RdO&X`Pi3 z5Y7WVCwxLLZuRwoU@-Io37({h^5G88zH{>XgiZhYP9AaLva`=;DRnl7;_PEzd?^y- zvAA6E)2ONj-pwOk^~s-p3!)ZHDT$YsM&2%Ex%2fIr+MZd5zBNn_l~kgm?vJ!7r^na z_eXjarh$@;&hqVDiuKlYGo(MMlCA#)Dkll?xXY)?v;uD)NaKz zP1r-Z^3~SGD*Hju2P$JZS?uV?#ByKoL#Si}GOA@1jp0S`=18AbRn}WICX3m6-ROsi zn&B19Irh!8mo4vA7yFhJPm;>dEJ@E!@(#Y5_2rF1S7kJq(9a@}x*??5S#X%w z>%ALaxbBYkGfsTWnD;WIp`bQc8wrsjwXx!V|yN2lHX?j@0IFH z-vDv^>3_uQLxo!m`oA02f3D##dEh^r#18iRX8*k7DYpdu4A6g$0^RS{hcO*pU3PX6 zvpgWbTG-&Tagjl^zbi?a>!a2?G#W23MMiP(gl%XzEN!lAPnTTnR%aR@HUtD>kq zJfU%-PEgbW>BPhQuCd{g>-VSJhwBfp%yxy|cc&?0T?J~zBqb%Sb7|P^-IcyEsuGD~ zMhLu(Vk%zB30AvE>t-tou76afG6lVXH41O$xJsM-)%^4MtodiCRFfe=^0?AYUiT!@ zY+z0)V*Gol#e#m?t`t`fT48TAlwo|}U3pRayWQ3*EA{f)CcW+pZ;v*<0DOwaKi=!F zZbe4CS3@Sq*tgz=YMG~xqBizOI7}AiW=LK1_E3X;*X8=T$uhJnyPl`6D3dj2S}P3z z|8o}$SKVw!Zw~^aVqo92Ja47jj^`cNnl7$?eqiXTB(L_@Em%fnnRHD{)sGq})@Opq zkHEj>QmMN@L*#3K;&YxbRb=$n^tHo$Q;Xi@>VU0JVnZKHyK(xDYVR&YNYO_OEx)ExVX4=6IuBKjoxayN>ZY{oNGQpHFYGjK z`MS4fAwMv0`Pb#|$IMq+Jhl%o?jZ&$&ziO+arr;X;~4?-anbH?MbZFfr5%7SB^db? z6I(8lH#0q0vB}Zcj$x8T`W``@?tR5Ih{qk4V6-Cz!AQKt0;7n&b#2V*S9=vQ zb>)sc@iZf-yOxhKcqs-co>Ez)pK2~oh?=jNn!Oh_$%-AAeTDbC0yC^C_TAw< zkg}q7XIbmr%}?^A6lmxB%JQLF2Fwk|7;-m9g*D#pmA07uqQ)N_Clf^;X$Kxa-nP7IHa{3W~}}WNn72lkH=^5sT(C;y&W{ zAMPhI`F3S#Yo2iIxF>X}fyq6Cx3;lXjVWfzB+h&LRVi=7=dZ_!X}+;&QsQ?v#lhDd zA6}+~Lqq-g*Y0nN-{vWH-f=^XC8>IqeN!F3A?rc*yA8%L(ViS1q=Q&bhK>z-D}`05!2R>f8*J!DL-{56d{Qx& z!7;8-Nnuzye7hmW%z*Mn$V?@`;YoAMwl#m{m418SIRofp$Jm6~B{~(Qw~_SjcmJvn zM^}xHt|;oH4Uv8B5{tWn=gP_y{rFxAu8UGzDB8`tx=*yGtEjciODU z#ZO=G#CV3PK5NKWz=wq1&T7P0l+SfdgHz3Vd((mAu1uNQV6E`Z@zMM2TEgbOfUIz- zt1H$UrCehwz)3bd6(}lW3 zy~yYKXNb#E&7;4Bq1Pm(dr>5i2aBf2-2rQ#bpo-q=vYJ=r1}S3zIg=2a!WhPTUXhH zw?;;{wYi3~ILvD?H-4JVP$?#gH!OFHLu6F%r~r$)aImTqV&GV&aDq%nVTZ$<&M=*=gw z+U(UZG2(T?FdioX+4B52vMUC=7bwr>w(r19W|Fj())IcSS;X3m`|f9GtEsw4D*-@; zzuW94+RHTFMtj7vdG;EQP(r_a$p7xTkbkDQfnP*K=28mKhO_Z3WD4Ym%f zcrI|zI?k?~e?ia1OFNLm$25=_{I6WmLF?5y#`u$+&QC9`|x#Swspz8_P#^%A7cuCXw<)>p1Q4Z-Ps1R@u=3IR5L(72mbxL;&yMfzfc zD#q?)2_Iq!nddV-67qEX87P z(@mE={X2+t65zar@Lj?e@JS?TvL!T=)7#cIcW&e@kNKUW7cPhCzJ@&B3Io(G*Y2m> z+b3=xdh#!>uMWtE9uVO-w{5%C%RMcSenT&m41qXNLKUF7RgJq;)rqeGoEHZ?cS2d2 z)Mmm3ttW=|7`K?4q0Lpjx>M!lC_o#`mPn20j>k3TMPa7D<|Y-)#jz~ULmLl0_(s?^ zF@E@=c7ZH3v2wxPx!c>FPto5H+y$86Y~awysgTM908!X&EvwBgudeu{Angi5i=ee$ z75fP@1C6F3m|W}6rh*3ZkR%Mi)kq@E%=sIN9k$%ECfFF^!G`&$}Whzfb&X+L{V}92(qiyr4Op0VZM7(ouOvqnc z>ra$pMqvvq zN51~u_9zh(pS$ygC0l*kM?sfOZKv+XNaum1n_}nz<32h2q-vySNZ`b(sFU}dUq>~D z^Y0X=e2zSYXxm8_`9(5k0QYhKX>Ngk0*UG(UL(D8yhwTopw!GX<1i!~)=}hh(1IC9 zBBG|sLuIN1(HRI64H+r6tuX2`beDlAg{v$*Kp|Y&0~%c0@G@mcBfJA+Sk|5Rd%rC3 ziYQAMDGba2?rvD5P1IptGMmkfZY(a^-5Tut7y)$@g_JV#_uE$X4a6V&x&@A^`Mi(v zM?Mzbi*3e^pFMC8T7aCRCCyH6$!S+yYDkZ*Szf~cw?1@@a0CV95hN1aHQklrsKi;s zwHJqjYAmb@rKTxt2rS1rP(W!9p+Pds zZ?dk@#gQcqkhis6$a3S1LqT(B#RglS*h}lz|J2znHgTss3jYVhaX-jGn&+Pb0tEd} z&{T^Ps9+HxKp+7ao*W?hbnH(9|5K%3l>sTpwpXTf(MCp(V2{=iWo2bcS= zihU4$J1m?3Q49Zf*#rdBmj5l7f{y&Uz{B)k4fSxpn1ALEIITU$H}U@xLbaE7vZnvL z=`czAbQ8G5ze*602VguZbM-%L4aH5 z{{u(X{yRDQH$kffe%;vr@z?!>7XDwK?j@=-wn?V{orTZEf{6K}R+lpWp9gbUH z{PN|?5MaNb(#T`iBe$TO+#{qFVV~@U>wg04 zV!{9+f|7Hf&y2H^nU)s3$fT|6u7x`>gRUF5mM_lP>W*wuz-H|HZ`|AEo#jOzy=6y5 zJrvY6*tHi7`Kz2K{v`nlR11$|#LwgQEb&6S_i z^Oh{04xNb7HKV?-p#3KV5L3Pi=UVQn1lEViiihp0(E&BSn*bEJ{GWIH5EnnpnCF+HG1=dia>6# zHvd;QP$*!p`%#KpCC3$=h>OL*^3+B>6#^1x)9Rr-v^p>0Qp;0Hya*@{;H=CSurRQg z$$BAjrhaLVf3hz1Ugo~6DiV706!tkKv326PR)IBB!ooGPr-fH%yLMb!s%~UxwZ-_v zJQ_YT8?R8<$Xwhb=$YRp3r%H7l}FeyKWPA|$V*wtn-QGody1Q@uKdm?axsJPQX+?f zaKCRaKJkp_^*}q8&W*w8o7a#LwiPv8A=S7+8pHTuP95n?6R`oMc6*+Fk)AT%Dberi z6J2k4yFwxwXQM0EJQrs#;mVKqXwC9UfUxLtaB49mrKMpdWa|dSNhn|r2vrv}DHI3q zi+Xe|fBn>dr)VU_;qiDQ3#OK-LZJ;`^%r&oVpE5@`C>Te#d+0WceQzuW6MqW!8fUD zle}VGt1%>(E1yO%#Ob{?4Fe<(6i|cBU;e1`GMQZ47$&I=9{+KPDJ>yk;~+)`z@oh$ z(^bl_lkJkaw^>zx%41W5WHlaD7zv)tniwm)%!k(9QBOXf!RuJ+&r4l9jJ_2RHJj0M zE+^7V8sMfS0zSKH;E*8lrSQ&)QZtjJGl{y(#D?V~E0znW%KCyvKpuEo|06$elTcC@ zu-(F!sFZj9K>r@o8-Q16Px^xpKBv4z=Ov@0Z#&7zj|aL!a%O)TQqcPzE(nV>eEsDC zi{-?Q(+M-58blF!xu)yu&{_7CiSS*S^6c}=g|fR9wLztPq}_Wqi~EZ*!-;F=Y1c7_ zV%$HRY-`Br)@kA1EBfn$$HR`LhXf|Ilr3iudEcaE3C?t#?A2hkvorC9_V@!Lu@Na> zSdh2*QLYQehxkFqJe?-4TDHtpXpgc&Qb)U2XudE0af?~Ii9J%M3V5EcxEzdWNGP8< zZg}S?$kVqveWi6f6{jn8F&_bX1*x9br{0m}$Iqx30up28FYs>43@wHnW?AO$^HTKN)*GZf#^iYJ zUnb~5=OUR zNO)?Un5bc_)R8ZF4^zKX-SUyuMBpm`y((wiAbj%Tg}GFeYkid_@6W}Lq0J5B@0h`w zAuF@;1B9R=z0g!4&tBi2?{`;CsJXnG3U=L2^5q6c%1J6Y7AaQ-&EHn;*|3a&CSWL_ z1KS@0(t}ny&5*>XLX1D%^x(wSIewN(1bEID5Ib1$z# zyMqAEyYZ-{7yLak)S^NlNFk1SWT56)*}Nn>Leo`aVG;K6((p;o;(-ilH2;Yy`osXP zrSzKe23N)kN8Y?{1u^vy^8GsNVJC*O$X{ z+zgjj+8Y*+>yMg*8>rBk%^%vBr`zuXzF?+{pz7mzN#~X+p8MOXuhrb;V5l=4wtDhx z1EO6@lUe1te6W#vY;NiqhrM)1wR8Uc-2IAK{Yr{g&unuW9~z4QWI3={wcd6)Y-1Yy z@$t0ueu}J4pM8H~pBz5m!g%$v%D)`gKWO6c%i&cRvy^5dU68~t^T|A&~O zUR&|cRnDj#uA#%9NE7py)%+(3*`)XAl|4v;J_s3@{Ovi@&jXqYRK7X_KtHE`eY#x% zKn27#GGNTi0*^L4P=o~ecw)61eKxGd&-^TR2U6O#9nf8ZeY?&Dz)(z6^j;esR`O(6 zh4}7`co7btE&5AMe*&;#;lP#`y2>674ogej-8x@r*llMI%uEWoqWelKdG|HMT<&tQ zild0C$tv6Q>JqUjS|*#+Zo_pH*K?e>NUIMVLs~d6W4(88quP-Mx)Iz(CoZvUH8t;z z8!s}icFhPIZv?tz_u$$CnGxPfmMM1L++wjP>gO>R?+<>@N9!=}+r`W*NXzoC&dZ03 zr{L<|00Hy83J$eQkyQFuCO)omMN#v;#9KKB(UsWpjP?4pU?~afl)hWml(;9CVG7ee)-yv?Wu z1X!o~QsnY_K;zcBn0R{3vT01H%;3F5udd_E17WKs7Y?C`@)!(0;e0E2C}I6i69i>V zA6oW{8q97<{z6LW*3iB4p4#KrvBE)l?|^5fh#_f!nB4wl#|smcU=0RDhuFK1z228{ z7x&zNgfqvng2Lb2&hk)t*t^%xyfbA@_-c+$<1tXT)el<)V`}KI z7|(F}ErxJa^cB^l4g9<4cC!EW>5s_-T+dNpyTJ!42oefY$XqL5yJ@drQ=Zt6+uv<@*tsGr<2u zuuwKg?+gD7a`q1Ix-mIk9O8>a1bFsLQyAc^drrOhG-JN)MTZ}{H(~JeRu{l7cOL8+ zsUh}4nj7kyr}IJDfgCfBg@NYx;82ma26&BCS{EIYZM(dyH#{a3=T<+*o3AEvW^K=M zuuNZyRlRV$px|g z(2ndHJ+`0ni!Z<5ke@&Pv2&YWf+38S!AEqC45Xk=bdjTdMknp%V0-k- zM-_HN-is9${lsQlmjZ?uzIGQ{re9ZJ_%yRnPQ`{}d;9OUF)fF5l|g5`O*+Jx6J!uA z4-pL@ztl-($8c2iryov9Zwyf(#G8^ZYOx7}=dMRJl?8*4Hr>o5K}U;ymd3XH+-2Qd z41MT9@M>Q++6pnh77Of)t&fdA3lQ_FRYl zRIu6n;^AD3TIPF;@dFUI)8b*gw~=q{C4DpwNGOXYG!02kWL- zgCb>xtWWNuw&I!E***5d(5HHF@}z6OiOgoc<&XunWEXgabN}(iOInZ7idNarag4%1 zy*sF~?76cp+qER1=sfb}Wvo4aK73`;q9~L9k=8??=IVrLfPUUo?ETF?M2gc zFvRrJaVFy))nrJWd}mz8iuy0~qp)h6E^}(7aR@{Y=NN729T*cT`_WMxYpMQxYUCwY zbzh(ab$S0e+3pR)C4_N#zBNZi@laBgo;&-6|GR1_J+_kX=K&sF%0;z2q@gi_b+0*@ z2Yo93y7+8#bD86NlicT?=-Ur;zM@=JaLKs;HNHlttuEWI&Ug^>!F6w{SbCb@K{n~4P;((0QzfM}*@g6-Uz zAlT--T647Ac(lP|+u18)y3*`k?a+PAPvSVbindxybmKpr#=P+!-GwPqb%idf-c?wP zicMDY2TQAa~`ld2SXZBp@prVXDq6^>&_)Sa;j*WwYq#UOe7wKriqRV1R%|A3Q( zJkvXar{egxIbEH*+?{uLI#J6VPE1Ox23(c2tRI;|W*iBW1X@F5>4!&$enBP z>u2;{qZNVXz#4ShdI%rzVj(6Bp5SAa@AunEOI8(W^c5;*IWm@Cv00X})k!vc_#uM0@J`uea1x7!u0g?=C`X(mz47@oZJlS?-Q zLerLdSR2H+5?Y-*8F4foP@bpJSM*n$Wo#y|?1S0wL&JrHX^>7$&`clDBWy__XlA$r z!5$`95sHvs_x^w*fqU*bsIEG7X#SjZu-2f(e*agWufJM=UVMIBI?V=XpQ{Co7^j^K zb~yN;S|Y1l+jYhm;WSLuMqkV|c@hCC=AXA|*ez}2IXfJL(XBvVNZ<`=uY$mX^hl}C2>k3d~i;qzbvw9hKXVW^i zNO;i!{U*;sghu>&FYp30I6djB79+<#gCUS3j{j&Y0xuZwIKk)cAf@j~A#>`Uv6E}6 zpUz%s-GSA(EKi;SiI2enZN?1ktg`DbYu(cWveu}!Z|Sk0#nl2n(piDqcq7Q-sEzC* zklN9DjEVFiUoBIRTe)*m6Sc}mfCGqOfH98;^g^LqeYCd9MLJYv(C2;K!Pz|f>&K3_`slH9J)edX{^CACw_g7(aHB ze$Gx9;Eh-ba6>;XLKuNG!k4_ipyDu!E)U}hk0%!_K2GfZPhHC`5;-S1R92&S={U+ ztTlqnA76XCwEog}jQE#@NpSiFk6aTJ*XZcIhB#nx1~>~nmx&Jyz?vV^-zA>0K)!^x z#HU79^pVvERyiI+>rWkK{ovGv?jy8+>cEer>VG4g{;yLGI9H6c}mfapT3dSwvRSbvCFIY*?-KuXGS@=`+2NEUQI{3kL zaZOM1lQSw6h-L1OZF*FE!N@OB-R6!V-rBhzRoYErvcDi2GJLS1=^*GcFPuM1xNC zK>9{x7_q9hAr{chOqaRWT3OoGf@*`>23Y7HO`&s))@uJ+v4>VMyF{}9&(z1m4i}R} z9I7uIWpkAId+LGuLPu>bKAAaJa)40VmB#F@QGKU1a;LpZTQ`?GiMtTh>3Ly1xb&t885cjy^jotre1k6vnw5ZmFyQ8M9ucL6hMZCTwXfXr7wP-`FxTa zFK&3i-cOvD70pQg1_d2nK7B+%9#C`~hZfzo&z9exa&yPu$%7@&U`qq;iijm|O5qy3#N;p^D zAHO`ZSS0sy@OqD!Q|}w^41t>tSXGhL<7(3oGWCg}nK|XhHZ`Gra zKRXS$os&jf2Yr6Ob}>bH5LQ8<{AjWO=3+abC$KXrX8Q73dY;AO{?4stTg3)y{avGA z7|~O_V1`R3?11SIqCZGFDI>LbqFZ!v+uM=4xW&(@?_*P_TBF^+o2VundL)LvMxk;m z{U_6s$DtTSTV;AHlQN?AcBK@?^w>Ek;6q%z1H2yNI{iP_T_CSCzsqL%>EeUy=S;Fo zD4+7X9Gk#$2kNK5Ggy^1b4)krxe9(HC>yzE){XAaSmX#F2-ag zJ5+1GNS$-2JxpLAZ-F+Z&(`EV;c&Qz{C0Fm`;c}aT%l8i9yoML5~Phbd0;tKy5$&; z;meAX-z{82K)lfb>TJO95&zLhI{VT+3+o!g#QiSff%`EVAo$}FVb6x#2t6}K;-a-* z6=+ok7|E*Lk&iG#9;9It^rkyo&NnbBVjV-T{iR{3Omoli%E0_URE>iWlY{nEkh&Jb+7 z&g7N|UJLyY)dd87mq)K}DNLESNMrgiKr!DIq@0qBc-&_Kl|zRWN#vI#{xQSQNzt#G zz-#FywD>och)5k@HtpeA$AOx`=1TDv$Ig%s#J_V~T6c6Cke>YyQ9wPs4%o49z>Wpd zYH2$@$Ln(MHvoh~d}IJ&w0hr=Yk)Vo6lTPV zk7L#O*9N$vuJcwq>@w&JK&#W&S(S}XJ0BRu%CKiU2F?QOrUPrp0|JHImDP%q$0(IdFbnylB*t`%HfI6fbJPE=>@zMXaP0=?J1#S>=y)+wV^W@xJ)(R z<@!D~LKr$YnN#Q5KPV?NBZq^P+p4@dmDRc*peX})JY@(Jn2P=jR}m2Ml4 zwB0BD;RKGbt8Klk{3hW1KK*=h)4D)H7Re+o1gY$6f#*Af|7|ud$0&9ulUTDOO%7A!NsS|W4ZIl&U4g_wnr^~hI+8lkl> zL&Fw^qH3n38i^Cx8czYk1Y?gW&}v;9pz&klozDoIpLRkYE3R&*EscOyPkE!E;*H># zBdUM6Z&J%Qk7~iVIkW{{c$(`ZHk7g)tQ^xb{9GD-8iy|kVLaI&t2F^qRhJo#EF*<*uF&msjW6S5*MP zosuhnwq#diYa>*T;X=58N)OI{!IVBy7ei)T=56Jet+$T*XE>6zmJsJjs_Np2-@)w! z+TFsE_WP&|{GXauhELz@F9G~8sR`TuT~7c@{F(=#zS`r%eeVwbT}F(52gi*HODTp( zdwUT3%+kYWA-=ELaXsavCA$=q%&F_(sT0tVJ`*lshWzFs1u*FSv&7`2MC}HxBrq`( zC6-oJNzFWfBzAV@;2+$2TNF?>8!DW%k>{v!$q!%?+ z^kK`YaTxCJXYoY(2>B?r4 zP@5znhzHoB{t1d62cjIpeTQ_@>$PZDX-5@j%eqG`swYVoTVNYZ;je0s$H2?9T|=ii zch8<`te`2T4yUmY1k~8b*hjedLTXgxU6=^h;DTCldQ^W5Hvys+eJN(QD0RT=k+Dk% zqP*{#(v_p!qInZUcU-$XcEN3fC8)?$}P*30|Qdx5ty4A!k_(y7Spp+;h+_cG zkO(7S#t_nX!ZSKqVUmrp_%J5qPHuO@`V%L0(M2kYUWYm*NJ{R!(Q&PE-AD7St0(6 zV1ljXrY|wflQ6x$LgKMeEy9K+JKxS zscL6_l@)m7R^8N@@DY;{WJ*-$?Mrdy3I2)*o!%z&%K?(^KvP+-fC^2Wsps3=9*FwZ z)2X3X{G6w$Li=vQw-^7ugFc_Wpq6@(%}PmWL7^&kW3>D|Rd|!8hE`2gpR`O>)(3|t zz-xnFNpn7J`TBc+3v7(P(sND@j-Bcc@LNd6ZgSQhsCu$6Ulq&54t%&OV^~B)S|8szSO0Y57%Ci{RQLN+qDEC_>_T5sKUyKE%NrN$AU zvXZ>Y6%}ON?HnyhLMRk+thS!kG*`$BJb#^nqs$S*(Yw5648ZIy`tw;gO7(y7^} zTmah1{d#&gYAJL?vJtf{vO(5u-MZuI)u$dsA8$?ULX#`H6d#wzg@hhebQ4o6{M#3w zvyqlZFXAa*=|T=ijh%?zpKR}3fFkP^(tBHUzh$AmY@#pQwK#_5kt<8 literal 0 HcmV?d00001 diff --git a/cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.svg b/cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.svg new file mode 100644 index 000000000..fa6c9424d --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/accounts-drive-withdrawal.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + Machine tool + + CLI / operator + + Application contract + + EVM Reader (node) + + + + + + + + + + drive-root-proof.json + and account-proof.json + + + + proveAccountsDriveMerkleRoot(root, proof) + permissionless, once per app + + + + AccountsDriveMerkleRootProved + record block, tx, root + + + + withdraw(account, accountProof) + gas payer can differ from recipient + + + + Withdrawal(accountIndex, account, output) + stored by (application_id, account_index) + 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 af5855f37..18f05ea24 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 @@ -3,7 +3,7 @@ id: emergency-withdrawal title: Emergency Withdrawal (guest requirements) --- -[Emergency withdrawal](../../development/foreclosure/overview.md) lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the **guest application** (the code running inside the Cartesi Machine) must do to support it. +[Emergency withdrawal](../../development/emergency-withdrawal/overview.md) lets users recover their in-app balances directly from the base layer after an application is foreclosed. For that to work, the on-chain contracts need a way to read each account's balance from the settled machine state. This page describes what the **guest application** (the code running inside the Cartesi Machine) must do to support it. ## The accounts drive @@ -11,8 +11,9 @@ 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. +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 If the layout the guest writes and the config the contract was given disagree, proofs will not validate and funds cannot be withdrawn. @@ -26,6 +27,41 @@ The [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md) describes 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. +## 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: + +```toml +[machine] +# ...your existing machine settings... +final_hash = true + +# The application and OS, built from your Dockerfile. +[drives.root] +builder = "docker" +dockerfile = "Dockerfile" +format = "ext2" + +# The accounts drive: a raw, unformatted flash drive for the balance ledger. +[drives.accounts] +builder = "empty" +format = "raw" +size = 4194304 # size in bytes +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. + +Two properties of the drive must agree with the [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md): + +- **Size.** The drive must be large enough to hold the entire account tree, which spans `2^(5 + log2MaxNumOfAccounts + log2LeavesPerAccount)` bytes. A single-token ledger with `log2LeavesPerAccount = 0` and `log2MaxNumOfAccounts = 12`, for example, occupies `2^17` bytes (128 KiB), well within the drive declared above. +- **Position.** `accountsDriveStartIndex` records where the drive begins in machine memory, expressed as its start address divided by that account-tree size. You do not compute it by hand: `cartesi build` places the drive, and you read the assigned position from `.cartesi/image/config.json`. That value is the `accountsDriveStartIndex` you supply in the [`WithdrawalConfig`](../contracts/withdrawal/withdrawal-config.md#drive-geometry) at deploy time. + +With the drive declared and sized, the guest fills it with balance records, as described next. + ## Keeping the balances You rarely need to write the drive by hand. A ledger library maintains the accounts drive for you: it credits deposits, debits withdrawals and transfers, and stores every balance in the drive so it stays provable from the machine state. See the [Asset Management Library](https://cartesi.github.io/docs/pr-preview/pr-303/cartesi-rollups/2.0/api-reference/asset-management/overview/) for how to store and manage balances this way. 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 da8bd9556..385821a0e 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 @@ -12,7 +12,7 @@ The **Application** contract serves as the base layer representation of the appl 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). -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/foreclosure/overview.md) for the full flow. These functions are documented below under [Guardian & Foreclosure](#guardian--foreclosure) and [Emergency Withdrawal](#emergency-withdrawal). +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). ## Functions @@ -320,7 +320,7 @@ Triggered when the application is foreclosed. ## Emergency Withdrawal -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/foreclosure/recovery-guide.md); for the output-building contracts see the [Withdrawal](./withdrawal/overview.md) subsection. +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. Withdrawal-related functions take an `AccountValidityProof`: 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 96b347dcd..ef0ac50f3 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/foreclosure/overview.md). +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). ## How the pieces fit together diff --git a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md index 5fced019d..21ecb5721 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/deployment/self-hosted/overview.md @@ -7,7 +7,7 @@ slug: /deployment/self-hosted Self-hosting means running a Cartesi Rollups node yourself to deploy and operate your application, instead of using a third-party provider. This section covers two paths: - **[Standard deployment](./standard.md)** runs the node and deploys a regular application. Start here if you do not need emergency withdrawal. -- **[Deployment with emergency withdrawal](./with-emergency-withdrawal.md)** builds on the standard setup and deploys the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so a guardian can foreclose it and users can recover their funds directly from the contracts. Read the [Foreclosure & Emergency Withdrawal](../../development/foreclosure/overview.md) concept first. +- **[Deployment with emergency withdrawal](./with-emergency-withdrawal.md)** builds on the standard setup and deploys the application with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so a guardian can foreclose it and users can recover their funds directly from the contracts. Read the [Foreclosure & Emergency Withdrawal](../../development/emergency-withdrawal/overview.md) concept first. :::warning Production Warning **This self-hosted approach should NOT be used in _production_.** It is designed for development and testing on **testnet**. It lacks production requirements such as public snapshot verification, security hardening, and production-grade infrastructure. 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 3bfde4d53..46eb6d9ad 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 @@ -3,7 +3,7 @@ id: with-emergency-withdrawal title: Self-hosted with Emergency Withdrawal --- -This guide runs a self-hosted node and deploys an application that supports [emergency withdrawal](../../development/foreclosure/overview.md): a guardian can foreclose it, and users can then recover their funds directly from the contracts. It follows the same flow as the [standard deployment](./standard.md), with a few additions. Read the [Foreclosure & Emergency Withdrawal overview](../../development/foreclosure/overview.md) first for the concept. +This guide runs a self-hosted node and deploys an application that supports [emergency withdrawal](../../development/emergency-withdrawal/overview.md): a guardian can foreclose it, and users can then recover their funds directly from the contracts. It follows the same flow as the [standard deployment](./standard.md), with a few additions. Read the [Foreclosure & Emergency Withdrawal overview](../../development/emergency-withdrawal/overview.md) first for the concept. :::warning Production Warning Like the standard setup, this is for development and testing on **testnet**, not production. @@ -19,35 +19,9 @@ 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 flash drive that holds the balance ledger. Declare it in your `cartesi.toml` alongside the root drive, and enable `final_hash` so the machine hash is produced for on-chain deployment: - -```toml -[machine] -# ...your existing machine settings... -final_hash = true - -# The application and OS, built from your Dockerfile. -[drives.root] -builder = "docker" -dockerfile = "Dockerfile" -format = "ext2" - -# The accounts drive: a raw, unformatted flash drive for the balance ledger. -[drives.accounts] -builder = "empty" -format = "raw" -size = 4194304 # size in bytes -mount = false -user = "dapp" -``` - -The accounts drive is deliberately **raw and unmounted**: the application opens the block device directly (for example `/dev/pmem1`) and writes balance records into it, with no filesystem in between. +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`. -**Your application must use a ledger library to write those balances in a recoverable (provable) layout.** The library keeps the record layout consistent with the [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), so that after foreclosure the balances can be proved on-chain and withdrawn. For how to store and manage balances this way, see the [Asset Management Library](https://cartesi.github.io/docs/pr-preview/pr-303/cartesi-rollups/2.0/api-reference/asset-management/overview/). - -:::note -The drive's `size`, the ledger's record layout, and the `WithdrawalConfig` values (`log2_leaves_per_account`, `log2_max_num_of_accounts`, `accounts_drive_start_index`) must be chosen together. `accounts_drive_start_index` equals the drive's machine-memory start address divided by the proven-region size `2^(5 + log2_max_num_of_accounts + log2_leaves_per_account)`. You can read the built drive's position from `.cartesi/image/config.json`. -::: +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. ## Configuration @@ -134,4 +108,4 @@ Create a `withdrawal.json` describing the guardian and the accounts-drive layout ## Recovery -When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../development/foreclosure/recovery-guide.md). +When the operator is gone, the guardian forecloses and users withdraw directly from the contracts. The full procedure (foreclose, replay, prove the accounts drive, anchor the root, withdraw, and verify) is in the [Emergency Withdrawal Recovery Guide](../../development/emergency-withdrawal/recovery-guide.md). diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/installation-guide.md b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/installation-guide.md new file mode 100644 index 000000000..fca54f0ad --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/installation-guide.md @@ -0,0 +1,85 @@ +--- +id: installation-Guide +title: Installing the required tools +--- + +The [Emergency Withdrawal Recovery Guide](./recovery-guide.md) runs its tools directly on your machine. This is convenient on a local devnet, where you interact with them directly rather than through the node's containers. This page installs everything you need. Each tool below has a short description, followed by Linux and then macOS steps. + +## Cartesi Machine emulator + +The Cartesi Machine is the deterministic RISC-V virtual machine your application runs in. The machine tool spawns it to reproduce the settled state and generate the withdrawal proofs, so the emulator must be installed (version 0.20.x). + +### Linux (Debian or Ubuntu) + +Add the Cartesi APT repository, then install the emulator: + +```sh +wget -qO - https://dist.cartesi.io/apt/keys/cartesi-deb-key.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/cartesi-deb-key.gpg +echo "deb https://dist.cartesi.io/apt stable/" | sudo tee /etc/apt/sources.list.d/cartesi-deb-apt.list +sudo apt-get update +sudo apt-get install cartesi-machine +``` + +### macOS + +Install with Homebrew: + +```sh +brew tap cartesi/tap +brew install cartesi-machine +``` + +If a package is not yet available for your system, build the emulator from source following the [Cartesi Machine installation instructions](https://github.com/cartesi/machine-emulator#installation). + +## Cartesi Rollups Node tools + +The recovery flow uses two command-line tools that ship together with the Cartesi Rollups Node: + +- **`cartesi-rollups-cli`** sends the on-chain transactions (foreclose, anchor the drive root, withdraw) and reads withdrawals; +- **`cartesi-rollups-machine-tool`** reproduces the settled machine state (`replay`) and generates the accounts-drive proofs (`prove accounts-drive`). + +Prebuilt packages are published only as Debian `.deb` files (amd64 and arm64). On macOS, and on other systems, you build them from source. + +### Linux (Debian or Ubuntu, amd64 or arm64) + +Download the node package for your architecture from the [Cartesi Rollups Node releases](https://github.com/cartesi/rollups-node/releases). The file is named `cartesi-rollups-node-v_.deb`. Install it (this installs all node binaries, including both tools): + +```sh +sudo dpkg -i cartesi-rollups-node-v_.deb +``` + +To install only the two tools, extract them from the package instead: + +```sh +dpkg-deb -x cartesi-rollups-node-v_.deb out/ +sudo cp out/usr/bin/cartesi-rollups-cli out/usr/bin/cartesi-rollups-machine-tool /usr/local/bin/ +``` + +### macOS + +No prebuilt binaries are published for macOS, so build the tools from source. You need the Cartesi Machine emulator (above), Go >= 1.24.1, and GNU Make >= 3.81. Install Go and Make with Homebrew: + +```sh +brew install go make +``` + +Then build and install: + +```sh +git clone --branch next/2.0 https://github.com/cartesi/rollups-node.git +cd rollups-node +make +sudo make install +``` + +This installs the binaries under `/opt/cartesi/bin` on macOS (and `/usr/bin` on Linux). Make sure that directory is on your `PATH`. + +## Verify + +```sh +cartesi-machine --version +cartesi-rollups-cli --version +cartesi-rollups-machine-tool --help +``` + +Once these run, continue with the [Emergency Withdrawal Recovery Guide](./recovery-guide.md). diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/lifecycle.md b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/lifecycle.md new file mode 100644 index 000000000..2ed0d5676 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/lifecycle.md @@ -0,0 +1,73 @@ +--- +id: lifecycle +title: Claim & Foreclosure Lifecycle +--- + +To understand foreclosure, it helps to first see how an application's inputs turn into settled state, and where foreclosure fits in. This page walks through that lifecycle. + +## From inputs to a settled claim + +**Inputs.** A user action (a deposit through a portal, or a message sent to the app) becomes an **input**, recorded on-chain in the [`InputBox`](../../api-reference/contracts/input-box.md). + +**Epochs.** Inputs are not settled one at a time. They are grouped into **epochs**: batches of consecutive inputs that are settled together as a single claim. Every input belongs to exactly one epoch. How epoch boundaries are drawn depends on the consensus; under Authority and Quorum an epoch covers a range of blocks, set by the consensus `epochLength`. + +**Claims.** The application runs as a deterministic Cartesi Machine. The node feeds each input to the machine as it arrives, advancing the machine's state and producing outputs. When the epoch closes, the node reduces the resulting state to a single fingerprint, a **claim** (a Merkle root), and posts it on-chain so the consensus contract can trust the off-chain computation by verifying one hash. + +Posting a claim happens in **two transactions**: + +1. **Submit** (`submitClaim`) posts the claim. The epoch becomes `CLAIM_STAGED`. +2. **Accept** (`acceptClaim`) finalizes it, once a waiting period has passed. The epoch becomes `CLAIM_ACCEPTED`. + +The waiting period between the two is the **claim staging period**, measured in blocks and fixed when the consensus is deployed. The consensus contract enforces it: `acceptClaim` reverts until enough blocks have passed. A staging period of `0` lets acceptance happen right away. + +## The epoch status flow + +An epoch moves through these statuses: + +![Epoch status flow: OPEN to INPUTS_PROCESSED to CLAIM_COMPUTED to CLAIM_STAGED to CLAIM_ACCEPTED, with a foreclosure branch diverting an unfinalized claim to CLAIM_FORECLOSED](../../epoch-flow.png) + +- **OPEN**: the epoch's block range is still current and collecting inputs. +- **INPUTS_PROCESSED**: the epoch has closed and the machine has processed all of its inputs. +- **CLAIM_COMPUTED**: the node has the claim ready. +- **CLAIM_STAGED**: the claim was submitted on-chain and is in its staging window. +- **CLAIM_ACCEPTED**: the staging period elapsed and the claim was finalized. This is the settled state that outputs (and emergency withdrawal) rely on. +- **CLAIM_FORECLOSED**: a terminal status a claim reaches if the application is foreclosed before that claim finalizes (see below). +- **CLAIM_REJECTED**: this is a related terminal status, but a **node-level** one rather than an on-chain outcome. The node marks its own epoch `CLAIM_REJECTED` (and the application `DIVERGED`) when it observes that a claim different from the one it computed was accepted on-chain, for example on a Quorum where another validator's claim won the vote. + +## Foreclosure + +Everything above assumes the operator keeps running the node and the application operates in optimum condition. Foreclosure is what happens when you can no longer depend on that. + +**Foreclosure** is the act of permanently freezing a Cartesi Rollups application at its last accepted state, this process can be triggered in situations where; the operator abandons the application, a bug is discovered in the application code, a compromised authority, a dishonest quorum majority, or a false claim is left unchallenged in a PRT dispute tournament. + +The claim staging period is the guardian's window to act: foreclosing before such a claim is accepted terminalizes it as `CLAIM_FORECLOSED` and freezes the application on the last state it still trusts, so users withdraw against that state and not the bad one. It's important to note that, Foreclosure does not reverse a claim that has already been accepted; once a state is accepted it is what emergency withdrawals pay out from, which is why the guardian's protection depends on acting within the staging window. + + +To forclose an application, the **guardian**, a single address fixed in the withdrawal config, calls [`foreclose()`](../../api-reference/contracts/application.md#foreclose) on the application contract. [`isForeclosed()`](../../api-reference/contracts/application.md#isforeclosed) becomes `true` and this permanently freezes the application: + +**A foreclosed application can no longer process inputs.** Once frozen it takes on no new inputs and settles no new state. The one procedure it can still run is [emergency withdrawal](./recovery-guide.md): returning the assets users already deposited back to them, directly from the contracts. + +Foreclosure is a property of the **application contract** and of the **node**. It takes both to make the freeze permanent: + +- **The contract** holds the on-chain truth. `foreclose()` can only be called by the guardian and sets `isForeclosed()`, after which the normal `submitClaim` and `acceptClaim` paths revert. The contract also gates emergency withdrawal so that path only opens once the application is foreclosed. +- **The node** observes that truth and acts on it. Its EVM Reader detects the on-chain `Foreclosure` event, records it in the node database, and stops claiming new inputs for that application, however it still keeps watching the base layer so as to index subsequent emergency withdrawals. The node also generates the accounts-drive proofs users need to withdraw. + +![Foreclosure sequence: the guardian calls foreclose() on the application contract; the node's EVM Reader observes isForeclosed(), records the foreclosure in its database, then continues its scanners to drain pre-foreclosure inputs and index post-foreclosure events](../../foreclosure-sequence.png) + +Foreclosure has three effects on claims: + +- **Accepted history is kept.** An epoch that already reached `CLAIM_ACCEPTED` stays accepted. Foreclosure does not rewrite settled history. +- **In-flight claims are cancelled.** A claim that has not finalized cannot finalize once the operator's authority is frozen, so the node marks it terminal as `CLAIM_FORECLOSED` instead of leaving it stuck. This happens whether the claim was still pre-staging (`CLAIM_COMPUTED`) or already `CLAIM_STAGED`. +- **The state is frozen.** The application settles at its last accepted epoch, a final state that anyone can reproduce on their own. + +## After foreclosure: prove and withdraw + +Once frozen, the accounts drive (the in-app balance ledger inside the machine state) at the last accepted epoch is the source of truth for balances. Turning that into on-chain payouts takes three steps, one off-chain and two on-chain: + +1. **Generate the proofs.** Off-chain, anyone runs the **machine tool** (`cartesi-rollups-machine-tool`) to replay the settled machine state and then `prove accounts-drive`. Replay is deterministic, so anyone can reproduce the last accepted state independently, with no running node. This writes two proof files: `drive-root-proof.json` (the accounts-drive root and its proof against the machine state, used once in step 2) and `account-proof.json` (the per-account Merkle proofs, used in step 3). +2. **Anchor the ledger.** Anyone calls [`proveAccountsDriveMerkleRoot()`](../../api-reference/contracts/application.md#proveaccountsdrivemerkleroot) once, passing the root and proof from `drive-root-proof.json`. The contract checks it against the settled machine state and stores it. This is permissionless and happens once per application. +3. **Withdraw per account.** Each account is withdrawn with [`withdraw()`](../../api-reference/contracts/application.md#withdraw), passing the account and its Merkle proof from `account-proof.json`. The contract validates the account against the anchored root, builds a transfer output, runs it, and marks the account as withdrawn so it cannot be withdrawn twice. The gas payer can differ from the recipient. + +As each on-chain step lands, the node's EVM Reader indexes it: it records the `AccountsDriveMerkleRootProved` event when the ledger is anchored, and stores each `Withdrawal` event (keyed by application and account index) so clients can read withdrawals over JSON-RPC and the CLI. + +![Accounts-drive proof and withdrawal sequence: the machine tool produces drive-root-proof.json and account-proof.json; the operator calls proveAccountsDriveMerkleRoot() then withdraw() on the application contract; the node's EVM Reader indexes the AccountsDriveMerkleRootProved and Withdrawal events](../../accounts-drive-withdrawal.png) diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/overview.md similarity index 58% rename from cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md rename to cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/overview.md index 2a8510e2f..29463b85f 100644 --- a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/overview.md +++ b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/overview.md @@ -7,13 +7,16 @@ When users deposit assets into a Cartesi Rollups application, those assets are h **Foreclosure and emergency withdrawal** are the answer. They let a designated **guardian** freeze an application, after which any user can withdraw their in-app balance straight from the base-layer contracts by proving their account, with **no running node required**. -The feature is opt-in: an application only supports it if it was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md). Applications deployed without one behave exactly as before. +The feature is opt-in: an application only supports it if it was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md). Applications deployed without one behave exactly as before. In addition to that, the application is also expected to record the assets deposited into it using the CMA ledger library. This library keeps those balances inside the accounts drive in a recoverable, provable layout that matches the `WithdrawalConfig`. See the [Asset Management Library](https://cartesi.github.io/docs/pr-preview/pr-303/cartesi-rollups/2.0/api-reference/asset-management/overview/) section for more details about the CMA library. ## The two parts **Foreclosure** freezes the application. A guardian address, set in the withdrawal config, calls [`foreclose()`](../../api-reference/contracts/application.md#foreclose). From that moment the application is frozen at its last settled state, and it stays frozen forever. See [FOR-005](../../api-reference/contracts/application.md#foreclose) for the guardian-only rule. -**Emergency withdrawal** is the recovery path that foreclosure unlocks. The application's **accounts drive** (the in-app balance ledger, held inside the machine state) is proved on-chain once, and then each user withdraws their own balance by proving their account against that proved ledger. Everything happens directly against the contracts, so it keeps working even if the operator and its node are gone. +**Emergency withdrawal** is the recovery path that foreclosure unlocks, and it is built on the application's **accounts drive**. + +The accounts drive is a dedicated [drive](../advanced-configuration.md#drives), a region of the Cartesi Machine's memory, that the application uses as its balance ledger. It records how much each account owns, in a fixed layout described by the [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md). Like every drive, it sits at a known, fixed address in the machine's memory. +The machine's whole memory is a single Merkle tree whose root, the machine state root hash, is finalized on-chain as part of the settled claim. Because the accounts drive occupies a known address, its own Merkle root is a fixed branch of that tree, so it can be proven up to the machine state root hash with a short list of sibling hashes. After foreclosure, anyone submits that proof once to anchor the accounts-drive root on-chain against the application's last settled machine state. The ledger is then fixed on-chain, and each user withdraws their own balance by proving their account against that anchored drive. Everything happens directly against the contracts, so it keeps working even if the operator and its node are gone. ## When funds are recoverable diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/recovery-guide.md new file mode 100644 index 000000000..7dbe95953 --- /dev/null +++ b/cartesi-rollups_versioned_docs/version-2.0/development/emergency-withdrawal/recovery-guide.md @@ -0,0 +1,160 @@ +--- +id: recovery-guide +title: Emergency Withdrawal Recovery Guide +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This guide walks through foreclosing an application and withdrawing an account's funds directly from the base-layer contracts. For the concepts behind each step, see [Foreclosure & Emergency Withdrawal](./overview.md) and the [Claim & Foreclosure Lifecycle](./lifecycle.md). + +## Before you start + +You need: + +- An application that was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), and that has reached at least one accepted epoch; +- The **guardian** key (only the guardian can foreclose); +- The **machine tool** (`cartesi-rollups-machine-tool`), which reproduces the settled machine state and generates the proofs; +- To send the on-chain transactions, either the **`cartesi-rollups-cli`** (see [Installing the required tools](./installation-guide.md)) or, if you prefer, **Foundry's `cast`** with `jq`; +- The application's **accounts-drive parameters** from its withdrawal config: `accountsDriveStartIndex`, `log2MaxNumOfAccounts`, and `log2LeavesPerAccount`. These must match the values the application was deployed with. +- This should be done in the same environment of the node, with access to the database (and configuration variables) + +This guide assumes the application already maintains its accounts drive in the layout its `WithdrawalConfig` describes. For how that drive is created, sized, and kept, see [Emergency Withdrawal (guest requirements)](../../api-reference/backend/emergency-withdrawal.md), and in particular [Creating the accounts drive](../../api-reference/backend/emergency-withdrawal.md#creating-the-accounts-drive). + +The on-chain steps (1, 4, 5, and 6) can be run with either tool. Choose a tab in each step, and it applies to the others. Steps 2 and 3 use the machine tool either way. In the `cast` tabs, `` is the application contract address, `` is your node RPC endpoint, and the private key is the guardian's (step 1) or your own (steps 4 and 5). + +## Step 1: Foreclose the application + +Signed by the guardian, freeze the application: + + + + +```sh +cartesi-rollups-cli foreclose +``` + + + + +```sh +cast send 'foreclose()' \ + --private-key --rpc-url +``` + + + + +After this, `isForeclosed()` returns `true` and the application is frozen at its last accepted epoch. + +## Step 2: Reproduce the settled machine state + +Find the last accepted epoch, then replay the node database into a machine snapshot up to that epoch: + +```sh +cartesi-rollups-machine-tool replay \ + --template \ + --application \ + --to-epoch \ + --store replay-snapshot +``` + +Replay is deterministic: running it again produces the same machine state, so anyone can reproduce this snapshot independently. + +## Step 3: Generate the proofs + +From that snapshot, generate the accounts-drive-root proof and the per-account proof for the account you want to withdraw. The `--accounts-drive-*` values **must match the withdrawal config**. + +```sh +cartesi-rollups-machine-tool prove accounts-drive \ + --snapshot replay-snapshot \ + --accounts-drive-start-index \ + --log2-max-num-of-accounts \ + --log2-leaves-per-account \ + --account \ + --out-drive-root-proof drive-root-proof.json \ + --out-withdraw-proof account-proof.json +``` + +This writes two files: `drive-root-proof.json` (used once, in step 4) and `account-proof.json` (used per account, in step 5). The `cast` tabs below read their arguments out of these files with `jq`. + +## Step 4: Anchor the accounts-drive root on-chain + +Record the accounts-drive root against the settled machine state. This is permissionless and only needs to happen once per foreclosed application: + + + + +```sh +cartesi-rollups-cli prove-drive-root \ + --proof-file drive-root-proof.json +``` + + + + +```sh +ROOT=$(jq -r '.accounts_drive_merkle_root' drive-root-proof.json) +PROOF=$(jq -rc '.proof | join(",")' drive-root-proof.json) + +cast send 'proveAccountsDriveMerkleRoot(bytes32,bytes32[])' "$ROOT" "[$PROOF]" \ + --private-key --rpc-url +``` + + + + +On success the contract stores the root and emits `AccountsDriveMerkleRootProved`. Anchoring a root from the wrong epoch, or from a different application, is rejected. + +## Step 5: Withdraw the account's funds + +With the root anchored, withdraw the account: + + + + +```sh +cartesi-rollups-cli withdraw \ + --proof-file account-proof.json +``` + + + + +```sh +ACCT=$(jq -r '.account' account-proof.json) +IDX=$(jq -r '.account_index' account-proof.json) +SIBS=$(jq -rc '.account_root_siblings | join(",")' account-proof.json) + +cast send 'withdraw(bytes,(uint64,bytes32[]))' "$ACCT" "($IDX,[$SIBS])" \ + --private-key --rpc-url +``` + + + + +The contract validates the account against the anchored root, builds and runs the transfer, marks the account as withdrawn, and emits a `Withdrawal` event. Withdrawing the same account again is rejected. + +## Step 6: Verify + + + + +```sh +# the node indexes the on-chain Withdrawal event +cartesi-rollups-cli read withdrawals +``` + + + + +```sh +# read the on-chain flag directly (account index from account-proof.json) +cast call 'wereAccountFundsWithdrawn(uint256)(bool)' \ + --rpc-url +``` + + + + +Either way, [`wereAccountFundsWithdrawn(accountIndex)`](../../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md deleted file mode 100644 index f8a01ea4a..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/lifecycle.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -id: lifecycle -title: Claim & Foreclosure Lifecycle ---- - -To understand foreclosure, it helps to first see how an application's inputs turn into settled state, and where foreclosure fits in. This page walks through that lifecycle. - -## From inputs to a settled claim - -**Inputs.** A user action (a deposit through a portal, or a message sent to the app) becomes an **input**, recorded on-chain in the [`InputBox`](../../api-reference/contracts/input-box.md). - -**Epochs.** Inputs are not settled one at a time. They are grouped into **epochs**, where an epoch is a fixed range of blocks (set by the consensus `epochLength`). Every input is assigned to an epoch by the block it arrived in. - -**Claims.** The application runs as a deterministic Cartesi Machine. Once an epoch's block range closes, the node feeds that epoch's inputs to the machine, which updates its state and produces outputs. The node then reduces the result to a single fingerprint, a **claim** (a Merkle root), and posts it on-chain so the consensus contract can trust the off-chain computation by checking one hash. - -Posting a claim happens in **two transactions**, both sent by the operator: - -1. **Submit** (`submitClaim`) posts the claim. The epoch becomes `CLAIM_STAGED`. -2. **Accept** (`acceptClaim`) finalizes it, once a waiting period has passed. The epoch becomes `CLAIM_ACCEPTED`. - -The waiting period between the two is the **claim staging period**, measured in blocks and fixed when the consensus is deployed. The consensus contract enforces it: `acceptClaim` reverts until enough blocks have passed. A staging period of `0` lets acceptance happen right away. - -## The epoch status flow - -An epoch moves through these statuses: - -![Epoch status flow: OPEN to INPUTS_PROCESSED to CLAIM_COMPUTED to CLAIM_STAGED to CLAIM_ACCEPTED, with a foreclosure branch diverting an unfinalized claim to CLAIM_FORECLOSED](../../epoch-flow.png) - -- **OPEN**: the epoch's block range is still current and collecting inputs. -- **INPUTS_PROCESSED**: the range closed and the machine processed the inputs. -- **CLAIM_COMPUTED**: the node has the claim ready. -- **CLAIM_STAGED**: the claim was submitted on-chain and is in its staging window. -- **CLAIM_ACCEPTED**: the staging period elapsed and the claim was finalized. This is the settled state that outputs (and emergency withdrawal) rely on. -- **CLAIM_FORECLOSED**: a terminal status a claim reaches if the application is foreclosed before that claim finalizes (see below). - -## Foreclosure - -Everything above assumes the operator keeps running the node. Foreclosure is what happens when you no longer want to depend on that. - -The **guardian** calls [`foreclose()`](../../api-reference/contracts/application.md#foreclose). This freezes the application: [`isForeclosed()`](../../api-reference/contracts/application.md#isforeclosed) becomes `true` and stays `true`. Foreclosure has three effects on claims: - -- **Accepted history is kept.** An epoch that already reached `CLAIM_ACCEPTED` stays accepted. Foreclosure does not rewrite settled history. -- **In-flight claims are cancelled.** A claim that has not finalized cannot finalize once the operator's authority is frozen, so the node marks it terminal as `CLAIM_FORECLOSED` instead of leaving it stuck. This happens whether the claim was still pre-staging (`CLAIM_COMPUTED`) or already `CLAIM_STAGED`. -- **The state is frozen.** The application settles at its last accepted epoch, a final state that anyone can reproduce on their own. - -## After foreclosure: prove and withdraw - -Once frozen, the accounts drive (the in-app balance ledger inside the machine state) at the last settled epoch is the source of truth for balances. Turning that into on-chain payouts takes two on-chain steps: - -1. **Anchor the ledger.** Anyone calls [`proveAccountsDriveMerkleRoot()`](../../api-reference/contracts/application.md#proveaccountsdrivemerkleroot) once, proving the accounts-drive root against the settled machine state. The contract stores it. -2. **Withdraw per account.** Each user calls [`withdraw()`](../../api-reference/contracts/application.md#withdraw) with their account and a Merkle proof. The contract validates the account against the anchored root, builds a transfer output, runs it, and marks the account as withdrawn so it cannot be withdrawn twice. - -The [Emergency Withdrawal Recovery Guide](./recovery-guide.md) turns these steps into concrete commands. diff --git a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md b/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md deleted file mode 100644 index 7e14e4822..000000000 --- a/cartesi-rollups_versioned_docs/version-2.0/development/foreclosure/recovery-guide.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -id: recovery-guide -title: Emergency Withdrawal Recovery Guide ---- - -This guide walks through foreclosing an application and withdrawing an account's funds directly from the base-layer contracts. For the concepts behind each step, see [Foreclosure & Emergency Withdrawal](./overview.md) and the [Claim & Foreclosure Lifecycle](./lifecycle.md). - -## Before you start - -You need: - -- an application that was deployed with a [`WithdrawalConfig`](../../api-reference/contracts/withdrawal/withdrawal-config.md), and that has reached at least one accepted epoch; -- the **guardian** key (only the guardian can foreclose); -- the [`cartesi-rollups-cli`](../installation.md) and the **machine tool** (`cartesi-rollups-machine-tool`), which reproduces the settled machine state and generates the proofs; -- the application's **accounts-drive parameters** from its withdrawal config: `accountsDriveStartIndex`, `log2MaxNumOfAccounts`, and `log2LeavesPerAccount`. These must match the values the application was deployed with. - -## Step 1: Foreclose the application - -Signed by the guardian, freeze the application: - -```sh -cartesi-rollups-cli foreclose --yes -``` - -After this, `isForeclosed()` returns `true` and the application is frozen at its last accepted epoch. - -## Step 2: Reproduce the settled machine state - -Find the last accepted epoch, then replay the node database into a machine snapshot up to that epoch: - -```sh -cartesi-rollups-machine-tool replay \ - --template \ - --application \ - --to-epoch \ - --store replay-snapshot -``` - -Replay is deterministic: running it again produces the same machine state, so anyone can reproduce this snapshot independently. - -## Step 3: Generate the proofs - -From that snapshot, generate the accounts-drive-root proof and the per-account proof for the account you want to withdraw. The `--accounts-drive-*` values **must match the withdrawal config**. - -```sh -cartesi-rollups-machine-tool prove accounts-drive \ - --snapshot replay-snapshot \ - --accounts-drive-start-index \ - --log2-max-num-of-accounts \ - --log2-leaves-per-account \ - --account \ - --out-drive-root-proof drive-root-proof.json \ - --out-withdraw-proof account-proof.json -``` - -This writes two files: `drive-root-proof.json` (used once, in step 4) and `account-proof.json` (used per account, in step 5). - -## Step 4: Anchor the accounts-drive root on-chain - -Record the accounts-drive root against the settled machine state. This is permissionless and only needs to happen once per foreclosed application: - -```sh -cartesi-rollups-cli prove-drive-root \ - --proof-file drive-root-proof.json --yes -``` - -On success the contract stores the root and emits `AccountsDriveMerkleRootProved`. Anchoring a root from the wrong epoch, or from a different application, is rejected. - -## Step 5: Withdraw the account's funds - -With the root anchored, withdraw the account: - -```sh -cartesi-rollups-cli withdraw \ - --proof-file account-proof.json --yes -``` - -The contract validates the account against the anchored root, builds and runs the transfer, marks the account as withdrawn, and emits a `Withdrawal` event. Withdrawing the same account again is rejected. - -## Step 6: Verify - -```sh -# the node indexes the on-chain Withdrawal event -cartesi-rollups-cli read withdrawals -``` - -You can also read the on-chain state directly: [`wereAccountFundsWithdrawn(accountIndex)`](../../api-reference/contracts/application.md#wereaccountfundswithdrawn) returns `true`, and the token balance has moved from the application contract to the account owner. diff --git a/cartesi-rollups_versioned_docs/version-2.0/epoch-flow.png b/cartesi-rollups_versioned_docs/version-2.0/epoch-flow.png index b8ec3246b2cb2e7f85156f29d0a87814f69fb7a5..d76208bcd7dec49671b7384c6f2673d19df7ff94 100644 GIT binary patch literal 65626 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 E0cLap2LJ#7 literal 62070 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 literal 0 HcmV?d00001 diff --git a/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json b/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json index d2e233fab..6d50904f8 100644 --- a/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json +++ b/cartesi-rollups_versioned_sidebars/version-2.0-sidebars.json @@ -71,7 +71,7 @@ }, { "type": "category", - "label": "Withdrawal", + "label": "Emergency Withdrawal", "collapsed": true, "items": [ "api-reference/contracts/withdrawal/overview", @@ -156,7 +156,7 @@ }, { "type": "category", - "label": "Withdrawals", + "label": "Emergency Withdrawal", "items": [ "api-reference/jsonrpc/methods/withdrawals/withdrawals-list", "api-reference/jsonrpc/methods/withdrawals/withdrawals-get" @@ -182,12 +182,13 @@ "development/Advanced-configuration", { "type": "category", - "label": "Foreclosure & Emergency Withdrawal", + "label": "Emergency Withdrawal", "collapsed": true, "items": [ - "development/foreclosure/overview", - "development/foreclosure/lifecycle", - "development/foreclosure/recovery-guide" + "development/emergency-withdrawal/overview", + "development/emergency-withdrawal/lifecycle", + "development/emergency-withdrawal/installation-Guide", + "development/emergency-withdrawal/recovery-guide" ] } ] diff --git a/static/llms.txt b/static/llms.txt index a409e2140..e8f19e99c 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -91,9 +91,10 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C - [Query outputs](https://docs.cartesi.io/cartesi-rollups/2.0/development/query-outputs.md): Vouchers, notices and reports - [Asset handling](https://docs.cartesi.io/cartesi-rollups/2.0/development/asset-handling.md): Deposits and withdrawals - [Advanced configuration](https://docs.cartesi.io/cartesi-rollups/2.0/development/Advanced-configuration.md): Configure the Cartesi Machine via cartesi.toml -- [Foreclosure & Emergency Withdrawal](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/overview.md): What foreclosure and emergency withdrawal are, and when application funds are recoverable directly from the contracts -- [Claim & Foreclosure Lifecycle](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/lifecycle.md): How inputs become settled claims, and how foreclosure fits the epoch and claim lifecycle -- [Emergency Withdrawal Recovery Guide](https://docs.cartesi.io/cartesi-rollups/2.0/development/foreclosure/recovery-guide.md): Step-by-step foreclose, replay, prove the accounts drive, and withdraw +- [Foreclosure & Emergency Withdrawal](https://docs.cartesi.io/cartesi-rollups/2.0/development/emergency-withdrawal/overview.md): What foreclosure and emergency withdrawal are, and when application funds are recoverable directly from the contracts +- [Claim & Foreclosure Lifecycle](https://docs.cartesi.io/cartesi-rollups/2.0/development/emergency-withdrawal/lifecycle.md): How inputs become settled claims, how foreclosure fits the epoch and claim lifecycle, and how to prove the accounts drive and withdraw afterward +- [Emergency Withdrawal Recovery Guide](https://docs.cartesi.io/cartesi-rollups/2.0/development/emergency-withdrawal/recovery-guide.md): Step-by-step foreclose, replay, prove the accounts drive, and withdraw, using the Cartesi CLI or cast +- [Installing the required tools](https://docs.cartesi.io/cartesi-rollups/2.0/development/emergency-withdrawal/installation-Guide.md): Install the Cartesi Machine emulator plus cartesi-rollups-cli and the machine tool, on Linux or macOS ## Cartesi Rollups v2.0 — Development Snippets @@ -147,7 +148,7 @@ If a user's code or question references the old GraphQL API, `sunodo`, or v1.x C - [Reports](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/reports.md): Application logs - [Exception](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/exception.md): Register exceptions - [Finish](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/finish.md): Complete request processing -- [Emergency Withdrawal (guest requirements)](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/emergency-withdrawal.md): Maintaining the accounts drive so balances are recoverable after foreclosure +- [Emergency Withdrawal (guest requirements)](https://docs.cartesi.io/cartesi-rollups/2.0/api-reference/backend/emergency-withdrawal.md): Creating, sizing, and maintaining the accounts drive so balances stay provable and recoverable after foreclosure ## Cartesi Rollups v2.0 — Contracts API