Skip to content

Commit 56effcb

Browse files
Merge pull request #12 from aavegotchi/codex/auction-firstclass-bid
feat(auction): first-class bid UX, batch unbid command, Bankr env ergonomics
2 parents cd93a2c + 6f42799 commit 56effcb

20 files changed

Lines changed: 1688 additions & 25 deletions

CHANGELOG.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@
22

33
## Unreleased
44

5+
## 0.2.5 - 2026-02-27
6+
57
### Added
68

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

920
### Changed
1021

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

1526
## 0.2.4 - 2026-02-27
1627

README.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ npm run ag -- bootstrap --mode agent --profile prod --chain base --signer readon
4646
- `subgraph list|check|query`
4747
- `baazaar listing get|active|mine` (subgraph-first read wrappers)
4848
- `auction get|active|mine|bids|bids-mine` (subgraph-first read wrappers)
49+
- `auction bid|bid-unbid` (first-class write UX)
4950
- `<domain> read` (routes to generic onchain call for that domain)
5051

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

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

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

7273
```bash
7374
ag baazaar buy-now --help
74-
ag auction bid --help
7575
```
7676

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

174+
## First-class auction bidding
175+
176+
Single auction bid (no manual ABI/address/arg packing):
177+
178+
```bash
179+
npm run ag -- auction bid --auction-id 5666 --amount-ghst 1 --dry-run --json
180+
```
181+
182+
Bid all currently unbid auctions up to a max total:
183+
184+
```bash
185+
npm run ag -- auction bid-unbid --amount-ghst 1 --max-total-ghst 10 --dry-run --json
186+
```
187+
188+
Notes:
189+
190+
- `auction bid` resolves GBM diamond + ABI internally.
191+
- Preflight checks include auction-open state, expected/unbid checks, minimum bid, GHST balance, and GHST allowance.
192+
- `--auto-approve` can submit GHST `approve()` automatically when allowance is insufficient.
193+
- `auction bid-unbid` emits per-auction results and explicit skip reasons in one JSON report.
194+
174195
## Signer backends
175196

176197
- `readonly` (read-only mode)
@@ -179,6 +200,7 @@ npm run ag -- auction active --first 5 --raw --json
179200
- `remote:URL|ADDRESS|AUTH_ENV` (HTTP signer service)
180201
- `ledger:DERIVATION_PATH|ADDRESS|BRIDGE_ENV` (external bridge command signer)
181202
- `bankr[:ADDRESS|API_KEY_ENV|API_URL]` (Bankr-native signer via `/agent/me` + `/agent/submit`; defaults: `BANKR_API_KEY`, `https://api.bankr.bot`)
203+
- 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`)
182204

183205
Remote signer contract:
184206

@@ -195,7 +217,7 @@ Bankr bootstrap example:
195217

196218
```bash
197219
BANKR_API_KEY=... \
198-
npm run ag -- bootstrap --mode agent --profile bankr --chain base --signer bankr --json
220+
npm run ag -- bootstrap --mode agent --profile bankr --chain base --signer bankr --env-file ~/.config/openclaw/bankr.env --json
199221
```
200222

201223
Ledger bridge contract:

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aavegotchi-cli",
3-
"version": "0.2.4",
3+
"version": "0.2.5",
44
"description": "Agent-first CLI for automating Aavegotchi app and onchain workflows",
55
"license": "MIT",
66
"repository": {

src/command-catalog.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const BUILTIN_COMMANDS = [
3434
"auction mine",
3535
"auction bids",
3636
"auction bids-mine",
37+
"auction bid",
38+
"auction bid-unbid",
3739
] as const;
3840

3941
function listDomainReadCommands(): string[] {
@@ -76,11 +78,11 @@ function levenshteinDistance(a: string, b: string): number {
7678
}
7779

7880
export function listKnownCommands(): string[] {
79-
return [
81+
return [...new Set([
8082
...BUILTIN_COMMANDS,
8183
...listDomainReadCommands(),
8284
...listMappedCommands(),
83-
];
85+
])];
8486
}
8587

8688
export function suggestCommands(input: string, max = 5): string[] {

src/command-runner.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ import { CommandContext } from "./types";
55
const {
66
findMappedFunctionMock,
77
runMappedDomainCommandMock,
8+
runAuctionBidCommandMock,
9+
runAuctionBidUnbidCommandMock,
810
runAuctionSubgraphCommandMock,
911
runBaazaarListingSubgraphCommandMock,
1012
} = vi.hoisted(() => ({
1113
findMappedFunctionMock: vi.fn(),
1214
runMappedDomainCommandMock: vi.fn(),
15+
runAuctionBidCommandMock: vi.fn(),
16+
runAuctionBidUnbidCommandMock: vi.fn(),
1317
runAuctionSubgraphCommandMock: vi.fn(),
1418
runBaazaarListingSubgraphCommandMock: vi.fn(),
1519
}));
@@ -19,6 +23,11 @@ vi.mock("./commands/mapped", () => ({
1923
runMappedDomainCommand: runMappedDomainCommandMock,
2024
}));
2125

26+
vi.mock("./commands/auction-bid", () => ({
27+
runAuctionBidCommand: runAuctionBidCommandMock,
28+
runAuctionBidUnbidCommand: runAuctionBidUnbidCommandMock,
29+
}));
30+
2231
vi.mock("./commands/auction-subgraph", () => ({
2332
runAuctionSubgraphCommand: runAuctionSubgraphCommandMock,
2433
}));
@@ -75,4 +84,26 @@ describe("command runner routing", () => {
7584
expect(runAuctionSubgraphCommandMock).not.toHaveBeenCalled();
7685
expect(runMappedDomainCommandMock).toHaveBeenCalledTimes(1);
7786
});
87+
88+
it("routes auction bid to first-class command before mapped fallback", async () => {
89+
findMappedFunctionMock.mockReturnValue("commitBid");
90+
runAuctionBidCommandMock.mockResolvedValue({ status: "simulated" });
91+
92+
const result = await executeCommand(createCtx(["auction", "bid"]));
93+
94+
expect(result.commandName).toBe("auction bid");
95+
expect(result.data).toEqual({ status: "simulated" });
96+
expect(runAuctionBidCommandMock).toHaveBeenCalledTimes(1);
97+
expect(runMappedDomainCommandMock).not.toHaveBeenCalled();
98+
});
99+
100+
it("routes auction bid-unbid to first-class batch command", async () => {
101+
runAuctionBidUnbidCommandMock.mockResolvedValue({ summary: { success: 1 } });
102+
103+
const result = await executeCommand(createCtx(["auction", "bid-unbid"]));
104+
105+
expect(result.commandName).toBe("auction bid-unbid");
106+
expect(result.data).toEqual({ summary: { success: 1 } });
107+
expect(runAuctionBidUnbidCommandMock).toHaveBeenCalledTimes(1);
108+
});
78109
});

src/command-runner.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { runBatchRunCommand } from "./commands/batch";
55
import { runBootstrapCommand } from "./commands/bootstrap";
66
import { findMappedFunction, runMappedDomainCommand } from "./commands/mapped";
77
import { runOnchainCallCommand, runOnchainSendCommand } from "./commands/onchain";
8+
import { runAuctionBidCommand, runAuctionBidUnbidCommand } from "./commands/auction-bid";
89
import { runAuctionSubgraphCommand } from "./commands/auction-subgraph";
910
import { runBaazaarListingSubgraphCommand } from "./commands/baazaar-subgraph";
1011
import {
@@ -238,6 +239,20 @@ export async function executeCommand(ctx: CommandContext): Promise<CommandExecut
238239
}
239240

240241
if (root === "auction") {
242+
if (sub === "bid") {
243+
return {
244+
commandName: "auction bid",
245+
data: await runAuctionBidCommand(ctx),
246+
};
247+
}
248+
249+
if (sub === "bid-unbid") {
250+
return {
251+
commandName: "auction bid-unbid",
252+
data: await runAuctionBidUnbidCommand(ctx),
253+
};
254+
}
255+
241256
if (sub === "get" || sub === "active" || sub === "mine" || sub === "bids" || sub === "bids-mine") {
242257
return {
243258
commandName: ctx.commandPath.join(" "),

0 commit comments

Comments
 (0)