hyperliquid.core_writer

Documentation for eth_defi.hyperliquid.core_writer Python module.

CoreWriter transaction encoding for Hypercore native vaults.

Encodes raw action bytes for the CoreWriter system contract at 0x3333333333333333333333333333333333333333 on HyperEVM.

The raw action format is:

  • byte 0: version (always 1)

  • bytes 1-3: action ID (big-endian uint24)

  • bytes 4+: abi.encode(action-specific parameters)

See /README-Hypercore-guard for the full deposit/withdrawal flow.

Bridge fee note

Core -> HyperEVM linked-token withdrawals are not fee-free. Hyperliquid charges the bridge fee on HyperCore spot before the linked token settles back to HyperEVM. In manual mainnet verification, bridging 9 USDC in transaction 0x82c7ca18fed4952dfdfdffb4e7565cc768c2ab14fe7533bb42a0734cfdf36b16 returned 9 USDC to HyperEVM while reducing HyperCore spot by about 9.000783 USDC, implying an observed bridge fee of about 0.000783 USDC. Callers should therefore not assume that spot_before - amount == spot_after or that the bridged EVM amount will exactly match the full spot debit.

Example:

from eth_defi.hyperliquid.core_writer import (
    encode_vault_deposit,
    encode_transfer_usd_class,
    CORE_WRITER_ADDRESS,
)

# Build the raw action bytes for a vault deposit
raw_action = encode_vault_deposit(vault_address, usdc_amount_wei)

# Call CoreWriter.sendRawAction(raw_action) via the guard
core_writer = web3.eth.contract(
    address=CORE_WRITER_ADDRESS,
    abi=core_writer_abi,
)
fn_call = core_writer.functions.sendRawAction(raw_action)

Functions

build_activate_account_multicall(lagoon_vault)

Build a multicall to activate a Safe's HyperCore account.

build_hypercore_approve_deposit_wallet_call(...)

Build a single Safe transaction that approves USDC to CoreDepositWallet.

build_hypercore_deposit_for_spot_call(...[, ...])

Build a single Safe transaction that bridges USDC to a specific HyperCore spot account.

build_hypercore_deposit_multicall(...[, ...])

Build a single multicall transaction for the full Hypercore deposit flow.

build_hypercore_deposit_phase1(lagoon_vault, ...)

Build phase 1 of a two-phase Hypercore deposit: bridge USDC to HyperCore spot.

build_hypercore_deposit_phase2(lagoon_vault, ...)

Build phase 2 of a two-phase Hypercore deposit: spot to perp to vault.

build_hypercore_deposit_to_spot_call(...)

Build a single Safe transaction that bridges USDC from HyperEVM to HyperCore spot.

build_hypercore_deposit_to_vault_call(...)

Build a single Safe transaction that deposits USDC from perp into a HyperCore vault.

build_hypercore_send_asset_to_evm_call(...)

Build a single Safe transaction that bridges USDC from HyperCore spot back to HyperEVM.

build_hypercore_spot_send_call(lagoon_vault, ...)

Build a single Safe transaction that sends USDC to another HyperCore spot account.

build_hypercore_transfer_usd_class_call(...)

Build a single Safe transaction that moves USDC between spot and perp.

build_hypercore_vault_transfer_call(...)

Build a single Safe transaction for one HyperCore vaultTransfer leg.

build_hypercore_withdraw_from_vault_call(...)

Build a single Safe transaction that withdraws USDC from a HyperCore vault into perp.

build_hypercore_withdraw_multicall(...)

Build a single multicall transaction for the full Hypercore withdrawal flow.

compute_spot_to_evm_withdrawal_amount(...)

Compute the actual sendAsset amount after reserving bridge fee margin.

convert_evm_raw_amount_to_linked_token_wei(...)

Convert a linked-token EVM raw amount to the CoreWriter sendAsset amount.

encode_send_asset(destination, sub_account, ...)

Encode a CoreWriter sendAsset action (action ID 13).

encode_send_asset_to_evm(token_id, ...[, ...])

Encode a linked-token transfer from HyperCore spot back to HyperEVM.

encode_spot_send(destination, token_id, ...)

Encode a CoreWriter spotSend action (action ID 6).

encode_transfer_usd_class(amount_wei, to_perp)

Encode a CoreWriter transferUsdClass action (action ID 7).

encode_vault_deposit(vault, usdc_amount_wei)

Encode a CoreWriter vaultTransfer deposit action (action ID 2).

encode_vault_withdraw(vault, usdc_amount_wei)

Encode a CoreWriter vaultTransfer withdraw action (action ID 2).

fetch_token_system_address(token_id)

Get the HyperCore system address for a linked token index.

get_core_deposit_wallet_contract(web3, address)

Get a Contract instance for the CoreDepositWallet.

get_core_writer_contract(web3)

Get a Contract instance for the CoreWriter system contract.

build_activate_account_multicall(lagoon_vault, activation_amount=None)

Build a multicall to activate a Safe’s HyperCore account.

Smart contracts (like Safe multisigs) must be activated on HyperCore before CoreDepositWallet.deposit() bridge actions will clear the EVM escrow. This multicall performs the activation in a single transaction via the Safe’s trading strategy module:

  1. approve(CoreDepositWallet, activation_amount)

  2. CoreDepositWallet.depositFor(safe, activation_amount, SPOT_DEX)

Note

New HyperCore accounts incur a 1 USDC account creation fee. The default activation_amount of 2 USDC exceeds the fee.

Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • activation_amount (int | None) – USDC amount in raw units (6 decimals) for activation. Defaults to DEFAULT_ACTIVATION_AMOUNT (2 USDC).

Returns

Bound module.functions.multicall(data) ready to .transact().

Return type

ContractFunction

build_hypercore_approve_deposit_wallet_call(lagoon_vault, evm_usdc_amount)

Build a single Safe transaction that approves USDC to CoreDepositWallet.

Parameters
Return type

ContractFunction

build_hypercore_deposit_for_spot_call(lagoon_vault, evm_usdc_amount, destination=None)

Build a single Safe transaction that bridges USDC to a specific HyperCore spot account.

Parameters
  • lagoon_vault (LagoonVault) –

  • evm_usdc_amount (int) –

  • destination (HexAddress | str | None) –

Return type

ContractFunction

build_hypercore_deposit_multicall(lagoon_vault, evm_usdc_amount, hypercore_usdc_amount, vault_address, check_activation=False, chain_id=None, asset_address=None)

Build a single multicall transaction for the full Hypercore deposit flow.

Warning

The Safe must be activated on HyperCore before using the batched deposit. Pass check_activation=True to automatically verify, or use activate_account() beforehand. Without activation, deposited USDC gets permanently stuck in EVM escrow.

Batches the 4-step deposit into one EVM transaction:

  1. approve(CoreDepositWallet, amount) — approve USDC transfer

  2. CoreDepositWallet.deposit(amount, SPOT_DEX) — bridge USDC to HyperCore spot

  3. CoreWriter.sendRawAction(transferUsdClass) — move USDC from spot to perp

  4. CoreWriter.sendRawAction(vaultTransfer) — deposit into vault

When the EVM block finishes execution, all queued CoreWriter actions are processed sequentially on HyperCore (~47k gas per action).

For extra safety under heavy HyperCore load, use the two-phase approach with build_hypercore_deposit_phase1() and build_hypercore_deposit_phase2() with wait_for_evm_escrow_clear() between them.

Derives all contract instances internally from the LagoonVault:

  • module from LagoonVault.trading_strategy_module

  • usdc_contract from the vault’s underlying asset address

  • core_deposit_wallet from the chain ID (mainnet vs testnet)

  • core_writer at the system address CORE_WRITER_ADDRESS

Example:

from eth_defi.hyperliquid.core_writer import build_hypercore_deposit_multicall

fn = build_hypercore_deposit_multicall(
    lagoon_vault=lagoon_vault,
    evm_usdc_amount=10_000 * 10**6,
    hypercore_usdc_amount=10_000 * 10**6,
    vault_address="0x...",
    check_activation=True,
)
tx_hash = fn.transact({"from": asset_manager})
Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • evm_usdc_amount (int) – USDC amount in EVM wei (uint256) for approve and CDW deposit.

  • hypercore_usdc_amount (int) – USDC amount in HyperCore wei (uint64) for CoreWriter actions.

  • vault_address (HexAddress | str) – Hypercore native vault address (not the Lagoon vault address).

  • check_activation (bool) – If True, verifies the Safe is activated on HyperCore using the coreUserExists precompile before building the multicall. Set to False (default) in simulate/Anvil mode where the precompile is not available.

  • chain_id (int | None) – Override the chain ID used to look up the CoreDepositWallet address. When None (default), derived from lagoon_vault.spec.chain_id. Pass explicitly when using a LagoonSatelliteVault which has no .spec attribute.

  • asset_address (HexAddress | str | None) – Override the USDC token address used for the approve call. When None (default), derived from the vault’s underlying asset (lagoon_vault.vault_contract.functions.asset()). Pass explicitly when using a satellite vault which has no .vault_contract attribute.

Returns

Bound module.functions.multicall(data) ready to .transact().

Raises

RuntimeError – If check_activation is True and the Safe is not activated on HyperCore.

Return type

ContractFunction

build_hypercore_deposit_phase1(lagoon_vault, evm_usdc_amount)

Build phase 1 of a two-phase Hypercore deposit: bridge USDC to HyperCore spot.

This multicall performs:

  1. approve(CoreDepositWallet, amount) – approve USDC transfer

  2. CoreDepositWallet.deposit(amount, SPOT_DEX) – bridge USDC to HyperCore spot

After this transaction lands, the USDC enters EVM escrow. Use wait_for_evm_escrow_clear() to wait for the funds to arrive in the spot account, then call build_hypercore_deposit_phase2() for the remaining steps.

Example:

from eth_defi.hyperliquid.core_writer import (
    build_hypercore_deposit_phase1,
    build_hypercore_deposit_phase2,
)
from eth_defi.hyperliquid.evm_escrow import wait_for_evm_escrow_clear

# Phase 1: bridge USDC to HyperCore
fn1 = build_hypercore_deposit_phase1(lagoon_vault, evm_usdc_amount=1_000_000)
tx_hash = fn1.transact({"from": asset_manager})

# WARNING: Escrow clearance alone can be a misleading success signal
# for fast-settling deposits. If the caller needs to prove that a
# specific USDC amount reached HyperCore spot, pass expected_usdc and,
# when available, a true pre-phase baseline to wait_for_evm_escrow_clear().
# Wait for escrow to clear
wait_for_evm_escrow_clear(session, user=safe_address)

# Phase 2: move to perp and deposit into vault
fn2 = build_hypercore_deposit_phase2(
    lagoon_vault,
    hypercore_usdc_amount=1_000_000,
    vault_address="0x...",
)
tx_hash = fn2.transact({"from": asset_manager})
Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • evm_usdc_amount (int) – USDC amount in EVM wei (uint256) for approve and CDW deposit.

Returns

Bound module.functions.multicall(data) ready to .transact().

Return type

ContractFunction

build_hypercore_deposit_phase2(lagoon_vault, hypercore_usdc_amount, vault_address)

Build phase 2 of a two-phase Hypercore deposit: spot to perp to vault.

Batches two CoreWriter actions into a single multicall:

  1. transferUsdClass — move USDC from spot to perp

  2. vaultTransfer — deposit USDC from perp into vault

When the EVM block finishes execution, HyperCore processes all queued CoreWriter actions from that block sequentially, so the transferUsdClass completes before the vaultTransfer runs.

Must only be called after phase 1 USDC has cleared the EVM escrow and is available in the user’s HyperCore spot account. Use wait_for_evm_escrow_clear() between phase 1 and phase 2.

Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • hypercore_usdc_amount (int) – USDC amount in HyperCore wei (uint64) for both CoreWriter actions.

  • vault_address (HexAddress | str) – Hypercore native vault address (not the Lagoon vault address).

Returns

Bound module.functions.multicall(data) ready to .transact().

Return type

ContractFunction

build_hypercore_deposit_to_spot_call(lagoon_vault, evm_usdc_amount)

Build a single Safe transaction that bridges USDC from HyperEVM to HyperCore spot.

Parameters
Return type

ContractFunction

build_hypercore_deposit_to_vault_call(lagoon_vault, vault_address, hypercore_usdc_amount)

Build a single Safe transaction that deposits USDC from perp into a HyperCore vault.

Parameters
  • lagoon_vault (LagoonVault) –

  • vault_address (HexAddress | str) –

  • hypercore_usdc_amount (int) –

Return type

ContractFunction

build_hypercore_send_asset_to_evm_call(lagoon_vault, evm_usdc_amount)

Build a single Safe transaction that bridges USDC from HyperCore spot back to HyperEVM.

Parameters
  • evm_usdc_amount (int) – Amount in raw HyperEVM USDC decimals (6 decimals).

  • lagoon_vault (LagoonVault) –

Return type

ContractFunction

Note

The bridged amount is subject to Hyperliquid Core -> HyperEVM bridge fees paid from the Safe’s spot balance. In manual mainnet verification, transaction 0x82c7ca18fed4952dfdfdffb4e7565cc768c2ab14fe7533bb42a0734cfdf36b16 returned 9 USDC to HyperEVM and consumed about 0.000783 USDC in spot bridge fees.

Warning

When bridging the entire spot balance, the caller must reduce evm_usdc_amount to leave room for the bridge fee. Use compute_spot_to_evm_withdrawal_amount() to compute the adjusted amount. Without this the withdrawal silently fails (no error, no event — USDC stays in spot).

build_hypercore_spot_send_call(lagoon_vault, destination, hypercore_usdc_amount)

Build a single Safe transaction that sends USDC to another HyperCore spot account.

Parameters
  • lagoon_vault (LagoonVault) –

  • destination (HexAddress | str) –

  • hypercore_usdc_amount (int) –

Return type

ContractFunction

build_hypercore_transfer_usd_class_call(lagoon_vault, hypercore_usdc_amount, to_perp)

Build a single Safe transaction that moves USDC between spot and perp.

Parameters
Return type

ContractFunction

build_hypercore_vault_transfer_call(lagoon_vault, vault_address, hypercore_usdc_amount, to_vault)

Build a single Safe transaction for one HyperCore vaultTransfer leg.

This standalone builder is intended for composable multi-phase flows where the caller wants to execute and verify the vault leg separately from the later transferUsdClass or sendAsset actions.

Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • vault_address (HexAddress | str) – Hypercore native vault address.

  • hypercore_usdc_amount (int) – USDC amount in raw HyperCore / HyperEVM decimals (6 decimals).

  • to_vault (bool) – True to deposit from perp to vault, False to withdraw from vault to perp.

Return type

ContractFunction

build_hypercore_withdraw_from_vault_call(lagoon_vault, vault_address, hypercore_usdc_amount)

Build a single Safe transaction that withdraws USDC from a HyperCore vault into perp.

Parameters
  • lagoon_vault (LagoonVault) –

  • vault_address (HexAddress | str) –

  • hypercore_usdc_amount (int) –

Return type

ContractFunction

build_hypercore_withdraw_multicall(lagoon_vault, evm_usdc_amount, vault_address)

Build a single multicall transaction for the full Hypercore withdrawal flow.

Batches the 3-step withdrawal into one EVM transaction:

  1. CoreWriter.sendRawAction(vaultTransfer) — withdraw from vault

  2. CoreWriter.sendRawAction(transferUsdClass) — move USDC from perp to spot

  3. CoreWriter.sendRawAction(sendAsset) — bridge USDC back to HyperEVM

The final bridge leg is subject to Hyperliquid Core -> HyperEVM bridge fees paid from spot (see HYPERCORE_BRIDGE_FEE_MARGIN). The fee is an extra deduction from spot — the EVM side receives exactly the requested amount — so the fee is absorbed by any pre-existing spot surplus. If the Safe has no pre-existing spot balance, the caller should use compute_spot_to_evm_withdrawal_amount() to reduce the amount before building the multicall.

When the EVM block finishes execution, all queued CoreWriter actions are processed sequentially on HyperCore (~47k gas per action).

Derives all contract instances internally from the LagoonVault:

  • module from LagoonVault.trading_strategy_module

  • core_writer at the system address CORE_WRITER_ADDRESS

Parameters
  • lagoon_vault (LagoonVault) – Lagoon vault instance with trading_strategy_module_address configured.

  • evm_usdc_amount (int) – USDC amount in raw HyperEVM decimals (6 decimals). The final sendAsset leg is converted to linked-token wei internally.

  • vault_address (HexAddress | str) – Hypercore native vault address (not the Lagoon vault address).

Returns

Bound module.functions.multicall(data) ready to .transact().

Return type

ContractFunction

compute_spot_to_evm_withdrawal_amount(spot_balance, desired_amount)

Compute the actual sendAsset amount after reserving bridge fee margin.

HyperCore charges a bridge fee on spot before the linked token settles on HyperEVM. When the caller intends to bridge the entire spot balance, the requested amount must be reduced by HYPERCORE_BRIDGE_FEE_MARGIN so that enough USDC remains on spot to cover the fee.

If the desired amount already leaves sufficient margin (spot_balance - desired_amount >= HYPERCORE_BRIDGE_FEE_MARGIN), it is returned unchanged.

If the spot balance is too small (at or below the fee margin), returns Decimal(0) — callers must check for this and skip the withdrawal or raise an operator error.

Parameters
  • spot_balance (decimal.Decimal) – Current HyperCore spot free USDC balance (human-readable).

  • desired_amount (decimal.Decimal) – Amount the caller wants to bridge to HyperEVM (human-readable).

Returns

Adjusted withdrawal amount (human-readable). May be zero if the spot balance cannot cover the fee margin.

Return type

decimal.Decimal

convert_evm_raw_amount_to_linked_token_wei(token_id, evm_amount_raw)

Convert a linked-token EVM raw amount to the CoreWriter sendAsset amount.

Parameters
  • token_id (int) –

  • evm_amount_raw (int) –

Return type

int

encode_send_asset(destination, sub_account, source_dex, destination_dex, token_id, amount_wei)

Encode a CoreWriter sendAsset action (action ID 13).

sendAsset is the documented CoreWriter path for linked-token transfers between HyperCore spot and HyperEVM spot. To bridge USDC from HyperCore back to HyperEVM, pass the USDC system address as destination and SPOT_DEX for both dex fields.

Parameters
Return type

bytes

encode_send_asset_to_evm(token_id, evm_amount_raw, sub_account='0x0000000000000000000000000000000000000000')

Encode a linked-token transfer from HyperCore spot back to HyperEVM.

Parameters
Return type

bytes

Note

Hyperliquid charges the Core -> HyperEVM bridge fee on spot before settlement. In manual mainnet verification, a 9 USDC withdrawal in 0x82c7ca18fed4952dfdfdffb4e7565cc768c2ab14fe7533bb42a0734cfdf36b16 consumed about 0.000783 USDC in bridge fees on spot.

encode_spot_send(destination, token_id, amount_wei)

Encode a CoreWriter spotSend action (action ID 6).

Sends tokens between HyperCore spot accounts.

Note

This does not bridge linked tokens back to HyperEVM. For Core -> HyperEVM USDC withdrawals use encode_send_asset() with the token’s system address as the destination.

Parameters
  • destination (Union[eth_typing.evm.HexAddress, str]) – Recipient address (typically the Safe address for bridging back).

  • token_id (int) – HyperCore token index (0 = USDC).

  • amount_wei (int) – Amount in HyperCore wei (uint64).

Returns

Raw action bytes for CoreWriter.sendRawAction().

Return type

bytes

encode_transfer_usd_class(amount_wei, to_perp)

Encode a CoreWriter transferUsdClass action (action ID 7).

Moves USDC between spot and perp accounts on HyperCore.

Parameters
  • amount_wei (int) – USDC amount in HyperCore wei (uint64).

  • to_perp (bool) – True to move from spot to perp, False for perp to spot.

Returns

Raw action bytes for CoreWriter.sendRawAction().

Return type

bytes

encode_vault_deposit(vault, usdc_amount_wei)

Encode a CoreWriter vaultTransfer deposit action (action ID 2).

Parameters
  • vault (Union[eth_typing.evm.HexAddress, str]) – Hypercore native vault address.

  • usdc_amount_wei (int) – USDC amount in HyperCore wei (uint64). Note: HyperCore uses different decimal representations than EVM.

Returns

Raw action bytes for CoreWriter.sendRawAction().

Raises

AssertionError – If the deposit amount is below MINIMUM_VAULT_DEPOSIT.

Return type

bytes

encode_vault_withdraw(vault, usdc_amount_wei)

Encode a CoreWriter vaultTransfer withdraw action (action ID 2).

Parameters
Returns

Raw action bytes for CoreWriter.sendRawAction().

Return type

bytes

fetch_token_system_address(token_id)

Get the HyperCore system address for a linked token index.

Parameters

token_id (int) –

Return type

eth_typing.evm.HexAddress

get_core_deposit_wallet_contract(web3, address)

Get a Contract instance for the CoreDepositWallet.

Uses the MockCoreDepositWallet ABI which has the same deposit(uint256,uint32) signature as the real CoreDepositWallet.

Parameters
Returns

Contract instance with the CoreDepositWallet ABI.

Return type

web3.contract.contract.Contract

get_core_writer_contract(web3)

Get a Contract instance for the CoreWriter system contract.

Uses the MockCoreWriter ABI which exposes the same sendRawAction(bytes) interface as the real CoreWriter precompile.

Parameters

web3 (web3.main.Web3) – Web3 connection.

Returns

Contract instance at CORE_WRITER_ADDRESS.

Return type

web3.contract.contract.Contract