Skip to content

Scale withdraw, transfer and margin amounts without float truncation - #190

Open
hey-research-lab wants to merge 1 commit into
elliottech:mainfrom
hey-research-lab:fix/exact-amount-scaling
Open

hey-research-lab wants to merge 1 commit into
elliottech:mainfrom
hey-research-lab:fix/exact-amount-scaling

Conversation

@hey-research-lab

@hey-research-lab hey-research-lab commented Oct 23, 2026 •

Copy link
Copy Markdown

What

SignerClient.withdraw, transfer, transfer_same_master_account, update_margin and create_market_order_quote_amount convert a human amount to ticks with int(amount * scale). Binary floating point makes many ordinary amounts land just below the integer, so the truncation signs one tick less than asked: withdraw(ASSET_ID_USDC, ..., 2.01) signs 2009999 (2.009999 USDC), and withdraw(ASSET_ID_ETH, ..., 0.29) signs 28999999 (0.28999999 ETH). Of the two-decimal amounts from 0.01 to 1000.00, 1,196 are affected at the USDC scale (1e6); of those from 0.01 to 100.00, 698 are affected at the 1e8 scale.

Why

lighter/signer_client.py (before this change): line 941 quote_amount = int(quote_amount * 1e6), lines 1238, 1353 and 1369 amount = int(amount * self.ASSET_TO_TICKER_SCALE[asset_id]), and line 1471 usdc_amount = int(usdc_amount * self.USDC_TICKER_SCALE). 2.01 * 1e6 == 2009999.9999999998 and 0.29 * 1e8 == 28999999.999999996; int() truncates both down.

How

A small to_ticks(amount, scale) helper scales through the amount's decimal representation (Decimal(str(amount)) * Decimal(scale)) and truncates the result, so 2.01 becomes exactly 2010000, while precision finer than one tick is still truncated as before (1.0000009 USDC stays 1000000). The five call sites use it. No other behaviour changes.

Testing

Added test/test_amount_scaling.py, which calls SignerClient.withdraw with a stub sign_withdraw and checks the amount it receives.

  • Before the change: pytest test/test_amount_scaling.py → 2 failed (USDC 2.01 → 2009999, ETH 0.29 → 28999999), 1 passed.
  • After the change: pytest test/ → 4 passed.
  • flake8 . --select=E9,F63,F7,F82 (the CI's blocking lint) on the changed files → 0.

int(2.01 * 1e6) is 2009999, so withdraw(USDC, 2.01) signed 2.009999 USDC.
Scale through the amount's decimal representation instead.
@hey-research-lab
hey-research-lab force-pushed the fix/exact-amount-scaling branch from d31b936 to 20de90f Compare October 23, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant