@ondo-gm/1inch
Version:
1inch Fusion swap integration for Ondo SDK
369 lines (365 loc) • 11.7 kB
JavaScript
;
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