Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4dc316f
feat(cli): require cartesi-machine 0.22
brunomenezes Oct 20, 2026
e3ab230
test(cli): withdraw from nvram accounts drives
brunomenezes Oct 20, 2026
9f8f4b8
test(cli): withdraw next to an account with no balance
brunomenezes Oct 28, 2026
4cd6481
chore(cli): bump @cartesi/wagmi-plugin to 1.0.0-alpha.9
brunomenezes Nov 4, 2026
bbbef93
fix(cli): allow abandonment when undeploying
brunomenezes Nov 5, 2026
d1fa0cc
fix(cli): give the node the application factory for redeploys
brunomenezes Nov 5, 2026
14fa861
fix(cli): stop passing the old consensus to prt redeploys
brunomenezes Nov 5, 2026
c3eb3eb
fix(cli): drop pending from --default-block
brunomenezes Nov 5, 2026
e312a2b
fix(cli): keep $ in values forwarded to compose
brunomenezes Nov 5, 2026
5156523
fix(cli): copy node key files into the node container
brunomenezes Nov 5, 2026
96d2ad6
feat(cli): reject unsupported blockchain endpoints early
brunomenezes Nov 5, 2026
fb20093
feat(cli): default send and deposit to devnet account 8
brunomenezes Nov 5, 2026
88eff27
feat(cli): appoint prt sentries from cartesi.toml
brunomenezes Nov 5, 2026
a7a3370
feat(cli): run a sling node for local sentries
brunomenezes Nov 5, 2026
6e3122c
feat(cli): show the sentries in cartesi logs
brunomenezes Nov 7, 2026
79edc63
feat(cli): run a sling claimer with the node in reader mode
brunomenezes Nov 12, 2026
e2bdc4d
fix(cli): say appointed only for every entry the CLI doesn't run
brunomenezes Nov 12, 2026
28b4c8f
chore(cli): default to sdk 0.12.0-alpha.45
brunomenezes Nov 12, 2026
db40096
chore(cli): bump rollups-explorer to 2.0.0-alpha.6
brunomenezes Nov 12, 2026
00f4ee8
refactor(cli): replace [[prt.sentries]] with [prt.nodes.<label>]
brunomenezes Nov 12, 2026
8e19586
refactor(cli): a sentry flag and a reference entry instead of role
brunomenezes Nov 12, 2026
17d8153
chore: refresh bun.lock
brunomenezes Nov 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/afraid-birds-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi build` and `cartesi run` now default to SDK 0.12.0-alpha.45, which carries rollups-node 2.0.0-alpha.14 with Dave 3.0.0-alpha.6 and cartesi-machine 0.22. The node's database migration was edited in place, so a database created by an earlier node can't be reused. `cartesi run` recreates its own on every start, and a node you run yourself needs a fresh one.
5 changes: 5 additions & 0 deletions .changeset/few-carrots-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

`cartesi run --default-block` no longer accepts `pending`, which the rollups-node no longer supports. Use `latest`, `safe` or `finalized`.
5 changes: 5 additions & 0 deletions .changeset/fiery-flies-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

Bump the rollups-explorer service to 2.0.0-alpha.6, which supports rollups-node 2.0.0-alpha.14.
5 changes: 5 additions & 0 deletions .changeset/hot-rings-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

`cartesi run`'s Build and redeploy no longer fails with "CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS: variable not defined". The CLI now passes the devnet's ApplicationFactory address to the node, which `CARTESI_CONTRACTS_APPLICATION_FACTORY_ADDRESS` can still override.
5 changes: 5 additions & 0 deletions .changeset/lazy-cougars-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi run --prt` now runs a sling node for each `[prt.nodes.<label>]` entry with `type = "sling"`, as container `prt-node-<label>`, so claims the sentries agree with are accepted without waiting out `--claim-staging-period`. Pool accounts (devnet 20 to 29) are funded with 10,000 ETH by the CLI. An entry with `private_key_file` runs on your own key, whose address becomes the entry's, and you fund it. The nodes are stopped before a rebuild and started again for the redeployed application.
5 changes: 5 additions & 0 deletions .changeset/many-trams-stop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

The rollups-node has its own `[prt.nodes.<label>]` entry, `type = "reference"`, implied when omitted. `claim = false` on it runs the node in reader mode, following the tournaments and recording settled epochs while sling nodes claim, as production deployments may do. Changing it takes effect on the next `cartesi run`, not on a shell rebuild.
5 changes: 5 additions & 0 deletions .changeset/mighty-otters-know.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi send` and `cartesi deposit` now default to devnet account 8 instead of account 0, which the node uses to sign its claims. Pass `--from` to pick another account.
5 changes: 5 additions & 0 deletions .changeset/pretty-lilies-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi logs` and the shell's View logs now show the PRT nodes next to the rollups-node. Name services to pick some, e.g. `cartesi logs prt-node-green`.
5 changes: 5 additions & 0 deletions .changeset/quick-dancers-pick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

`CARTESI_*_FILE` key files set on the host now reach the node container as copies the node can read. Before, only the path was forwarded and the node couldn't read the file.
5 changes: 5 additions & 0 deletions .changeset/seven-moments-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

Require cartesi-machine 0.22. Machines stored by 0.21 can't be loaded by 0.22: rebuild and redeploy every application.
5 changes: 5 additions & 0 deletions .changeset/stale-clubs-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi run` now rejects a `CARTESI_BLOCKCHAIN_HTTP_ENDPOINT` the rollups-node can't use before starting anything. It must be an http(s) URL with a DNS name or IP address. The error doesn't show the value, which may hold credentials.
5 changes: 5 additions & 0 deletions .changeset/strict-grapes-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

Use the Dave 3.0.0-alpha.6 PRT contracts. Every PRT address moves, including the devnet DaveAppFactory. The rollups contract addresses are unchanged.
5 changes: 5 additions & 0 deletions .changeset/swift-berries-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

Keep `$` in the `CARTESI_*` variables `cartesi run` forwards to the node and in its `--fork-url`. Docker Compose read `$name` in them as a variable, so a value such as a password or an API key in a URL arrived changed.
5 changes: 5 additions & 0 deletions .changeset/witty-crews-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": minor
---

`cartesi run --prt` now deploys the application with the PRT sentries set in `cartesi.toml`. A `[prt]` section names an optional `sentry_manager` and one `[prt.nodes.<label>]` table per node, with `sentry = true` on the ones to appoint. The sentries are appointed on the consensus in file order. An entry with `type = "sling"` and no `address` gets one of the CLI's PRT pool, devnet accounts 20 to 29. An entry with only an `address` is appointed and run elsewhere. Without `--prt` the section is ignored.
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"/dist"
],
"devDependencies": {
"@cartesi/wagmi-plugin": "1.0.0-alpha.7",
"@cartesi/wagmi-plugin": "1.0.0-alpha.9",
"@commander-js/extra-typings": "^15.0.0",
"@inquirer/confirm": "^6.3.3",
"@inquirer/core": "^12.0.4",
Expand Down
5 changes: 4 additions & 1 deletion apps/cli/src/commands/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export const createDepositCommand = () => {
const command = new Command("deposit")
.description("Deposits an asset to the application")
.configureHelp({ showGlobalOptions: true })
.option("--from <address>", "input sender address")
.option(
"--from <address>",
"input sender address (default: devnet account 8)",
)
.option("--application <address>", "application address")
.option(
"--project-name <string>",
Expand Down
6 changes: 3 additions & 3 deletions apps/cli/src/commands/deposit/erc1155.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
bigintInput,
getInputApplicationAddress,
} from "../../prompts.js";
import { connect } from "../../wallet.js";
import { connect, getDefaultSender } from "../../wallet.js";
import type { DepositCommandOpts } from "../deposit.js";

type ERC1155Token = {
Expand Down Expand Up @@ -75,7 +75,7 @@ export const createErc1155SingleCommand = () => {
const account =
from && isAddress(from)
? getAddress(from)
: (await testClient.getAddresses())[0];
: await getDefaultSender(testClient);

const amount = amountString
? BigInt(amountString)
Expand Down Expand Up @@ -253,7 +253,7 @@ export const createErc1155BatchCommand = () => {
const account =
from && isAddress(from)
? getAddress(from)
: (await testClient.getAddresses())[0];
: await getDefaultSender(testClient);

const tokenAbi = testMultiTokenAbi;

Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/commands/deposit/erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
bigintInput,
getInputApplicationAddress,
} from "../../prompts.js";
import { connect } from "../../wallet.js";
import { connect, getDefaultSender } from "../../wallet.js";
import type { DepositCommandOpts } from "../deposit.js";

type ERC20Token = {
Expand Down Expand Up @@ -93,7 +93,7 @@ export const createErc20Command = () => {
const account =
from && isAddress(from)
? getAddress(from)
: (await testClient.getAddresses())[0];
: await getDefaultSender(testClient);

const token = await parseToken({
testClient,
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/commands/deposit/erc721.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
bigintInput,
getInputApplicationAddress,
} from "../../prompts.js";
import { connect } from "../../wallet.js";
import { connect, getDefaultSender } from "../../wallet.js";
import type { DepositCommandOpts } from "../deposit.js";

type ERC721Token = {
Expand Down Expand Up @@ -93,7 +93,7 @@ export const createErc721Command = () => {
const account =
from && isAddress(from)
? getAddress(from)
: (await testClient.getAddresses())[0];
: await getDefaultSender(testClient);

const token = await parseToken({
testClient,
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/commands/deposit/ether.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { formatUnits, getAddress, isAddress, isHex, parseUnits } from "viem";
import { getProjectName } from "../../base.js";
import { etherPortalAbi, etherPortalAddress } from "../../contracts.js";
import { bigintInput, getInputApplicationAddress } from "../../prompts.js";
import { connect } from "../../wallet.js";
import { connect, getDefaultSender } from "../../wallet.js";
import type { DepositCommandOpts } from "../deposit.js";

export const createEtherCommand = () => {
Expand All @@ -26,7 +26,7 @@ export const createEtherCommand = () => {
const account =
from && isAddress(from)
? getAddress(from)
: (await testClient.getAddresses())[0];
: await getDefaultSender(testClient);

// get dapp address from local node, or ask
const application = await getInputApplicationAddress({
Expand Down
111 changes: 94 additions & 17 deletions apps/cli/src/commands/logs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,89 @@
import { Command } from "@commander-js/extra-typings";
import { execa } from "execa";
import { getProjectName, getServiceInfo } from "../base.js";
import { getProjectName } from "../base.js";
import { isPrtNodeService } from "../compose/prt-node.js";

/** The node's compose service, shown by default and first. */
export const NODE_SERVICE = "rollups_node";

/**
* The services of a running environment, as compose lists them; an exited
* container is still listed, so its last logs can be read.
*/
export const listServices = async (projectName: string): Promise<string[]> => {
const { stdout } = await execa("docker", [
"compose",
"--project-name",
projectName,
"ps",
"--services",
"--all",
]);
return stdout
.split("\n")
.map((line) => line.trim())
.filter((line) => line.length > 0);
};

/**
* The services to show: the ones named, checked against the environment, or
* the node followed by every PRT node.
* @param services the environment's services, from `listServices`
* @param requested the services named on the command line
* @throws when the node isn't there, or a named service isn't
*/
export const selectLogServices = (
services: string[],
requested: string[],
): string[] => {
if (requested.length === 0) {
if (!services.includes(NODE_SERVICE)) {
throw new Error(`service ${NODE_SERVICE} not found`);
}
return [NODE_SERVICE, ...services.filter(isPrtNodeService)];
}
// compose shows nothing for an unknown service, without an error
const unknown = requested.filter((service) => !services.includes(service));
if (unknown.length > 0) {
throw new Error(
`service ${unknown.join(", ")} not found; the environment has ${services.join(", ")}`,
);
}
return requested;
};

/**
* The `docker compose logs` arguments. One service is shown as it is, like
* `docker container logs`; more than one get compose's per-service prefix,
* which tells the node's lines from the PRT nodes'.
*/
export const buildLogsArgs = (options: {
follow?: boolean;
projectName: string;
services: string[];
since?: string;
tail?: string;
until?: string;
}): string[] => {
const { follow, projectName, services, since, tail, until } = options;
const args = ["compose", "--project-name", projectName, "logs"];
if (follow) args.push("--follow");
if (since) args.push("--since", since);
if (tail) args.push("--tail", tail);
if (until) args.push("--until", until);
if (services.length === 1) args.push("--no-log-prefix");
return [...args, ...services];
};

export const createLogsCommand = () => {
return new Command("logs")
.description("Show logs of a local environment.")
.description(
"Show logs of a local environment: the node and its PRT nodes, or the services named.",
)
.argument(
"[service...]",
"services to show, as cartesi run names them (default: the node and the PRT nodes)",
)
.option(
"--project-name <string>",
"name of project (used by docker compose and cartesi-rollups-node)",
Expand All @@ -24,26 +103,24 @@ export const createLogsCommand = () => {
"Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)",
)
.configureHelp({ showGlobalOptions: true })
.action(async (options) => {
.action(async (requested, options) => {
const { follow, since, tail, until } = options;
const projectName = getProjectName(options);
const logOptions: string[] = [];
if (follow) logOptions.push("--follow");
if (since) logOptions.push("--since", since);
if (tail) logOptions.push("--tail", tail);
if (until) logOptions.push("--until", until);

const serviceInfo = await getServiceInfo({
projectName,
service: "rollups_node",
});
if (!serviceInfo) {
throw new Error(`service rollups_node not found`);
}
const services = selectLogServices(
await listServices(projectName),
requested,
);

await execa(
"docker",
["container", "logs", ...logOptions, serviceInfo.ID],
buildLogsArgs({
follow,
projectName,
services,
since,
tail,
until,
}),
{ stdio: "inherit" },
);
});
Expand Down
Loading
Loading