# Migrating

## From v1 to v2

Deroll v1 is based on Cartesi Rollups v1, while deroll v2 is based on Cartesi Rollups v2.

Here are the changes you should be aware of when migrating from v1 to v2:

### Rollup transport

Deroll v1 communicates with the Cartesi Machine through the **Rollup HTTP Server**, so `createApp` required its `url`:

```ts
// v1
const app = createApp({ url: "http://127.0.0.1:5004" });
```

Deroll v2 talks to the machine directly through [`@cartesi/rollup`](https://github.com/cartesi/rollups-ts), the native Node.js binding for libcmt. There is no `App` wrapper at all — you open the device and run its loop:

```ts
// v2
import { Rollup, chain } from "@cartesi/rollup";

const rollup = new Rollup();
rollup.run({ advance, inspect });
```

The `ROLLUP_HTTP_SERVER_URL` environment variable is no longer used, and `createApp` is gone along with `@deroll/app`. See [The Rollup Loop](/app/application).

### Input metadata

The input metadata received in an advance handler has changed, and it is no longer nested under a `metadata` property — the request is a single flat object.

```diff
-{ metadata: { chain_id: number; msg_sender: Address; epochIndex: bigint;
-              input_index: number; block_number: number; timestamp: number },
-  payload: Hex }
+{ type: "advance"; chainId: bigint; appContract: Address; msgSender: Address;
+  index: bigint; blockNumber: bigint; blockTimestamp: bigint;
+  prevRandao: bigint; payload: Buffer }
```

```ts
// v1

// v2
```

### Payload type

The input payload the application should handle in advance handlers and inspect handlers are now a Node.js [Buffer](https://nodejs.org/api/buffer.html#class-buffer) instead of a `Hex` string.

### Voucher value

Vouchers now have an optional bigint `value` field, which is the amount of native token to be sent during voucher execution.
With this new property withdraw vouchers can now be much simpler.

```ts twoslash
/// <reference types="node" />
// ---cut---
import { Rollup, chain } from "@cartesi/rollup";
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";

// open the rollup device
const rollup = new Rollup();

rollup.run({
    advance: (request, rollup) => {
        const token = "0x491604c0FDF08347Dd1fa4Ee062a822A5DD06B5D"; // CTSI address
        const to = "0x8f7599fa6fDDF2845a3beBcDCb055C7Ba1793a1f"; // CTSI recipient
        const amount = parseUnits("1", 18);

        const id = rollup.emitVoucher({
            destination: token,
            payload: encodeFunctionData({
                abi: erc20Abi,
                functionName: "transfer",
                args: [to, amount],
            }),
            value: 1000000000000000000n, // [!code focus]
        });
        return true;
    },
});
```

### Change in ERC-20 deposit input

The message format of a ERC-20 deposit dropped the byte of the success flag.
If you use the `@deroll/wallet` module this change is automatically handled for you.

### DAppAddressRelay removed

Now that the input metadata includes the application address there is no need to use the `DAppAddressRelay` contract anymore.

### Delegate-call vouchers

Cartesi Rollups v2 introduces a new output type, the **delegate-call voucher**, which the application contract executes with `DELEGATECALL` instead of `CALL`, running the target code in the application's own context.
Deroll v2 exposes it through [`emitDelegateCallVoucher`](/app/outputs#delegate-call-vouchers).

### Executing outputs on the base layer

In v1 each output type had its own entry point on the `CartesiDApp` contract (for example `executeVoucher`).
In Cartesi Rollups v2 all outputs — vouchers, delegate-call vouchers and notices — share a single Merkle tree and are executed and validated through unified functions on the application contract:

```solidity
function executeOutput(bytes output, OutputValidityProof proof);
function validateOutput(bytes output, OutputValidityProof proof);
```

This mainly affects the frontend or relayer code that executes vouchers, not the advance and inspect handlers you write with deroll.

### Handlers return a boolean

An advance handler used to return `"accept"` or `"reject"`.
Those were the `status` field of the Rollup HTTP Server's `/finish` request body, which deroll passed through verbatim; with the HTTP transport gone, handlers return a boolean instead, matching `finish({ accept })` in the binding.

```diff
-app.addAdvanceHandler(async (data) => {
-    if (!isMine(data)) return "reject";
-    return "accept";
-});
+rollup.run({
+    advance: (request) => {
+        if (!isMine(request)) return false;
+        return true;
+    },
+});
```

`true` accepts the input; `false` declines it and passes it to the next handler, exactly as `"reject"` used to.
The return type is a strict `boolean` with no `void` — `Rollup.run` in the binding accepts a request unless a handler returns `false`, while deroll rejects unless a handler opts in, so a handler that falls off its end has to be a type error rather than a silent accept.

### Outputs are synchronous

Emitting an output is a write to the rollup device, not I/O the event loop can interleave with, so the output methods are synchronous and no longer return promises.
The notice and report payloads are also passed directly, rather than wrapped in an object.

```diff
-const id = await app.createNotice({ payload: stringToHex("hello") });
-await app.createReport({ payload: stringToHex("hello") });
-const id = await app.createVoucher({ destination, payload });
+const id = rollup.emitNotice(stringToHex("hello"));
+rollup.emitReport(stringToHex("hello"));
+const id = rollup.emitVoucher({ destination, payload });
```

The rollup is handed to every handler as a second argument, so a handler does not need to close over anything to emit an output. Vouchers keep their object argument, since they carry a `destination` and an optional `value` besides the payload. See [Outputs](/app/outputs).

Handlers may still be `async` — they are awaited — but they no longer have to be.

### Registering several handlers

`addAdvanceHandler` and `addInspectHandler` are gone: `Rollup.run` takes one handler of each kind. To run several advance handlers, compose them with `chain` from [`@cartesi/rollup`](https://github.com/cartesi/rollups-ts):

```diff
-app.addAdvanceHandler(wallet.handler);
-app.addAdvanceHandler(application);
-app.addInspectHandler(inspect);
-app.start();
+rollup.run({
+    advance: chain(wallet.handler, application),
+    inspect,
+});
```

The `broadcastAdvanceRequests` option is now `broadcast`, chosen per group of handlers rather than for the whole application, and the two nest (`chain(a, broadcast(b, c))`).

### The router was removed

`@deroll/router` is gone, and there is no v2 release of it.
It matched inspect payloads against URL patterns, which made sense when an inspect request *was* an HTTP `GET` and the payload was the path it was made to.
It is now an arbitrary buffer whose [encoding the application chooses](/app/data-encoding), and the routing key follows from that choice: a segment of a string, a field of a JSON object, or a function selector under ABI.
Only the first of those looks like a URL, so the abstraction stopped paying for itself.

Dispatch in the handler instead.
`createRouter().add("hello/:name", …)` becomes:

```ts twoslash
/// <reference types="node" />
// ---cut---
import type { InspectRequestHandler } from "@cartesi/rollup";
import { stringToHex } from "viem";

const inspect: InspectRequestHandler = ({ payload }, rollup) => {
    const [command, name] = payload.toString().split("/");

    switch (command) {
        case "hello":
            rollup.emitReport(stringToHex(`Hello ${name}`));
            return true;
        default:
            return false; // no match: `chain` moves on, as the router did
    }
};
```

Returning `false` where no route matched preserves the router's behaviour, so a handler composed with `chain` still falls through.
To keep pattern matching, depend on [`path-to-regexp`](https://github.com/pillarjs/path-to-regexp) directly — it is what the router used, and calling it yourself is a few lines.
See [Dispatching queries](/app/inspect-handlers#dispatching-queries) for that and for the JSON and ABI equivalents.

The published `@deroll/router` versions are deprecated but remain installable, so v1 applications keep resolving.

### registerException

`registerException` is now `rollup.emitException(payload)`.
It signals that a request could not be processed at all, which halts the machine.

### Handler exceptions

An exception raised by an advance handler now rejects the input immediately instead of falling through to the next handler, and the error is emitted as a report.
See [Advance Handlers](/app/advance-handlers#exceptions).

### Protocol types come from @cartesi/rollup

deroll no longer declares its own copies of the rollup protocol types.
They come straight from [`@cartesi/rollup`](https://github.com/cartesi/rollups-ts), the libcmt binding:

* `AdvanceRequest`, `InspectRequest` and `RollupRequest` replace `AdvanceRequestData`, `InspectRequestData`, `AdvanceRequestMetadata` and the `RollupAdvanceRequest`/`RollupInspectRequest` pair.
* `BytesLike` replaces `Payload`, and it is what the output methods accept.
* `Voucher` and `DelegateCallVoucher` now come from the binding, so `destination` accepts a `Uint8Array` as well as a hex address, and a voucher `value` accepts a `number` or hex as well as a `bigint`.
* The `Notice`, `Report` and `Exception` wrapper types are gone, along with the `NoticeResponse`/`ReportResponse`/`VoucherResponse` types left over from the HTTP transport.

`@cartesi/rollup` is a peer dependency of the deroll packages, which keeps a single copy of the native binding in the dependency tree — the rollup device allows only one open handle per process.

### GraphQL service deprecated

In v1 the inputs and outputs (notices, vouchers and reports) of an application were queried through a **GraphQL service**.
In v2 the GraphQL service is deprecated in favor of a [JSON-RPC API](/app/quick-start#querying-json-rpc) (for example `cartesi_listInputs`).
This is a frontend or off-chain concern and does not affect the advance and inspect handlers you write with deroll.
