({
tokenId,
currentPrice = 0.5,
outcomeName = "YES",
negRisk = false,
defaultSide = "BUY",
compact = false,
autoFocusAmount = false,
onSuccess,
}: OrderFormProps)
| 116 | type Side = "BUY" | "SELL"; |
| 117 | |
| 118 | export default function OrderForm({ |
| 119 | tokenId, |
| 120 | currentPrice = 0.5, |
| 121 | outcomeName = "YES", |
| 122 | negRisk = false, |
| 123 | defaultSide = "BUY", |
| 124 | compact = false, |
| 125 | autoFocusAmount = false, |
| 126 | onSuccess, |
| 127 | }: OrderFormProps) { |
| 128 | const { t } = useI18n(); |
| 129 | const amountInputRef = useRef<HTMLInputElement>(null); |
| 130 | const BUY_PRESETS = [-100, 100, 1000] as const; |
| 131 | const SELL_PRESETS = [10, 25, 50, 100] as const; |
| 132 | const { address, isConnected, chainId } = useAccount(); |
| 133 | const { connect, connectors } = useConnect(); |
| 134 | const { signTypedDataAsync } = useSignTypedData(); |
| 135 | const { signMessageAsync } = useSignMessage(); |
| 136 | const { data: walletClient } = useWalletClient(); |
| 137 | const { writeContractAsync } = useWriteContract(); |
| 138 | |
| 139 | const { tradeSession, setTradeSession, setWallet, proxyAddress } = useWalletStore(); |
| 140 | const addTradeToast = useToastStore((s) => s.addTradeToast); |
| 141 | |
| 142 | const [side, setSide] = useState<Side>(defaultSide); |
| 143 | const [price, setPrice] = useState(currentPrice.toFixed(2)); |
| 144 | const [amount, setAmount] = useState(""); |
| 145 | const [limitOnly, setLimitOnly] = useState(false); |
| 146 | const isMarketOrder = !limitOnly; |
| 147 | const [status, setStatus] = useState<"idle" | "authorizing" | "approving" | "signing" | "submitting" | "done" | "error">("idle"); |
| 148 | const [errorMsg, setErrorMsg] = useState<string | null>(null); |
| 149 | const [orderId, setOrderId] = useState<string | null>(null); |
| 150 | const [minOrderShares, setMinOrderShares] = useState(5); |
| 151 | const [tickSize, setTickSize] = useState(0.01); |
| 152 | const [optimisticSharesHeld, setOptimisticSharesHeld] = useState<number | null>(null); |
| 153 | const [ctfApprovalFallback, setCtfApprovalFallback] = useState(false); |
| 154 | const [quotedMarketPrice, setQuotedMarketPrice] = useState<number | null>(null); // execution price (display) |
| 155 | const [quotedLimitPrice, setQuotedLimitPrice] = useState<number | null>(null); // buffered limit price (order submission) |
| 156 | const quotedAtRef = useRef<number | null>(null); |
| 157 | const [quoteRefreshKey, setQuoteRefreshKey] = useState(0); |
| 158 | |
| 159 | const priceDecimals = useMemo(() => tickSize <= 0.001 ? 3 : tickSize <= 0.01 ? 2 : 1, [tickSize]); |
| 160 | const centsStep = useMemo(() => tickSize * 100, [tickSize]); |
| 161 | const centsDecimals = useMemo(() => Math.max(0, priceDecimals - 2), [priceDecimals]); |
| 162 | const minPrice = tickSize; |
| 163 | const maxPrice = 1 - tickSize; |
| 164 | |
| 165 | useEffect(() => { setPrice(currentPrice.toFixed(priceDecimals)); }, [currentPrice, priceDecimals]); |
| 166 | // Reset state when the traded token changes; also clear stale orderbook prices |
| 167 | useEffect(() => { |
| 168 | setSide(defaultSide); setAmount(""); setStatus("idle"); setErrorMsg(null); setCtfApprovalFallback(false); |
| 169 | }, [tokenId, defaultSide]); |
| 170 | |
| 171 | // Fetch market-specific minimum order size from CLOB (via orderbook API) |
| 172 | useEffect(() => { |
| 173 | if (!tokenId) return; |
| 174 | fetch(`/api/orderbook?tokenId=${tokenId}`) |
| 175 | .then(r => r.ok ? r.json() : null) |
nothing calls this directly
no test coverage detected