UNPKG

@faktoryfun/styx-sdk

Version:

Bitcoin deposit SDK for Stacks applications, enabling trustless Bitcoin-to-sBTC deposits

517 lines (453 loc) 12.9 kB
// patch/sdk-patch.js - Updated with regtest support // BitcoinDepositAPI class class BitcoinDepositAPI { constructor(baseUrl, apiKey) { this.baseUrl = baseUrl; this.apiKey = apiKey || "key"; this.headers = { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }; } async fetch(endpoint, options = {}) { const url = `${this.baseUrl}${endpoint}`; const response = await fetch(url, { ...options, headers: { ...this.headers, ...options.headers, }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } async getFeeEstimates() { try { const data = await this.fetch("/deposits/sdk/bitcoin-fees"); return data; } catch (error) { console.error("Error fetching fee rates:", error); return { low: 1, medium: 2, high: 5 }; } } // Updated createDeposit method with backward compatibility async createDeposit(data) { try { const depositData = { ...data, isBlaze: data.isBlaze ?? false, poolId: data.poolId ?? "main", swapType: data.swapType ?? "sbtc", }; // Only add these fields if they exist (for AI BTC pool or swaps) if (data.minTokenOut !== undefined) { depositData.minTokenOut = data.minTokenOut; } if (data.dexId !== undefined) { depositData.dexId = data.dexId; } if (data.aiAccountReceiver) { depositData.aiAccountReceiver = data.aiAccountReceiver; } const responseData = await this.fetch("/deposits", { method: "POST", body: JSON.stringify(depositData), }); const result = responseData.data || responseData; if (result && typeof result === "object" && "id" in result) { return result.id; } if (typeof result === "string") { return result; } console.error("Unexpected response format:", result); throw new Error("Invalid response format from server"); } catch (error) { console.error("Error creating deposit:", error); throw error; } } async updateDeposit(data) { try { const responseData = await this.fetch(`/deposits/sdk/${data.id}`, { method: "PATCH", body: JSON.stringify(data.data), }); return responseData; } catch (error) { console.error("Error updating deposit:", error); throw error; } } async getDepositHistory(userAddress) { try { const responseData = await this.fetch( `/deposits/sdk/user/${userAddress}` ); return responseData; } catch (error) { console.error("Error fetching deposit history:", error); return []; } } async getAllDepositsHistory(poolId) { try { let endpoint = "/deposits/sdk/list"; if (poolId) { endpoint += `?poolId=${encodeURIComponent(poolId)}`; } const responseData = await this.fetch(endpoint); return ( responseData || { aggregateData: { totalDeposits: 0, totalVolume: 0, uniqueUsers: 0, }, recentDeposits: [], } ); } catch (error) { console.error("Error fetching all deposits:", error); return { aggregateData: { totalDeposits: 0, totalVolume: 0, uniqueUsers: 0, }, recentDeposits: [], }; } } // Updated prepareTransaction with backward compatibility async prepareTransaction(params) { try { const requestData = { ...params, poolId: params.poolId ?? "main", }; // Only add these fields if they exist if (params.swapType) { requestData.swapType = params.swapType; } if (params.minTokenOut !== undefined) { requestData.minTokenOut = params.minTokenOut; } if (params.dexId !== undefined) { requestData.dexId = params.dexId; } if (params.aiAccountReceiver) { requestData.aiAccountReceiver = params.aiAccountReceiver; } const responseData = await this.fetch( "/deposits/sdk/prepare-transaction", { method: "POST", body: JSON.stringify(requestData), } ); return responseData; } catch (error) { console.error("Error preparing transaction:", error); throw error; } } async updateDepositStatus(params) { try { const responseData = await this.fetch(`/deposits/${params.id}`, { method: "PUT", body: JSON.stringify(params.data), }); return responseData.data || responseData; } catch (error) { console.error("Error updating deposit status:", error); throw error; } } async executeTransaction(params) { try { const responseData = await this.fetch( "/deposits/sdk/execute-transaction", { method: "POST", body: JSON.stringify(params), } ); return responseData; } catch (error) { console.error("Error executing transaction:", error); throw error; } } async getPoolStatus(poolId) { try { let endpoint = "/pool-status"; if (poolId) { endpoint += `?poolId=${encodeURIComponent(poolId)}`; } const responseData = await this.fetch(endpoint); return responseData; } catch (error) { console.error("Error fetching pool status:", error); return { realAvailable: 0, estimatedAvailable: 0, lastUpdated: Date.now(), }; } } async getBTCPrice() { try { const responseData = await this.fetch("/fetchBtcPrice"); return responseData.price || null; } catch (error) { console.error("Error fetching BTC price:", error); return null; } } async getDepositStatus(depositId) { try { const responseData = await this.fetch(`/deposits/sdk/${depositId}`); return responseData; } catch (error) { console.error(`Error fetching status for deposit ${depositId}:`, error); throw error; } } async getDepositStatusByTxId(btcTxId) { try { const responseData = await this.fetch(`/deposits/sdk/tx/${btcTxId}`); return responseData; } catch (error) { console.error( `Error fetching status for Bitcoin transaction ${btcTxId}:`, error ); throw error; } } // NEW: AI BTC Pool specific methods async getAvailablePools() { try { const pools = await this.fetch("/pools/available"); return pools; } catch (error) { console.error("Error fetching available pools:", error); return []; } } async getAllowlistedPairs(poolId = "aibtc") { try { const pairs = await this.fetch(`/pools/${poolId}/allowlisted-pairs`); return pairs; } catch (error) { console.error("Error fetching allowlisted pairs:", error); return []; } } async getSwapStatus(poolId = "aibtc") { try { const status = await this.fetch(`/pools/${poolId}/swap-status`); return status; } catch (error) { console.error("Error fetching swap status:", error); return { paused: false, poolId, network: "unknown", checkedAt: Date.now(), error: "Failed to fetch swap status", }; } } async areSwapsPaused(poolId = "aibtc") { try { const response = await this.fetch(`/pools/${poolId}/swap-status`); return response.paused; } catch (error) { console.error("Error checking swap status:", error); return false; } } async isTokenAllowlisted(ftContract, poolId = "aibtc") { try { const pairs = await this.getAllowlistedPairs(poolId); return pairs.some( (pair) => pair.ftContract === ftContract && pair.isActive ); } catch (error) { console.error("Error checking if token is allowlisted:", error); return false; } } async checkFtPair(ftContract, poolId = "aibtc") { try { const response = await this.fetch( `/admin/pools/${poolId}/check-ft-pair`, { method: "POST", body: JSON.stringify({ ftContract }), } ); return response; } catch (error) { console.error("Error checking FT pair:", error); return { success: false, error: "Failed to check FT pair", ftContract, }; } } } // Constants const MIN_DEPOSIT_SATS = 10000; const MAX_DEPOSIT_SATS = 300000; // Legacy pool limit const MAX_DEPOSIT_SATS_AIBTC = 1000000; // AI BTC pool limit // Pool-specific limits const POOL_LIMITS = { main: { min: 10000, max: 300000 }, aibtc: { min: 10000, max: 1000000 }, }; function getPoolLimits(poolId = "main") { return POOL_LIMITS[poolId] || POOL_LIMITS.main; } // Network configurations - UPDATED with regtest support const NETWORK_CONFIGS = { mainnet: { apiUrl: "https://styx-be.vercel.app/api", }, testnet: { apiUrl: "https://backend-styx-testnet.vercel.app/api", }, regtest: { apiUrl: "https://backend-styx-testnet.vercel.app/api", // Your local backend for regtest }, }; function getApiUrl(network = "mainnet") { return NETWORK_CONFIGS[network]?.apiUrl || NETWORK_CONFIGS.mainnet.apiUrl; } // Default API credentials - now points to mainnet const DEFAULT_API_URL = getApiUrl("mainnet"); const DEFAULT_API_KEY = "jc_e4d2e10396eef95215a7afd492f42d743a3325739d29200c2a28b256f778be01"; // StyxSDK class - UPDATED with regtest support class StyxSDK { constructor( baseUrl = DEFAULT_API_URL, apiKey = DEFAULT_API_KEY, network = "mainnet" ) { this.network = network; const apiUrl = baseUrl || getApiUrl(network); this.api = new BitcoinDepositAPI(apiUrl, apiKey); } getCurrentNetwork() { return this.network; } async getFeeEstimates() { return this.api.getFeeEstimates(); } async updateDeposit(data) { return this.api.updateDeposit(data); } async getDepositHistory(userAddress) { return this.api.getDepositHistory(userAddress); } async getAllDepositsHistory(poolId) { return this.api.getAllDepositsHistory(poolId); } async prepareTransaction(params) { return this.api.prepareTransaction(params); } async createDeposit(params) { return this.api.createDeposit(params); } async updateDepositStatus(params) { return this.api.updateDepositStatus(params); } async executeTransaction(params) { return this.api.executeTransaction(params); } async getPoolStatus(poolId) { return this.api.getPoolStatus(poolId); } async getBTCPrice() { return this.api.getBTCPrice(); } async getDepositStatus(depositId) { return this.api.getDepositStatus(depositId); } async getDepositStatusByTxId(btcTxId) { return this.api.getDepositStatusByTxId(btcTxId); } // NEW: AI BTC Pool methods async getAvailablePools() { return this.api.getAvailablePools(); } async getAllowlistedPairs(poolId) { return this.api.getAllowlistedPairs(poolId); } async areSwapsPaused(poolId) { return this.api.areSwapsPaused(poolId); } async isTokenAllowlisted(ftContract, poolId) { return this.api.isTokenAllowlisted(ftContract, poolId); } async checkFtPair(ftContract, poolId) { return this.api.checkFtPair(ftContract, poolId); } // Convenience method for AI BTC deposits async createAIBTCDeposit(data) { return this.api.createDeposit({ ...data, poolId: "aibtc", swapType: data.swapType || "aibtc", }); } // Helper to check DEX pair compatibility async isDexPairAllowed(ftContract, dexContract, poolId = "aibtc") { try { const allowlistedPairs = await this.getAllowlistedPairs(poolId); return allowlistedPairs.some( (pair) => pair.ftContract === ftContract && pair.dexContract === dexContract && pair.isActive ); } catch (error) { console.error("Error checking DEX pair allowlist:", error); return false; } } } // Transaction priorities const TransactionPriority = { Low: "low", Medium: "medium", High: "high", }; // Create SDK instances - UPDATED with regtest support const sdk = new StyxSDK(); const mainnetStyxSDK = new StyxSDK(undefined, DEFAULT_API_KEY, "mainnet"); const testnetStyxSDK = new StyxSDK(undefined, DEFAULT_API_KEY, "testnet"); const regtestStyxSDK = new StyxSDK(undefined, DEFAULT_API_KEY, "regtest"); // NEW // Exports module.exports = { BitcoinDepositAPI, StyxSDK, MIN_DEPOSIT_SATS, MAX_DEPOSIT_SATS, MAX_DEPOSIT_SATS_AIBTC, POOL_LIMITS, getPoolLimits, TransactionPriority, styxSDK: sdk, mainnetStyxSDK, testnetStyxSDK, regtestStyxSDK, // NEW getApiUrl, default: sdk, };