import { getCsrfToken } from '@shared/api/csrf' import { refreshAccessToken } from '@shared/api/tokenStore' const B2B_API_URL = 'https://app.b2b.elcsa.ru' async function doB2bRequest( path: string, options: RequestInit, allowRetry: boolean, ): Promise { const csrf = await getCsrfToken() const res = await fetch(`${B2B_API_URL}${path}`, { ...options, credentials: 'include', headers: { 'X-CSRF-Token': csrf, ...options.headers, }, }) if (res.status === 401 && allowRetry) { try { await refreshAccessToken() return doB2bRequest(path, options, false) } catch { throw new Error('Unauthorized') } } const data = await res.json() if (!res.ok) throw data return data as T } export interface CreatePurchaseRequestBody { rub_amount: number | string comment?: string | null target_wallet_chain?: string | null target_wallet_address?: string | null } export interface B2bPurchaseRequest { id: string organization_id: string status: string usdt_amount: string rub_amount: string | null exchange_rate: string | null service_fee_percent: string | null comment: string | null admin_comment: string | null target_wallet_chain: string | null target_wallet_address: string | null tx_hash: string | null created_at: string | null updated_at: string | null completed_at: string | null } export interface B2bPurchaseRequestListResponse { items: B2bPurchaseRequest[] total: number } export function createPurchaseRequest( body: CreatePurchaseRequestBody, ): Promise { return doB2bRequest('/purchase-requests', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }, true) } export function getMyPurchaseRequests( limit = 50, offset = 0, ): Promise { return doB2bRequest(`/purchase-requests?limit=${limit}&offset=${offset}`, {}, true) } // --- Organizations (legal-entity wallets) --- // Note: organizations endpoints live under /v1, unlike /purchase-requests. export interface OrgWallet { id: string chain: string address: string derivation_path: string created_at: string | null } export interface OrgAmountRaw { raw: string formatted: string decimals: number // null when pricing is unavailable (e.g. an upstream provider error). usd_price: string | null usd_value: string | null } export interface OrgWalletBalance { id: string chain: string address: string derivation_path: string native_symbol: string native: OrgAmountRaw tokens: Record // null when the wallet's balance could not be fetched (see `error`). total_usd: string | null error: string | null } export interface OrgBalancesResponse { items: OrgWalletBalance[] total_usd: string | null has_errors: boolean } export interface OrgMnemonicResponse { mnemonic: string } export interface OrgSecretKey { chain: string address: string derivation_path: string private_key: string } export function getOrganizationWallets(): Promise { return doB2bRequest('/v1/organizations/wallets', {}, true) } export function getOrganizationBalances(): Promise { return doB2bRequest('/v1/organizations/wallets/balances', {}, true) } export function getOrganizationMnemonic(): Promise { return doB2bRequest('/v1/organizations/wallets/mnemonic', {}, true) } export function getOrganizationSecretKeys(): Promise { return doB2bRequest('/v1/organizations/wallets/secret-keys', {}, true) }