@perawallet/swap
Version:
Algorand swap utilities and widget integration
1 lines • 22.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/utils.ts","../src/swap.ts","../src/types.ts","../src/controller.ts"],"names":["SwapWidgetSearchParamKey"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Helper function to make HTTP requests\n */\nexport async function makeRequest<T>(\n baseURL: string,\n endpoint: string,\n options: RequestInit = {}\n): Promise<T> {\n const url = `${baseURL}${endpoint}`\n const response = await fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers\n },\n ...options\n })\n\n if (!response.ok) {\n // Try to get error details from response body\n let errorDetails = ''\n try {\n errorDetails = await response.json()\n } catch {\n try {\n errorDetails = await response.text()\n } catch {\n errorDetails = 'Unable to read error details'\n }\n }\n\n throw new Error(JSON.stringify(errorDetails))\n }\n\n return response.json()\n}\n\n/**\n * Get the base URL for the Pera API based on network\n */\nexport function getPeraBaseUrl(network: 'mainnet' | 'testnet'): string {\n return network === 'mainnet'\n ? \"https://mainnet.api.perawallet.app\"\n : \"https://testnet.api.perawallet.app\"\n}\n\n/**\n * Default widget URL\n */\nexport const DEFAULT_WIDGET_URL = 'https://swap-widget.perawallet.app' ","import { CreateQuoteBody, SwapQuote, PrepareTransactionsResponse, Asset, GetAssetsResponse, UpdateSwapStatusBody } from './types'\nimport { makeRequest, getPeraBaseUrl } from './utils'\n\n/**\n * PeraSwap class for managing swap operations and widget generation\n */\nexport class PeraSwap {\n private network: 'mainnet' | 'testnet'\n private baseURL: string\n private referrerUrl?: string\n \n constructor(network: 'mainnet' | 'testnet' = 'mainnet', referrerUrl?: string) {\n this.network = network\n this.baseURL = getPeraBaseUrl(network)\n this.referrerUrl = referrerUrl\n }\n\n /**\n * Update the network for all subsequent operations\n */\n updateNetwork(network: 'mainnet' | 'testnet'): void {\n this.network = network\n this.baseURL = getPeraBaseUrl(network)\n }\n\n /**\n * Get the current network\n */\n getNetwork(): 'mainnet' | 'testnet' {\n return this.network\n }\n\n /**\n * Create a swap quote\n */\n async createQuote(body: CreateQuoteBody, signal?: AbortSignal): Promise<{results: SwapQuote[]}> {\n const bodyData = {\n ...body,\n referrer_url: this.referrerUrl\n }\n \n const response = await makeRequest<{results: SwapQuote[]}>(this.baseURL, \"/v2/dex-swap/quotes/\", {\n method: 'POST',\n body: JSON.stringify(bodyData),\n signal\n })\n\n // Filter results by providers if specified\n if (body.providers && body.providers.length > 0) {\n response.results = response.results.filter(quote => \n body.providers.includes(quote.provider)\n )\n }\n\n return response\n }\n\n /**\n * Update the status of a swap\n */\n async updateSwapStatus(swapId: string, body: UpdateSwapStatusBody): Promise<any> {\n const bodyData = {\n ...body,\n platform: \"js-sdk\",\n swap_version: \"v2\"\n }\n return makeRequest(this.baseURL, `/v2/dex-swap/swaps/${swapId}/`, {\n method: 'PATCH',\n body: JSON.stringify(bodyData)\n })\n }\n\n /**\n * Prepare transactions for a swap\n */\n async prepareTransactions(quoteId: string, depositAddress?: string): Promise<PrepareTransactionsResponse> {\n return makeRequest<PrepareTransactionsResponse>(\n this.baseURL,\n `/v2/dex-swap/prepare-transactions/`,\n {\n method: 'POST',\n body: JSON.stringify({\n quote: quoteId,\n deposit_address: depositAddress\n })\n }\n )\n }\n\n /**\n * Get available assets for swapping\n */\n async getAvailableAssets(params: {asset_in_id: number; q?: string}): Promise<{results: Asset[]}> {\n const searchParams = new URLSearchParams()\n searchParams.append('asset_in_id', params.asset_in_id.toString())\n if (params.q) searchParams.append('q', params.q)\n \n return makeRequest<{results: Asset[]}>(this.baseURL, `/v1/dex-swap/available-assets/?${searchParams}`)\n }\n\n /**\n * Get assets by IDs or search query\n */\n async getAssets(params: {asset_ids?: string[]; q?: string}): Promise<GetAssetsResponse> {\n const searchParams = new URLSearchParams()\n if (params.asset_ids) searchParams.append('asset_ids', params.asset_ids.join(','))\n if (params.q) searchParams.append('q', params.q)\n \n return makeRequest<GetAssetsResponse>(this.baseURL, `/v1/assets/?${searchParams}`)\n }\n\n /**\n * Get ALGO price in USD\n */\n async getAlgoPrice(): Promise<{exchange_price: string}> {\n return makeRequest<{exchange_price: string}>(this.baseURL, \"/v1/currencies/USD/\")\n }\n\n /**\n * Get asset information by ID\n */\n async getAsset(assetId: number): Promise<Asset | null> {\n try {\n const response = await this.getAssets({ asset_ids: [assetId.toString()] })\n return response.results[0] || null\n } catch (error) {\n console.error('Error fetching asset:', error)\n return null\n }\n }\n\n /**\n * Search for assets by name\n */\n async searchAssets(query: string): Promise<Asset[]> {\n try {\n const response = await this.getAssets({ q: query })\n return response.results\n } catch (error) {\n console.error('Error searching assets:', error)\n return []\n }\n }\n} ","/** Search param keys that can be passed to the widget for configuration */\nexport enum SwapWidgetSearchParamKey {\n /** When set to `true`, the widget will always try to\n * communicate with the parent app to get the txns signed */\n USE_PARENT_SIGNER = \"useParentSigner\",\n\n /** Should be passed if `useParentSigner` is `true`, (otherwise it will be ignored)\n * the widget will use this address as the signer of the txns */\n ACCOUNT_ADDRESS = \"accountAddress\",\n\n /** The preferred Algorand network that will be used by the widget */\n NETWORK = \"network\",\n\n /** The preferred theme of the widget */\n THEME = \"theme\",\n\n /** ID of the asset to be used as the input asset for the swap, default = ALGO */\n ASSET_IN = \"assetIn\",\n\n /** ID of the asset to be used as the output asset for the swap, default = USDC */\n ASSET_OUT = \"assetOut\",\n\n /** Background color of the widget, default = #FFFFFF */\n IFRAME_BACKGROUND = \"iframeBg\"\n}\n\nexport type WidgetAppTheme = \"light\" | \"dark\"\n\nexport type WidgetNetwork = \"mainnet\" | \"testnet\"\n\nexport interface WidgetConfig {\n /** The preferred Algorand network that will be used by the widget */\n network?: WidgetNetwork;\n \n /** The preferred theme of the widget */\n theme?: WidgetAppTheme;\n \n /** ID of the asset to be used as the input asset for the swap, default = ALGO */\n assetIn?: string | number;\n \n /** ID of the asset to be used as the output asset for the swap, default = USDC */\n assetOut?: string | number;\n \n /** Background color of the widget, default = #FFFFFF */\n iframeBg?: string;\n \n /** When set to `true`, the widget will always try to\n * communicate with the parent app to get the txns signed */\n useParentSigner?: boolean;\n \n /** Should be passed if `useParentSigner` is `true`, (otherwise it will be ignored)\n * the widget will use this address as the signer of the txns */\n accountAddress?: string;\n}\n\nexport interface WidgetThemeColorVariables {\n theme: WidgetAppTheme | null;\n iframeBg: string | null;\n}\n\nexport type WidgetThemeVariables = WidgetThemeColorVariables;\n\n// Swap API Types\nexport type SwapProvider = \"tinyman\" | \"tinyman-swap-router\" | \"vestige-v4\"\n\nexport type SwapType = \"fixed-input\" | \"fixed-output\"\n\nexport type VerificationTier = \"verified\" | \"unverified\" | \"suspicious\"\n\nexport interface Asset {\n asset_id: number\n name: string\n logo: string\n unit_name: string\n fraction_decimals: number\n usd_value: string | null\n is_verified: boolean\n verification_tier: VerificationTier\n type: \"standard_asset\" | \"collectible\" | \"dapp_asset\"\n}\n\nexport interface SwapQuote {\n id: number\n quote_id_str: string\n provider: SwapProvider\n swap_type: SwapType\n swapper_address: string\n asset_in: Asset\n asset_out: Asset\n amount_in: string\n amount_in_with_slippage: string\n amount_in_usd_value: null | string\n amount_out: string\n amount_out_with_slippage: string\n amount_out_usd_value: null | string\n slippage: string\n price: string\n price_impact: string\n pera_fee_amount: string\n exchange_fee_amount: string\n}\n\nexport interface CreateQuoteBody {\n providers: SwapProvider[]\n swapper_address: string\n swap_type: SwapType\n asset_in_id: number\n asset_out_id: number\n amount: string\n slippage: string\n}\n\nexport interface SwapTransactionGroup {\n purpose: \"opt-in\" | \"swap\" | \"fee\"\n transaction_group_id: string\n transactions: string[]\n signed_transactions: string[]\n}\n\nexport interface PrepareTransactionsResponse {\n swap_id: number;\n swap_version: string;\n transaction_groups: SwapTransactionGroup[]\n}\n\nexport interface UpdateSwapStatusBody {\n status: \"failed\" | \"in_progress\";\n submitted_transaction_ids?: string[];\n reason?: \"other\" | \"user_cancelled\" | \"invalid_submission\" | \"blockchain_error\";\n platform?: string;\n swap_version?: \"v1\" | \"v2\";\n}\n\nexport interface GetAssetsResponse {\n next: string | null\n previous: string | null\n results: Asset[]\n}\n\n// Message types for iframe communication\nexport interface TxnSignRequestMessage {\n message: {\n type: 'TXN_SIGN_REQUEST'\n txGroups: Uint8Array[][]\n }\n}\n\nexport interface TxnSignResponseMessage {\n message: {\n type: 'TXN_SIGN_RESPONSE'\n signedTxns: Uint8Array[]\n }\n}\n\nexport interface FailedTxnSignMessage {\n message: {\n type: 'FAILED_TXN_SIGN'\n error: Error\n }\n}\n\nexport interface TxnSignRequestTimeoutMessage {\n message: {\n type: 'TXN_SIGN_REQUEST_TIMEOUT'\n }\n}\n\nexport interface SwapSuccessMessage {\n message: {\n type: 'SWAP_SUCCESS'\n data: Uint8Array[]\n }\n}\n\nexport type WidgetMessage = \n | TxnSignRequestMessage\n | TxnSignResponseMessage\n | FailedTxnSignMessage\n | TxnSignRequestTimeoutMessage\n | SwapSuccessMessage ","import algosdk, { Transaction } from 'algosdk'\nimport { WidgetConfig } from './types'\nimport { DEFAULT_WIDGET_URL } from './utils'\n\nexport interface WidgetControllerConfig {\n onTxnSignRequest?: (data: { txGroups: Transaction[][] }) => Promise<Uint8Array[]>\n onTxnSignRequestTimeout?: () => void\n onSwapSuccess?: (response: Uint8Array[]) => void\n}\n\n\n\nexport class WidgetController {\n private config: WidgetControllerConfig\n\n constructor(config: WidgetControllerConfig = {}) {\n this.config = config\n }\n\n /**\n * Generate a URL for the Pera Swap Widget iframe\n */\n static generateWidgetUrl(config: WidgetConfig = {}): string {\n const url = new URL(DEFAULT_WIDGET_URL)\n \n // Add search parameters based on config\n if (config.network) {\n url.searchParams.set('network', config.network)\n }\n \n if (config.theme) {\n url.searchParams.set('theme', config.theme)\n }\n \n if (config.assetIn !== undefined) {\n url.searchParams.set('assetIn', String(config.assetIn))\n }\n \n if (config.assetOut !== undefined) {\n url.searchParams.set('assetOut', String(config.assetOut))\n }\n \n if (config.iframeBg) {\n url.searchParams.set('iframeBg', config.iframeBg)\n }\n \n if (config.useParentSigner) {\n url.searchParams.set('useParentSigner', 'true')\n \n if (config.accountAddress) {\n url.searchParams.set('accountAddress', config.accountAddress)\n }\n }\n \n return url.toString()\n }\n\n\n\n /**\n * Create an iframe element with the swap widget\n */\n static createWidgetIframe(\n config: WidgetConfig = {},\n options: {\n width?: string;\n height?: string;\n className?: string;\n id?: string;\n } = {}\n ): HTMLIFrameElement {\n const iframe = document.createElement('iframe')\n \n iframe.src = WidgetController.generateWidgetUrl(config)\n iframe.width = options.width || '100%'\n iframe.height = options.height || '488px'\n \n if (options.className) {\n iframe.className = options.className\n }\n \n if (options.id) {\n iframe.id = options.id\n }\n \n return iframe\n }\n\n /**\n * Send message to widget iframe\n */\n static sendMessageToWidget({\n data,\n targetWindow\n }: {\n data: { message: { type: string; [key: string]: unknown } }\n targetWindow?: Window | null\n }): void {\n if (targetWindow) {\n targetWindow.postMessage(data, '*')\n }\n }\n\n /**\n * Add event listeners for widget communication\n */\n addWidgetEventListeners(): void {\n window.addEventListener('message', this.handleMessage.bind(this))\n }\n\n /**\n * Remove event listeners\n */\n removeWidgetEventListeners(): void {\n window.removeEventListener('message', this.handleMessage.bind(this))\n }\n\n /**\n * Handle messages from the widget\n */\n private handleMessage(event: MessageEvent): void {\n // Accept messages from the widget iframe; only require a structured payload\n if (!event.data || !event.data.type || !event.data.message) {\n return\n }\n\n switch (event.data.type) {\n case 'TXN_SIGN_REQUEST': {\n const { txGroups } = event.data.message as { txGroups: Uint8Array[][] }\n\n // Decode bytes to Transaction objects before handing to consumer\n const decodedTxGroups: Transaction[][] = txGroups.map((group) =>\n group.map((bytes) => algosdk.decodeUnsignedTransaction(bytes))\n )\n\n if (this.config.onTxnSignRequest) {\n this.config.onTxnSignRequest({ txGroups: decodedTxGroups })\n .then((signedTxns) => {\n WidgetController.sendMessageToWidget({\n data: {\n message: {\n type: 'TXN_SIGN_RESPONSE',\n signedTxns\n }\n },\n targetWindow: event.source as Window\n })\n })\n .catch((error) => {\n WidgetController.sendMessageToWidget({\n data: {\n message: {\n type: 'FAILED_TXN_SIGN',\n error\n }\n },\n targetWindow: event.source as Window\n })\n })\n }\n break\n }\n\n case 'TXN_SIGN_REQUEST_TIMEOUT': {\n if (this.config.onTxnSignRequestTimeout) {\n this.config.onTxnSignRequestTimeout()\n }\n break\n }\n\n case 'SWAP_SUCCESS': {\n if (this.config.onSwapSuccess) {\n this.config.onSwapSuccess(event.data.message)\n }\n break\n }\n\n default:\n break\n }\n }\n}\n"]}