Skip to content

feat(deposit): auto-clear Binance travel-rule frozen deposits (0.2.17) - #53

Merged
outerlook merged 2 commits into
developfrom
feat/binance-travel-rule-deposit
Jul 2, 2026
Merged

feat(deposit): auto-clear Binance travel-rule frozen deposits (0.2.17)#53
outerlook merged 2 commits into
developfrom
feat/binance-travel-rule-deposit

Conversation

@outerlook

@outerlook outerlook commented Jul 1, 2026

Copy link
Copy Markdown
Member

Why

AUSTRAC's travel rule (live 2026-07-01) freezes inbound Binance deposits too: the deposit is credited but held in getUserAsset.freeze — invisible to the free+locked balances that FetchBalances, the maker, HB lanes, and diagnostics read, so the capital looks gone. The maker's funding churn (master-withdraw → owner wallet → sub-redeposit) re-freezes capital every cycle. The withdraw leg was solved in v0.2.15/v0.2.16 (#51, #52); this adds the deposit counterpart.

What

A broker-internal origin-proved reconciler that auto-answers the deposit questionnaire so churn-frozen capital self-releases within minutes — policy-driven and fail-closed.

  • Polls GET /sapi/v1/localentity/deposit/history for requireQuestionnaire && travelRuleStatusV2=PENDING, and submits PUT /sapi/v1/localentity/deposit/provide-info only when a deposit's on-chain sender (eth_getTransactionByHash().from, via a configured RPC) is a policy-declared originator.
  • Compliance invariant: undeclared origin, unresolvable sender, non-AU entity, and FAILED status all fail closed (skip + surface) — it never attests an origin it cannot prove is ours.
  • reconcileAccountOnce is a pure core with all I/O injected, so these invariants are unit-tested without a network.

Changes

  • src/helpers/travel-rule.tsaustraliaDepositQuestionnaireSchema (self-owned only; distinct shape from the withdraw questionnaire — depositOriginator/receiveFrom vs isAddressOwner/sendTo — so a copy-paste fails at policy-load), getEnabledTravelRuleDepositConfig, resolveDepositOriginatorQuestionnaire, registerBinanceTravelRuleDepositEndpoints.
  • src/helpers/travel-rule-deposit-reconciler.ts (new) — reconciler + on-chain origin proof + env config. Idempotent by tranId, per-tranId backoff (no hot-loop on content errors), account-wide rate-limit cooldown, active 60s / idle 600s cadence, AU entity gate via questionnaire-requirements.
  • ccxt patch extended: localentity/deposit/provide-info signs the questionnaire raw (else -1022), mirroring the withdraw fix. Guarded by a real-ccxt regression test.
  • Wired into applyCommonExchangeConfig (endpoint registration) and CEXBroker.run()/stop() (lifecycle; restarts on policy hot-reload). Self-disables when no policy has travelRule.rule[].deposits.enabled → byte-identical current behavior.
  • Observability: travel_rule_frozen_deposits gauge + travel_rule_deposit_submissions_total / travel_rule_deposit_anomalies_total counters; every submission audit-logged. Chose metrics over changing the FetchBalances gRPC contract.
  • Bump to 0.2.17; document TRAVEL_RULE_RPC_URL_<NETWORK> in .env.sample.

Deploy note

TRAVEL_RULE_RPC_URL_ARBITRUM is deliberately not CEX_BROKER_-prefixed (the credential scan skips it), so under SGX it must be added to the Gramine manifest passthrough allowlist — done on the fiet-maker side.

Tests

bun test327 pass, 0 fail. New deposit-signing regression guards the ccxt patch across version bumps; existing withdraw regression still green. tsc --noEmit clean.

Summary by CodeRabbit

  • New Features

    • Added travel-rule deposit auto-clear handling for Binance localentity deposits, including questionnaire-based submission.
    • Added configuration guidance for per-network RPC URLs, polling/idle timing overrides, and optional questionnaire country override.
    • Enabled separate deposit-side travel-rule settings from existing withdraw-side configuration.
  • Bug Fixes

    • Improved fail-closed behavior for frozen deposits when deposit provenance, originator declaration, or required configuration is missing.
    • Added stricter startup validation for deposit questionnaire/config shape to prevent incorrect provisioning.

AUSTRAC's travel rule (live 2026-07-01) also freezes INBOUND Binance
deposits — credited but held in getUserAsset.freeze, invisible to
free+locked balances — until a per-deposit questionnaire is answered.
The maker's funding churn re-freezes capital every cycle. This adds the
deposit counterpart to the already-shipped withdraw leg.

A broker-internal reconciler polls localentity/deposit/history and submits
PUT localentity/deposit/provide-info ONLY for deposits whose on-chain
sender (eth_getTransactionByHash().from, via a configured RPC) is a
policy-declared originator. Undeclared origin, unresolvable sender, non-AU
entity and FAILED status all fail closed (skip + surface), never
auto-attesting an origin we cannot prove is ours. The core
(reconcileAccountOnce) takes injected I/O so these invariants are
unit-tested without a network.

- travel-rule.ts: australiaDepositQuestionnaireSchema (self-owned only;
  distinct shape from the withdraw questionnaire so a copy-paste fails at
  policy-load), getEnabledTravelRuleDepositConfig,
  resolveDepositOriginatorQuestionnaire, registerBinanceTravelRuleDepositEndpoints.
- travel-rule-deposit-reconciler.ts (new): reconciler + on-chain origin
  proof + env config. Idempotent by tranId, per-tranId backoff (no
  hot-loop), account-wide rate-limit cooldown, active/idle cadence, AU
  entity gate. Metrics: frozen gauge + submissions/anomalies counters;
  every submission audit-logged.
- ccxt patch: sign localentity/deposit/provide-info raw (else -1022),
  mirroring the withdraw fix; guarded by a real-ccxt regression test.
- Wired into applyCommonExchangeConfig (endpoints) and CEXBroker
  run()/stop() (lifecycle, restarts on policy hot-reload). Self-disables
  when no policy has travelRule.rule[].deposits.enabled.
- Bump to 0.2.17; document TRAVEL_RULE_RPC_URL_<NETWORK> in .env.sample.
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ed6d830-7148-46fd-ba43-f9e7541b9b81

📥 Commits

Reviewing files that changed from the base of the PR and between 188f235 and 0d66a06.

📒 Files selected for processing (3)
  • src/helpers/travel-rule-deposit-reconciler.ts
  • src/helpers/travel-rule.ts
  • test/travel-rule-deposit.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/helpers/travel-rule.ts
  • src/helpers/travel-rule-deposit-reconciler.ts
  • test/travel-rule-deposit.test.ts

Walkthrough

Adds Binance travel-rule deposit support: new deposit types and policy validation, Binance endpoint wiring, a polling reconciler that clears frozen deposits after on-chain and questionnaire checks, broker lifecycle integration, ccxt patch updates, docs, version bump, and tests.

Changes

Travel-rule deposit reconciliation feature

Layer / File(s) Summary
Deposit config types and policy schema
src/types.ts, src/helpers/index.ts, src/helpers/travel-rule.ts, src/helpers/broker.ts
Adds deposit questionnaire/config types, extends travel-rule policy validation for deposits, and wires deposit endpoint registration into broker setup.
Reconciler parsing, sender resolution, and core loop
src/helpers/travel-rule-deposit-reconciler.ts
Adds deposit parsing, on-chain sender resolution, reconciliation state, one-shot account reconciliation, and env-based reconciler config loading.
Broker lifecycle wiring for the reconciler
src/index.ts
Starts and stops the deposit reconciler with broker lifecycle and hot-reload handling.
ccxt Binance patch for localentity paths
patches/@usherlabs%2Fccxt@0.0.14.patch
Expands Binance request-path matching for the deposit provide-info route in both bundled builds and adds Bun marker files.
Env documentation and version bump
.env.sample, package.json
Documents the new reconciler environment variables and bumps the package version.
Deposit reconciler and schema test suite
test/travel-rule-deposit.test.ts
Adds coverage for schema validation, config resolution, endpoint registration, policy loading, parsing, sender resolution, env config loading, and reconciliation behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CEXBroker
  participant TravelRuleDepositReconciler
  participant Binance API
  participant On-chain RPC

  CEXBroker->>TravelRuleDepositReconciler: start()
  TravelRuleDepositReconciler->>Binance API: fetch localentity/deposit/history
  TravelRuleDepositReconciler->>On-chain RPC: eth_getTransactionByHash(txHash)
  On-chain RPC-->>TravelRuleDepositReconciler: sender address or null
  TravelRuleDepositReconciler->>Binance API: submit localentity/deposit/provide-info
  CEXBroker->>TravelRuleDepositReconciler: stop()
Loading

Possibly related PRs

  • usherlabs/cex-broker#24: Shares the broker-side OTEL metrics wiring used by the reconciler lifecycle in src/index.ts.
  • usherlabs/cex-broker#51: Touches the same Binance travel-rule helper and policy integration points, but for withdraw-side flows.
  • usherlabs/cex-broker#52: Updates the same patched ccxt Binance path-handling logic for travel-rule request signing.

Poem

A bunny hops where frozen deposits gleam,
Checking each sender like a careful stream. 🐰
If clues align, the rabbit gives a nod,
And quietly clears the frost with a code-paved rod.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: auto-clearing Binance travel-rule frozen deposits in version 0.2.17.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/binance-travel-rule-deposit

Comment @coderabbitai help to get the list of available commands.

@outerlook
outerlook marked this pull request as ready for review July 1, 2026 21:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/index.ts (1)

258-276: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Shutdown ordering can race an in-flight reconciler tick against otelMetrics.close().

depositReconciler.stop() is fire-and-forget and, per its implementation, only clears the timer/flag — it does not wait for a currently in-flight #tick() to finish:

stop(): void {
    this.#stopped = true;
    if (this.#timer) {
        clearTimeout(this.#timer);
        this.#timer = null;
    }
}

If stop() (in CEXBroker.stop(), lines 263-266) is called while a tick is awaiting fetchDepositHistory/resolveSender/submitProvideInfo, that tick keeps running to completion and still calls #emit(), which does void metrics?.recordGauge(...)/recordCounter(...) — right after this.otelMetrics.close() has already run a few lines later (line 270-272). If the OTel exporter throws/rejects post-close, the void-discarded promise becomes an unhandled rejection, and on Node 15+ the default behavior is to terminate the process with a non-zero exit code — turning a graceful shutdown into a crash. The same overlap window exists more briefly in run()'s hot-reload teardown (lines 285-290), though without the close() step it's lower risk there (just a possible double metrics emission during the handoff).

A minimal mitigation is to make the reconciler's stop() return a promise that resolves once any in-flight tick settles, and await it before closing metrics:

🔧 Proposed fix
 	public async stop(): Promise<void> {
 		if (this.#policyFilePath) {
 			unwatchFile(this.#policyFilePath);
 			log.info(`Stopped watching policy file: ${this.#policyFilePath}`);
 		}
 		if (this.depositReconciler) {
-			this.depositReconciler.stop();
+			await this.depositReconciler.stop();
 			this.depositReconciler = undefined;
 		}
 		if (this.server) {
 			await this.server.forceShutdown();
 		}

This requires TravelRuleDepositReconciler.stop() (in src/helpers/travel-rule-deposit-reconciler.ts, not in this cohort's files) to become async and await its own in-flight tick promise before returning.

Also applies to: 285-290, 318-328

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 258 - 276, The shutdown flow in CEXBroker.stop()
can close otelMetrics while an in-flight TravelRuleDepositReconciler tick is
still emitting metrics, so update the reconciler lifecycle to wait for any
active tick to settle before proceeding. Make depositReconciler.stop() async (or
otherwise await its in-flight work) and change CEXBroker.stop() to await that
stop before calling otelMetrics.close() and otelLogs.close(); use the existing
symbols depositReconciler.stop(), CEXBroker.stop(), and
TravelRuleDepositReconciler.#tick/#emit to locate the change.
🧹 Nitpick comments (2)
src/helpers/travel-rule.ts (1)

171-185: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate entry-lookup logic vs resolveTravelRuleDecision.

This re-implements the same "find TravelRuleEntry by uppercased exchange name" logic already in resolveTravelRuleDecision (lines 96-100). Extracting a shared findTravelRuleEntry(policy, exchange) helper would remove the duplication and keep both lookups in sync if the matching semantics ever change.

♻️ Proposed refactor
+function findTravelRuleEntry(
+	policy: PolicyConfig,
+	exchange: string,
+): TravelRuleEntry | undefined {
+	const rules = policy.travelRule?.rule ?? [];
+	const exchangeNorm = exchange.trim().toUpperCase();
+	return rules.find((rule) => rule.exchange.trim().toUpperCase() === exchangeNorm);
+}
+
 export function getEnabledTravelRuleDepositConfig(
 	policy: PolicyConfig,
 	exchange: string,
 ): TravelRuleDepositConfig | null {
-	const rules = policy.travelRule?.rule ?? [];
-	const exchangeNorm = exchange.trim().toUpperCase();
-	const entry = rules.find(
-		(rule) => rule.exchange.trim().toUpperCase() === exchangeNorm,
-	);
+	const entry = findTravelRuleEntry(policy, exchange);
 	const deposits = entry?.deposits;
 	if (!deposits || !deposits.enabled) {
 		return null;
 	}
 	return deposits;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/helpers/travel-rule.ts` around lines 171 - 185, The exchange-entry lookup
in getEnabledTravelRuleDepositConfig duplicates the same matching logic already
used by resolveTravelRuleDecision. Extract a shared helper such as
findTravelRuleEntry(policy, exchange) in travel-rule.ts that normalizes and
finds the matching TravelRuleEntry, then reuse it in both
resolveTravelRuleDecision and getEnabledTravelRuleDepositConfig so the matching
behavior stays consistent.
test/travel-rule-deposit.test.ts (1)

1-536: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Good coverage of the pure helpers; scheduling class and #emit metrics/log mapping are untested.

The suite thoroughly covers australiaDepositQuestionnaireSchema, getEnabledTravelRuleDepositConfig, resolveDepositOriginatorQuestionnaire, registerBinanceTravelRuleDepositEndpoints, parseLocalEntityDeposit, resolveOnChainSender, loadTravelRuleDepositReconcilerConfigFromEnv, and the compliance-critical reconcileAccountOnce — all consistent with the upstream contracts (e.g. australiaDepositQuestionnaireSchema restricting depositOriginator/receiveFrom to 1, getEnabledTravelRuleDepositConfig's enabled-gating). There's no coverage, however, for TravelRuleDepositReconciler itself: hasEnabledExchange, #targets() (per-account fan-out including secondary brokers), the active/idle poll cadence switch in #tick(), or #emit()'s mapping from outcome kind to log level/metric name/tags. The #emit mapping in particular is the audit-log/metrics contract this PR's objectives call out ("Metrics and audit logging for frozen deposits and submissions") — a bug there (wrong metric name, missing tag, wrong log level for undeclared-origin vs submitted) wouldn't be caught by any current test. Given metrics and log are easy to stub, adding a few targeted tests around #emit (or exposing it for testing) would close this gap.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/travel-rule-deposit.test.ts` around lines 1 - 536, Add targeted tests
for TravelRuleDepositReconciler because the suite currently covers only the pure
helpers and reconcileAccountOnce, leaving hasEnabledExchange, `#targets`(),
`#tick`(), and especially `#emit`() unverified. Stub the metrics and log
dependencies and assert that `#emit` maps each outcome kind to the correct metric
name, tags, and log level, and add a couple of tests for the active/idle cadence
in `#tick`() plus per-account fan-out from `#targets`() using the
TravelRuleDepositReconciler class.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/helpers/travel-rule-deposit-reconciler.ts`:
- Around line 58-67: The `parseLocalEntityDeposit` helper is incorrectly
accepting `id` as a fallback for provide-info tranIds, which can map to the
wrong Binance id space. Update `parseLocalEntityDeposit` to only read the
provide-info identifier from `tranId` (and keep the null return when it is
missing), removing the `id` fallback from the `depositField` lookup while
preserving the existing `trId`/tranId handling if needed for that flow.
- Around line 355-411: The candidate-processing loop in
travel-rule-deposit-reconciler should stop once a rate-limit is detected so the
same tick does not keep hammering Binance/RPC. Update the logic around
resolveSender and submitProvideInfo in the candidate iteration to break or
return immediately after isRateLimitError sets state.rateLimitedUntil, while
preserving the existing backoff, submittedTranIds, and outcome handling for
non-rate-limit cases.
- Around line 111-120: The RPC call inside resolveOnChainSender currently has no
timeout, so a stalled fetch can block the reconciler tick. Update the fetch to
use an AbortController-based timeout (or equivalent) around the
eth_getTransactionByHash request, and ensure the timeout is cleared/aborted
after the request completes. Keep the change localized to resolveOnChainSender
in travel-rule-deposit-reconciler.ts so the existing polling flow can recover if
the RPC hangs.

In `@src/helpers/travel-rule.ts`:
- Around line 220-232: The `defineRestApi` mapping for
`localentity/deposit/provide-info` is using an incorrect request cost of `1`
instead of the UID-600 weight expected by Binance docs and the sibling
`localentity/withdraw/apply` endpoint. Update the `sapi.put` registration in
`travel-rule.ts` so `localentity/deposit/provide-info` uses the same cost value
as `localentity/withdraw/apply` (`4.0002`), keeping the rest of the API
registration unchanged.

---

Outside diff comments:
In `@src/index.ts`:
- Around line 258-276: The shutdown flow in CEXBroker.stop() can close
otelMetrics while an in-flight TravelRuleDepositReconciler tick is still
emitting metrics, so update the reconciler lifecycle to wait for any active tick
to settle before proceeding. Make depositReconciler.stop() async (or otherwise
await its in-flight work) and change CEXBroker.stop() to await that stop before
calling otelMetrics.close() and otelLogs.close(); use the existing symbols
depositReconciler.stop(), CEXBroker.stop(), and
TravelRuleDepositReconciler.#tick/#emit to locate the change.

---

Nitpick comments:
In `@src/helpers/travel-rule.ts`:
- Around line 171-185: The exchange-entry lookup in
getEnabledTravelRuleDepositConfig duplicates the same matching logic already
used by resolveTravelRuleDecision. Extract a shared helper such as
findTravelRuleEntry(policy, exchange) in travel-rule.ts that normalizes and
finds the matching TravelRuleEntry, then reuse it in both
resolveTravelRuleDecision and getEnabledTravelRuleDepositConfig so the matching
behavior stays consistent.

In `@test/travel-rule-deposit.test.ts`:
- Around line 1-536: Add targeted tests for TravelRuleDepositReconciler because
the suite currently covers only the pure helpers and reconcileAccountOnce,
leaving hasEnabledExchange, `#targets`(), `#tick`(), and especially `#emit`()
unverified. Stub the metrics and log dependencies and assert that `#emit` maps
each outcome kind to the correct metric name, tags, and log level, and add a
couple of tests for the active/idle cadence in `#tick`() plus per-account fan-out
from `#targets`() using the TravelRuleDepositReconciler class.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e60e0972-843c-4bb0-8d75-b33a9a4dfac1

📥 Commits

Reviewing files that changed from the base of the PR and between 5279fc7 and 188f235.

📒 Files selected for processing (10)
  • .env.sample
  • package.json
  • patches/@usherlabs%2Fccxt@0.0.14.patch
  • src/helpers/broker.ts
  • src/helpers/index.ts
  • src/helpers/travel-rule-deposit-reconciler.ts
  • src/helpers/travel-rule.ts
  • src/index.ts
  • src/types.ts
  • test/travel-rule-deposit.test.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-04-14T06:47:01.283Z
Learnt from: csmithington
Repo: usherlabs/cex-broker PR: 38
File: src/client.dev.ts:0-0
Timestamp: 2026-04-14T06:47:01.283Z
Learning: In this codebase, gRPC action constants such as `FetchTicker`, `FetchFees`, and `FetchAccountId` should be sourced from `src/helpers/constants.ts` and imported from there (e.g., used by both `src/client.dev.ts` and `src/server.ts`). Do not import or reference generated proto TypeScript artifacts (for example `./proto/cex_broker/Action`), since those generated files are git-ignored and won’t be available/committed consistently.

Applied to files:

  • src/helpers/broker.ts
  • src/types.ts
  • src/helpers/index.ts
  • src/index.ts
  • src/helpers/travel-rule.ts
  • src/helpers/travel-rule-deposit-reconciler.ts
🪛 ast-grep (0.44.0)
test/travel-rule-deposit.test.ts

[warning] 217-217: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFileSync(tempPath, JSON.stringify(policy))
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)

🪛 dotenv-linter (4.0.0)
.env.sample

[warning] 31-31: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🔇 Additional comments (10)
.env.sample (1)

19-31: LGTM!

package.json (1)

3-3: LGTM!

patches/@usherlabs%2Fccxt@0.0.14.patch (1)

1-29: LGTM!

src/helpers/travel-rule-deposit-reconciler.ts (1)

51-56: LGTM!

Also applies to: 141-184, 190-262, 426-500, 506-589, 591-609, 611-689, 691-835

src/types.ts (1)

51-97: LGTM!

src/helpers/index.ts (1)

17-20: LGTM!

Also applies to: 37-51, 112-126

src/helpers/travel-rule.ts (1)

3-8: LGTM!

Also applies to: 138-219

src/helpers/broker.ts (1)

7-10: LGTM!

Also applies to: 58-63

src/index.ts (1)

9-11: LGTM!

Also applies to: 49-49, 318-328

test/travel-rule-deposit.test.ts (1)

1-249: LGTM!

Also applies to: 299-536

Comment thread src/helpers/travel-rule-deposit-reconciler.ts
Comment thread src/helpers/travel-rule-deposit-reconciler.ts Outdated
Comment thread src/helpers/travel-rule-deposit-reconciler.ts
Comment thread src/helpers/travel-rule.ts
…limit break, provide-info weight

- parseLocalEntityDeposit: accept only `tranId`, drop the `id`/`trId`
  fallback. `id` is the capital/deposit/hisrec id space and provide-info
  rejects it ("Deposit request not found"); tranId is the sole valid id.
- resolveOnChainSender: bound the fetch with a 10s AbortController timeout
  so a hung RPC can't stall the reconciler tick (candidates resolve
  sequentially → a hang blocks the next poll).
- reconcileAccountOnce: break the candidate loop once a rate-limit signal
  sets the account-wide cooldown, instead of compounding the -1003 across
  the remaining candidates.
- registerBinanceTravelRuleDepositEndpoints: provide-info is a 600-weight
  UID write; declare its ccxt cost as 4.0002 (same as capital/withdraw/apply)
  instead of 1, which under-throttles the write path.

Adds regression tests for the tranId-only parse and the mid-loop
rate-limit break. Full suite: 329 pass.
@outerlook
outerlook merged commit c1fc3cb into develop Jul 2, 2026
5 checks passed
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.

1 participant