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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

### Added

- Built-in ABI defaults for all mapped write commands, removing the need to manually look up ABI signatures for mapped execution and `--help`.

### 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`.

## 0.2.4 - 2026-02-27

### Added
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Planned domain namespaces are stubbed for parity tracking:
- `gotchi`, `portal`, `wearables`, `items`, `inventory`, `baazaar`, `auction`, `lending`, `staking`, `gotchi-points`, `realm`, `alchemica`, `forge`, `token`

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 explicit metadata: `ag lending create --abi-file ./abis/GotchiLendingFacet.json --address 0x... --args-json '[...]' --json`

Expand Down
223 changes: 216 additions & 7 deletions src/commands/mapped-defaults.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,103 @@
import { parseAbi, type Abi } from "viem";

import { BASE_GBM_DIAMOND } from "../subgraph/sources";
import {
BASE_AAVEGOTCHI_DIAMOND,
BASE_FORGE_DIAMOND,
BASE_GBM_DIAMOND,
BASE_GLTR_STAKING,
BASE_MERKLE_DISTRIBUTOR,
} from "../subgraph/sources";

export interface MappedWriteDefaults {
address?: `0x${string}`;
abi?: Abi;
source: string;
}

const AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI = parseAbi([
"function addGotchiLending(uint32,uint96,uint32,uint8[3],address,address,uint32,address[],uint256)",
"function agreeGotchiLending(uint32,uint32,uint96,uint32,uint8[3])",
"function batchDropClaimXPDrop(bytes32[],address[],uint256[][],bytes32[][],uint256[][],uint256[][])",
"function batchExecuteERC1155Listing((uint256,address,uint256,uint256,uint256,address)[])",
"function cancelERC1155Listing(uint256)",
"function cancelERC721Listing(uint256)",
"function cancelGotchiLending(uint32)",
"function claimAavegotchi(uint256,uint256)",
"function claimAndEndGotchiLending(uint32)",
"function createWhitelist(string,address[])",
"function decreaseAndDestroy(uint256,uint256)",
"function equipDelegatedWearables(uint256,uint16[16],uint256[16])",
"function openPortals(uint256[])",
"function spendSkillPoints(uint256,int16[4])",
"function transferEscrow(uint256,address,address,uint256)",
"function updateERC1155ListingPriceAndQuantity(uint256,uint256,uint256)",
"function updateWhitelist(uint32,address[])",
"function useConsumables(uint256,uint256[],uint256[])",
]);

const GBM_MAPPED_WRITE_ABI = parseAbi([
"function buyNow(uint256 _auctionID)",
"function cancelAuction(uint256 _auctionID)",
"function commitBid(uint256 _auctionID,uint256 _bidAmount,uint256 _highestBid,address _tokenContract,uint256 _tokenID,uint256 _amount,bytes _unused)",
"function swapAndCommitBid((address tokenIn,uint256 swapAmount,uint256 minGhstOut,uint256 swapDeadline,address recipient,uint256 auctionID,uint256 bidAmount,uint256 highestBid,address tokenContract,uint256 _tokenID,uint256 _amount,bytes _signature) ctx)",
"function createAuction((uint80 startTime,uint80 endTime,uint56 tokenAmount,uint8 category,bytes4 tokenKind,uint256 tokenID,uint96 buyItNowPrice,uint96 startingBid) _info,address _tokenContract,uint256 _auctionPresetID) returns (uint256)",
"function buyNow(uint256)",
"function cancelAuction(uint256)",
"function commitBid(uint256,uint256,uint256,address,uint256,uint256,bytes)",
"function createAuction((uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),address,uint256)",
"function swapAndBuyNow((address,uint256,uint256,uint256,address,uint256))",
"function swapAndCommitBid((address,uint256,uint256,uint256,address,uint256,uint256,uint256,address,uint256,uint256,bytes))",
]);

const FORGE_MAPPED_WRITE_ABI = parseAbi([
"function claimForgeQueueItems(uint256[])",
"function forgeWearables(uint256[],uint256[],uint40[])",
"function reduceQueueTime(uint256[],uint40[])",
"function smeltWearables(uint256[],uint256[])",
]);

const GLTR_STAKING_MAPPED_WRITE_ABI = parseAbi(["function batchHarvest(uint256[])"]);
const WRAP_MAPPED_WRITE_ABI = parseAbi(["function enterWithUnderlying(uint256)", "function leaveToUnderlying(uint256)"]);
const GHST_STAKING_MAPPED_WRITE_ABI = parseAbi(["function withdrawFromPool(address,uint256)"]);
const SOCKET_VAULT_MAPPED_WRITE_ABI = parseAbi(["function bridge(address,uint256,uint256,address,bytes,bytes)"]);
const MERKLE_DISTRIBUTOR_MAPPED_WRITE_ABI = parseAbi(["function claim(uint256,bytes32[])"]);
const GOTCHI_POINTS_MAPPED_WRITE_ABI = parseAbi(["function convertAlchemica(address,uint256,uint256,uint256,uint256)"]);
const ERC20_MAPPED_WRITE_ABI = parseAbi(["function approve(address,uint256)"]);
const ERC1155_MAPPED_WRITE_ABI = parseAbi([
"function safeTransferFrom(address,address,uint256,uint256,bytes)",
"function setApprovalForAll(address,bool)",
]);

const MAPPED_WRITE_DEFAULTS: Record<string, MappedWriteDefaults> = {
"auction bid": {
"lending create": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"lending agree": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"token approve": {
abi: ERC20_MAPPED_WRITE_ABI,
source: "canonical.erc20",
},
"gotchi xp claim-batch": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"baazaar listing batch-execute": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"realm harvest batch": {
address: BASE_GLTR_STAKING,
abi: GLTR_STAKING_MAPPED_WRITE_ABI,
source: "base.gltr-staking",
},
"token bridge": {
abi: SOCKET_VAULT_MAPPED_WRITE_ABI,
source: "canonical.socket-vault",
},
"baazaar buy-now": {
address: BASE_GBM_DIAMOND,
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
Expand All @@ -32,16 +112,145 @@ const MAPPED_WRITE_DEFAULTS: Record<string, MappedWriteDefaults> = {
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
},
"baazaar cancel-erc1155": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"baazaar cancel-erc721": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"lending cancel": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"forge claim": {
address: BASE_MERKLE_DISTRIBUTOR,
abi: MERKLE_DISTRIBUTOR_MAPPED_WRITE_ABI,
source: "base.merkle-distributor",
},
"portal claim": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"lending claim-end": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"forge queue claim": {
address: BASE_FORGE_DIAMOND,
abi: FORGE_MAPPED_WRITE_ABI,
source: "base.forge-diamond",
},
"auction bid": {
address: BASE_GBM_DIAMOND,
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
},
"gotchi-points convert-alchemica": {
abi: GOTCHI_POINTS_MAPPED_WRITE_ABI,
source: "canonical.gotchi-points",
},
"auction create": {
address: BASE_GBM_DIAMOND,
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
},
"lending whitelist create": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"staking unstake-destroy": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"staking enter-underlying": {
abi: WRAP_MAPPED_WRITE_ABI,
source: "canonical.wrap",
},
"gotchi equip-delegated": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"forge craft": {
address: BASE_FORGE_DIAMOND,
abi: FORGE_MAPPED_WRITE_ABI,
source: "base.forge-diamond",
},
"staking leave-underlying": {
abi: WRAP_MAPPED_WRITE_ABI,
source: "canonical.wrap",
},
"portal open": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"forge speedup": {
address: BASE_FORGE_DIAMOND,
abi: FORGE_MAPPED_WRITE_ABI,
source: "base.forge-diamond",
},
"inventory transfer": {
abi: ERC1155_MAPPED_WRITE_ABI,
source: "canonical.erc1155",
},
"token set-approval-for-all": {
abi: ERC1155_MAPPED_WRITE_ABI,
source: "canonical.erc1155",
},
"forge smelt": {
address: BASE_FORGE_DIAMOND,
abi: FORGE_MAPPED_WRITE_ABI,
source: "base.forge-diamond",
},
"gotchi spend-skill-points": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"baazaar swap-buy-now": {
address: BASE_GBM_DIAMOND,
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
},
"auction swap-bid": {
address: BASE_GBM_DIAMOND,
abi: GBM_MAPPED_WRITE_ABI,
source: "base.gbm-diamond",
},
"lending transfer-escrow": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"baazaar update-erc1155": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"lending whitelist update": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"gotchi feed": {
address: BASE_AAVEGOTCHI_DIAMOND,
abi: AAVEGOTCHI_DIAMOND_MAPPED_WRITE_ABI,
source: "base.aavegotchi-diamond",
},
"staking withdraw-pool": {
abi: GHST_STAKING_MAPPED_WRITE_ABI,
source: "canonical.ghst-staking",
},
};

export function getMappedWriteDefaults(commandPath: string[]): MappedWriteDefaults | undefined {
Expand Down
16 changes: 10 additions & 6 deletions src/commands/mapped-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,24 @@ describe("mapped command execution defaults", () => {
});
});

it("keeps non-defaulted mapped commands requiring explicit metadata", async () => {
it("allows ABI-only defaults for commands that still need explicit address", async () => {
runOnchainSendWithFunctionMock.mockResolvedValue({ ok: true });

const result = await runMappedDomainCommand(createCtx(["baazaar", "buy-now"]));
const result = await runMappedDomainCommand(createCtx(["token", "approve"]));
const call = runOnchainSendWithFunctionMock.mock.calls[0];
const defaultsArg = call?.[3] as { abi?: unknown; address?: unknown; source?: unknown };

expect(runOnchainSendWithFunctionMock).toHaveBeenCalledTimes(1);
expect(defaultsArg.abi).toBeUndefined();
expect(defaultsArg.abi).toBeDefined();
expect(defaultsArg.address).toBeUndefined();
expect(defaultsArg.source).toBeUndefined();
expect(defaultsArg.source).toBe("canonical.erc20");
expect(result).toMatchObject({
mappedMethod: "buyNow",
defaults: null,
mappedMethod: "approve",
defaults: {
source: "canonical.erc20",
address: null,
abi: "available",
},
result: { ok: true },
});
});
Expand Down
16 changes: 16 additions & 0 deletions src/commands/mapped.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { describe, expect, it } from "vitest";

import { findMappedFunction, listMappedCommands, listMappedCommandsForRoot } from "./mapped";
import { getMappedWriteDefaults } from "./mapped-defaults";
import { BASE_AAVEGOTCHI_DIAMOND, BASE_FORGE_DIAMOND, BASE_GBM_DIAMOND, BASE_GLTR_STAKING } from "../subgraph/sources";

describe("mapped domain commands", () => {
it("resolves known mapping", () => {
Expand All @@ -22,4 +24,18 @@ describe("mapped domain commands", () => {
expect(all).toContain("baazaar buy-now");
expect(all).toContain("token approve");
});

it("provides built-in ABI defaults for every mapped command", () => {
const all = listMappedCommands();
const missing = all.filter((command) => !getMappedWriteDefaults(command.split(" "))?.abi);
expect(missing).toEqual([]);
});

it("pins canonical contract addresses for high-confidence commands", () => {
expect(getMappedWriteDefaults(["lending", "create"])?.address).toBe(BASE_AAVEGOTCHI_DIAMOND);
expect(getMappedWriteDefaults(["auction", "bid"])?.address).toBe(BASE_GBM_DIAMOND);
expect(getMappedWriteDefaults(["forge", "craft"])?.address).toBe(BASE_FORGE_DIAMOND);
expect(getMappedWriteDefaults(["realm", "harvest", "batch"])?.address).toBe(BASE_GLTR_STAKING);
expect(getMappedWriteDefaults(["token", "approve"])?.address).toBeUndefined();
});
});
11 changes: 10 additions & 1 deletion src/output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ describe("help output", () => {
expect(text).toContain("Mapped to onchain function:");
expect(text).toContain("buyNow");
expect(text).toContain("--args-json");
expect(text).toContain("--abi-file <path> --address <0x...> --args-json");
expect(text).toContain("ag baazaar buy-now --profile <name> --args-json");
expect(text).toContain("address: 0x80320a0000c7a6a34086e2acad6915ff57ffda31");
});

it("prints ABI defaults while still requiring --address for generic token approve", () => {
const text = buildHelpText(["token", "approve"]);
expect(text).toContain("approve(address,uint256)");
expect(text).toContain("ag token approve --profile <name> --address <0x...> --args-json");
expect(text).toContain("source: canonical.erc20");
expect(text).toContain("--abi-file (override built-in ABI)");
});

it("prints built-in mapped defaults for auction bid without --abi-file", () => {
Expand Down
3 changes: 3 additions & 0 deletions src/subgraph/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export const GBM_BASE_ENDPOINT =

export const BASE_AAVEGOTCHI_DIAMOND = "0xa99c4b08201f2913db8d28e71d020c4298f29dbf" as const;
export const BASE_GBM_DIAMOND = "0x80320a0000c7a6a34086e2acad6915ff57ffda31" as const;
export const BASE_FORGE_DIAMOND = "0x50af2d63b839aa32b4166fd1cb247129b715186c" as const;
export const BASE_GLTR_STAKING = "0xab449dca14413a6ae0bcea9ea210b57ace280d2c" as const;
export const BASE_MERKLE_DISTRIBUTOR = "0xf50326e1a6c6949cc390c4efe8ea538e29a4fa11" as const;

const SOURCE_MAP: Record<SubgraphSourceAlias, SubgraphSourceDefinition> = {
"core-base": {
Expand Down