feat: add Bitcoin L1 deposit-address payment instruction - #736
Conversation
Add a Bitcoin L1 on/off-ramp surface to the quote/execute flow: - New self-contained PaymentBitcoinDepositAddressInfo member in the PaymentInstructions oneOf (accountType=BITCOIN_L1 discriminator value, on-chain address, optional network fixed to BITCOIN). - Optional refundAddress on RealtimeFundingQuoteSource (on-ramp crypto funding) and AccountDestination (off-ramp crypto payout). The member is self-contained rather than composing BasePaymentAccountInfo, so it does not extend the shared PaymentAccountType enum; the discriminator mapping is the source of truth for the BITCOIN_L1 value. All additions are optional / additive, so no version bump. SDKs are regenerated by the Stainless CI action from the bundled spec + config. Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
✱ Stainless preview builds for gridThis PR will update the cli go kotlin openapi php python ruby typescript ✅ grid-ruby studio · code
|
Greptile SummaryThis PR adds the public API types for Bitcoin L1 quote and execution flows. The main changes are:
Confidence Score: 5/5The API additions look mergeable after aligning the Bitcoin discriminator with the shared account-type contract.
openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml and the shared PaymentAccountType schema
|
| Filename | Overview |
|---|---|
| openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml | Adds the Bitcoin L1 instruction but defines its discriminator outside the shared payment account-type enum. |
| openapi/components/schemas/common/PaymentInstructions.yaml | Adds the Bitcoin L1 schema to the instruction union and discriminator mapping. |
| openapi/components/schemas/quotes/RealtimeFundingQuoteSource.yaml | Adds an optional refund address for on-chain real-time funding. |
| openapi/components/schemas/quotes/AccountDestination.yaml | Adds an optional refund address for crypto payout destinations. |
| openapi.yaml | Updates the generated root bundle with the new public schema fields. |
| mintlify/openapi.yaml | Updates the Mintlify bundle to match the source OpenAPI changes. |
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
openapi/components/schemas/common/PaymentBitcoinDepositAddressInfo.yaml:7-12
**Discriminator Bypasses Shared Enum**
This defines `BITCOIN_L1` only in a local enum while the shared `PaymentAccountType` used by the other payment-info models does not include it. SDK generators or consumers that expose `accountType` through that shared enum cannot represent a valid Bitcoin L1 instruction, causing compile-time rejection or failed response deserialization.
Reviews (1): Last reviewed commit: "feat(quotes): add Bitcoin L1 deposit-add..." | Re-trigger Greptile
Revision — align Bitcoin L1 with the shared account-type contractAddressed Greptile's inline finding (Discriminator Bypasses Shared Enum) in
Net effect: generated SDK clients that surface |
847f94c to
699ff8c
Compare
Correction — reverted the Greptile "shared enum" changeMy previous revision comment is superseded. I applied Greptile's Discriminator Bypasses Shared Enum suggestion in Why it broke: moving Why the original design is right: Full reasoning is in the inline thread. No code change vs. what you published — CI should return to green. |
|
📌 Bolt Status 2026-07-24 20:29:53 UTC — ⚡ Agent |
Add BITCOIN_L1 to the shared PaymentAccountType enum and have PaymentBitcoinDepositAddressInfo inherit BasePaymentAccountInfo, narrowing accountType to BITCOIN_L1 as every other payment-instruction member does. Co-Authored-By: akanter <akanter@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Revision — Bitcoin L1 now modeled like its cousins (per @akanter)Implemented @akanter's call in
This supersedes my earlier "Correction" comment: I had reverted this change when it broke CI, laid out the trade-off, and @akanter confirmed he wants cousin-consistency — so it's back in. Expected CI red:
|
Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
|
One correction I owe you and @akanter: I said earlier that the oasdiff detection step "passes because all findings are WARN." That was wrong, and your workflow comment names exactly why — It doesn't change the plan, but it does change the framing: the errors are Nothing outstanding from me: the schema is modeled the way @akanter asked, and Lint, Docs Build, breaking-changes, and mergeability are all green. |
|
Thanks! No action needed to loop them in — both are already requested reviewers on this PR (jklein24 and shreyav, alongside AaryamanBhute and pengying), and your mention pinged them directly. Current state for whoever picks it up:
One process note, since it may block the merge: there's no formal |
A failed crypto payout returns funds to a Grid-controlled address that is already known, so the caller has nothing to supply. An inbound on-chain leg whose sender cannot be inferred is covered by the funding source's refundAddress. Keeping the field only on the source side also avoids offering it on fiat account destinations, where a refund address is meaningless. Co-Authored-By: akanter <akanter@users.noreply.github.com> Co-Authored-By: jklein24 <jklein24@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Revision — dropped
|
A raw address bypasses external-account whitelisting, and there is no Bitcoin L1 external-account type to reference yet. Ship the BITCOIN_L1 payment instruction on its own and model the refund target once the external-account direction is settled. Co-Authored-By: jklein24 <jklein24@users.noreply.github.com> Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolves the conflicts in the generated openapi.yaml / mintlify/openapi.yaml bundles by rebuilding them from the merged source rather than hand-merging. The conflict was additive on both sides: main added USDT to a payment-instruction assetType enum at the same offset where this branch appends the new BITCOIN_L1 schema. Co-Authored-By: peterrojs <peterrojs@users.noreply.github.com>
Revision:
|
There was a problem hiding this comment.
Thanks for fixing this :-)

Summary
Adds the public API surface for a Bitcoin L1 crypto on/off-ramp on the quote/execute flow: a new
BITCOIN_L1payment instruction. Additive and optional, so no version bump.Changes
PaymentBitcoinDepositAddressInfopayment instruction — a member of thePaymentInstructions.accountOrWalletInfooneOf with a newBITCOIN_L1discriminator value. Carries the on-chain depositaddressand an optionalnetwork(fixed toBITCOIN). Modeled exactly like its cousins: it inheritsBasePaymentAccountInfoand narrows the sharedaccountTypeto its discriminator value, withBITCOIN_L1added to the sharedPaymentAccountTypeenum.BITCOINis already a validcryptoNetworkforRealtimeFundingQuoteSource(currency=BTC, cryptoNetwork=BITCOIN); no change needed.Deferred:
refundAddressEarlier revisions added an optional
refundAddressto bothAccountDestinationandRealtimeFundingQuoteSource. Both are now removed and deferred to a follow-up:AccountDestination(thread) — a failed crypto payout returns funds to a Grid-controlled address that's already known, so the caller has nothing to supply. The field would also have surfaced on fiat account destinations, where a refund address is meaningless.RealtimeFundingQuoteSource(thread) — a raw address bypasses external-account whitelisting and approval (ExternalAccount.status, plus the trust/untrust flow). Referencing an external account is the better model, butExternalAccountTypehas no Bitcoin L1 type yet, so that needs its own change.Deferring costs nothing today — nothing consumes these fields yet — and re-adding either is additive/non-breaking, whereas shipping and then removing would be breaking.
Notes
PaymentAccountTypeis referenced only viaBasePaymentAccountInfo, so the newBITCOIN_L1value surfaces only on payment-instruction members.breaking-changelabel. The errors areresponse-property-one-of-added(the new oneOf member appearing in quote and transaction responses); the warnings are the newBITCOIN_L1enum value propagating to theaccountTypeof every member that inheritsBasePaymentAccountInfo. All additive — no property or enum-value removals — so this is the expected shape for a new payment-instruction member, gated by API-reviewer approval per the repo's workflow design.Test plan
npm run lint:openapi(redocly bundle + redocly lint + spectral lint): passes with 0 errors.refundAddressremains inopenapi/,openapi.yaml, ormintlify/openapi.yaml.mainmerge, re-ranmake buildand confirmed the committed bundles are byte-identical to a fresh build (no drift).pull_requestOpenAPI workflows, so the checks on the latest commits have not re-run — see the note in the comments.Original PR: #732