Skip to content

feat(jingswap): add V2 limit-price auction tools#464

Open
Rapha-btc wants to merge 1 commit intoaibtcdev:mainfrom
Rapha-btc:feat/jingswap-v2-limit-auctions
Open

feat(jingswap): add V2 limit-price auction tools#464
Rapha-btc wants to merge 1 commit intoaibtcdev:mainfrom
Rapha-btc:feat/jingswap-v2-limit-auctions

Conversation

@Rapha-btc
Copy link
Copy Markdown
Contributor

Summary

  • Adds 12 new jingswap_v2_* MCP tools for Jingswap V2 limit-price auctions alongside existing V1 tools (no breaking changes)
  • Two markets: sbtc-stx-market (0% premium) and sbtc-stx-20bp-stx-premium (0.20% STX bonus)
  • Deposits require mandatory limit prices in sats/STX (auto-defaults to 20% in-the-money if omitted)
  • Settlement uses bundled close-and-settle-with-refresh (single atomic tx) — close-deposits is NOT exposed separately to avoid stuck cycles
  • New clearing-preview tool simulates limit filtering at current oracle to predict if settlement will succeed

Tools added

Query: jingswap_v2_get_cycle_state, jingswap_v2_get_user_deposit, jingswap_v2_get_clearing_preview, jingswap_v2_get_prices

Deposit (with limit): jingswap_v2_deposit_stx, jingswap_v2_deposit_sbtc

Limit management: jingswap_v2_set_stx_limit, jingswap_v2_set_sbtc_limit

Cancel: jingswap_v2_cancel_stx, jingswap_v2_cancel_sbtc

Settlement: jingswap_v2_close_and_settle_with_refresh, jingswap_v2_cancel_cycle

V2 vs V1 key differences

Feature V1 V2
Phases 3 (deposit/buffer/settle) 2 (deposit/settle)
Deposit args (amount) (amount, limitPrice)
Settlement Separate close + settle Bundled atomic tx
Deposit blocks 150 (~5 min) 10 (~20s)
Cancel threshold 530 (~17.5 min) 42 (~84s)

Test plan

  • Build passes (npm run build — only pre-existing tx-schemas errors, no new errors)
  • V1 tools still work unchanged
  • V2 cycle-state returns 2-phase data for deployed contracts
  • V2 deposit-stx with limit price broadcasts successfully
  • V2 clearing-preview returns projected clearing amounts

🤖 Generated with Claude Code

12 new tools for Jingswap V2 alongside existing V1 tools:

Query:
- jingswap_v2_get_cycle_state (2-phase: deposit → settle, no buffer)
- jingswap_v2_get_user_deposit (includes limit prices in sats/STX)
- jingswap_v2_get_clearing_preview (simulates limit filtering at oracle)
- jingswap_v2_get_prices (oracle + default limit suggestions)

Deposit (with mandatory limit price):
- jingswap_v2_deposit_stx (limit = floor in sats/STX, default 20% ITM)
- jingswap_v2_deposit_sbtc (limit = ceiling in sats/STX, default 20% ITM)

Limit management:
- jingswap_v2_set_stx_limit (update without re-depositing)
- jingswap_v2_set_sbtc_limit (update without re-depositing)

Cancel:
- jingswap_v2_cancel_stx / jingswap_v2_cancel_sbtc

Settlement:
- jingswap_v2_close_and_settle_with_refresh (bundled, single tx)
- jingswap_v2_cancel_cycle (safety valve, 42 blocks after close)

close-deposits is NOT exposed separately to avoid stuck cycles.

Markets: sbtc-stx-market (0%), sbtc-stx-20bp-stx-premium (0.20% STX bonus)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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 12 new `jingswap_v2_*` tools for limit-price batch auctions — clean design overall, and the decision to bundle close-and-settle into a single atomic tx (instead of exposing `close-deposits` separately) is exactly right for preventing stuck cycles.

One blocking issue before this can merge: a live API key is hardcoded in the fallback.

What looks good:

  • 2-phase model is simpler to reason about than V1's 3-phase; the clearing-preview tool is a nice safety net before committing to settlement
  • `assertV2DepositPhase` consistently guards all deposit/cancel ops — no path skips it
  • The `cancel-cycle` vs individual cancel distinction is well-handled
  • No breaking changes to V1 tools — additive-only

[blocking] Hardcoded API key in source code (src/tools/jingswap-v2.tools.ts:23)

const JINGSWAP_API_KEY =
  process.env.JINGSWAP_API_KEY || "jc_b058d7f2e0976bd4ee34be3e5c7ba7ebe45289c55d3f5e45f666ebc14b7ebfd0";

This key is now permanently in the git history and should be treated as compromised. Even if it's a low-privilege API key today, hardcoded secrets are a bad pattern — they get copied, committed again in forks, and are hard to rotate. Suggest:

const JINGSWAP_API_KEY = process.env.JINGSWAP_API_KEY ?? "";

Then add a startup check or let the first 401 from the API surface a useful error. Users who need the key can set the env var; everyone else fails fast with a clear message. (Operational note: we hit a 401 on the same backend recently in our arc-starter sensor — having the env var as the only path would have made the issue immediately obvious.)


[suggestion] PostConditionMode.Allow on cancel operations (jingswap_v2_cancel_stx, jingswap_v2_cancel_sbtc)

Both cancel tools broadcast with `PostConditionMode.Allow` and no post-conditions. This means if the contract ever has a bug or a malicious upgrade, there's no on-chain protection preventing more funds from leaving than expected. For cancel/refund flows, it's safer to assert that you receive back at most what you put in:

postConditionMode: PostConditionMode.Deny,
postConditions: [
  Pc.principal(JINGSWAP_CONTRACT_ADDRESS + "." + m.contractName)
    .willSendEq(depositAmount)
    .ustx(),
],

This requires tracking the deposit amount at call time, but it tightly bounds the blast radius if the contract behaves unexpectedly.


[suggestion] Missing `btcUsd <= 0` guard in `getOracleSatsPerStx` (jingswap-v2.tools.ts:108)

if (!stxUsd || !btcUsd || stxUsd <= 0) throw new Error("Oracle prices unavailable");

`!btcUsd` catches zero but not negative. Since `btcUsd` flows into division, a negative value produces a negative satsPerStx that passes into `satsPerStxToRaw`, which only checks `> 0`. Add `|| btcUsd <= 0` for symmetry with the STX check.


[suggestion] No timeout in `jingswapGet` (jingswap-v2.tools.ts:90)

The bare `fetch` has no timeout — if the backend hangs, the MCP call hangs indefinitely. Since settlement calls chain multiple `jingswapGet` calls sequentially (pyth-vaas, cycle-state), a hung backend means a hung tool. Consider:

const res = await fetch(`${JINGSWAP_API}${path}`, {
  headers: { "x-api-key": JINGSWAP_API_KEY },
  signal: AbortSignal.timeout(10_000),
});

[suggestion] Duplicate limit resolution logic (jingswap_v2_deposit_stx, jingswap_v2_deposit_sbtc)

Both deposit handlers have identical limit-resolution blocks. Could be a small helper:

async function resolveLimit(explicit: number | undefined, m: MarketConfigV2, side: "stx" | "sbtc"): Promise<number> {
  if (explicit) return explicit;
  const oracle = await getOracleSatsPerStx(m);
  return defaultLimitSatsPerStx(oracle, side);
}

Not blocking, just reduces copy-paste drift if the default logic needs to change.


Code quality notes:

  • PRICE_PRECISION = 100_000_000 is defined at the top but only used inside jingswap_v2_get_clearing_preview. The other conversions use 1e16 and 1e8 directly — worth being consistent (either use the constant everywhere or remove it).
  • jingswapGet returns any — the callers immediately destructure API responses without null checks (pyth.stxUsd.price, data.phase). A thin typed interface per endpoint would surface shape mismatches at call sites rather than at runtime.

Operational context: We've had our aibtc-agent-trading sensor calling the same faktory-dao-backend and hit 401s when the API started requiring a key. Adding key support to the MCP tools is the right call — just via env var only, not as a hardcoded default.

azagh72-creator added a commit to azagh72-creator/aibtc-mcp-server that referenced this pull request Apr 17, 2026
Implements Jingswap V2 2-phase atomic settlement system before
upstream PR aibtcdev#464 merges — establishes Flying Whale prior art.

New tools: jingswap_v2_get_cycle_state, jingswap_v2_get_user_deposit,
jingswap_v2_get_clearing_preview, jingswap_v2_get_prices,
jingswap_v2_deposit_stx, jingswap_v2_deposit_sbtc,
jingswap_v2_set_stx_limit, jingswap_v2_set_sbtc_limit,
jingswap_v2_cancel_stx, jingswap_v2_cancel_sbtc,
jingswap_v2_close_and_settle_with_refresh, jingswap_v2_cancel_cycle

V2 improvements over V1: 2-phase (no buffer), 20s deposit window
vs 5min, mandatory limit prices, atomic close+settle in single tx.
Smart limit auto-defaults (±20% of oracle price).

COPYRIGHT 2026 Flying Whale — zaghmout.btc | ERC-8004 aibtcdev#54
IP hash: 5756b1ca74b146158a07cc9594fc989ddaf5cc4379ac717b4a4cb22cfe583496
To register: call whale-ip-store-v1.register-ip after MCP restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@whoabuddy
Copy link
Copy Markdown
Contributor

@Rapha-btc — 17 days since @arc0btc's CHANGES_REQUESTED review on commit fba4880 (one specific blocking concern). The bulk of the work is solid — 12 new jingswap_v2_* tools, clean atomic close-and-settle design — but it can't merge until the blocking item is addressed.

If you have follow-up planned, no rush. If direction has shifted or you'd rather close this, that's also fine. Just flagging as part of Wave 2 cleanup — wanted to make sure it wasn't sitting forgotten.

— Wave 2 sprint cleanup (Claude Opus 4.7)

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.

3 participants