Repository navigation
docs(deposit-addresses): require a signing wallet for refundTo and recoveryAddress - #514
scout-relayprotocol[bot] wants to merge 4 commits into
Conversation
Integrators have set recoveryAddress to addresses they cannot sign with, such as a deposit address issued by another protocol. When the depositor is blocked, the recovered funds are credited on the Hub to recoveryAddress and only its signature can withdraw them, so those funds are stranded. - State that recoveryAddress must be a wallet the integrator controls and can sign with, and list the address types that do not qualify. - Document the blocked-depositor path: no fill, no refund, Hub credit to recoveryAddress when set, withdrawal by signature only. - Show how to read the credit with GET /withdrawals/balances using the recoveryAddress and ownerChainId parameters. - Add the same signing requirement to the withdrawals guide.
The withdrawals guide already supports Safe wallets through ERC-1271 contract signatures, so requiring recoveryAddress to sign with its own key was too strict, and the custodial exclusion conflicted with the custodian exception. Describe the requirement as a supported signature, EOA or ERC-1271, and keep the exceptions consistent on both pages.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
[Low impact] The PR appears safe to merge, with non-blocking corrections needed in the refund and balance guidance. Findings
|
| - **`recoveryAddress`**: the `recoveryAddress` you set on the quote. | ||
| - **`ownerChainId`**: the numeric Relay chain id of the origin chain, from `chains[].id` in the [chains API](/references/api/get-chains). | ||
|
|
||
| The response lists each credited balance with the raw `amount` and its `currency`. An empty `balances` array means that nothing is credited to that owner on that chain. To withdraw, follow the steps in [Programmatic Withdrawals](/references/protocol/guides/withdrawals#discover-credited-balances-optional) with `recoveryAddress` as the `owner`, or connect the wallet at [relay.link/withdraw](https://relay.link/withdraw). |
There was a problem hiding this comment.
An empty balances array does not prove that no funds are credited. The endpoint's docs say results are eventually consistent, so a newly credited deposit may not appear yet. This could lead integrators to tell users their recovery funds are missing. Qualify the statement and tell readers to retry before concluding that no credit exists.
| The response lists each credited balance with the raw `amount` and its `currency`. An empty `balances` array means that nothing is credited to that owner on that chain. To withdraw, follow the steps in [Programmatic Withdrawals](/references/protocol/guides/withdrawals#discover-credited-balances-optional) with `recoveryAddress` as the `owner`, or connect the wallet at [relay.link/withdraw](https://relay.link/withdraw). | |
| The response lists each credited balance with the raw `amount` and its `currency`. Balance discovery is eventually consistent, so an empty `balances` array may not yet reflect a newly credited deposit. Retry before concluding that no credit exists for that owner on that chain. To withdraw, follow the steps in [Programmatic Withdrawals](/references/protocol/guides/withdrawals#discover-credited-balances-optional) with `recoveryAddress` as the `owner`, or connect the wallet at [relay.link/withdraw](https://relay.link/withdraw). |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
…und after manual review Solver PR 14140 lets the recovery worker pay a recovered deposit to the protocol depositor, which is recoveryAddress when set. Replace the statements that said recoveryAddress never receives refunds and that only its signature can move the funds.
|
Claude finished @maxbayuk's task in 1m 14s —— View job Code review: PR #514
The direction is right, and the links and anchors resolve ( 1. An empty balance does not mean nothing is credited —
Three sources contradict this:
A reader who gets 2. "Must be able to sign" now conflicts with the manual-review path — After
3. The ERC-1271 wording promises more than the withdrawals guide supports —
4. Check that the manual-review payout is deployed — commit The commit message cites solver PR 14140. AGENTS.md §1.2 asks to "distinguish deployed platform routes from … future rollouts." Please confirm 14140 is merged and live before this merges. If it is not, the 5. Related pages left out of date
6. Style (AGENTS.md §2.10, 2–3 sentences per paragraph)
Not checked: |
…ndTo Relay records refundTo or recoveryAddress as the protocol depositor, so both must be wallets the integrator can sign with. Per Compliance.
|
Claude finished @maxbayuk's task in 1m 15s —— View job Code review: PR #514
The new commit 1. " The page tells readers to set
2. The requirement says "you", but the recommended setup uses the user's address — Recommended Setup ( 3. Which address is the protocol depositor is now inconsistent —
Please confirm the solver precedence and make 4. Still open from the previous review
5. Style (AGENTS.md §2.10, 2–3 sentences per paragraph)
Verified: Not checked: a |
| - **Open deposit addresses**: Set `refundTo` to the user's address for automatic refunds. | ||
| - **Strict deposit addresses**: Always set `refundTo`. If the sender is unknown (e.g., CEX withdrawal), use an app-controlled address so your support team can manage refunds. | ||
| - **Auto-refund to depositor**: When users deposit from wallets they control, you can pass `refundTo` as the origin chain's native-currency address (EVM `0x0000000000000000000000000000000000000000`, Bitcoin `bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8`, Solana `11111111111111111111111111111111`) to refund to the original depositor automatically. The first of the two resulting `outTxs` is the transfer to the depositor — track that one for refund delivery. Avoid this when deposits may originate from a centralized exchange, or pair it with a [`recoveryAddress`](#recoveryaddress) so funds Relay cannot safely auto-refund remain recoverable. | ||
| - **Auto-refund to depositor**: When users deposit from wallets they control, you can pass `refundTo` as the origin chain's native-currency address (EVM `0x0000000000000000000000000000000000000000`, Bitcoin `bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8`, Solana `11111111111111111111111111111111`) to refund to the original depositor automatically. The first of the two resulting `outTxs` is the transfer to the depositor. Track that one for refund delivery. Avoid this when deposits may originate from a centralized exchange, or pair it with a [`recoveryAddress`](#recoveryaddress) so funds Relay cannot safely auto-refund remain recoverable. Both `refundTo` and `recoveryAddress` must be wallets you can sign with. See [The wallet must be able to sign](#the-wallet-must-be-able-to-sign). |
There was a problem hiding this comment.
This bullet recommends the native-currency address for refundTo, then requires both refundTo and recoveryAddress to be wallets the integrator can sign with. The native-currency address is a special value, not a signing wallet, so both instructions cannot be followed. Integrators may replace supported automatic refunds with an unnecessary app-controlled refund address.
Exempt the native-currency value from the signing requirement and explain that withdrawals need the recorded depositor's signature. Also allow the user to sign when refundTo is their wallet.
Knowledge Base Used: Deposit-address workflows
What changed
refundToandrecoveryAddressmust both be origin-chain wallets the integrator controls and can authorize a withdrawal with: an EOA signature, or an ERC-1271 contract signature such as a Safe. Relay records one of them as the protocol depositor, and the depositor owns any funds that Relay cannot fill or refund. A new section lists the address types that do not qualify: exchange deposit addresses, deposit addresses issued by another protocol (for example NEAR Intents), custodial addresses whose custodian cannot sign, and smart contract wallets that cannot produce a valid ERC-1271 signature.refundTois now documented: no fill, no refund, the deposit is credited on the Hub torecoveryAddresswhen set. The integrator withdraws it with that wallet's signature, or Relay pays it torecoveryAddressafter a manual review.recoveryAddressnever receives refunds is replaced. Since unevenlabs/solver#14140 the protocol refund pays the protocol depositor, which isrecoveryAddresswhen set. The new note says automatic refunds still followrefundTo, andrecoveryAddressreceives funds only when Relay cannot fill and cannot refund the depositor.GET /withdrawals/balances?recoveryAddress=<addr>&ownerChainId=<chainId>.protocol.deposit.origin.depositor), which is the configuredrefundToorrecoveryAddress, and carries the same signing requirement.Why
Integrators have set
recoveryAddressto an address they cannot sign with. When the depositor fails wallet screening, the recovered funds are credited to that address on the Hub. The integrator cannot withdraw them, and the payout then depends on a manual review by Relay. The current text says "integrator-controlled EOA" but does not say the wallet must be able to authorize a withdrawal, and it saysrecoveryAddressnever receives refunds, which is no longer true.Compliance confirmed on 2026-10-23 that the same requirement applies to
refundTo, because both fields can become the protocol depositor.Supersedes #512, which was opened from a fork.
Review notes
Requested by max.
--
View Junior Session [Sentry]