Deposit Addresses

Generate a counterfactual deposit address that users can send funds to in order to initiate a crosschain transfer.

Early Access.
Deposit addresses are available for approved integrators. Reach out on Telegram to get access.

Supported routes.
Deposit addresses currently only support USDC (Arbitrum, Ethereum, Base) to USDH (HyperEVM, HyperCore). More routes will be added soon.

Overview

Deposit addresses let users initiate crosschain transfers by sending tokens to a generated address. Call /swap/counterfactual with your route parameters and receive a unique depositAddress. The user sends the input token to that address on the origin chain. Across detects the transfer, sweeps the funds, and completes the crosschain transfer to the recipient on the destination chain.

This is ideal for:

  • Onramps: user withdraws from a CEX or fiat onramp directly to a deposit address
  • Bots and automation: no wallet signing flow needed
  • Simplified UX: reduce the integration to a single token transfer

How It Works

API key required.
This endpoint requires a valid API key in the Authorization header. Requests without one will return a 403 error. Request your API key and integrator ID

Generate a deposit address

Call /swap/counterfactual with the route parameters, recipient, and refund address.

generate-deposit-address.ts
const params = new URLSearchParams({
  useDepositAddress: "true",
  originChainId: "42161",
  destinationChainId: "1337",
  inputToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
  outputToken: "0x2000000000000000000000000000000000000168", // USDH on HyperCore
  amount: "1000000",
  recipient: "0xRecipientAddress",
  refundAddress: "0xUserOriginAddress",
});

const response = await fetch(
  `https://app.across.to/api/swap/counterfactual?${params}`,
  {
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
    },
  }
);
const data = await response.json();

console.log("Deposit address:", data.depositAddress);
console.log("Send", data.inputToken.symbol, "to this address on origin chain");

Send tokens to the deposit address

Transfer the input token to the depositAddress on the origin chain. This is a standard ERC-20 transfer, no special calldata needed.

send-tokens.ts
import { erc20Abi } from "viem";

const hash = await walletClient.writeContract({
  address: data.inputToken.address,
  abi: erc20Abi,
  functionName: "transfer",
  args: [data.depositAddress, BigInt(data.inputAmount)],
});

console.log("Transfer tx:", hash);

Across handles the rest

After detecting the token transfer, Across:

  1. Fetches a fresh quote for the route
  2. Deploys the deposit address contract and sweeps funds into the SpokePool
  3. Completes the crosschain swap

The recipient receives the output token on the destination chain.

API Parameters

Request

ParameterTypeRequiredDescription
useDepositAddressbooleanYesMust be true
inputTokenstringYesToken address on origin chain
outputTokenstringYesToken address on destination chain
originChainIdnumberYesOrigin chain ID
destinationChainIdnumberYesDestination chain ID
amountstringYesAmount in smallest unit (wei)
recipientstringYesAddress receiving tokens on destination
refundAddressstringYesAddress for refunds on origin chain

Response

FieldTypeDescription
depositAddressstringAddress to send tokens to on origin chain
idstringUnique quote identifier
crossSwapTypestringType of crosschain swap (e.g. "bridgeableToBridgeable")
amountTypestringAmount type used (e.g. "exactInput")
inputTokenobjectInput token details: address, symbol, name, decimals, chainId
outputTokenobjectOutput token details: address, symbol, name, decimals, chainId
refundTokenobjectToken used for refunds: address, symbol, name, decimals, chainId
inputAmountstringAmount of input token (smallest unit)
maxInputAmountstringMaximum input amount
expectedOutputAmountstringExpected output amount after fees
minOutputAmountstringMinimum guaranteed output amount
expectedFillTimenumberExpected fill time in seconds
quoteExpiryTimestampnumberUnix timestamp when this quote expires
checksobjectAllowance and balance checks: allowance (token, spender, actual, expected) and balance (token, actual, expected)
stepsobjectBreakdown of the bridge step including inputAmount, outputAmount, tokenIn, tokenOut, fees, and provider
feesobjectFee breakdown: total (amount, amountUsd, pct, details), totalMax, and originGas
swapTxobjectTransaction to execute: ecosystem, simulationSuccess, chainId, to, data, value, gas

The fees.total.details object contains a full breakdown including bridge fees (relayer capital, destination gas, LP fee) and swapImpact. See the API playground for the complete nested structure.

Address Lifecycle

Each call to /swap/counterfactual returns a new, unique address. Deposit addresses are not intended to be reused.

BehaviorDetail
UniquenessNew address generated per quote
TTL24 hours: address expires if no token transfer is received
After first transferAcross processes the transfer and stops monitoring the address
Reuse within TTLIf additional transfers are sent within the TTL, they will be processed, but this is not the intended flow

Do not cache or persist deposit addresses. Generate a new one for each transfer.

Tracking Status

Track deposit status using the depositAddress and index parameters on /deposit/status:

GET /deposit/status?depositAddress=0x1234...abcd&index=0

The index is 0-based. Use 0 for the first (and typically only) deposit to that address.

The response uses the same status values as standard deposits: pending > filled / expired > refunded.

See Tracking Deposits for the full polling guide.

Fees

There is currently no deployment fee charged for generating deposit addresses. If a fee is introduced in the future, it will be:

  • A fixed amount (not a percentage)
  • Deducted from the user's input amount
  • Included in the quote response

Bridge fees (relayer capital, destination gas, LP) are included in the response under fees.total and steps.bridge.fees.

Refund Behavior

Always set refundAddress to an address the user controls on the origin chain. This address receives refunds if the transfer cannot be completed.

ScenarioWhat happens
Bot submits intent but relayer can't fillRefund sent automatically to refundAddress on origin chain
Bot cannot submit deposit (e.g. infrastructure issue)Across retries with a new quote. If retries fail, contract is deployed and funds can be withdrawn by refundAddress or admin
Wrong token sent to deposit addressManual withdrawal required by refundAddress or admin

For general refund timing and behavior, see Refunds.

Try it in the API playground: /swap/counterfactual

On this page