feat(relayer): xreserve adapter — USDCx inbound tracking - #374
Open
sadiq1971 wants to merge 5 commits into
Open
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feat/bridge-foundation #374 +/- ##
==========================================================
+ Coverage 34.91% 35.52% +0.60%
==========================================================
Files 167 170 +3
Lines 13004 13288 +284
==========================================================
+ Hits 4540 4720 +180
- Misses 8098 8187 +89
- Partials 366 381 +15
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
sadiq1971
force-pushed
the
feat/xreserve-inbound
branch
2 times, most recently
from
July 27, 2026 11:53
b6ad2bd to
dac0db3
Compare
First adapter on the TokenBridge foundation (#357). Observer mechanism: Circle executes the bridge, so Sources() is empty and Step only tracks progress - transfers are registered at initiation via the relayer API. - bridges/xreserve: deposit stage machine '' -> awaiting_attestation -> awaiting_mint -> completed(minted). Mint detection is balance-based against a baseline snapshotted on the first step (before Ethereum finality). Transient attestation-service failures keep polling instead of burning transfer retries. - circle.go: attestation HTTP client (path/schema pinned to the devstack stub; Circle production schema tracked in #360) - service: POST /api/v1/transfers registers observer-mechanism transfers (idempotent, validated against registered bridge keys) - config: per-token xreserve block (attestation_url, instrument_admin, instrument_id, poll intervals) - wiring: xreserve case in buildBridgeRegistry Note: relayer's Canton token must carry read rights over user parties (CanReadAsAnyParty) for holding detection, as the indexer already requires.
- reject non-positive amounts at registration (was: amount=0/-N completes a transfer instantly with no mint, fabricating a success record) - idempotent replay only for the same owner: a conflicting bridge_key or sender returns 409 instead of disclosing the foreign row (IDOR) - bearer-token guard on the internal registration endpoint (env RELAYER_REGISTRATION_TOKEN); compose binds the relayer API to loopback so it is not host-exposed - deposits that never mint are failed after a completion deadline instead of polling forever and holding step-loop batch slots - treat 429/408 (and 5xx) attestation responses as transient (keep polling) so a rate-limited but healthy deposit is not force-failed - document the balance-delta detection limitation (concurrent same- recipient deposits / unrelated credits) as gated on #360 mint-event data
sadiq1971
force-pushed
the
feat/xreserve-inbound
branch
from
July 27, 2026 12:29
dac0db3 to
864d5ff
Compare
sadiq1971
marked this pull request as ready for review
July 29, 2026 09:50
The bridge.tokens schema landed but the shipped configs never used it. Add a USDCx xreserve token to the docker + local-devnet relayer configs (devstack stub host / Sepolia addresses); mainnet stays disabled pending #360.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #357 and epic #361. Stacked on #373 (TokenBridge foundation) — review the last commit only until #373 merges.
What
The first
TokenBridgeadapter:bridges/xreservetracks USDCx deposits (Ethereum USDC → Canton USDCx via Circle xReserve), plus the relayer registration endpoint observer mechanisms need.Design
xreserve is an observer mechanism — Circle executes the bridge, we are never in the critical path:
Sources()returns nothing; transfers are registered at initiation via the new internalPOST /api/v1/transfers(called by the api-server when the dapp submitsdepositToRemote; feat(api): bridge API — deposit quotes, registration, unified status #358 adds that caller). Registration is idempotent and rejects bridge keys no adapter owns.Stepstage machine:"" → awaiting_attestation → awaiting_mint → completed(stageminted).token.Token.GetHoldingsByParty, the Splice HoldingV1 interface query) — before Ethereum finality, so before any mint for this deposit can exist.BridgeUserAgreement, never by us. Relayer downtime cannot affect bridging, only status display.Config
Notes / caveats for review
CanReadAsAnyParty, same as the indexer). Devnet config change, called out in the deploy notes.Remaining on #357 (follow-ups, not this PR)
BridgeUserAgreementonboarding w/ pre-approval at user registration (shares the DA Utilities burn-mint-factory plumbing with feat: USDCx outbound — burn via BridgeUserAgreement + release tracking #359)Testing
golangci-lintclean; existing tests pass