Drift
For hosted-mode cancelOrder, TypeScript validates that a signer and a wallet address are both configured before making any network call. Python's equivalent validates the wallet address first, then immediately fires the cancel_order_build network request, and only discovers a missing signer after that round-trip completes — leaking the cancel intent to the server and wasting a request.
This is the inverse of the already-tracked #1502 ("hosted createOrder checks for a signer only after the remote build call in TypeScript; Python checks before any network call") — that issue is specific to createOrder. For cancelOrder, the languages swap roles: TypeScript is the one that front-loads the check, and Python is the one that defers it past the network call.
TypeScript SDK
sdks/typescript/pmxt/client.ts:2622-2633 (_hostedCancelOrder):
private async _hostedCancelOrder(orderId: string): Promise<Order> {
const signer = this.requireHostedSigner(); // throws synchronously if no signer — no network call yet
if (!this.walletAddress) {
throw new MissingWalletAddress("hosted cancelOrder requires walletAddress");
}
const buildRequest = { order_id: orderId, user_address: this.walletAddress };
const buildRoute = HOSTED_METHOD_ROUTES.get("cancelOrderBuild")!;
const buildPayload = await _tradingRequest(this, { // network call only after both checks pass
method: buildRoute.method, path: buildRoute.path, body: buildRequest,
}) as Record<string, unknown>;
requireHostedSigner() (client.ts:530-537) throws MissingWalletAddress immediately if this.signer is falsy.
Python SDK
sdks/python/pmxt/client.py:1008-1028 (_hosted_cancel_order):
def _hosted_cancel_order(self, order_id, signer=None) -> "Order":
wallet_address = resolve_wallet_address(self) # wallet checked first
build_request = {"order_id": order_id, "user_address": wallet_address}
build_payload = self._hosted_response_data(
self._hosted_request("cancel_order_build", body=build_request) # NETWORK CALL — signer not yet checked
)
...
signature = self._sign_hosted_typed_data(build_payload, "typed_data", route, wallet_address, build_request, signer=signer)
The signer check lives in _call_hosted_signer (client.py:884-887):
@staticmethod
def _call_hosted_signer(signer, typed_data):
if signer is None:
raise InvalidSignature("signer is required for hosted trading") # only discovered here, after the round-trip
Expected
Python's _hosted_cancel_order should validate that a signer is configured before issuing the cancel_order_build request, matching TypeScript's synchronous front-loaded check (and matching the resolution direction #1502 will presumably pick for createOrder).
Impact
A Python caller invoking hosted cancel_order without a configured signer sends a real network request to cancel_order_build (revealing the order they intend to cancel to the server) before failing with InvalidSignature. TypeScript fails fast with no network I/O in the same scenario. Beyond the extra request, this is also an unnecessary side effect for any caller who accidentally omits a signer.
Found by automated SDK cross-language drift audit
Drift
For hosted-mode
cancelOrder, TypeScript validates that a signer and a wallet address are both configured before making any network call. Python's equivalent validates the wallet address first, then immediately fires thecancel_order_buildnetwork request, and only discovers a missing signer after that round-trip completes — leaking the cancel intent to the server and wasting a request.This is the inverse of the already-tracked #1502 ("hosted
createOrderchecks for a signer only after the remote build call in TypeScript; Python checks before any network call") — that issue is specific tocreateOrder. ForcancelOrder, the languages swap roles: TypeScript is the one that front-loads the check, and Python is the one that defers it past the network call.TypeScript SDK
sdks/typescript/pmxt/client.ts:2622-2633(_hostedCancelOrder):requireHostedSigner()(client.ts:530-537) throwsMissingWalletAddressimmediately ifthis.signeris falsy.Python SDK
sdks/python/pmxt/client.py:1008-1028(_hosted_cancel_order):The signer check lives in
_call_hosted_signer(client.py:884-887):Expected
Python's
_hosted_cancel_ordershould validate that a signer is configured before issuing thecancel_order_buildrequest, matching TypeScript's synchronous front-loaded check (and matching the resolution direction #1502 will presumably pick forcreateOrder).Impact
A Python caller invoking hosted
cancel_orderwithout a configured signer sends a real network request tocancel_order_build(revealing the order they intend to cancel to the server) before failing withInvalidSignature. TypeScript fails fast with no network I/O in the same scenario. Beyond the extra request, this is also an unnecessary side effect for any caller who accidentally omits a signer.Found by automated SDK cross-language drift audit