Unauthorized deposits - Recovery

To prevent unauthorized deposits initiated outside the Auth flow, please follow the recovery steps outlined below.

Introduction

This guide outlines how to identify and recover unauthorized deposits that are initiated outside of the standard zerohash Auth flow. While such cases are rare, it's important for platforms to detect and handle them gracefully to maintain a secure and consistent user experience. The following sections describe the end-to-end flow, from detection to user resolution.

Recovery steps

1. Unauthorized deposit received

A deposit is made that bypasses the intended Auth flow.


2. Webhook triggered

zerohash sends a DEPOSIT_FAILED webhook event to the platform, notifying it of the incoming deposit.


3. User authentication via Platform SSO

The user signs into using the Platform's login flow using normal SSO credentials.


4. User notification

The Platform, on their UI, will display an in-app banner or create some call to action that a resolution is required. It is also recommended to send an email explaining the resolution process.

Once the action has been taken, the Platform should invoke the Auth SDK - allowing the user to link an external exchange or wallet account and initiate a withdraw.

Example front end - see call-to-action banner in the center

Example front end - see call-to-action banner in the center


5. User initiates withdrawal

The user will successfully sign into their custodial or non-custodial account to initiate the withdrawal. Zerohash will also allow for a "Manual Transfer" withdraw method as well. Note: zerohash will only permit withdrawals of the same asset that they deposited - no exchanges.

Withdraw method selection screen

Withdraw method selection screen


Technical integration + front end journey

1. Webhook - Unauthorized deposit detected

When zerohash detects that a deposit was sent to an address outside of the auth flow, we will send a DEPOSIT_FAILED webhooks. Example payload:

{
  "participant_code": "<PARTICIPANT_CODE>",
  "asset": "USDC.BASE",
  "quantity": "100",
  "transaction_id": "a07407e8f98c21b037b4aa0cbc852b8489c5e122fcc3d4b33b7827d0605ad8ff",
  "success": false
}

2. Invoke Auth SDK

To generate a JWT token for the unauthorized deposit-specific flow, include the following parameters in the POST /client_auth_token. request body:

  • "permission": "auth" - indicates the request is for the Auth SDK
  • "recovery": "true" - enables support for the recovery flow

Example call:

{
    "participant_code": "<PARTICIPANT_CODE_HERE>",
    "permissions": ["auth"],
    "recovery": "true"
}

From there, you can invoke the SDK. Example using React:

import React from 'react';  
import ZeroHashSDK, { AppIdentifier } from 'zh-web-sdk';
const App = () => {  
  const sdk = new ZeroHashSDK({  
    zeroHashAppsURL: "<https://web-sdk.cert.zerohash.com">, //prod: <https://web-sdk.zerohash.com>  
    authJWT: "\<JWT_TOKEN_HERE>"  
  });

  sdk.openModal({ appIdentifier: AppIdentifier.AUTH })  
  return \<>\</>;  
}
export default App;

3. Screen 1 - Display all unauthorized deposits

This screen will display a line item-per unauthorized deposit. It will contain important data points such as blockchain transaction hash, timestamp of receipt, asset received, network received on, and amount.

From there, the user will select each transaction to resolve and withdraw out to an external wallet.


4. Screen 2 - Select withdraw method

Withdraw method selection screen

The user can choose from a Custodial account, non-custodial account or can choose to transfer manually by entering their address manually


5. Screens 3 - 9 Custodial or Non-custodial account


The user will be prompted to:

  • Sign into their account
  • Perform 2FA
  • Confirm the details of their transfer
  • Perform 2FA once more
  • Ultimately initiate the transfer

6. Screens 3 - 7 Transfer Manually


The user will be prompted to:

  • Enter the destination address
    • zerohash will screen the address against our transaction monitoring deny-lists, ensuring funds are not sent to tainted addresses
  • Initiate the transfer

7. Webhook - Transfer initiated

When the transfer has been sent on-chain, zerohash will send a series of webhooks that lets the Platform understand the progress of the transfer

submitted example - the transfer has started:

{
   "payment_details":{
      "withdrawal_request_id":"b752503c-1c42-4dfe-ad1d-7b39da5db59c",
      "trade_id":"",
      "on_chain_transaction_id":"",
      "network_fee_notional":"",
      "network_fee_quantity":"",
      "destination_address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
   },
   "asset":"USDC",
   "network":"BASE",
   "payment_type":"auth_withdrawal",
   "external_account_id":"2cc93b20-ee43-4877-8cdc-863e61829015",
   "participant_code":"<PARTICIPANT_CODE>",
   "quantity":"",
   "status":"submitted",
   "created_at":"2024-09-26T13:05:22.657Z",
   "updated_at":"2024-09-26T13:05:22.657Z",
   "total":"100.00
}

posted example - the transfer is officially pending on-chain and is on its way to the external wallet:

{
   "payment_details":{
      "withdrawal_request_id":"b752503c-1c42-4dfe-ad1d-7b39da5db59c",
      "trade_id":"",
      "on_chain_transaction_id":"FLaUcxdNxRwnaSXp6pXeRSfANXEHouqYbqF6X1bgRxg2",
      "network_fee_notional":".01",
      "network_fee_quantity":".001",
      "destination_address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
   },
   "asset":"USDC",
   "network":"BASE",
   "payment_type":"auth_withdrawal",
   "external_account_id":"2cc93b20-ee43-4877-8cdc-863e61829015",
   "participant_code":"<PARTICIPANT_CODE>",
   "quantity":"",
   "status":"posted",
   "created_at":"2024-09-26T13:05:22.657Z",
   "updated_at":"2024-09-26T13:05:22.657Z",
   "total":"100.00
}

settled example - the transfer is complete and the user has their funds:

{
   "payment_details":{
      "withdrawal_request_id":"b752503c-1c42-4dfe-ad1d-7b39da5db59c",
      "trade_id":"",
      "on_chain_transaction_id":"FLaUcxdNxRwnaSXp6pXeRSfANXEHouqYbqF6X1bgRxg2",
      "network_fee_notional":".01",
      "network_fee_quantity":".001",
      "destination_address":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
   },
   "asset":"USDC",
   "network":"BASE",
   "payment_type":"auth_withdrawal",
   "external_account_id":"2cc93b20-ee43-4877-8cdc-863e61829015",
   "participant_code":"<PARTICIPANT_CODE>",
   "quantity":"",
   "status":"settled",
   "created_at":"2024-09-26T13:05:22.657Z",
   "updated_at":"2024-09-26T13:05:22.657Z",
   "total":"100.00
}