UNPKG

@ondo-gm/1inch

Version:

1inch Fusion swap integration for Ondo SDK

369 lines (365 loc) 11.7 kB
'use strict'; var fusionSdk = require('@1inch/fusion-sdk'); var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } __name(sleep, "sleep"); var FusionClient = class { static { __name(this, "FusionClient"); } constructor(chainId, provider, signer, baseUrl, approveAllowance, authKey) { this.networkId = this.getNetworkEnum(chainId); this.baseUrl = baseUrl; this.chainId = chainId; this.web3Provider = new fusionSdk.Web3ProviderConnector(provider); this.signer = signer; this.approveAllowance = approveAllowance; this.sdk = new fusionSdk.FusionSDK({ url: `${baseUrl}/fusion`, network: this.networkId, blockchainProvider: this.web3Provider, authKey // Optional API key for better rate limits }); } async getNativeSwapQuote(fromToken, toToken, amount) { const baseUrl = `${this.baseUrl}/swap/v6.1/${this.chainId}/quote`; const params = new URLSearchParams({ src: fromToken, dst: toToken, amount }); const url = `${baseUrl}?${params}`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const quote = response.json(); return quote; } catch (e) { console.error(e); } } async swapNativeToken(address, fromToken, toToken, amount) { const baseUrl = `${this.baseUrl}/swap/v6.1/${this.chainId}/swap`; const params = new URLSearchParams({ src: fromToken, dst: toToken, amount, from: address, origin: address, slippage: "1" }); const url = `${baseUrl}?${params}`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const callData = await response.json(); await this.signer.sendTransaction(callData.tx); return callData; } catch (e) { console.error(e); } } isNativeToken(token) { return token === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; } /** * Gets the wrapped token address for a given chain ID */ getWrappedTokenAddress(chainId) { switch (chainId) { case 1: return "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; // WETH case 137: return "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"; // WMATIC case 8453: return "0x4200000000000000000000000000000000000006"; // WETH default: return "0x4200000000000000000000000000000000000006"; } } /** * Creates a fusion order based on the provided configuration */ async createFusionOrder(config) { try { if (this.isNativeToken(config.fromTokenAddress)) { const wrappedToken = this.getWrappedTokenAddress(this.chainId); if (config.toTokenAddress.toLowerCase() === wrappedToken.toLowerCase()) { await this.swapNativeToken( config.walletAddress, config.fromTokenAddress, wrappedToken, config.amount ); throw new Error("Direct native to wrapped token swap completed. No fusion order needed."); } throw new Error( `Cannot create fusion order with native token. Please swap to wrapped token first: ${wrappedToken}` ); } const orderParams = { fromTokenAddress: config.fromTokenAddress, toTokenAddress: config.toTokenAddress, amount: config.amount, walletAddress: config.walletAddress, receiver: config.receiverAddress, preset: this.mapPresetToEnum(config.preset) }; const orderData = await this.sdk.createOrder(orderParams); return { order: orderData, quoteId: orderData.quoteId, settlementAddress: orderData.order.settlementExtensionContract.toString(), extension: orderData.order.extension.encode(), orderHash: orderData.hash }; } catch (error) { console.error("Error creating fusion order:", error); throw new Error( `Failed to create fusion order: ${error instanceof Error ? error.message : "Unknown error"}` ); } } /** * Signs a fusion order using EIP-712 */ async signFusionOrder(orderResult) { try { const { order } = orderResult.order; await this.approveAllowance( order.makerAsset.toString(), "0x111111125421cA6dc452d289314280a0f8842A65", order.makingAmount.toString(), this.signer ); const signature = await this.sdk.signOrder(orderResult.order.order); return { order: orderResult.order, signature, orderHash: orderResult.orderHash, quoteId: orderResult.quoteId }; } catch (error) { console.error("Error signing fusion order:", error); throw new Error( `Failed to sign fusion order: ${error instanceof Error ? error.message : "Unknown error"}` ); } } /** * Submits a signed fusion order to the 1inch relayer */ async submitFusionOrder(signedOrderResult) { try { const info = await this.sdk.submitOrder( signedOrderResult.order.order, signedOrderResult.quoteId ); return info; } catch (error) { console.error("Error submitting fusion order:", error); throw new Error( `Failed to submit fusion order: ${error instanceof Error ? error.message : "Unknown error"}` ); } } /** * Creates, signs, and submits a fusion order in one call */ async createAndSubmitFusionOrder(config) { const orderResult = await this.createFusionOrder(config); const signResult = await this.signFusionOrder(orderResult); return await this.submitFusionOrder(signResult); } async getOrderStatus(info) { while (true) { try { const data = await this.sdk.getOrderStatus(info.orderHash); if (data.status === fusionSdk.OrderStatus.Filled) { console.log("fills", data.fills); return data; } if (data.status === fusionSdk.OrderStatus.Expired) { console.log("Order Expired"); return data; } if (data.status === fusionSdk.OrderStatus.Cancelled) { console.log("Order Cancelled"); return data; } await sleep(1e4); } catch (e) { console.log(e); } } } async getTokens(tokens) { const url = `${this.baseUrl}/token/v1.2/${this.chainId}/custom`; const params = new URLSearchParams(); const addresses = tokens; addresses.forEach((address) => params.append("addresses", address)); const fullUrl = `${url}?${params.toString()}`; try { const response = await fetch(fullUrl); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = response.json(); return data; } catch (e) { console.error(e); } } async getBalance(walletAddress) { const balanceUrl = `${this.baseUrl}/balance/v1.2/${this.chainId}/balances/${walletAddress}`; try { const response = await fetch(balanceUrl, { headers: { accept: "application/json", "content-type": "application/json" } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); const tokenAddresses = Object.keys(data).filter((key) => parseInt(data[key]) > 0); const tokenDetails = await this.getTokens(tokenAddresses); const balanceData = {}; Object.keys(tokenDetails).map((tokenAddress) => { const balance = data[tokenAddress]; balanceData[tokenAddress] = { ...tokenDetails[tokenAddress], balance }; }); return balanceData; } catch (e) { console.error("Error fetching balances", e); return null; } } /** * Gets a quote from the 1inch quoter API */ async getQuote(config) { if (this.isNativeToken(config.fromTokenAddress)) { const wrappedToken = this.getWrappedTokenAddress(this.chainId); if (config.toTokenAddress.toLowerCase() === wrappedToken.toLowerCase()) { return await this.getNativeSwapQuote(config.fromTokenAddress, wrappedToken, config.amount); } throw new Error( `Cannot get fusion quote with native token. Please use wrapped token instead: ${wrappedToken}` ); } try { const quoteParams = { fromTokenAddress: config.fromTokenAddress, toTokenAddress: config.toTokenAddress, amount: config.amount, walletAddress: config.walletAddress, enableEstimate: false, source: "0xe26b9977" }; return await this.sdk.getQuote(quoteParams); } catch (error) { console.error("Error fetching quote:", error); throw new Error( `Failed to fetch quote: ${error instanceof Error ? error.message : "Unknown error"}` ); } } /** * Maps chain ID to NetworkEnum */ getNetworkEnum(chainId) { switch (chainId) { case 1: return fusionSdk.NetworkEnum.ETHEREUM; case 56: return fusionSdk.NetworkEnum.BINANCE; case 137: return fusionSdk.NetworkEnum.POLYGON; case 42161: return fusionSdk.NetworkEnum.ARBITRUM; case 10: return fusionSdk.NetworkEnum.OPTIMISM; case 8453: return fusionSdk.NetworkEnum.COINBASE; case 43114: return fusionSdk.NetworkEnum.AVALANCHE; case 250: return fusionSdk.NetworkEnum.FANTOM; case 100: return fusionSdk.NetworkEnum.GNOSIS; default: throw new Error(`Unsupported chain ID: ${chainId}`); } } /** * Maps preset string to PresetEnum */ mapPresetToEnum(preset) { switch (preset) { case "fast": return fusionSdk.PresetEnum.fast; case "medium": return fusionSdk.PresetEnum.medium; case "slow": return fusionSdk.PresetEnum.slow; case "custom": return fusionSdk.PresetEnum.custom; default: return fusionSdk.PresetEnum.medium; } } }; // src/factory.ts function createFusionClient(config) { const web3Provider = { eth: { //@ts-expect-error add call to ethers call: /* @__PURE__ */ __name(async (config2) => { if (!config2.signer.provider) throw new Error("Provider not available"); return await config2.signer.provider.call({ to: config2.to, data: config2.data }); }, "call") }, extend: /* @__PURE__ */ __name((extension) => { const methods = extension.methods || []; const extended = {}; methods.forEach((method) => { if (method.name === "signTypedDataV4") { extended.signTypedDataV4 = async (walletAddress, typedDataString) => { const typedData = JSON.parse(typedDataString); const { domain, types, message } = typedData; const cleanTypes = { ...types }; delete cleanTypes.EIP712Domain; return await config.signer.signTypedData(domain, cleanTypes, message); }; } }); return extended; }, "extend") }; return new FusionClient( config.chainId, web3Provider, config.signer, config.apiUrl, config.approveAllowance ); } __name(createFusionClient, "createFusionClient"); exports.FusionClient = FusionClient; exports.createFusionClient = createFusionClient; exports.sleep = sleep; //# sourceMappingURL=index.cjs.map //# sourceMappingURL=index.cjs.map