Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 15 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,26 @@

## Unreleased

## 0.2.5 - 2026-02-27

### Added

- Built-in ABI defaults for all mapped write commands, removing the need to manually look up ABI signatures for mapped execution and `--help`.
- First-class auction bid UX (no manual ABI/address/args):
- `ag auction bid --auction-id <id> --amount-ghst <amount> [--dry-run]`
- internal GBM diamond + ABI resolution for `commitBid`
- preflight checks for auction-open state, expected/unbid status, minimum bid, GHST balance, and GHST allowance
- Batch-native unbid flow:
- `ag auction bid-unbid --amount-ghst <amount> --max-total-ghst <amount> [--dry-run]`
- per-auction summary and explicit skip reasons
- Bankr environment ergonomics:
- profile-level env file support via `bootstrap --env-file <path>`
- Bankr env auto-discovery (`AGCLI_BANKR_ENV_FILE`, `AGCLI_HOME` defaults, `~/.config/openclaw/bankr.env`, local `.env.bankr`/`bankr.env`)

### Changed

- Expanded mapped metadata coverage beyond auctions:
- canonical Base addresses now auto-resolve for high-confidence command families (Aavegotchi diamond, GBM diamond, Forge diamond, GLTR staking, Merkle distributor).
- command families with dynamic target contracts still auto-resolve ABI and only require `--address`.
- Added optional GHST auto-approve path for auction bidding (`--auto-approve`).
- Added race-safe auction submit behavior by rechecking auction highest bid/bidder immediately before send.
- Improved simulation revert decoding with structured `reasonCode` details (for example: `INSUFFICIENT_ALLOWANCE`, `BID_BELOW_START`, `AUCTION_STATE_CHANGED`).

## 0.2.4 - 2026-02-27

Expand Down
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ npm run ag -- bootstrap --mode agent --profile prod --chain base --signer readon
- `subgraph list|check|query`
- `baazaar listing get|active|mine` (subgraph-first read wrappers)
- `auction get|active|mine|bids|bids-mine` (subgraph-first read wrappers)
- `auction bid|bid-unbid` (first-class write UX)
- `<domain> read` (routes to generic onchain call for that domain)

Planned domain namespaces are stubbed for parity tracking:
Expand All @@ -54,7 +55,7 @@ Planned domain namespaces are stubbed for parity tracking:

Many Base-era write flows are already executable as mapped aliases in those namespaces (internally routed through `onchain send`).
Mapped writes now include built-in ABI defaults, so `--abi-file` is no longer required for mapped command execution/help.
Example with built-in defaults: `ag auction bid --args-json '[...]' --dry-run --json`
Example with built-in defaults: `ag baazaar buy-now --args-json '[...]' --dry-run --json`
Example with explicit metadata: `ag lending create --abi-file ./abis/GotchiLendingFacet.json --address 0x... --args-json '[...]' --json`

## Command help and discoverability
Expand All @@ -71,7 +72,6 @@ Mapped write commands now expose their onchain function mapping, defaults (if av

```bash
ag baazaar buy-now --help
ag auction bid --help
```

If you provide `--abi-file` with `--help`, the CLI prints ABI-derived function signature and input names for the mapped method:
Expand Down Expand Up @@ -171,6 +171,27 @@ Raw GraphQL passthrough (typed projection remains included):
npm run ag -- auction active --first 5 --raw --json
```

## First-class auction bidding

Single auction bid (no manual ABI/address/arg packing):

```bash
npm run ag -- auction bid --auction-id 5666 --amount-ghst 1 --dry-run --json
```

Bid all currently unbid auctions up to a max total:

```bash
npm run ag -- auction bid-unbid --amount-ghst 1 --max-total-ghst 10 --dry-run --json
```

Notes:

- `auction bid` resolves GBM diamond + ABI internally.
- Preflight checks include auction-open state, expected/unbid checks, minimum bid, GHST balance, and GHST allowance.
- `--auto-approve` can submit GHST `approve()` automatically when allowance is insufficient.
- `auction bid-unbid` emits per-auction results and explicit skip reasons in one JSON report.

## Signer backends

- `readonly` (read-only mode)
Expand All @@ -179,6 +200,7 @@ npm run ag -- auction active --first 5 --raw --json
- `remote:URL|ADDRESS|AUTH_ENV` (HTTP signer service)
- `ledger:DERIVATION_PATH|ADDRESS|BRIDGE_ENV` (external bridge command signer)
- `bankr[:ADDRESS|API_KEY_ENV|API_URL]` (Bankr-native signer via `/agent/me` + `/agent/submit`; defaults: `BANKR_API_KEY`, `https://api.bankr.bot`)
- Optional profile env file support (`bootstrap --env-file <path>`) plus Bankr auto-discovery (`$AGCLI_BANKR_ENV_FILE`, `$AGCLI_HOME/bankr.env`, `$AGCLI_HOME/.env.bankr`, `~/.config/openclaw/bankr.env`, `./.env.bankr`, `./bankr.env`)

Remote signer contract:

Expand All @@ -195,7 +217,7 @@ Bankr bootstrap example:

```bash
BANKR_API_KEY=... \
npm run ag -- bootstrap --mode agent --profile bankr --chain base --signer bankr --json
npm run ag -- bootstrap --mode agent --profile bankr --chain base --signer bankr --env-file ~/.config/openclaw/bankr.env --json
```

Ledger bridge contract:
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aavegotchi-cli",
"version": "0.2.4",
"version": "0.2.5",
"description": "Agent-first CLI for automating Aavegotchi app and onchain workflows",
"license": "MIT",
"repository": {
Expand Down
6 changes: 4 additions & 2 deletions src/command-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const BUILTIN_COMMANDS = [
"auction mine",
"auction bids",
"auction bids-mine",
"auction bid",
"auction bid-unbid",
] as const;

function listDomainReadCommands(): string[] {
Expand Down Expand Up @@ -76,11 +78,11 @@ function levenshteinDistance(a: string, b: string): number {
}

export function listKnownCommands(): string[] {
return [
return [...new Set([
...BUILTIN_COMMANDS,
...listDomainReadCommands(),
...listMappedCommands(),
];
])];
}

export function suggestCommands(input: string, max = 5): string[] {
Expand Down
31 changes: 31 additions & 0 deletions src/command-runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import { CommandContext } from "./types";
const {
findMappedFunctionMock,
runMappedDomainCommandMock,
runAuctionBidCommandMock,
runAuctionBidUnbidCommandMock,
runAuctionSubgraphCommandMock,
runBaazaarListingSubgraphCommandMock,
} = vi.hoisted(() => ({
findMappedFunctionMock: vi.fn(),
runMappedDomainCommandMock: vi.fn(),
runAuctionBidCommandMock: vi.fn(),
runAuctionBidUnbidCommandMock: vi.fn(),
runAuctionSubgraphCommandMock: vi.fn(),
runBaazaarListingSubgraphCommandMock: vi.fn(),
}));
Expand All @@ -19,6 +23,11 @@ vi.mock("./commands/mapped", () => ({
runMappedDomainCommand: runMappedDomainCommandMock,
}));

vi.mock("./commands/auction-bid", () => ({
runAuctionBidCommand: runAuctionBidCommandMock,
runAuctionBidUnbidCommand: runAuctionBidUnbidCommandMock,
}));

vi.mock("./commands/auction-subgraph", () => ({
runAuctionSubgraphCommand: runAuctionSubgraphCommandMock,
}));
Expand Down Expand Up @@ -75,4 +84,26 @@ describe("command runner routing", () => {
expect(runAuctionSubgraphCommandMock).not.toHaveBeenCalled();
expect(runMappedDomainCommandMock).toHaveBeenCalledTimes(1);
});

it("routes auction bid to first-class command before mapped fallback", async () => {
findMappedFunctionMock.mockReturnValue("commitBid");
runAuctionBidCommandMock.mockResolvedValue({ status: "simulated" });

const result = await executeCommand(createCtx(["auction", "bid"]));

expect(result.commandName).toBe("auction bid");
expect(result.data).toEqual({ status: "simulated" });
expect(runAuctionBidCommandMock).toHaveBeenCalledTimes(1);
expect(runMappedDomainCommandMock).not.toHaveBeenCalled();
});

it("routes auction bid-unbid to first-class batch command", async () => {
runAuctionBidUnbidCommandMock.mockResolvedValue({ summary: { success: 1 } });

const result = await executeCommand(createCtx(["auction", "bid-unbid"]));

expect(result.commandName).toBe("auction bid-unbid");
expect(result.data).toEqual({ summary: { success: 1 } });
expect(runAuctionBidUnbidCommandMock).toHaveBeenCalledTimes(1);
});
});
15 changes: 15 additions & 0 deletions src/command-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { runBatchRunCommand } from "./commands/batch";
import { runBootstrapCommand } from "./commands/bootstrap";
import { findMappedFunction, runMappedDomainCommand } from "./commands/mapped";
import { runOnchainCallCommand, runOnchainSendCommand } from "./commands/onchain";
import { runAuctionBidCommand, runAuctionBidUnbidCommand } from "./commands/auction-bid";
import { runAuctionSubgraphCommand } from "./commands/auction-subgraph";
import { runBaazaarListingSubgraphCommand } from "./commands/baazaar-subgraph";
import {
Expand Down Expand Up @@ -238,6 +239,20 @@ export async function executeCommand(ctx: CommandContext): Promise<CommandExecut
}

if (root === "auction") {
if (sub === "bid") {
return {
commandName: "auction bid",
data: await runAuctionBidCommand(ctx),
};
}

if (sub === "bid-unbid") {
return {
commandName: "auction bid-unbid",
data: await runAuctionBidUnbidCommand(ctx),
};
}

if (sub === "get" || sub === "active" || sub === "mine" || sub === "bids" || sub === "bids-mine") {
return {
commandName: ctx.commandPath.join(" "),
Expand Down
Loading