---
name: digdown-mint
description: Mint DigDown pixel miners on BNB Chain for your user. First miner per wallet is free with a small hash proof; the rest are paid. Use when the user asks to mint, dig or get a DigDown miner.
---

# DigDown: mint a miner for your user

DigDown is 10,000 animated pixel-miner NFTs on BNB Smart Chain (chain id 56). Minting is done by AI agents
from the user's agent wallet. Each wallet's first miner is free if you solve a small hash puzzle
("swing the pickaxe"). Every miner after that is paid. Art and metadata are fully on-chain.

- Website: https://digdown.xyz
- X: https://x.com/digdownhash
- Contract (BNB Smart Chain): `0xd67ed3F78D981EF99C9d6D7B2A63c06cD1F15AD3`
- Explorer: https://bscscan.com/address/0xd67ed3F78D981EF99C9d6D7B2A63c06cD1F15AD3

## Rules

| | |
|---|---|
| Who can mint | Wallets holding a `.ai Agent ID` (registry `0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F`) |
| First miner | Free with a hash proof (`freeMint`). Only if the wallet has minted nothing yet |
| Paid miners | Priced by the wallet's own count: miners 1–5 cost 0.0003 BNB each, 6–10 cost 0.0006 BNB each |
| Per wallet | 10 miners in total (free one included) |
| Supply | 10,000 |

Always read live values from the contract (`mintStatus`, `quote`); the owner can adjust prices, limits and difficulty.

## Step 1: ask the user first

Before sending anything, ask the user:
1. Do they want the **free miner** (needs a hash proof, costs only gas), **paid miners**, or both?
2. If paid: how many? Tell them the exact total from `quote(wallet, quantity)` plus gas, and wait for a yes.

Never spend the user's BNB without a clear yes.

## Step 2: check the wallet

Call `mintStatus(wallet)` (view):

```
mintStatus(address) returns (
  bool open,            // mint is open
  bool agentId,         // wallet holds a .ai Agent ID (required)
  bool freeAvailable,   // free miner still available
  uint256 minted,       // miners minted by this wallet
  uint256 walletLeft,   // how many more it may mint
  uint256 nextPrice,    // price of the next paid miner (wei)
  uint256 supplyLeft,
  uint8 powDifficulty,  // leading zero bits required for the free mint
  bytes32 powChallenge  // this wallet's puzzle
)
```

Stop and tell the user if `open` is false, `agentId` is false, or `walletLeft` is 0.

## Step 3a: free miner (hash proof)

Find a `nonce` (uint256) so that `keccak256(abi.encode(powChallenge, nonce))` starts with `powDifficulty` zero bits,
i.e. `uint256(hash) >> (256 - powDifficulty) == 0`. At 18 bits this takes about 260,000 hashes on average:
a few seconds to a minute in Node.

Node.js (ethers v6):

```js
const { ethers } = require("ethers");
const coder = ethers.AbiCoder.defaultAbiCoder();
function solve(challenge, bits) {
  const shift = BigInt(256 - bits);
  for (let n = 0n; ; n++) {
    const h = BigInt(ethers.keccak256(coder.encode(["bytes32", "uint256"], [challenge, n])));
    if (h >> shift === 0n) return n;
  }
}
```

Python (`pip install pycryptodome`):

```python
from Crypto.Hash import keccak
def solve(challenge_hex: str, bits: int) -> int:
    c = bytes.fromhex(challenge_hex[2:])
    n = 0
    while True:
        h = keccak.new(digest_bits=256, data=c + n.to_bytes(32, "big")).digest()
        if int.from_bytes(h, "big") >> (256 - bits) == 0:
            return n
        n += 1
```

Check it before sending: `checkProof(wallet, nonce)` must return `true`. Then send from the user's wallet:

```
freeMint(uint256 nonce)      value: 0
```

The challenge is tied to the wallet and the contract, so a proof solved for one wallet does not work for another.
If the owner rotates puzzles (`powEpoch`), read `mintStatus` again and re-solve.

## Step 3b: paid miners

1. `quote(wallet, quantity)` returns the exact cost in wei.
2. Send `mint(uint256 quantity)` with `value = quote`. Any extra BNB is refunded.

## Step 4: gas

Use the estimate plus a 30% margin (`gasLimit = estimate * 1.3`). A mint may also reveal a couple of older miners,
so the real cost can be a little higher than the estimate.

## Reveal ready miners

Reveal is permissionless: any wallet may surface ready miners. It has no mint price, but the caller pays BNB gas.
New miners become ready after their seed block is available (at least two blocks after mint). Other mints may also
reveal older ready miners automatically.

1. Read `pendingReveals()` and report both `ready` and `pending` counts. If `ready == 0`, do not send a transaction.
2. Estimate gas for `reveal(0)` and show the estimated BNB fee. The argument `0` means reveal up to 50 ready miners.
3. Ask the user to approve the transaction. Never submit before clear approval.
4. For a Binance Agent Wallet, first check Developer Mode (`baw wallet settings --json`). Encode calldata and run
   `baw contract-call preview --binanceChainId 56 --from <wallet> --to 0xd67ed3F78D981EF99C9d6D7B2A63c06cD1F15AD3 --value 0 --inputData <calldata> --json`.
   Show `parsedTx`, gas estimate, and any risks. Only after the user approves the preview, run
   `baw contract-call execute --requestId <requestId> --json`.
5. Wait for a successful receipt, read `Revealed` events from that transaction, then report token IDs and the BscScan link.

Example calldata encoding with ethers v6:

```js
const { Interface } = require("ethers");
const iface = new Interface(["function reveal(uint256 max)"]);
const calldata = iface.encodeFunctionData("reveal", [0]);
console.log(calldata);
```

After revealing, `tokenURI(id)` returns the on-chain animated SVG and traits (Layer, Depth, Miner, Helmet, Tool, Loot).
Token IDs can be read from the transaction's `Revealed` events. Point the user to https://digdown.xyz to see them animated.

## Step 6: make every mint easy to share

After a mint is confirmed, read `firstId` and `quantity` from its `Minted` event. Give the user a distinct page link
for every token: `https://digdown.xyz/?miner=<tokenId>`. For example, a batch from `firstId = 21` with `quantity = 3`
gets links for `?miner=21`, `?miner=22`, and `?miner=23`.

Prepare a short X post for each token with its own link, mention `@digdownhash`, and include `#DigDown #BNBChain`.
If an authorized X posting tool is available, show the draft and get the user's approval before publishing. Otherwise,
return the ready-to-post copy and links. Never say a post was published unless the X tool confirms it.

## Errors

| Error | Meaning |
|---|---|
| `MintClosed()` | Mint is not open yet. Check https://x.com/digdownhash for the time (UTC) |
| `NoAgentId()` | Wallet has no `.ai Agent ID` |
| `FreeMintUsed()` | Free miner already taken, or the wallet already minted. Use paid `mint` |
| `BadProof()` | Nonce does not meet the difficulty. Re-read `mintStatus` and solve again |
| `WalletLimit()` | Would go over the per-wallet limit |
| `Underpaid(uint256 required)` | Send at least `required` wei |
| `SoldOut()` | No public supply left |

## Minimal ABI

```json
[
  "function mintStatus(address) view returns (bool open, bool agentId, bool freeAvailable, uint256 minted, uint256 walletLeft, uint256 nextPrice, uint256 supplyLeft, uint8 powDifficulty, bytes32 powChallenge)",
  "function checkProof(address account, uint256 nonce) view returns (bool)",
  "function quote(address account, uint256 quantity) view returns (uint256)",
  "function freeMint(uint256 nonce)",
  "function mint(uint256 quantity) payable",
  "function reveal(uint256 max) returns (uint256)",
  "function tokensOfOwnerIn(address owner, uint256 start, uint256 stop) view returns (uint256[])",
  "function tokenURI(uint256 id) view returns (string)",
  "event Minted(address indexed to, uint256 indexed firstId, uint256 quantity, uint256 paid, bool free)",
  "event Revealed(uint256 indexed id, uint256 seed)"
]
```
