aavegotchi-gbm-skill
View, create, cancel, bid, and claim Aavegotchi GBM auctions on Base mainnet (8453). Subgraph-first discovery (Goldsky), with onchain verification + execution via Foundry cast. Safety-first: DRY_RUN defaults to 1 (simulate with cast call; only broadcast with cast send when DRY_RUN=0 and explicitly instructed).
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-aavegotchi-gbm-skill
Repository
Skill path: skills/cinnabarhorse/aavegotchi-gbm-skill
View, create, cancel, bid, and claim Aavegotchi GBM auctions on Base mainnet (8453). Subgraph-first discovery (Goldsky), with onchain verification + execution via Foundry cast. Safety-first: DRY_RUN defaults to 1 (simulate with cast call; only broadcast with cast send when DRY_RUN=0 and explicitly instructed).
Open repositoryBest for
Primary workflow: Research & Ops.
Technical facets: Full Stack, Testing.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install aavegotchi-gbm-skill into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding aavegotchi-gbm-skill to shared team environments
- Use aavegotchi-gbm-skill for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: aavegotchi-gbm-skill
description: >
View, create, cancel, bid, and claim Aavegotchi GBM auctions on Base mainnet (8453).
Subgraph-first discovery (Goldsky), with onchain verification + execution via Foundry cast.
Safety-first: DRY_RUN defaults to 1 (simulate with cast call; only broadcast with cast send when DRY_RUN=0 and explicitly instructed).
homepage: https://github.com/aavegotchi/aavegotchi-gbm-skill
metadata:
openclaw:
requires:
bins:
- cast
- curl
- python3
env:
- FROM_ADDRESS
- PRIVATE_KEY
- BASE_MAINNET_RPC
- DRY_RUN
- RECIPIENT_ADDRESS
- GBM_SUBGRAPH_URL
- GOLDSKY_API_KEY
- GBM_DIAMOND
- GHST
- USDC
- SLIPPAGE_PCT
- GHST_USD_PRICE
- ETH_USD_PRICE
primaryEnv: PRIVATE_KEY
---
## Safety Rules
- Default to `DRY_RUN=1`. Never broadcast unless explicitly instructed.
- Always verify Base mainnet:
- `~/.foundry/bin/cast chain-id --rpc-url "${BASE_MAINNET_RPC:-https://mainnet.base.org}"` must be `8453`.
- Always verify key/address alignment:
- `~/.foundry/bin/cast wallet address --private-key "$PRIVATE_KEY"` must equal `$FROM_ADDRESS`.
- Always refetch from the subgraph immediately before any simulate/broadcast step (auctions can be outbid, ended, claimed, or cancelled).
- Always gate onchain immediately before simulating or broadcasting:
- ensure the onchain `highestBid` matches the `highestBid` you pass into `commitBid` / `swapAndCommitBid`.
- ensure token params match (token contract, token id, quantity).
- Never print or log `$PRIVATE_KEY`.
## Shell Input Safety (Avoid RCE)
This skill includes shell commands. Treat any value you copy from a user or an external source (subgraph responses, chat messages, etc.) as untrusted.
Rules:
- Never execute user-provided strings as shell code (avoid `eval`, `bash -c`, `sh -c`).
- Only substitute addresses that match `0x` + 40 hex chars.
- Only substitute uint values that are base-10 digits (no commas, no decimals).
- In the command examples below, auction-specific inputs are written as quoted placeholders like `"<AUCTION_ID>"` to avoid accidental shell interpolation. Replace them with literal values only after validation.
Quick validators (replace the placeholder values):
```bash
python3 - <<'PY'
import re
auction_id = "<AUCTION_ID>" # digits only
token_contract = "<TOKEN_CONTRACT_ADDRESS>" # 0x + 40 hex chars
token_id = "<TOKEN_ID>" # digits only
amount = "<TOKEN_AMOUNT>" # digits only
if not re.fullmatch(r"[0-9]+", auction_id):
raise SystemExit("AUCTION_ID must be base-10 digits only")
if not re.fullmatch(r"0x[a-fA-F0-9]{40}", token_contract):
raise SystemExit("TOKEN_CONTRACT_ADDRESS must be a 0x + 40-hex address")
if not re.fullmatch(r"[0-9]+", token_id):
raise SystemExit("TOKEN_ID must be base-10 digits only")
if not re.fullmatch(r"[0-9]+", amount):
raise SystemExit("TOKEN_AMOUNT must be base-10 digits only")
print("ok")
PY
```
## Required Setup
Required env vars:
- `PRIVATE_KEY`: EOA private key used for `cast send` (never print/log).
- `FROM_ADDRESS`: EOA address that owns NFTs and will submit txs.
- `BASE_MAINNET_RPC`: RPC URL. If unset, use `https://mainnet.base.org`.
- `GBM_SUBGRAPH_URL`: Goldsky subgraph endpoint for auctions.
Optional env vars:
- `DRY_RUN`: `1` (default) to only simulate via `cast call`. Set to `0` to broadcast via `cast send`.
- `RECIPIENT_ADDRESS`: for swap flows; receives any excess GHST refunded by the contract. Defaults to `FROM_ADDRESS`.
- `GOLDSKY_API_KEY`: optional; if set, include `Authorization: Bearer ...` header in subgraph calls.
- `SLIPPAGE_PCT`: defaults to `1` (%); used in `swapAmount` estimate math.
- `GHST_USD_PRICE`, `ETH_USD_PRICE`: optional overrides; if unset, fetch from CoinGecko in the swap math snippets.
Recommended defaults (override via env if needed):
```bash
export BASE_MAINNET_RPC="${BASE_MAINNET_RPC:-https://mainnet.base.org}"
export GBM_DIAMOND="${GBM_DIAMOND:-0x80320A0000C7A6a34086E2ACAD6915Ff57FfDA31}"
export GHST="${GHST:-0xcD2F22236DD9Dfe2356D7C543161D4d260FD9BcB}"
export USDC="${USDC:-0x833589fCD6eDb6E08f4c7C32D4f71b54BDA02913}"
export GBM_SUBGRAPH_URL="${GBM_SUBGRAPH_URL:-https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-gbm-baazaar-base/prod/gn}"
export DRY_RUN="${DRY_RUN:-1}"
export SLIPPAGE_PCT="${SLIPPAGE_PCT:-1}"
```
Notes:
- Commands below use `~/.foundry/bin/cast` so they work in cron/non-interactive shells.
## View / List Auctions (Subgraph First)
See `references/subgraph.md` for canonical queries.
Auction by id (quick):
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($id:ID!){ auction(id:$id){ id type contractAddress tokenId quantity seller highestBid highestBidder totalBids startsAt endsAt claimAt claimed cancelled presetId category buyNowPrice startBidPrice } }",
"variables":{"id":"<AUCTION_ID>"}
}'
```
Active auctions (ends soonest first):
```bash
NOW=$(date +%s)
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data "{
\"query\":\"query(\$now:BigInt!){ auctions(first:20, orderBy: endsAt, orderDirection: asc, where:{claimed:false, cancelled:false, startsAt_lte:\$now, endsAt_gt:\$now}){ id type contractAddress tokenId quantity highestBid highestBidder totalBids startsAt endsAt claimAt presetId category seller } }\",
\"variables\":{\"now\":\"$NOW\"}
}"
```
## Onchain Verification (Required Before Bids / Sends)
The onchain source of truth is the GBM diamond.
Confirm core auction fields (full struct decode):
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" \
'getAuctionInfo(uint256)((address,uint96,address,uint88,uint88,bool,bool,address,(uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),(uint64,uint64,uint64,uint64,uint256),uint96,uint96))' \
"<AUCTION_ID>" \
--rpc-url "$BASE_MAINNET_RPC"
```
Useful individual getters:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getAuctionHighestBid(uint256)(uint256)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getAuctionHighestBidder(uint256)(address)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getAuctionStartTime(uint256)(uint256)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getAuctionEndTime(uint256)(uint256)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getContractAddress(uint256)(address)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getTokenId(uint256)(uint256)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getTokenKind(uint256)(bytes4)' "<AUCTION_ID>" --rpc-url "$BASE_MAINNET_RPC"
```
## Create Auction
Onchain method:
- `createAuction((uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),address,uint256)(uint256)`
High-level steps:
1. Ensure the token contract is whitelisted on the GBM diamond (otherwise revert `ContractNotAllowed`).
2. Ensure the token is approved to the GBM diamond:
- ERC721/1155: `setApprovalForAll(GBM_DIAMOND,true)`
3. Choose `InitiatorInfo`:
- `startTime` must be in the future.
- `endTime - startTime` must be between 3600 and 604800 seconds (1h to 7d).
- `tokenKind` is `0x73ad2146` (ERC721) or `0x973bb640` (ERC1155).
- `buyItNowPrice` optional; `startingBid` optional (if nonzero, you must approve GHST for the 4% prepaid fee).
4. Simulate with `cast call` using `--from "$FROM_ADDRESS"`.
5. Broadcast with `cast send` only when explicitly instructed (`DRY_RUN=0`).
6. Post-tx: query subgraph for newest seller auctions and match `(contractAddress, tokenId)`.
Simulate create (ERC721 example):
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" \
'createAuction((uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),address,uint256)(uint256)' \
"(<START_TIME>,<END_TIME>,1,<CATEGORY>,0x73ad2146,<TOKEN_ID>,<BUY_NOW_GHST_WEI>,<STARTING_BID_GHST_WEI>)" \
"<ERC721_CONTRACT_ADDRESS>" "<PRESET_ID>" \
--from "$FROM_ADDRESS" \
--rpc-url "$BASE_MAINNET_RPC"
```
Broadcast create (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" \
'createAuction((uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),address,uint256)(uint256)' \
"(<START_TIME>,<END_TIME>,1,<CATEGORY>,0x73ad2146,<TOKEN_ID>,<BUY_NOW_GHST_WEI>,<STARTING_BID_GHST_WEI>)" \
"<ERC721_CONTRACT_ADDRESS>" "<PRESET_ID>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
Post-create (find your newest auctions and confirm):
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($seller:Bytes!){ auctions(first:10, orderBy: createdAt, orderDirection: desc, where:{seller:$seller}){ id type contractAddress tokenId quantity createdAt startsAt endsAt claimed cancelled } }",
"variables":{"seller":"<FROM_ADDRESS_LOWERCASE>"}
}'
```
## Cancel Auction
Onchain method:
- `cancelAuction(uint256)`
Steps:
1. Subgraph: check `claimed`, `cancelled`, `endsAt`, `highestBid`.
2. Onchain: call `getAuctionInfo(auctionId)` to verify ownership and state.
3. Simulate with `cast call` (`--from "$FROM_ADDRESS"`).
4. Broadcast only when explicitly instructed.
Simulate:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" 'cancelAuction(uint256)' "<AUCTION_ID>" \
--from "$FROM_ADDRESS" \
--rpc-url "$BASE_MAINNET_RPC"
```
Broadcast (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" 'cancelAuction(uint256)' "<AUCTION_ID>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Bid With GHST (commitBid)
Onchain method:
- `commitBid(uint256,uint256,uint256,address,uint256,uint256,bytes)` (last `bytes` is ignored; pass `0x`)
Steps:
1. Subgraph: fetch auction fields (id, contractAddress, tokenId, quantity, highestBid, startsAt, endsAt, claimed/cancelled).
2. Onchain: refetch `highestBid` and token params; you must pass the exact current onchain `highestBid` or it reverts `UnmatchedHighestBid`.
3. Compute a safe minimum next bid using `references/bid-math.md` (uses onchain `bidDecimals` + `stepMin`).
4. Ensure GHST allowance to the GBM diamond covers `bidAmount`.
5. Simulate via `cast call` (optional but recommended).
6. Broadcast only when explicitly instructed.
Simulate:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" \
'commitBid(uint256,uint256,uint256,address,uint256,uint256,bytes)' \
"<AUCTION_ID>" "<BID_AMOUNT_GHST_WEI>" "<HIGHEST_BID_GHST_WEI>" "<TOKEN_CONTRACT_ADDRESS>" "<TOKEN_ID>" "<TOKEN_AMOUNT>" 0x \
--from "$FROM_ADDRESS" \
--rpc-url "$BASE_MAINNET_RPC"
```
Broadcast (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" \
'commitBid(uint256,uint256,uint256,address,uint256,uint256,bytes)' \
"<AUCTION_ID>" "<BID_AMOUNT_GHST_WEI>" "<HIGHEST_BID_GHST_WEI>" "<TOKEN_CONTRACT_ADDRESS>" "<TOKEN_ID>" "<TOKEN_AMOUNT>" 0x \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Bid With USDC Swap (swapAndCommitBid)
Onchain method:
- `swapAndCommitBid((address,uint256,uint256,uint256,address,uint256,uint256,uint256,address,uint256,uint256,bytes))`
Struct fields (in order):
1. `tokenIn` (USDC)
2. `swapAmount` (USDC 6dp)
3. `minGhstOut` (GHST wei; must be >= bidAmount)
4. `swapDeadline` (unix; must be <= now + 86400)
5. `recipient` (refund receiver for excess GHST)
6. `auctionID`
7. `bidAmount` (GHST wei)
8. `highestBid` (must match onchain)
9. `tokenContract`
10. `tokenID`
11. `amount` (tokenAmount/quantity)
12. `_signature` (ignored; pass `0x`)
Compute `swapAmount` estimate in `references/swap-math.md`.
Simulate:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" \
'swapAndCommitBid((address,uint256,uint256,uint256,address,uint256,uint256,uint256,address,uint256,uint256,bytes))' \
"($USDC,<SWAP_AMOUNT_USDC_6DP>,<MIN_GHST_OUT_GHST_WEI>,<SWAP_DEADLINE_UNIX>,${RECIPIENT_ADDRESS:-$FROM_ADDRESS},<AUCTION_ID>,<BID_AMOUNT_GHST_WEI>,<HIGHEST_BID_GHST_WEI>,<TOKEN_CONTRACT_ADDRESS>,<TOKEN_ID>,<TOKEN_AMOUNT>,0x)" \
--from "$FROM_ADDRESS" \
--rpc-url "$BASE_MAINNET_RPC"
```
Broadcast (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" \
'swapAndCommitBid((address,uint256,uint256,uint256,address,uint256,uint256,uint256,address,uint256,uint256,bytes))' \
"($USDC,<SWAP_AMOUNT_USDC_6DP>,<MIN_GHST_OUT_GHST_WEI>,<SWAP_DEADLINE_UNIX>,${RECIPIENT_ADDRESS:-$FROM_ADDRESS},<AUCTION_ID>,<BID_AMOUNT_GHST_WEI>,<HIGHEST_BID_GHST_WEI>,<TOKEN_CONTRACT_ADDRESS>,<TOKEN_ID>,<TOKEN_AMOUNT>,0x)" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Bid With ETH Swap (swapAndCommitBid)
Same method as above, but:
- `tokenIn = 0x0000000000000000000000000000000000000000`
- `--value <SWAP_AMOUNT_WEI>` must equal the `swapAmount` you pass inside the tuple.
Broadcast (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" \
'swapAndCommitBid((address,uint256,uint256,uint256,address,uint256,uint256,uint256,address,uint256,uint256,bytes))' \
"(0x0000000000000000000000000000000000000000,<SWAP_AMOUNT_WEI>,<MIN_GHST_OUT_GHST_WEI>,<SWAP_DEADLINE_UNIX>,${RECIPIENT_ADDRESS:-$FROM_ADDRESS},<AUCTION_ID>,<BID_AMOUNT_GHST_WEI>,<HIGHEST_BID_GHST_WEI>,<TOKEN_CONTRACT_ADDRESS>,<TOKEN_ID>,<TOKEN_AMOUNT>,0x)" \
--value "<SWAP_AMOUNT_WEI>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Claim Auction
Onchain methods:
- `claim(uint256)`
- `batchClaim(uint256[])`
Claim readiness:
- Auction owner can claim at `now >= endsAt`.
- Highest bidder can claim at `now >= endsAt + cancellationTime`.
- `cancellationTime` is readable from storage slot 12 (see `references/recipes.md`).
- Subgraph may provide `claimAt` (if populated), but always verify onchain.
Simulate:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" 'claim(uint256)' "<AUCTION_ID>" \
--from "$FROM_ADDRESS" \
--rpc-url "$BASE_MAINNET_RPC"
```
Broadcast (only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GBM_DIAMOND" 'claim(uint256)' "<AUCTION_ID>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Optional: Buy Now
Onchain methods:
- `buyNow(uint256)`
- `swapAndBuyNow((address,uint256,uint256,uint256,address,uint256))`
These are not required for the primary use case, but are adjacent to bidding flows. If you use them, follow the same safety gating:
- refetch from subgraph
- verify onchain price/state
- simulate (`cast call`)
- only broadcast when explicitly instructed
## Smoke Tests (No Funds Required)
1. Subgraph reachable (introspection lists `auction`, `auctions`, `bid`, `bids`):
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{ "query":"{ __schema { queryType { fields { name } } } }" }' \
| python3 -c 'import json,sys; f=[x[\"name\"] for x in json.load(sys.stdin)[\"data\"][\"__schema\"][\"queryType\"][\"fields\"]]; print([n for n in f if n in (\"auction\",\"auctions\",\"bid\",\"bids\")])'
```
2. Subgraph data sane:
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{\"query\":\"query($id:ID!){ auction(id:$id){ id contractAddress tokenId } }\",\"variables\":{\"id\":\"0\"}}'
```
3. Onchain reachable + matches subgraph:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" \
'getAuctionInfo(uint256)((address,uint96,address,uint88,uint88,bool,bool,address,(uint80,uint80,uint56,uint8,bytes4,uint256,uint96,uint96),(uint64,uint64,uint64,uint64,uint256),uint96,uint96))' \
0 \
--rpc-url "$BASE_MAINNET_RPC"
```
## Common Failure Modes
- `UnmatchedHighestBid`: you passed a stale `highestBid` param. Refetch onchain and retry.
- `InvalidAuctionParams`: token contract / id / amount mismatch. Refetch and verify.
- `AuctionNotStarted` / `AuctionEnded`: timing mismatch. Check `startsAt`/`endsAt` (subgraph + onchain).
- `AuctionClaimed`: already claimed or cancelled. Check `claimed` (subgraph + onchain).
- `BiddingNotAllowed`: diamond paused, contract bidding disabled, or re-entrancy lock. Refetch onchain state.
- Swap errors:
- `LibTokenSwap: swapAmount must be > 0`
- `LibTokenSwap: deadline expired`
- `LibTokenSwap: Insufficient output amount` (increase `swapAmount` or slippage)
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/subgraph.md
```markdown
# Subgraph Queries (Base GBM Auctions)
Endpoint:
- `GBM_SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-gbm-baazaar-base/prod/gn`
Notes:
- `Bytes` fields (addresses) are lowercase in responses; when filtering, use lowercase addresses.
- Treat `Auction.id` as the canonical `auctionId` you pass to `cast` methods.
- Goldsky API key is optional for the public endpoint. If you set `GOLDSKY_API_KEY`, add:
- `-H "Authorization: Bearer $GOLDSKY_API_KEY"`
## Auction By ID
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($id:ID!){ auction(id:$id){ id type contractAddress tokenId quantity seller highestBid highestBidder totalBids lastBidTime startsAt endsAt claimAt claimed cancelled presetId category buyNowPrice startBidPrice bidDecimals stepMin incMin incMax bidMultiplier dueIncentives auctionDebt } }",
"variables":{"id":"<AUCTION_ID>"}
}'
```
## Active Auctions (Now Between startsAt and endsAt)
```bash
NOW=$(date +%s)
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data "{
\"query\":\"query(\$now:BigInt!){ auctions(first:20, orderBy: endsAt, orderDirection: asc, where:{claimed:false, cancelled:false, startsAt_lte:\$now, endsAt_gt:\$now}){ id type contractAddress tokenId quantity highestBid highestBidder totalBids startsAt endsAt claimAt presetId category seller } }\",
\"variables\":{\"now\":\"$NOW\"}
}"
```
## Your Auctions (seller)
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($seller:Bytes!){ auctions(first:50, orderBy: createdAt, orderDirection: desc, where:{seller:$seller}){ id type contractAddress tokenId quantity highestBid highestBidder totalBids startsAt endsAt claimAt claimed cancelled } }",
"variables":{"seller":"<FROM_ADDRESS_LOWERCASE>"}
}'
```
## Bids For An Auction
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($aid:String!){ bids(first:50, orderBy: bidTime, orderDirection: desc, where:{auction:$aid}){ id bidder amount bidTime outbid previousBid previousBidder } }",
"variables":{"aid":"<AUCTION_ID>"}
}'
```
## Your Bids (bidder)
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($bidder:Bytes!){ bids(first:50, orderBy: bidTime, orderDirection: desc, where:{bidder:$bidder}){ id auction { id type contractAddress tokenId quantity endsAt claimAt claimed cancelled } amount bidTime outbid } }",
"variables":{"bidder":"<FROM_ADDRESS_LOWERCASE>"}
}'
```
## Subgraph Reachability Smoke Test (Introspection)
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{ "query":"{ __schema { queryType { fields { name } } } }" }' \
| python3 -c 'import json,sys; f=[x["name"] for x in json.load(sys.stdin)["data"]["__schema"]["queryType"]["fields"]]; print([n for n in f if n in ("auction","auctions","bid","bids")])'
```
```
### references/bid-math.md
```markdown
# Bid Math (Minimum Next Bid)
When bidding (`commitBid` / `swapAndCommitBid`), you must:
- Pass the exact current onchain `highestBid` as the `_highestBid` argument (else revert `UnmatchedHighestBid`).
- Bid at or above the contract's effective minimum step, based on preset `stepMin` and `bidDecimals`.
## Effective Minimum Next Bid (Matches Onchain Behavior)
The incentives math uses:
```
baseBid = highestBid * (bidDecimals + stepMin) / bidDecimals
```
If `newBid < baseBid`, the incentives calculation underflows and the bid reverts.
Additionally, if the auction has `startingBid` set, the bid must be:
- `bidAmount >= startingBid`
So the safe minimum is:
```
minNextBid = max(startingBid, baseBid) (and baseBid is forced to >= 1 when highestBid is 0)
```
### Python Helper (Recommended)
Provide:
- `highestBid` (from onchain `getAuctionHighestBid`)
- `startingBid` (from onchain `getAuctionInfo`, or from subgraph `startBidPrice`)
- `bidDecimals` and `stepMin` (from onchain getters or subgraph fields)
```bash
python3 - <<'PY'
highest_bid = int("<HIGHEST_BID_GHST_WEI>") # replace
starting_bid = int("<STARTING_BID_GHST_WEI>") # replace (0 if none)
bid_decimals = int("<BID_DECIMALS>") # e.g. 100000
step_min = int("<STEP_MIN>") # e.g. 5000
base_bid = (highest_bid * (bid_decimals + step_min)) // bid_decimals
if base_bid == 0:
base_bid = 1
min_next = max(starting_bid, base_bid)
print("minNextBid (GHST wei):", min_next)
PY
```
## Interpreting Presets (Rule of Thumb)
On Base mainnet, presets typically use:
- `bidDecimals = 100000`
- `stepMin` of `1000`, `5000`, or `10000`
This corresponds to a minimum step of roughly:
- `1%`, `5%`, or `10%` (because `stepMin / bidDecimals`)
Verify per-auction via subgraph fields or onchain getters:
- `getAuctionBidDecimals(auctionId)(uint256)`
- `getAuctionStepMin(auctionId)(uint64)`
```
### references/swap-math.md
```markdown
# Swap Amount Math (USDC / ETH -> GHST)
This file defines how to estimate the `swapAmount` argument for:
- `swapAndCommitBid((...))`
- `swapAndBuyNow((...))`
Important notes:
- `swapAmount` is the amount of `tokenIn` you will spend (USDC 6dp or ETH wei).
- `minGhstOut` is a GHST wei minimum output (slippage protection). For bidding and buy-now, set it to the exact required GHST amount:
- bid: `minGhstOut = bidAmount`
- buy-now: `minGhstOut = buyNowPrice`
- Swaps can still fail due to price impact or route conditions (`LibTokenSwap: Insufficient output amount`). If that happens, increase `swapAmount` and/or `SLIPPAGE_PCT`.
Defaults:
- `SLIPPAGE_PCT=1` (1%)
## Price Sources (CoinGecko)
If `GHST_USD_PRICE` / `ETH_USD_PRICE` are unset, fetch them:
```bash
curl -s 'https://api.coingecko.com/api/v3/simple/price?ids=aavegotchi,ethereum&vs_currencies=usd' \
| python3 -c 'import json,sys; j=json.load(sys.stdin); print(\"GHST_USD\", j[\"aavegotchi\"][\"usd\"]); print(\"ETH_USD\", j[\"ethereum\"][\"usd\"])'
```
## USDC swapAmount (6 decimals)
Given:
- `min_ghst_out_wei` (bidAmount or buyNowPrice)
- `ghst_usd_price`
Compute:
1. `ghst = min_ghst_out_wei / 1e18`
2. `usd = ghst * ghst_usd_price`
3. `base_usdc_6dp = usd * 1e6`
4. `swapAmount = ceil(base_usdc_6dp * (1 + SLIPPAGE_PCT/100))`
Python reference:
```bash
python3 - <<'PY'
from decimal import Decimal, getcontext, ROUND_CEILING
getcontext().prec = 80
min_ghst_out_wei = Decimal("<MIN_GHST_OUT_GHST_WEI>") # replace
ghst_usd_price = Decimal("<GHST_USD_PRICE>") # replace
slippage_pct = Decimal("<SLIPPAGE_PCT>") # default 1
ghst = min_ghst_out_wei / (Decimal(10) ** 18)
usd = ghst * ghst_usd_price
base_usdc = usd * (Decimal(10) ** 6)
swap_amount = (base_usdc * (Decimal(1) + slippage_pct / Decimal(100))).to_integral_value(rounding=ROUND_CEILING)
print("swapAmount (USDC 6dp):", int(swap_amount))
PY
```
## ETH swapAmount (wei)
Given:
- `min_ghst_out_wei`
- `ghst_usd_price`
- `eth_usd_price`
Compute:
1. `ghst = min_ghst_out_wei / 1e18`
2. `usd = ghst * ghst_usd_price`
3. `eth = usd / eth_usd_price`
4. `base_eth_wei = eth * 1e18`
5. `swapAmountWei = ceil(base_eth_wei * (1 + SLIPPAGE_PCT/100))`
Python reference:
```bash
python3 - <<'PY'
from decimal import Decimal, getcontext, ROUND_CEILING
getcontext().prec = 80
min_ghst_out_wei = Decimal("<MIN_GHST_OUT_GHST_WEI>") # replace
ghst_usd_price = Decimal("<GHST_USD_PRICE>") # replace
eth_usd_price = Decimal("<ETH_USD_PRICE>") # replace
slippage_pct = Decimal("<SLIPPAGE_PCT>") # default 1
ghst = min_ghst_out_wei / (Decimal(10) ** 18)
usd = ghst * ghst_usd_price
eth = usd / eth_usd_price
base_eth_wei = eth * (Decimal(10) ** 18)
swap_amount = (base_eth_wei * (Decimal(1) + slippage_pct / Decimal(100))).to_integral_value(rounding=ROUND_CEILING)
print("swapAmount (ETH wei):", int(swap_amount))
PY
```
```
### references/recipes.md
```markdown
# Common Recipes (Foundry cast + Subgraph)
Commands below use `~/.foundry/bin/cast` so they work in cron/non-interactive shells. If `cast` is on `PATH`, you can replace `~/.foundry/bin/cast` with `cast`.
Assumes you set defaults from `references/addresses.md`.
## Safety Checks
Verify chain id is Base mainnet (must be `8453`):
```bash
~/.foundry/bin/cast chain-id --rpc-url "${BASE_MAINNET_RPC:-https://mainnet.base.org}"
```
Verify private key corresponds to FROM_ADDRESS (must match exactly):
```bash
~/.foundry/bin/cast wallet address --private-key "$PRIVATE_KEY"
```
Lowercase your address for subgraph filters:
```bash
python3 - <<'PY'
addr = "<FROM_ADDRESS>"
print(addr.lower())
PY
```
## Subgraph Convenience: Auction By ID
```bash
curl -s "$GBM_SUBGRAPH_URL" -H 'content-type: application/json' ${GOLDSKY_API_KEY:+-H "Authorization: Bearer $GOLDSKY_API_KEY"} --data '{
"query":"query($id:ID!){ auction(id:$id){ id type contractAddress tokenId quantity seller highestBid highestBidder totalBids startsAt endsAt claimAt claimed cancelled presetId category buyNowPrice startBidPrice } }",
"variables":{"id":"<AUCTION_ID>"}
}'
```
## ERC20: Balances / Allowances
GHST balance:
```bash
~/.foundry/bin/cast call "$GHST" 'balanceOf(address)(uint256)' "$FROM_ADDRESS" --rpc-url "$BASE_MAINNET_RPC"
```
USDC balance:
```bash
~/.foundry/bin/cast call "$USDC" 'balanceOf(address)(uint256)' "$FROM_ADDRESS" --rpc-url "$BASE_MAINNET_RPC"
```
GHST allowance to GBM diamond:
```bash
~/.foundry/bin/cast call "$GHST" 'allowance(address,address)(uint256)' "$FROM_ADDRESS" "$GBM_DIAMOND" --rpc-url "$BASE_MAINNET_RPC"
```
USDC allowance to GBM diamond:
```bash
~/.foundry/bin/cast call "$USDC" 'allowance(address,address)(uint256)' "$FROM_ADDRESS" "$GBM_DIAMOND" --rpc-url "$BASE_MAINNET_RPC"
```
Approve GHST (broadcast; do this only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$GHST" 'approve(address,uint256)' "$GBM_DIAMOND" "<AMOUNT_GHST_WEI>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
Approve USDC (broadcast; do this only when explicitly instructed):
```bash
~/.foundry/bin/cast send "$USDC" 'approve(address,uint256)' "$GBM_DIAMOND" "<AMOUNT_USDC_6DP>" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## ERC721 / ERC1155: Approval For All
Check (ERC721 or ERC1155 contract):
```bash
~/.foundry/bin/cast call "<NFT_CONTRACT_ADDRESS>" 'isApprovedForAll(address,address)(bool)' "$FROM_ADDRESS" "$GBM_DIAMOND" \
--rpc-url "$BASE_MAINNET_RPC"
```
Set approval (broadcast; do this only when explicitly instructed):
```bash
~/.foundry/bin/cast send "<NFT_CONTRACT_ADDRESS>" 'setApprovalForAll(address,bool)' "$GBM_DIAMOND" true \
--private-key "$PRIVATE_KEY" \
--rpc-url "$BASE_MAINNET_RPC"
```
## Auction Time Helpers
Compute start/end times (example: start in 60s, duration 24h):
```bash
python3 - <<'PY'
import time
now = int(time.time())
start = now + 60
end = start + 24*60*60
print("startTime:", start)
print("endTime: ", end)
PY
```
Swap deadline (now + 600):
```bash
python3 - <<'PY'
import time
print(int(time.time()) + 600)
PY
```
## Read hammerTimeDuration / cancellationTime (Storage Slot 12)
Storage slot `12` packs two uint128 values:
- low 128 bits: `hammerTimeDuration`
- high 128 bits: `cancellationTime`
Fetch raw slot:
```bash
~/.foundry/bin/cast storage "$GBM_DIAMOND" 12 --rpc-url "$BASE_MAINNET_RPC"
```
Decode:
```bash
python3 - <<'PY'
slot_hex = "<SLOT_12_HEX>" # replace output of cast storage
v = int(slot_hex, 16)
mask = (1 << 128) - 1
hammer = v & mask
cancellation = v >> 128
print("hammerTimeDuration:", hammer)
print("cancellationTime: ", cancellation)
PY
```
## Auction Nonce (Optional Onchain Discovery)
Storage slot `13` is `auctionNonce` (next auction id):
```bash
~/.foundry/bin/cast storage "$GBM_DIAMOND" 13 --rpc-url "$BASE_MAINNET_RPC"
```
In general, prefer the subgraph for listing and discovery.
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "cinnabarhorse",
"slug": "aavegotchi-gbm-skill",
"displayName": "Aavegotchi GBM Skill",
"latest": {
"version": "0.1.0",
"publishedAt": 1771147668598,
"commit": "https://github.com/openclaw/skills/commit/6c85b7b01bee756b654c08e0f0e3da182869d0a8"
},
"history": []
}
```
### references/addresses.md
```markdown
# Addresses / Constants (Base Mainnet)
Chain:
- Chain ID: `8453` (Base mainnet)
- Default RPC: `https://mainnet.base.org` (override via `BASE_MAINNET_RPC`)
GBM diamond (entrypoint for auctions):
- `GBM_DIAMOND=0x80320A0000C7A6a34086E2ACAD6915Ff57FfDA31`
ERC20s:
- GHST (18 decimals): `GHST=0xcD2F22236DD9Dfe2356D7C543161D4d260FD9BcB`
- USDC (6 decimals): `USDC=0x833589fCD6eDb6E08f4c7C32D4f71b54BDA02913`
Subgraph (Goldsky, no auth required):
- `GBM_SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-gbm-baazaar-base/prod/gn`
GBM Diamond deploy block (useful for log scans):
- `DEPLOY_BLOCK=33276452` (Base mainnet)
Token kind constants (used in `createAuction` InitiatorInfo):
- `ERC721=0x73ad2146`
- `ERC1155=0x973bb640`
Likely-whitelisted token contracts on Base mainnet (from the GBM repo deployment config):
- Aavegotchi diamond (ERC721): `0xA99c4B08201F2913Db8D28e71d020c4298F29dBF`
- Forge diamond (ERC1155): `0x50aF2d63b839aA32b4166FD1Cb247129b715186C`
- Fake Gotchi Card diamond (ERC721): `0xe46B8902dAD841476d9Fee081F1d62aE317206A9`
- Fake Gotchi Art diamond (ERC721): `0xAb59CA4A16925b0a4BaC5026C94bEB20A29Df479`
Recommended shell defaults (allow overrides):
```bash
export BASE_MAINNET_RPC="${BASE_MAINNET_RPC:-https://mainnet.base.org}"
export GBM_DIAMOND="${GBM_DIAMOND:-0x80320A0000C7A6a34086E2ACAD6915Ff57FfDA31}"
export GHST="${GHST:-0xcD2F22236DD9Dfe2356D7C543161D4d260FD9BcB}"
export USDC="${USDC:-0x833589fCD6eDb6E08f4c7C32D4f71b54BDA02913}"
export GBM_SUBGRAPH_URL="${GBM_SUBGRAPH_URL:-https://api.goldsky.com/api/public/project_cmh3flagm0001r4p25foufjtt/subgraphs/aavegotchi-gbm-baazaar-base/prod/gn}"
export DRY_RUN="${DRY_RUN:-1}"
export SLIPPAGE_PCT="${SLIPPAGE_PCT:-1}"
```
```
### references/logs.md
```markdown
# Logs / Event Scans (Optional)
You can discover auctions and activity via events, but for day-to-day listing and filtering, prefer the subgraph (`references/subgraph.md`).
If you do use logs:
- Some RPCs restrict `eth_getLogs` to a max block range (commonly 10,000 blocks).
- Some RPCs intermittently 503 on large log queries.
- Chunk your requests.
Constants:
- GBM diamond: `0x80320A0000C7A6a34086E2ACAD6915Ff57FfDA31`
- Deploy block (Base mainnet): `33276452`
## Common Events
- `Auction_Initialized(uint256 indexed _auctionID,uint256 indexed _tokenID,uint256 indexed _tokenAmount,address _contractAddress,bytes4 _tokenKind,uint256 _presetID)`
- `Auction_BidPlaced(uint256 indexed _auctionID,address indexed _bidder,uint256 _bidAmount)`
- `AuctionCancelled(uint256 indexed _auctionId,uint256 _tokenId)`
- `Auction_ItemClaimed(uint256 indexed _auctionID)`
## Example: Fetch Recent Auction_Initialized Logs (Chunked)
```bash
python3 - <<'PY'
import subprocess
rpc = "https://1rpc.io/base" # override as needed
addr = "0x80320A0000C7A6a34086E2ACAD6915Ff57FfDA31"
event = "Auction_Initialized(uint256,uint256,uint256,address,bytes4,uint256)"
# Keep chunk <= 10k blocks for providers that enforce that limit.
start = 33276452
end = int(subprocess.check_output(["cast", "block-number", "--rpc-url", rpc]).decode().strip())
chunk = 8000
for a in range(start, end + 1, chunk):
b = min(a + chunk - 1, end)
cmd = [
"cast", "logs", event,
"--from-block", str(a),
"--to-block", str(b),
"--address", addr,
"--rpc-url", rpc,
"--json",
]
out = subprocess.check_output(cmd)
if out.strip() not in (b"", b"[]"):
print(f"range {a}-{b}:", out.decode().strip()[:300], "...")
PY
```
```
### references/presets.md
```markdown
# GBM Auction Presets (Base)
Presets are stored onchain and copied into each auction at creation time.
Read a preset:
```bash
~/.foundry/bin/cast call "$GBM_DIAMOND" 'getAuctionPresets(uint256)((uint64,uint64,uint64,uint64,uint256))' 0 --rpc-url "$BASE_MAINNET_RPC"
```
Base mainnet presets (from the GBM repo deployment config; verify onchain):
Preset `0` (low):
- `incMin=500`
- `incMax=1000`
- `bidMultiplier=500`
- `stepMin=1000`
- `bidDecimals=100000`
- Interpreting `stepMin/bidDecimals`: ~`1%` minimum step (used in bid math)
Preset `1` (medium):
- `incMin=500`
- `incMax=5000`
- `bidMultiplier=4970`
- `stepMin=5000`
- `bidDecimals=100000`
- Interpreting `stepMin/bidDecimals`: ~`5%` minimum step
Preset `2` (high):
- `incMin=1000`
- `incMax=10000`
- `bidMultiplier=11000`
- `stepMin=10000`
- `bidDecimals=100000`
- Interpreting `stepMin/bidDecimals`: ~`10%` minimum step
Tip:
- If you are creating an auction for a specific contract and you want to match platform defaults, query recent auctions for that contract in the subgraph and copy the `presetId` used.
```