Skip to main content

Onboarding

This document describes the on-chain account lifecycle, funding flows, and API wallet management for Market Makers.

Overview

Hypercall uses a manager/agent model:

  • Manager: The EOA that owns the account (typically your main wallet)
  • Account: A minimal proxy contract (clone) that holds funds and executes on-chain actions
  • API Wallet: An EOA authorized by the manager to sign trading requests (agent)

All on-chain interactions occur via the Exchange contract.

Contract Addresses

Testnet

  • Exchange: ``

Mainnet

  • Details are shared privately.

Account Lifecycle

1. Check Existing Accounts

Before creating a new account, check if you already have accounts:

function getAccounts(address manager) external view returns (ManagedAccount[] memory);

Example (ethers.js):

const exchange = new ethers.Contract(EXCHANGE_ADDRESS, EXCHANGE_ABI, provider);
const accounts = await exchange.getAccounts(managerAddress);
// Returns: [{ account: "0x...", manager: "0x...", apiWallets: ["0x..."] }]

2. Create Account

Creates a new account with msg.sender as the manager:

function createAccount() external payable returns (address account);

Requirements:

  • accountImpl must be set by governance
  • msg.value >= getCreationDeposit() (minimum deposit in HYPE)
    • If creationDepositUsd == 0, no minimum deposit is required
    • Otherwise, getCreationDeposit() converts USD amount to HYPE using current spot price

Behavior:

  • Deploys a deterministic minimal proxy (clone) of accountImpl
  • Sets msg.sender as the account manager
  • If msg.value > 0, performs a HYPE deposit on behalf of the account
    • Transfers HYPE to HYPE_SYSTEM_ADDRESS (HyperCore bridge)
    • If deposit >= $1 worth of HYPE, account is activated on HyperCore (activation fee deducted)

Example (ethers.js):

// Get minimum deposit (in HYPE wei)
const minDeposit = await exchange.getCreationDeposit();
// Or set to ~$1-2 worth of HYPE for activation
const depositAmount = ethers.parseEther("0.001"); // Adjust based on HYPE price

const tx = await exchange.createAccount({ value: depositAmount });
const receipt = await tx.wait();
// Account address is deterministic - can predict before creation

Predict Account Address:

function predictNextAccount(address manager) external view returns (address);

Use this to know the account address before creation (useful for UI/UX).

3. Account Transfer

Managers can transfer account ownership (not directly callable; occurs during creation or via governance):

event AccountTransferred(address indexed account, address indexed oldManager, address indexed newManager);

Account transfer functionality is provided on request.

API Wallet Management

API wallets are EOAs authorized by the manager to sign trading requests. They sign EIP-712 messages that are verified on-chain.

Add API Wallet

function addApiWallet(address account, address apiWallet) external;

Requirements:

  • msg.sender == managers[account] (must be the account manager)
  • apiWallet must not be active for any other account/manager
  • account != address(0) and apiWallet != address(0)

Behavior:

  • Maps apiWallet -> account and apiWallet -> manager
  • Adds apiWallet to the account's API wallet set
  • Emits ApiWalletAdded(account, manager, apiWallet)

Example:

const tx = await exchange.addApiWallet(accountAddress, apiWalletAddress);
await tx.wait();

Remove API Wallet

function removeApiWallet(address account, address apiWallet) external;

Requirements:

  • msg.sender == managers[account]
  • apiWallet must be active for this account/manager

Behavior:

  • Removes mappings for apiWallet
  • Removes apiWallet from the account's API wallet set
  • Emits ApiWalletRemoved(account, manager, apiWallet)

Query API Wallets

function getAccountByApiWallet(address apiWallet) external view returns (ManagedAccount memory);

Returns the account, manager, and all API wallets for the account if apiWallet is active. Returns zero struct if inactive.

Example:

const managedAccount = await exchange.getAccountByApiWallet(apiWalletAddress);
if (managedAccount.account !== ethers.ZeroAddress) {
console.log("Account:", managedAccount.account);
console.log("Manager:", managedAccount.manager);
console.log("API Wallets:", managedAccount.apiWallets);
}

Funding & Deposits

USDC Deposit To Hypercall

function depositUsdcFor(address account, uint256 amount) external;

depositUsdcFor is the direct HyperEVM funding path for Hypercall cash balances. It transfers native HyperEVM USDC from msg.sender into Exchange, then Exchange deposits that USDC into its HyperCore balance through Circle's CoreDepositWallet.

Who may call it:

  • Any wallet, router, solver, or zap contract may call this method.
  • msg.sender pays the USDC.
  • account is the Hypercall account or wallet to credit. Do not infer the credited account from msg.sender.

Requirements:

  • account != address(0)
  • amount > 0
  • msg.sender must approve Exchange for amount native HyperEVM USDC
  • The deployed Exchange implementation must be constructed with the native HyperEVM USDC token and CoreDepositWallet addresses for the target network

Events and crediting:

event UsdcDeposit(
address indexed account,
address indexed from,
address indexed token,
uint256 amount,
uint32 dstDex
);

The event is emitted by Exchange after the CoreDepositWallet.depositFor call. The backend must match this event to the observed HyperCore deposit into the Exchange balance before crediting Hypercall cash. The credited Hypercall account is the explicit account event field.

Example:

const usdc = new ethers.Contract(USDC_ADDRESS, ERC20_ABI, signer);
const exchange = new ethers.Contract(EXCHANGE_ADDRESS, EXCHANGE_ABI, signer);

await usdc.approve(EXCHANGE_ADDRESS, amount);
await exchange.depositUsdcFor(accountAddress, amount);

Option Token Deposit Function

function depositOption(address account, address token, uint256 amount) external;

Supported Token Types:

  1. Option ERC20 Tokens (registered in OptionRegistry):
    • msg.value == 0 (required)
    • Burns the option token via IOptionToken(token).burnFrom(msg.sender, amount)
    • Emits Deposit(account, msg.sender, token, amount)
    • RSM indexer picks up the event and credits the account's option position

Requirements:

  • account must be a registered Hypercall account
  • optionRegistry != address(0) (must be set)
  • msg.sender must have approved Exchange for amount

Example (option token deposit):

const option = new ethers.Contract(OPTION_TOKEN_ADDRESS, ERC20_ABI, signer);
const exchange = new ethers.Contract(EXCHANGE_ADDRESS, EXCHANGE_ABI, signer);

await option.approve(EXCHANGE_ADDRESS, amount);
await exchange.depositOption(accountAddress, OPTION_TOKEN_ADDRESS, amount);

Transfer From Account

Managers can transfer tokens from their account to any recipient on HyperEVM:

function transferFromAccount(address account, address token, address recipient, uint256 amount) external;

Requirements:

  • msg.sender == managers[account]
  • recipient != address(0)

Use Cases:

  • Complete HyperCore -> HyperEVM transfers initiated by the account
  • Rescue funds from an account
  • Withdraw to a different address

Example:

await exchange.transferFromAccount(
accountAddress,
tokenAddress,
recipientAddress,
amount
);

Integration with Off-Chain API

Once an account is created and an API wallet is added:

  1. Off-chain API authentication: Use the API wallet's private key to sign EIP-712 messages (see Authentication)
  2. On-chain verification: The RSM Sequencer calls Exchange.hlRequestOrder (or similar) with your signed request
  3. Execution: The Exchange verifies the signature, recovers the API wallet, maps it to your account, and executes on-chain actions

See Also:

Events

event AccountTransferred(address indexed account, address indexed oldManager, address indexed newManager);
event ApiWalletAdded(address indexed account, address indexed manager, address indexed apiWallet);
event ApiWalletRemoved(address indexed account, address indexed manager, address indexed apiWallet);
event Deposit(address indexed account, address indexed from, address indexed token, uint256 amount);
event Withdraw(address indexed account, address indexed to, address indexed token, uint256 amount);

Errors

All errors are defined in IExchangeBase.sol:

  • Exchange__AccountManagerNotSet(address account): Account doesn't exist
  • Exchange__ApiWalletAlreadyActive(address apiWallet): API wallet already in use
  • Exchange__ApiWalletNotActive(address apiWallet): API wallet not found
  • Exchange__CreationDepositNotMet(uint256 expected): Insufficient msg.value
  • Exchange__TokenNotSupported(address token): Token not supported for deposit
  • Exchange__MsgValueIncorrect(uint256 expected): msg.value mismatch
  • Exchange__NotManager(address account, address notManager): Caller is not the manager

Security Considerations

  1. Manager Key Security: The manager key controls account ownership and API wallet management. Store securely (hardware wallet recommended).

  2. API Wallet Key Security: API wallet keys sign trading requests. Use separate keys per account/environment. Rotate regularly.

  3. Nonce Management: Each signer (API wallet, manager, RSM) has a separate nonce space. Track nonces off-chain to avoid replay attacks.

  4. Account Activation: Accounts must be activated on HyperCore (deposit >= $1 HYPE) before they can trade perps. Check activation status via HyperCore API.

  5. Deterministic Addresses: Account addresses are deterministic based on manager address and creation count. Use predictNextAccount to know addresses before creation.