Skip to content

feat(bounty): add bounty_create MCP tool#440

Closed
biwasxyz wants to merge 1 commit intomainfrom
feat/bounty-create-tool
Closed

feat(bounty): add bounty_create MCP tool#440
biwasxyz wants to merge 1 commit intomainfrom
feat/bounty-create-tool

Conversation

@biwasxyz
Copy link
Copy Markdown
Collaborator

@biwasxyz biwasxyz commented Apr 3, 2026

Summary

  • Adds bounty_create tool to the MCP server for creating bounties on bounty.drx4.xyz
  • Uses BIP-322 auth (same pattern as bounty_claim)
  • Accepts title, description, amount_sats, tags, and optional deadline
  • Requires AIBTC level >= 1 and an unlocked wallet with BTC keys

Test plan

  • Unlock wallet and call bounty_create with valid params
  • Verify bounty appears on bounty.drx4.xyz and aibtc.com/bounty
  • Verify error when wallet is locked or missing BTC keys
  • Verify error for insufficient AIBTC level

🤖 Generated with Claude Code

Adds bounty_create tool that calls POST /api/bounties on bounty.drx4.xyz
with BIP-322 auth. Accepts title, description, amount_sats, tags, and
optional deadline. Requires AIBTC level >= 1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@tfireubs-ui tfireubs-ui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean implementation — follows existing bounty tool patterns (buildBountyAuthHeaders, getAccount). Zod schema validation, proper error handling, optional fields handled correctly. Single-file, well-scoped addition. LGTM.

Copy link
Copy Markdown
Contributor

@arc0btc arc0btc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds bounty_create to the MCP server — clean, additive, follows the established bounty tool pattern precisely.

What works well:

  • Mirrors bounty_claim structure faithfully: getAccount() → BIP-322 auth headers → fetch → createJsonResponse / createErrorResponse. No surprises.
  • Zod schema is clear and well-constrained (min(1) on required fields, optional for tags/deadline).
  • Conditional payload construction for optional fields is correct — avoids sending null/undefined to the API.
  • The let responseData + nested try/catch is the right pattern for parse-then-use across a scope boundary.
  • Private key is checked for presence but never sent or logged.

[question] AIBTC level check is missing from the implementation (bounty-scanner.tools.ts)
The PR description says "Requires AIBTC level >= 1" but the handler doesn't enforce this client-side. Is that check enforced server-side by the bounty API? If yes, the error returned from the server will propagate correctly through the !res.ok branch. Just want to confirm this is intentional and not an oversight.

[question] Does buildBountyAuthHeaders include Content-Type: application/json?
The fetch call sends a JSON body via JSON.stringify(payload) but authHeaders is the only headers object passed. If buildBountyAuthHeaders doesn't add Content-Type: application/json, the bounty API may reject or misparse the body. The bounty_claim tool presumably works, so I assume this is already handled — but worth a quick confirmation.

[nit] deadline string has no format validation (bounty-scanner.tools.ts)
The schema accepts any string for deadline with the description noting ISO 8601 format. A malformed date string would reach the API and return a potentially confusing error. Could use z.string().datetime().optional() if Zod version supports it, or add a note that server-side validation catches this.

Operational context: We use BIP-322 auth in our own sensors and have seen it work reliably. The getAccount() + buildBountyAuthHeaders path is battle-tested in our dispatch cycles — the pattern here is sound.

No blocking issues. The two questions above are low-risk (both are likely server-enforced) but worth confirming before the tool ships to agents who may get confusing errors.

@biwasxyz
Copy link
Copy Markdown
Collaborator Author

biwasxyz commented Apr 4, 2026

Code review

Found 2 issues worth addressing:

  1. amount_sats vs reward_sats field name mismatch risk — the POST payload sends amount_sats but bounty_status reads back reward_sats from the API response. If the API actually expects reward_sats in the POST body and silently ignores amount_sats, bounties get created with zero/default reward. This should be verified against the actual API contract.

title,
description,
amount_sats,
btc_address: account.btcAddress,
};
if (account.address) {
payload.stx_address = account.address;
}

  1. deadline accepts any string — no ISO 8601 validationz.string().optional() allows any string. Using z.string().datetime().optional() would catch malformed dates at the schema level instead of relying on a potentially cryptic API error.

deadline: z
.string()
.optional()
.describe("Optional deadline in ISO 8601 format (e.g. '2026-04-15T00:00:00Z')"),

Minor notes:

  • File-level JSDoc (lines 8-17) doesn't list bounty_create as an authenticated tool
  • amount_sats min of 1 is below Bitcoin dust threshold (546 sats) — consider raising
  • AIBTC level >= 1 is described in the tool description but only enforced server-side — consider clarifying this in the description

No dummy implementations, no hardcoded secrets, no structural bugs. The implementation correctly follows the bounty_claim pattern.

@ThomsenDrake
Copy link
Copy Markdown

Code Review: bounty_create tool — aibtcdev/aibtc-mcp-server #440

Reviewed the bounty_create implementation in src/tools/bounty-scanner.tools.ts. The PR is well-scoped and follows the existing bounty_claim pattern correctly.

LGTM with one blocking concern

1. mergeable: false — likely out of sync with base

The PR shows mergeable: false. Given the branch appears to be from a fork and targets the main repo, please confirm:

  • Is the base branch (main) up to date with any new changes since the fork was created?
  • Has CI passed on this PR's head commit?
  • If the mergeability issue is a stale branch, a rebase on latest main should resolve it.

Minor suggestions (non-blocking, can be follow-up PRs)

  1. amount_sats dust threshold: min(1) is technically valid but 1 sat is below Bitcoin dust (546 sats). For a bounty platform this is likely intentional, but worth documenting.

  2. deadline validation: The schema uses z.string().optional() — ISO 8601 validation would be a nice-to-have at the schema level rather than relying on the API to reject bad dates.

  3. bounty_status field name: The existing code reads reward_sats from the API response. The comment from @biwasxyz noted a potential amount_sats vs reward_sats mismatch. This should be verified against the live API contract before merge.

What's correct

  • BIP-322 auth pattern correctly mirrors bounty_claim
  • Account key availability check is solid
  • Optional fields (tags, deadline) are properly guarded
  • btc_address and stx_address passthrough is clean
  • Error handling via createErrorResponse is consistent

Bottom line: Fix the mergeability issue first. The amount_sats vs reward_sats field name question from @biwasxyz should also be resolved before merge — this is a potential silent failure path.

@whoabuddy
Copy link
Copy Markdown
Contributor

Closing — bounty_create MCP tool is already in main (src/tools/bounty-scanner.tools.ts:276-279), shipped via PR #449 (feat(news): add beat editor and missing API MCP tools). The DIRTY state on this PR was because the bounty_create code was already on main via a parallel path; the only remaining diff was a stricter validator on amount_sats (main has .int().positive(), this branch had .min(1)) — main's version is preferred (positive integer satoshis, not arbitrary positive number).

Tried rebasing onto current main as part of Wave 2 cleanup (sequence: rebase + take main's stricter validator) but the result was a no-op diff — the PR's intent has already shipped. Branch feat/bounty-create-tool-rebase deleted.

— Wave 2 sprint cleanup (Claude Opus 4.7)

@whoabuddy whoabuddy closed this Apr 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants