This script helps users who got their Hyperliquid account restricted (e.g., after using a VPN) recover funds by:
- Selling a spot position (e.g., PURR/USDC),
- Transferring resulting USDC from Spot to Perps balance, and
- Optionally withdrawing to an Arbitrum address.
It was built for the "stuck funds" scenario and aims to provide a safe, automated path to exit.
- Not affiliated with Hyperliquid.
- Use at your own risk. Make sure you comply with local laws and the Hyperliquid Terms of Service.
- Reads your account address and private key from
.env. - Uses Hyperliquid public
/infoendpoints to fetch metadata and balances. - Places an Immediate-or-Cancel “market-like” sell on spot via the official Python SDK.
- Transfers available USDC from Spot → Perps.
- Optionally initiates a bridge withdrawal from Perps to an Arbitrum address.
- Python 3.10+ recommended
- A wallet that is connected to your Hyperliquid account
- Your private key for that wallet (hex string)
- Network access to Hyperliquid API
git clone https://github.com/yourname/hyperliquid-recoverty.git
cd hyperliquid-recoverty
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtCopy the example env and fill in values:
HL_ACCOUNT_ADDRESS=
HL_SECRET_KEY=
PAIR_NAME = "PURR/USDC"
BASE_TOKEN = "PURR"
QUOTE_TOKEN = "USDC"
- HL_ACCOUNT_ADDRESS: your EVM address used on Hyperliquid (checksummed, e.g., 0xABC…)
- HL_SECRET_KEY: the hex private key for that address (e.g., 0xabc123…)
- PAIR_NAME: spot pair to sell (default
"PURR/USDC") - BASE_TOKEN: base asset symbol (default
"PURR") - QUOTE_TOKEN: quote asset symbol (default
"USDC")
Optional variables (not in the example, but supported):
- HL_API_URL:
- Mainnet (default):
https://api.hyperliquid.xyz - Testnet:
https://api.hyperliquid-testnet.xyz
- Mainnet (default):
- HL_SIGNATURE_CHAIN_ID:
- Mainnet default:
0xa4b1(Arbitrum One) - Testnet default:
0x66eee(Arbitrum Sepolia)
- Mainnet default:
Create .env in the project root and paste your values there. Keep .env private and never commit it.
General syntax:
python3 hl_purr_to_perps.py --mode {sell_and_transfer|transfer_only|withdraw} [options]Common options:
--purr-amount <Decimal>: amount ofBASE_TOKENto sell on spot. If omitted, sells ALL available.--usdc-amount <Decimal>: amount of USDC to transfer/withdraw. If omitted, uses ALL available (with a tiny safety buffer).--slippage-bps <int>: cushion for the IOC “market-like” order; default 30 bps.
Sell all available PURR and move resulting USDC to Perps:
python hl_purr_to_perps.py --mode sell_and_transferSell a specific PURR amount (e.g., 123.45 PURR):
python hl_purr_to_perps.py --mode sell_and_transfer --purr-amount 123.45Increase slippage if fills fail on illiquid books (example: 75 bps):
python hl_purr_to_perps.py --mode sell_and_transfer --slippage-bps 75Move existing Spot USDC to Perps:
python hl_purr_to_perps.py --mode transfer_onlySpecify an amount (e.g., 100.25 USDC):
python hl_purr_to_perps.py --mode transfer_only --usdc-amount 100.25Withdraw 50.12345678 USDC from Perps to your Arbitrum wallet:
python hl_purr_to_perps.py --mode withdraw --usdc-amount 50.12345678 --dest 0xYourArbitrumAddressDecimals are handled safely (floored to 8 decimals for USDC).
To try on testnet, add to your .env:
HL_API_URL=https://api.hyperliquid-testnet.xyz
The script will auto-adjust signature chain id defaults for testnet.
- Never share your private key or seed phrase. The script only needs the private key corresponding to
HL_ACCOUNT_ADDRESS. - Keep
.envoutside version control. - Consider creating and funding a fresh wallet dedicated to recovery if you’re worried about exposure.
- “Pair PURR/USDC not found”:
- Verify
PAIR_NAMEmatches a live spot market.
- Verify
- “Token PURR/USDC not found”:
- Check
BASE_TOKENandQUOTE_TOKENspelling.
- Check
- “No PURR available on Spot.”:
- Ensure your PURR balance exists on Spot, not Perps.
- “No USDC on Spot after sell (order may not have filled).”:
- The IOC order didn’t fill; increase
--slippage-bpsor check order book liquidity.
- The IOC order didn’t fill; increase
- HTTP 401/403:
- Re-check
HL_SECRET_KEYandHL_ACCOUNT_ADDRESS. Ensure the wallet is the one tied to your Hyperliquid account.
- Re-check
- Precision errors:
- The script floors amounts to token decimals and subtracts one tick for safety. If you see “Computed size <= 0”, reduce amount slightly.
- Configure
.envwith your HL address and private key. - Run:
This sells your PURR into USDC on Spot and moves USDC to Perps.
python hl_purr_to_perps.py --mode sell_and_transfer
- Withdraw from Perps to your Arbitrum address:
python hl_purr_to_perps.py --mode withdraw --usdc-amount <amount> --dest 0xYourArbitrumAddress
- If you prefer a third-party bridge (e.g., deBridge), you can withdraw to your own address and then bridge normally using their UI.
- Default network is Mainnet. Override with
HL_API_URL. - Default slippage is 30 bps. Illiquid books may need more.
- The script waits ~1.2s after placing the spot order before transferring, to allow fills to settle.
MIT. See LICENSE.