Skip to content

feat(wallets): add self-custody support to blockchain wallets - #78

Merged
juninhopo merged 2 commits into
mainfrom
darlan/wallet-self-custody
Sep 30, 2026
Merged

juninhopo merged 2 commits into
mainfrom
darlan/wallet-self-custody

Conversation

@juninhopo

@juninhopo juninhopo commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Why

BCB Resolution 588 requires us to report to COAF any transfer of US$10k or more to or from a self-custodied wallet. To do that, we need to know, per external wallet, whether the customer holds the keys. This only applies to Brazilian customers and external blockchain wallets (custodial/offramp wallets are unaffected).

The backend side is in blindpaylabs/blindpay-v2#2632: https://github.com/blindpaylabs/blindpay-v2/pull/2632

Merge order: this PR must merge (and release) only after blindpay-v2#2632 is deployed. Until then the API ignores the new input and the PATCH route does not exist.

What changed

  • wallets.blockchain: wallet responses (list, get, createWithAddress, createWithHash) now include is_self_custody: boolean | null (null = never answered).
  • createWithAddress / createWithHash accept an optional is_self_custody: boolean. The API requires it when the customer's country is BR (400 self_custody_required).
  • New wallets.blockchain.setSelfCustody({ customer_id, id, is_self_custody }) → PATCH /v1/instances/{instance_id}/customers/{customer_id}/blockchain-wallets/{id}. It can be set only once, while the value is null; afterwards the API returns 409 self_custody_already_set. Returns the wallet.
  • New webhook event blockchainWallet.update in WebhookEvents (same payload as blockchainWallet.new).
  • .api-sync/contract-check-allowlist.json: 6 entries for is_self_custody, since the committed spec snapshot does not have the field yet. Remove them once api-sync refreshes the snapshot after v2#2632 ships.
  • Minor changeset.

Follow-up risk: /receivers/ → /customers/ redirect

The API renamed /receivers/ to /customers/, and /receivers/ now answers with a 301. With fetch, following a 301 on a POST can turn it into a GET, which silently breaks wallet creation. On current main this SDK already calls /customers/ everywhere, and setSelfCustody uses /customers/ too. Any integrator still on an older SDK major that calls /receivers/ is exposed to this and should upgrade. This PR does not change any existing paths.

Testing

  • bun run check-types: pass
  • bun run lint:check: pass (3 existing warnings, none new)
  • node scripts/contract-check.mjs: OK
  • bun scripts/api-sync/index.ts --check: OK, no drift
  • bun run test: all blockchain wallet and webhook tests pass. The new tests check the method, URL and body of the PATCH, and that is_self_custody is sent on create. 2 failures in scripts/api-sync (map.test.ts spec-map nested shape for PayinOut, plus the golden test that re-runs the suite) also fail on main before this change and are unrelated.

Unrelated CI fix

scripts/api-sync/map.test.ts was failing on main because the spec snapshot has tracking_payment.review_contexts on PayinOut/CreatePayinOut with no recorded omission. Second commit records it in .api-sync/unmodeled.json so the suite is green (183/183 locally).

Add is_self_custody to blockchain wallet responses and as an optional
input on createWithAddress/createWithHash, a setSelfCustody method
(PATCH on the customers route), and the blockchainWallet.update webhook
event.
@BernardoSM

BernardoSM commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

…odeled

The spec snapshot already carries this nested shape and map.test.ts has been
failing on main because of it.
@juninhopo
juninhopo merged commit a7f757b into main Sep 30, 2026
11 checks passed
@juninhopo
juninhopo deleted the darlan/wallet-self-custody branch September 30, 2026 21:40
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