Skip to main content
The Deposit Service handles the complete flow of depositing USDC from HyperEVM to Hyperliquid L1 (HyperCore) trading accounts. It includes three main modules:
  1. USDC Arrival Detection - Monitor for bridged USDC on HyperEVM
  2. Deposit Execution - Execute deposits to Hyperliquid L1
  3. L1 Confirmation Monitoring - Confirm deposits on Hyperliquid L1

USDC Arrival Detection

Monitor for USDC arrival on HyperEVM after a bridge transaction.

Exports

import {
  detectUsdcArrival,
  detectUsdcArrivalFromSnapshot,
  snapshotUsdcBalance,
  checkUsdcBalance,
  UsdcArrivalTimeoutError,
  isUsdcArrivalTimeoutError,
  ARRIVAL_DETECTION_TIMEOUT_MS,
  ARRIVAL_POLL_INTERVAL_MS,
} from '@mina-bridge/sdk/services/deposit';

detectUsdcArrival(walletAddress, options?)

Poll for USDC balance increase on HyperEVM.
async function detectUsdcArrival(
  walletAddress: string,
  options?: DetectionOptions
): Promise<UsdcArrivalResult>
ParameterTypeRequiredDescription
walletAddressstringYesWallet address to monitor
optionsDetectionOptionsNoDetection options
DetectionOptions:
OptionTypeDefaultDescription
timeoutnumber300000Timeout in ms (5 minutes)
pollIntervalnumber5000Poll interval in ms (5 seconds)
onPoll(attempt, balance) => void-Callback for each poll
expectedAmountstring-Expected amount for validation
Returns: UsdcArrivalResult
PropertyTypeDescription
detectedbooleanWhether arrival was detected
amountstringAmount received (smallest unit)
amountFormattedstringFormatted amount with decimals
receivingTxHashstring | undefinedHyperEVM transaction hash
timestampnumberDetection timestamp
previousBalancestringPre-bridge balance
currentBalancestringCurrent balance
Throws: UsdcArrivalTimeoutError if timeout is reached. Example:
const arrival = await detectUsdcArrival('0x...', {
  timeout: 300000, // 5 minutes
  onPoll: (attempt, balance) => {
    console.log(`Poll ${attempt}: Balance = ${balance}`);
  },
});

if (arrival.detected) {
  console.log(`USDC arrived: ${arrival.amountFormatted} USDC`);
  // Proceed to deposit
}

snapshotUsdcBalance(walletAddress)

Take a balance snapshot before bridging.
async function snapshotUsdcBalance(walletAddress: string): Promise<string>
Example:
// Before bridge
const preBalance = await snapshotUsdcBalance('0x...');

// Execute bridge...
await execute({ quote, signer });

// Detect arrival from snapshot
const arrival = await detectUsdcArrivalFromSnapshot(
  '0x...',
  preBalance,
  { expectedAmount: quote.toAmount }
);

detectUsdcArrivalFromSnapshot(walletAddress, previousBalance, options?)

Detect arrival from a known balance snapshot.
async function detectUsdcArrivalFromSnapshot(
  walletAddress: string,
  previousBalance: string,
  options?: DetectionOptions
): Promise<UsdcArrivalResult>

checkUsdcBalance(walletAddress)

One-time check of USDC balance on HyperEVM.
async function checkUsdcBalance(walletAddress: string): Promise<{
  balance: string;
  balanceFormatted: string;
  chainId: number;
  tokenAddress: string;
}>
Example:
const { balance, balanceFormatted } = await checkUsdcBalance('0x...');
console.log(`HyperEVM USDC: ${balanceFormatted}`);

Deposit Execution

Execute deposits from HyperEVM to Hyperliquid L1.

Exports

import {
  executeDeposit,
  executeDepositFor,
  validateDepositRequirements,
  approveUsdcForDeposit,
  checkDepositAllowance,
  // Constants
  CORE_DEPOSIT_WALLET_ADDRESS,
  MINIMUM_DEPOSIT_AMOUNT,
  DestinationDex,
  CORE_DEPOSIT_WALLET_ABI,
  ERC20_ABI,
  // Errors
  MinimumDepositError,
  InsufficientGasError,
  DepositTransactionError,
  InvalidDepositAddressError,
  isMinimumDepositError,
  isInsufficientGasError,
  isDepositTransactionError,
  isInvalidDepositAddressError,
} from '@mina-bridge/sdk/services/deposit';

executeDeposit(signer, options)

Execute a deposit to Hyperliquid L1 trading account.
async function executeDeposit(
  signer: DepositSigner,
  options: DepositOptions
): Promise<DepositResult>
DepositSigner:
interface DepositSigner {
  sendTransaction: (request: {
    to: string;
    data: string;
    value?: string;
    gas?: string;
    chainId: number;
  }) => Promise<string>;
  getAddress: () => Promise<string>;
  waitForTransactionReceipt?: (hash: string) => Promise<{
    status: 'success' | 'reverted';
    blockNumber: bigint;
    gasUsed: bigint;
  }>;
}
DepositOptions:
OptionTypeRequiredDefaultDescription
amountstringYes-Amount in smallest units
walletAddressstringYes-Wallet address
destinationDexDestinationDexTypeNo0 (PERPS)Destination DEX
onDepositSubmitted(txHash) => voidNo-Deposit tx callback
onApprovalSubmitted(txHash) => voidNo-Approval tx callback
onStatusChange(status) => voidNo-Status callback
infiniteApprovalbooleanNofalseInfinite approval
Returns: DepositResult
PropertyTypeDescription
successbooleanWhether deposit succeeded
depositTxHashstringDeposit transaction hash
approvalTxHashstring | undefinedApproval tx hash (if needed)
amountstringDeposited amount
amountFormattedstringFormatted amount
destinationDexDestinationDexTypeDestination DEX
blockNumbernumber | undefinedConfirmation block
gasUsedstring | undefinedGas used
Throws:
  • MinimumDepositError if amount < 5 USDC
  • InsufficientBalanceError if USDC balance insufficient
  • InsufficientGasError if HYPE balance insufficient
  • DepositTransactionError if transaction fails
  • UserRejectedError if user rejects
Example:
import { executeDeposit, DestinationDex } from '@mina-bridge/sdk';

const result = await executeDeposit(walletSigner, {
  amount: '10000000', // 10 USDC (6 decimals)
  walletAddress: '0x...',
  destinationDex: DestinationDex.PERPS, // Trading account
  onStatusChange: (status) => {
    console.log(`Status: ${status}`);
    // checking_balance -> checking_allowance -> approving ->
    // approval_pending -> approval_confirmed -> depositing ->
    // deposit_pending -> deposit_confirmed -> completed
  },
  onDepositSubmitted: (txHash) => {
    console.log(`Deposit submitted: ${txHash}`);
  },
  infiniteApproval: true, // Save gas on future deposits
});

if (result.success) {
  console.log(`Deposited ${result.amountFormatted} USDC`);
  console.log(`TxHash: ${result.depositTxHash}`);
}

executeDepositFor(signer, recipientAddress, options)

Deposit on behalf of another address.
async function executeDepositFor(
  signer: DepositSigner,
  recipientAddress: string,
  options: DepositOptions
): Promise<DepositResult>
Example:
// Deposit to a different trading account
const result = await executeDepositFor(
  walletSigner,
  '0xRecipientAddress...',
  {
    amount: '50000000', // 50 USDC
    walletAddress: '0xMyWallet...',
    destinationDex: DestinationDex.PERPS,
  }
);

validateDepositRequirements(walletAddress, amount)

Pre-flight validation before deposit.
async function validateDepositRequirements(
  walletAddress: string,
  amount: string
): Promise<DepositValidation>
Returns: DepositValidation
PropertyTypeDescription
validbooleanCan deposit proceed
usdcBalancestringUSDC balance
usdcBalanceFormattedstringFormatted USDC balance
gasBalancestringHYPE (gas) balance
currentAllowancestringCurrent deposit allowance
needsApprovalbooleanWhether approval needed
errorstring | undefinedError message
Example:
const validation = await validateDepositRequirements(
  '0x...',
  '10000000' // 10 USDC
);

if (!validation.valid) {
  console.error('Cannot deposit:', validation.error);
  return;
}

if (validation.needsApproval) {
  console.log('Approval will be required');
}

console.log(`USDC Balance: ${validation.usdcBalanceFormatted}`);
console.log(`Gas Balance: ${validation.gasBalance}`);

approveUsdcForDeposit(signer, amount, onSubmitted?)

Execute USDC approval for CoreDepositWallet.
async function approveUsdcForDeposit(
  signer: DepositSigner,
  amount: string,
  onSubmitted?: (txHash: string) => void
): Promise<{
  txHash: string;
  receipt: {
    status: 'success' | 'reverted';
    blockNumber: bigint;
    gasUsed: bigint;
  };
}>

checkDepositAllowance(walletAddress)

Check current USDC allowance for CoreDepositWallet.
async function checkDepositAllowance(walletAddress: string): Promise<{
  allowance: string;
  allowanceFormatted: string;
}>

L1 Confirmation Monitoring

Monitor deposit confirmation on Hyperliquid L1.

Exports

import {
  monitorL1Confirmation,
  waitForL1Confirmation,
  getHyperliquidBalance,
  getL1TradingBalance,
  checkHyperliquidAccountExists,
  createBridgeCompleteSummary,
  // Constants
  HYPERLIQUID_INFO_API,
  L1_CONFIRMATION_TIMEOUT_MS,
  L1_HARD_MAX_TIMEOUT_MS,
  L1_POLL_INTERVAL_MS,
  L1_USDC_DECIMALS,
  // Errors
  L1MonitorCancelledError,
  InvalidL1AddressError,
  isL1MonitorCancelledError,
  isInvalidL1AddressError,
} from '@mina-bridge/sdk/services/deposit';

monitorL1Confirmation(walletAddress, expectedAmount, hyperEvmTxHash, options?)

Monitor L1 with cancellation support.
function monitorL1Confirmation(
  walletAddress: string,
  expectedAmount: string,
  hyperEvmTxHash: string,
  options?: L1MonitorOptions
): {
  result: Promise<L1ConfirmationResult>;
  controller: L1MonitorController;
}
L1MonitorOptions:
OptionTypeDefaultDescription
timeoutnumber120000Timeout in ms (2 minutes)
pollIntervalnumber5000Poll interval in ms
onProgress(progress) => void-Progress callback
onTimeoutWarning(warning) => void-Timeout warning callback
Returns: Object with:
  • result: Promise that resolves to L1ConfirmationResult
  • controller: L1MonitorController for managing monitoring
L1MonitorController:
interface L1MonitorController {
  cancel: () => void;
  extendTimeout: (additionalMs: number) => void;
  getStatus: () => {
    elapsed: number;
    timeout: number;
    isRunning: boolean;
    cancelled: boolean;
    completed: boolean;
  };
}
Example:
// Start monitoring with controller
const { result, controller } = monitorL1Confirmation(
  '0x...',
  '10000000', // Expected 10 USDC
  depositResult.depositTxHash,
  {
    timeout: 120000, // 2 minutes
    onProgress: (p) => {
      console.log(`Checking L1... ${p.elapsed / 1000}s elapsed`);
      console.log(`Balance: ${p.currentBalance}`);
    },
    onTimeoutWarning: (w) => {
      console.warn('Timeout warning - still monitoring');
    },
  }
);

// Can extend timeout if needed
setTimeout(() => {
  const status = controller.getStatus();
  if (status.isRunning && status.elapsed > 60000) {
    console.log('Extending timeout by 1 minute...');
    controller.extendTimeout(60000);
  }
}, 60000);

// Await the result
try {
  const confirmation = await result;
  console.log(`Confirmed: ${confirmation.amountFormatted} USDC`);
  console.log(`Final balance: ${confirmation.finalBalanceFormatted}`);
  console.log(`Time: ${confirmation.confirmationTime}ms`);
} catch (error) {
  if (isL1MonitorCancelledError(error)) {
    console.log('Monitoring cancelled or timed out');
  }
}

waitForL1Confirmation(walletAddress, expectedAmount, hyperEvmTxHash, options?)

Simple L1 confirmation (without controller).
async function waitForL1Confirmation(
  walletAddress: string,
  expectedAmount: string,
  hyperEvmTxHash: string,
  options?: L1MonitorOptions
): Promise<L1ConfirmationResult>
Example:
const confirmation = await waitForL1Confirmation(
  '0x...',
  '10000000',
  depositResult.depositTxHash
);

console.log(`Deposit confirmed: ${confirmation.amountFormatted} USDC`);

getHyperliquidBalance(walletAddress)

Get Hyperliquid L1 trading account balance.
async function getHyperliquidBalance(walletAddress: string): Promise<string>
Returns: Account value in smallest units (raw USD * 10^6). Throws:
  • InvalidL1AddressError if address is invalid
  • NetworkError if API fails
Example:
const balance = await getHyperliquidBalance('0x...');
console.log(`L1 Balance: ${Number(balance) / 1e6} USD`);

getL1TradingBalance(walletAddress)

Get formatted L1 trading balance.
async function getL1TradingBalance(walletAddress: string): Promise<{
  balance: string;
  balanceFormatted: string;
  chainId: number;
}>
Example:
const { balanceFormatted, chainId } = await getL1TradingBalance('0x...');
console.log(`Hyperliquid (${chainId}) Balance: ${balanceFormatted} USD`);

checkHyperliquidAccountExists(walletAddress)

Check if account has any trading history.
async function checkHyperliquidAccountExists(walletAddress: string): Promise<boolean>

createBridgeCompleteSummary(params)

Create a complete summary of the bridge-to-trading flow.
function createBridgeCompleteSummary(params: {
  sourceChainId: number;
  sourceChainName: string;
  sourceTxHash: string;
  bridgeSteps: CompletedStep[];
  bridgeStartTime: number;
  depositResult: DepositResult;
  depositStartTime: number;
  l1MonitorStartTime?: number;
  l1Confirmation: L1ConfirmationResult;
  inputAmount: string;
  totalFeesUsd: number;
}): BridgeCompleteSummary
Returns: BridgeCompleteSummary
PropertyTypeDescription
sourceChain{ id, name }Source chain info
sourceTxHashstringFirst transaction hash
bridgeStepsCompletedStep[]All bridge steps
bridgeTimenumberBridge time in ms
hyperEvmDepositTxHashstringDeposit tx hash
hyperEvmDepositTimenumberDeposit time in ms
l1ConfirmationTimenumberL1 confirmation time
inputAmountstringOriginal input
inputAmountFormattedstringFormatted input
outputAmountstringDeposited amount
outputAmountFormattedstringFormatted output
finalTradingBalancestringFinal L1 balance
finalTradingBalanceFormattedstringFormatted L1 balance
totalTimenumberTotal time in ms
totalFeesUsdstringTotal fees
completedAtnumberCompletion timestamp

Constants

Contract Addresses

ConstantValueDescription
CORE_DEPOSIT_WALLET_ADDRESS0x6B9E773128f453f5c2C60935Ee2DE2CBc5390A24CoreDepositWallet on HyperEVM
HYPEREVM_USDC_ADDRESS0xb88339cb7199b77e23db6e890353e22632ba630fUSDC on HyperEVM

Amounts

ConstantValueDescription
MINIMUM_DEPOSIT_AMOUNT5000000Minimum deposit (5 USDC)

DestinationDex

const DestinationDex = {
  PERPS: 0,           // Trading account (perps)
  SPOT: 4294967295,   // Spot DEX (uint32.max)
} as const;

Timing

ConstantValueDescription
ARRIVAL_DETECTION_TIMEOUT_MS3000005 min - arrival timeout
ARRIVAL_POLL_INTERVAL_MS50005 sec - arrival poll
L1_CONFIRMATION_TIMEOUT_MS1200002 min - L1 timeout
L1_HARD_MAX_TIMEOUT_MS180000030 min - hard max
L1_POLL_INTERVAL_MS50005 sec - L1 poll

APIs

ConstantValueDescription
HYPERLIQUID_INFO_APIhttps://api.hyperliquid.xyz/infoHyperliquid Info API

Complete Flow Example

import {
  detectUsdcArrival,
  executeDeposit,
  monitorL1Confirmation,
  DestinationDex,
} from '@mina-bridge/sdk';

async function bridgeAndDeposit(
  quote: Quote,
  signer: TransactionSigner,
  walletAddress: string
) {
  // 1. Execute bridge
  console.log('Starting bridge...');
  const bridgeResult = await execute({ quote, signer });

  if (bridgeResult.status !== 'completed') {
    throw new Error('Bridge failed');
  }

  // 2. Detect USDC arrival on HyperEVM
  console.log('Waiting for USDC arrival on HyperEVM...');
  const arrival = await detectUsdcArrival(walletAddress, {
    expectedAmount: quote.toAmount,
    onPoll: (attempt) => console.log(`Checking... (attempt ${attempt})`),
  });

  console.log(`USDC arrived: ${arrival.amountFormatted}`);

  // 3. Execute deposit to Hyperliquid L1
  console.log('Depositing to Hyperliquid L1...');
  const depositResult = await executeDeposit(signer, {
    amount: arrival.amount,
    walletAddress,
    destinationDex: DestinationDex.PERPS,
    onStatusChange: (status) => console.log(`Deposit: ${status}`),
  });

  // 4. Monitor L1 confirmation
  console.log('Waiting for L1 confirmation...');
  const { result, controller } = monitorL1Confirmation(
    walletAddress,
    arrival.amount,
    depositResult.depositTxHash,
    { onProgress: (p) => console.log(`L1 check... ${p.elapsed / 1000}s`) }
  );

  const l1Confirmation = await result;

  console.log('\n=== Bridge Complete ===');
  console.log(`Input: ${quote.fromAmount} USDC`);
  console.log(`Deposited: ${l1Confirmation.amountFormatted} USDC`);
  console.log(`Final L1 Balance: ${l1Confirmation.finalBalanceFormatted}`);
  console.log(`Total Time: ${l1Confirmation.confirmationTime}ms`);

  return { bridgeResult, depositResult, l1Confirmation };
}