Exchange
suibets
Severity
MEDIUM
What Our Normalizer Expects
core/src/exchanges/suibets/normalizer.ts reads raw.isOnchain to determine whether an offer is backed by an on-chain contract, and conditionally surfaces raw.onchainOfferId:
// normalizer.ts
isOnchain: raw.isOnchain,
onchainOfferId: raw.onchainOfferId,
SuibetsRawOffer (fetcher.ts) declares both as optional fields:
isOnchain?: boolean;
onchainOfferId?: string;
What The Live API Returns
The live GET https://www.suibets.com/api/p2p/offers response does not include isOnchain:
[].isOnchain ← ABSENT (field no longer in response)
Endpoint tested: GET https://www.suibets.com/api/p2p/offers?status=all
Note: onchainOfferId and onchainState sub-object are still present for on-chain offers.
Impact
MEDIUM: raw.isOnchain is always undefined (falsy) for every offer, regardless of whether the offer is actually on-chain. Any downstream logic that gates behavior on isOnchain === true silently treats all offers as off-chain:
- On-chain routing and settlement paths are never triggered
- UI elements that distinguish on-chain vs off-chain offers (e.g. chain explorer links) are suppressed for all offers including those with on-chain contracts
- The presence of
onchainState or a non-null onchainOfferId can serve as a proxy, but is not used
Suggested Fix
Replace the isOnchain field access with a derived check based on the still-present onchainState or onchainOfferId:
// normalizer.ts — derive isOnchain from surviving fields
isOnchain: raw.onchainOfferId != null || raw.onchainState != null,
onchainOfferId: raw.onchainOfferId,
Also remove isOnchain?: boolean from SuibetsRawOffer to reflect the actual API response shape.
Found by automated response shape drift audit
Exchange
suibets
Severity
MEDIUM
What Our Normalizer Expects
core/src/exchanges/suibets/normalizer.tsreadsraw.isOnchainto determine whether an offer is backed by an on-chain contract, and conditionally surfacesraw.onchainOfferId:SuibetsRawOffer(fetcher.ts) declares both as optional fields:What The Live API Returns
The live
GET https://www.suibets.com/api/p2p/offersresponse does not includeisOnchain:Endpoint tested:
GET https://www.suibets.com/api/p2p/offers?status=allNote:
onchainOfferIdandonchainStatesub-object are still present for on-chain offers.Impact
MEDIUM:
raw.isOnchainis alwaysundefined(falsy) for every offer, regardless of whether the offer is actually on-chain. Any downstream logic that gates behavior onisOnchain === truesilently treats all offers as off-chain:onchainStateor a non-nullonchainOfferIdcan serve as a proxy, but is not usedSuggested Fix
Replace the
isOnchainfield access with a derived check based on the still-presentonchainStateoronchainOfferId:Also remove
isOnchain?: booleanfromSuibetsRawOfferto reflect the actual API response shape.Found by automated response shape drift audit