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.

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)

Module Attributes

CORE_WRITER_ADDRESS

CoreWriter system contract address on HyperEVM

CORE_DEPOSIT_WALLET

CoreDepositWallet addresses by chain ID.

USDC_TOKEN_INDEX

USDC token index on HyperCore

SPOT_DEX

Spot dex constant (type(uint32).max)

MINIMUM_VAULT_DEPOSIT

Minimum USDC deposit into a Hypercore vault (raw, 6 decimals).

Functions

build_activate_account_multicall(lagoon_vault)

Build a multicall to activate a Safe's HyperCore 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_withdraw_multicall(...)

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

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).

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.

CORE_WRITER_ADDRESS: eth_typing.evm.HexAddress = '0x3333333333333333333333333333333333333333'

CoreWriter system contract address on HyperEVM

CORE_DEPOSIT_WALLET: dict[int, eth_typing.evm.HexAddress] = {998: '0x0B80659a4076E9E93C7DbE0f10675A16a3e5C206', 999: '0x6B9E773128f453f5c2C60935Ee2DE2CBc5390A24'}

CoreDepositWallet addresses by chain ID. Chain 999 = HyperEVM mainnet, chain 998 = HyperEVM testnet.

USDC_TOKEN_INDEX = 0

USDC token index on HyperCore

SPOT_DEX = 4294967295

Spot dex constant (type(uint32).max)

MINIMUM_VAULT_DEPOSIT = 5000000

Minimum USDC deposit into a Hypercore vault (raw, 6 decimals). Hyperliquid silently rejects vaultTransfer deposits below this amount. Determined by reverse-engineering the Hyperliquid web UI.

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

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_spot_send(destination, token_id, amount_wei)

Encode a CoreWriter spotSend action (action ID 6).

Sends tokens from HyperCore spot to an address. Used to bridge tokens from Core back to EVM (destination = EVM address).

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

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

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_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_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})

# 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_withdraw_multicall(lagoon_vault, hypercore_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(spotSend) — bridge USDC back to EVM Safe

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

  • safe_address from LagoonVault.safe_address

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

  • hypercore_usdc_amount (int) – USDC amount in HyperCore wei (uint64) for all 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