Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions sdks/python/pmxt/_exchanges.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ def __init__(
auto_start_server: Optional[bool] = None,
pmxt_api_key: Optional[str] = None,
wallet_address: Optional[str] = None,
api_base_url: Optional[str] = None,
signer: Optional[object] = None,
websocket: Optional[dict] = None,
) -> None:
Expand All @@ -604,6 +605,10 @@ def __init__(
auto_start_server: Automatically start server if not running (default: True)
pmxt_api_key: Hosted PMXT API key (optional; enables hosted mode)
wallet_address: Wallet address for hosted reads/writes (optional)
api_base_url: Base URL of the SuiBets exchange API itself (not the
sidecar — that is ``base_url``). Forwarded to the sidecar as the
``baseUrl`` credential; falls back to the SUIBETS_BASE_URL env
var on the sidecar side when unset (optional)
signer: Custom signer for hosted writes (optional)
websocket: WebSocket transport configuration dict (optional)
"""
Expand All @@ -616,11 +621,14 @@ def __init__(
signer=signer,
websocket=websocket,
)
self.api_base_url = api_base_url

def _get_credentials_dict(self) -> Optional[Dict[str, Any]]:
creds = super()._get_credentials_dict() or {}
if self.wallet_address:
creds["walletAddress"] = self.wallet_address
if self.api_base_url:
creds["baseUrl"] = self.api_base_url
return creds if creds else None


Expand Down
1 change: 1 addition & 0 deletions sdks/python/pmxt/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ class PolymarketOptions(ExchangeOptions, total=False):
class SuiBetsOptions(ExchangeOptions, total=False):
"""Constructor options for SuiBets clients."""
wallet_address: str
api_base_url: str


class RouterOptions(TypedDict, total=False):
Expand Down
19 changes: 19 additions & 0 deletions sdks/python/tests/test_hosted_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,25 @@ def test_suibets_constructor_accepts_wallet_address_for_hosted_mode() -> None:
assert api._get_credentials_dict() == {"walletAddress": WALLET_ADDRESS}


def test_suibets_constructor_forwards_api_base_url_credential() -> None:
api = SuiBets(
wallet_address=WALLET_ADDRESS,
api_base_url="https://suibets.example",
auto_start_server=False,
)

assert api._get_credentials_dict() == {
"walletAddress": WALLET_ADDRESS,
"baseUrl": "https://suibets.example",
}


def test_suibets_api_base_url_alone_produces_credentials() -> None:
api = SuiBets(api_base_url="https://suibets.example", auto_start_server=False)

assert api._get_credentials_dict() == {"baseUrl": "https://suibets.example"}


# --------------------------------------------------------------------------- #
# Read-method dispatch tests
# --------------------------------------------------------------------------- #
Expand Down
24 changes: 18 additions & 6 deletions sdks/typescript/pmxt/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3648,6 +3648,14 @@ export interface SuiBetsOptions extends ExchangeOptions {
* SUIBETS_WALLET_ADDRESS environment variable on the sidecar.
*/
walletAddress?: string;

/**
* Base URL of the SuiBets exchange API itself (not the PMXT sidecar —
* use `baseUrl` for that). Forwarded to the sidecar as the `baseUrl`
* credential. Can also be set via the SUIBETS_BASE_URL environment
* variable on the sidecar.
*/
apiBaseUrl?: string;
}

/**
Expand All @@ -3669,25 +3677,29 @@ export interface SuiBetsOptions extends ExchangeOptions {
*/
export class SuiBets extends Exchange {
private readonly _walletAddress?: string;
private readonly _apiBaseUrl?: string;

constructor(options: SuiBetsOptions = {}) {
super("suibets", options);
this._walletAddress = options.walletAddress;
this._apiBaseUrl = options.apiBaseUrl;
}

/**
* Includes walletAddress in the credentials sent to the sidecar so
* that fetchPositions() can reach the /api/p2p/my endpoint.
* Falls back to SUIBETS_WALLET_ADDRESS env var on the sidecar side
* when walletAddress is not set here.
* that fetchPositions() can reach the /api/p2p/my endpoint, and
* apiBaseUrl as the `baseUrl` credential controlling the SuiBets
* exchange API origin. Each falls back to the corresponding sidecar
* env var (SUIBETS_WALLET_ADDRESS / SUIBETS_BASE_URL) when unset.
*/
protected override getCredentials(): ExchangeCredentials | undefined {
const base = super.getCredentials();
if (!this._walletAddress) return base;
if (!this._walletAddress && !this._apiBaseUrl) return base;
return {
...(base ?? {}),
walletAddress: this._walletAddress,
} as ExchangeCredentials & { walletAddress: string };
...(this._walletAddress ? { walletAddress: this._walletAddress } : {}),
...(this._apiBaseUrl ? { baseUrl: this._apiBaseUrl } : {}),
} as ExchangeCredentials;
}
}

Expand Down
32 changes: 31 additions & 1 deletion sdks/typescript/tests/exchange-credentials.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { Exchange, ExchangeOptions } from "../pmxt/client";
import { Exchange, ExchangeOptions, SuiBets } from "../pmxt/client";

class TestExchange extends Exchange {
public exposedCredentials() {
return this.getCredentials();
}
}

class TestSuiBets extends SuiBets {
public exposedCredentials() {
return this.getCredentials();
}
}

describe("exchange credentials", () => {
it("accepts and forwards apiSecret with sidecar credentials", () => {
const options = {
Expand All @@ -23,4 +29,28 @@ describe("exchange credentials", () => {
privateKey: "private-key",
});
});

it("SuiBets forwards apiBaseUrl as the baseUrl credential", () => {
const exchange = new TestSuiBets({
walletAddress: "0x" + "ab".repeat(32),
apiBaseUrl: "https://suibets.example",
autoStartServer: false,
});

expect(exchange.exposedCredentials()).toMatchObject({
walletAddress: "0x" + "ab".repeat(32),
baseUrl: "https://suibets.example",
});
});

it("SuiBets apiBaseUrl alone produces credentials", () => {
const exchange = new TestSuiBets({
apiBaseUrl: "https://suibets.example",
autoStartServer: false,
});

expect(exchange.exposedCredentials()).toMatchObject({
baseUrl: "https://suibets.example",
});
});
});
Loading