SPB Git

Repository Public

withdraw-proof.test.ts 2.3 KB 26 lines typescript

1// Replays the testnet proof of the withdrawal signature (scripts/hl-withdraw-testnet.mts --send --record, 2026-11-11): the real2// isolated signer signed `withdraw3` with a throwaway wallet key; the venue refused the unfunded account BY NAME, i.e. it3// recovered our address from the signature over its own hash of the action. No network here.4import { describe, expect, it } from 'vitest';5import { buildWithdraw3TypedDataOnly, recoverTypedDataSigner } from '../../src/venues/hyperliquid/index.ts';6import { raw } from './helpers.ts';78describe('testnet proof: withdraw3 signed by the wallet key', () => {9  const p = raw('testnet-withdraw-proof.json') as { network: 'testnet'; endpoint: string; account: string; request: { action: { type: string; hyperliquidChain: string; signatureChainId: string; destination: string; amount: string; time: number }; nonce: number; signature: { r: string; s: string; v: number }; vaultAddress: null; expiresAfter: null }; status: number; answer: { status: string; response: string } };10  it('was sent to the testnet endpoint only, as a withdrawal to the signing address itself', () => {11    expect(p.endpoint).toBe('https://api.hyperliquid-testnet.xyz/exchange');12    expect(p.request.action).toEqual({ type: 'withdraw3', hyperliquidChain: 'Testnet', signatureChainId: '0x66eee', destination: p.account, amount: p.request.action.amount, time: p.request.nonce });13    expect([p.request.vaultAddress, p.request.expiresAfter]).toEqual([null, null]);14  });15  it('our typed data recovers the account from the recorded signature, and the venue named that same account', async () => {16    const a = p.request.action;17    const td = buildWithdraw3TypedDataOnly({ network: 'testnet', destination: a.destination, amount: a.amount, time: a.time }).typedData;18    expect(await recoverTypedDataSigner(td, p.request.signature)).toBe(p.account);19    expect(p.status).toBe(200);20    expect(p.answer).toEqual({ status: 'err', response: `Must deposit before performing actions. User: ${p.account}` });21    // the same signature read as a Mainnet action is someone else's22    const main = buildWithdraw3TypedDataOnly({ network: 'mainnet', destination: a.destination, amount: a.amount, time: a.time }).typedData;23    expect(await recoverTypedDataSigner(main, p.request.signature)).not.toBe(p.account);24  });25});26
Files main
Menu

Theme