feat: outbound transfer authorization#348
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements outbound authorization policies and recipient validation guards for the transfer service. Specifically, transfers addressed by raw party ID now require the sender's EVM address to be whitelisted, and transfers to the issuer/bridge-operator party or self-transfers are rejected to prevent supply accounting corruption. The review feedback suggests adding a nil guard check for the whitelist checker in checkSenderWhitelisted to prevent potential runtime panics if the service is misconfigured or initialized without it.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #348 +/- ##
=======================================
Coverage ? 32.09%
=======================================
Files ? 154
Lines ? 12270
Branches ? 0
=======================================
Hits ? 3938
Misses ? 8016
Partials ? 316
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Closes #318 (epic #321).
Policy (the three open questions)
to_party_id— non-custodialPOST /transfer/prepareand custodialPOST /transfer/custodial— requires the sender's EVM address to be whitelisted, reusing the samewhitelist.Checkerthat frontseth_sendRawTransaction. Party-id addressing can move value out to arbitrary external participants, so it gets the same gate as the inbound path. Checking at transfer time (registration is already gated) means removing an address from the whitelist immediately revokes its outbound capability. Transfers addressed by recipient EVM address stay between registered local users and are not gated.validateRecipient, shared by both handlers: syntactic party-id check, reject self-transfers, and reject the issuer party — which is also the bridge-operator party, sinceclient.propagateCommonConfigmaps both fromcanton.issuer_party. Sending user funds to the bridge escrow/mint-burn party would corrupt supply accounting.Changes
pkg/transfer/service.go:TransferServicenow takes awhitelist.Checkerand the issuer party id; newcheckSenderWhitelisted(403 on deny, 502 on checker failure) andvalidateRecipientguards wired intoPrepareandSendCustodial. Policy documented on the type.pkg/app/api/server.go: wires the existing shared whitelist service andcfg.Canton.IssuerPartyinto the transfer service.validateRecipienttable test.Note:
SendCustodialrecipient validation now runs after sender authentication (it needs the sender's party id for the self-check), so a malformed party id from an unknown sender now yields 401 rather than 400.