OpenPoly logo
Integration Flow

FX fees and rounding

FX snapshots, fee application, unit conversions, and flooring rules.

FX fees and rounding

OpenPoly settles with integer units only.

Units

  • credits-equivalent: integer, 10000 = 1 USDT
  • shares: integer micro-shares, 1000000 = 1 share
  • IDR: integer minor unit, exponent 0
  • FX rate: IDR per 1 USDT
  • BPS denominator: 10000

No floating settlement values are persisted.

FX freshness

  • target freshness: <= 30 seconds
  • hard stale threshold: 120 seconds
  • stale FX beyond hard threshold -> execution fails before wallet mutation

Fee model

  • fx_fee_bps
  • operator_fee_bps
  • total_fee_bps = fx_fee_bps + operator_fee_bps

Rules:

  • fee values are non-negative integers
  • total fee must stay < 10000
  • buy applies fee before AMM quote
  • sell and redemption apply fee after credits-equivalent proceeds known

Buy formula

Given:

  • amount_minor
  • idr_per_usdt
  • total_fee_bps
net_bps = 10000 - total_fee_bps
credits_equivalent = floor(amount_minor * net_bps * 10000 / (10000 * idr_per_usdt))

Debit amount remains original amount_minor.

Sell formula

Given AMM credits-equivalent proceeds:

net_bps = 10000 - total_fee_bps
external_amount_minor = floor(credits * idr_per_usdt * net_bps / (10000 * 10000))

Redemption formula

credits_equivalent = floor(shares_micro * 10000 / 1000000)
net_bps = 10000 - total_fee_bps
external_amount_minor = floor(credits_equivalent * idr_per_usdt * net_bps / (10000 * 10000))

Rounding rule

Always floor final integer conversion. Never round up payout or buying power.

Quote safety

Execution rejects when:

  • quote ID missing or changed
  • FX snapshot stale beyond hard threshold
  • final execution worse than accepted slippage

Why this matters for operators

  • wallet side always sees integer IDR minor amounts
  • webhook and reporting APIs expose already-rounded final values
  • operator reconciliation should compare integer amounts only
Copyright © 2026