UNPKG

baluni-api

Version:
351 lines (350 loc) 16 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // server.ts const express_1 = __importDefault(require("express")); const constants_1 = require("./constants"); const uniswap_1 = require("./uniswap"); const ethers_1 = require("ethers"); const vault_1 = require("./yearn/vault"); const fetchToken_1 = require("./utils/uniswap/fetchToken"); const cors_1 = __importDefault(require("cors")); const odos_1 = require("./odos"); const body_parser_1 = __importDefault(require("body-parser")); const smart_order_router_1 = require("@uniswap/smart-order-router"); const sdk_1 = require("@uniswap/sdk"); const sdk_core_1 = require("@uniswap/sdk-core"); const parseToken_1 = require("./utils/uniswap/parseToken"); const app = (0, express_1.default)(); const port = 3001; const CONFIGURATIONS = { protocols: constants_1.PROTOCOLS, oracle: constants_1.ORACLE, nativeTokens: constants_1.NATIVETOKENS, networks: constants_1.NETWORKS, }; app.use((0, cors_1.default)()); app.use(body_parser_1.default.json()); app.get('/', (req, res) => { res.send('Hello World!'); }); app.get('/:chainId/uni-v3/tokens', (req, res) => __awaiter(void 0, void 0, void 0, function* () { try { const response = yield fetch(constants_1.TOKENS_URL); const data = yield response.json(); const { chainId } = req.params; const filteredTokens = data.tokens.filter((token) => token.chainId === Number(chainId)); res.json(filteredTokens); } catch (error) { res.status(500).json({ message: 'Failed to fetch tokens', error: error }); } })); app.get('/:chainId/uni-v3/tokens/:tokenSymbol', (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { chainId, tokenSymbol } = req.params; if (!chainId || !tokenSymbol) { return res .status(400) .json({ error: 'Missing chainId or tokenName query parameter' }); } try { const response = yield fetch(constants_1.TOKENS_URL); const data = yield response.json(); const matchingTokens = data.tokens.filter((token) => token.chainId === Number(chainId) && token.symbol.toLowerCase() === tokenSymbol.toString().toLowerCase()); if (matchingTokens.length === 0) { return res.status(404).json({ error: 'Token not found' }); } res.json(matchingTokens[0]); // Returns the first matching token, assuming names are unique per chainId } catch (error) { res.status(500).json({ message: 'Failed to fetch tokens', error: error }); } })); app.get('/:chainId/yearn-v3/vaults/:tokenSymbol', (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { tokenSymbol, chainId } = req.params; const { strategyType, boosted } = req.query; const apiURL = `https://ydaemon.yearn.fi/${chainId}/vaults/all`; try { const response = yield fetch(apiURL); const data = yield response.json(); let filteredVaults = data.filter(vault => { var _a; const matchesSymbol = vault.token.symbol.toLowerCase() === tokenSymbol.toLowerCase(); const isVersion3 = ((_a = vault.version) === null || _a === void 0 ? void 0 : _a.startsWith('3.0')) || vault.name.includes('3.0') || vault.symbol.includes('3.0'); let matchesStrategyType = true; let matchesBoosted = true; if (strategyType === 'multi') { matchesStrategyType = vault.kind === 'Multi Strategy'; } else if (strategyType === 'single') { matchesStrategyType = vault.kind !== 'Multi Strategy'; } // Check if boosted filter is applied if (boosted === 'true') { matchesBoosted = vault.boosted === true; } return (matchesSymbol && isVersion3 && matchesStrategyType && matchesBoosted); }); if (filteredVaults.length === 0) { return res .status(404) .json({ error: 'Vault not found for the given criteria' }); } const vault = filteredVaults[0]; res.json({ vaultAddress: vault.address, vaultName: vault.name, vaultSymbol: vault.symbol, tokenAddress: vault.token.address, tokenName: vault.token.name, tokenSymbol: vault.token.symbol, strategyType: vault.kind, version: vault.version, boosted: vault.boosted, // Include boosted status in the response }); } catch (error) { console.error('Failed to fetch Yearn Finance vaults:', error); res.status(500).json({ error: 'Failed to fetch Yearn Finance vaults' }); } })); app.get('/:chainId/yearn-v3/vaults', (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { chainId } = req.params; const apiURL = `https://ydaemon.yearn.fi/${chainId}/vaults/all`; try { const response = yield fetch(apiURL); const data = yield response.json(); res.json(data.map(vault => ({ vaultAddress: vault.address, vaultName: vault.name, vaultSymbol: vault.symbol, tokenAddress: vault.token.address, tokenName: vault.token.name, tokenSymbol: vault.token.symbol, }))); } catch (error) { console.error('Failed to fetch Yearn Finance vaults:', error); res.status(500).json({ error: 'Failed to fetch Yearn Finance vaults.' }); } })); app.get('/config/:chainId/:protocolName/:contractName', (req, res) => { var _a, _b, _c; const { chainId, contractName, protocolName } = req.params; const config = (_c = (_b = (_a = CONFIGURATIONS['protocols']) === null || _a === void 0 ? void 0 : _a[chainId]) === null || _b === void 0 ? void 0 : _b[protocolName]) === null || _c === void 0 ? void 0 : _c[contractName.toUpperCase()]; if (!config) { return res .status(404) .json({ error: 'Configuration not found for the given parameters' }); } res.json({ chainId, contractName, address: config }); }); app.get('/:chainId/uni-v3/swap/:address/:token0/:token1/:reverse/:amount/:slippage', (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, token0, token1, reverse, chainId, amount, slippage } = req.params; try { const tokenAAddress = yield (0, fetchToken_1.fetchTokenAddressByName)(token0, Number(chainId)); const tokenBAddress = yield (0, fetchToken_1.fetchTokenAddressByName)(token1, Number(chainId)); const wallet = new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY, new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[chainId])); const swapResult = yield (0, uniswap_1.buildSwap)(wallet, address, tokenAAddress, tokenBAddress, Boolean(reverse), 'uni-v3', chainId, amount, Number(slippage)); console.log('Swap result:', swapResult); res.json({ Approvals: swapResult.Approvals, Calldatas: swapResult.Calldatas, TokensReturn: swapResult.TokensReturn, }); } catch (error) { console.error('Error during swap operation:', error); res.status(500).json({ error: 'Error during swap operation' }); } })); app.get('/:chainId/yearn-v3/deposit/:tokenSymbol/:strategy/:boosted/:amount/:receiver/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { try { const { tokenSymbol, strategy, amount, receiver, chainId, boosted } = req.params; // Ora `config` è del tipo corretto const filteredVaults = yield fetchYearnVaultsData(Number(chainId)); filteredVaults .filter(vault => { var _a; const matchesSymbol = vault.token.symbol.toLowerCase() === tokenSymbol.toLowerCase(); const isVersion3 = ((_a = vault.version) === null || _a === void 0 ? void 0 : _a.startsWith('3.0')) || vault.name.includes('3.0') || vault.symbol.includes('3.0'); let matchesStrategyType = true; let matchesBoosted = true; if (strategy === 'multi') { matchesStrategyType = vault.kind === 'Multi Strategy'; } else if (strategy === 'single') { matchesStrategyType = vault.kind !== 'Multi Strategy'; } if (boosted === 'true') { matchesBoosted = vault.boosted === true; } return (matchesSymbol && isVersion3 && matchesStrategyType && matchesBoosted); }) .map(vault => vault.address); const vaultAddress = filteredVaults[0]; const tokenAddress = yield (0, fetchToken_1.fetchTokenAddressByName)(tokenSymbol, Number(chainId)); const walletInstance = new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY, new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[chainId])); let adjAmount; if (tokenSymbol === 'USDC' || tokenSymbol === 'USDT' || tokenSymbol === 'USDC.E') { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 6); } else if (tokenSymbol === 'WBTC') { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 8); } else { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 18); } const result = yield (0, vault_1.depositToYearn)(walletInstance, tokenAddress, vaultAddress.address, adjAmount, receiver, chainId); res.json(result); } catch (error) { console.error(error); res.status(500).json({ error: error.toString() }); } })); app.get(':chainId/yearn-v3/redeem/:tokenSymbol/:strategy/:boosted/:amount/:receiver/', (req, res) => __awaiter(void 0, void 0, void 0, function* () { try { const { tokenSymbol, strategy, amount, receiver, chainId, boosted } = req.params; let adjAmount; if (tokenSymbol === 'USDC' || tokenSymbol === 'USDT' || tokenSymbol === 'USDC.E') { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 6); } else if (tokenSymbol === 'WBTC') { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 8); } else { adjAmount = ethers_1.ethers.utils.parseUnits(amount, 18); } const filteredVaults = yield fetchYearnVaultsData(Number(chainId)); filteredVaults .filter(vault => { var _a; const matchesSymbol = vault.token.symbol.toLowerCase() === tokenSymbol.toLowerCase(); const isVersion3 = ((_a = vault.version) === null || _a === void 0 ? void 0 : _a.startsWith('3.0')) || vault.name.includes('3.0') || vault.symbol.includes('3.0'); let matchesStrategyType = true; let matchesBoosted = true; if (strategy === 'multi') { matchesStrategyType = vault.kind === 'Multi Strategy'; } else if (strategy === 'single') { matchesStrategyType = vault.kind !== 'Multi Strategy'; } if (boosted === 'true') { matchesBoosted = vault.boosted === true; } return (matchesSymbol && isVersion3 && matchesStrategyType && matchesBoosted); }) .map(vault => vault.address); const vaultAddress = filteredVaults[0]; const walletInstance = new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY, new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[chainId])); const result = yield (0, vault_1.redeemFromYearn)(walletInstance, vaultAddress.address, adjAmount, receiver, chainId); res.json(result); } catch (error) { console.error(error); res.status(500).json({ error: error.toString() }); } })); app.post('/:chainId/odos/swap', (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, inputTokens, outputTokens, slippage } = req.body; const { chainId } = req.params; try { const inputTokensArray = inputTokens.map((token) => ({ tokenAddress: token.tokenAddress, amount: token.amount, })); const outputTokensArray = outputTokens.map((token) => ({ tokenAddress: token.tokenAddress, proportion: token.proportion, })); const wallet = new ethers_1.ethers.Wallet(process.env.PRIVATE_KEY, new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[chainId])); const swapResult = yield (0, odos_1.buildSwapOdos)(wallet, address, chainId, inputTokensArray, outputTokensArray, Number(slippage), 3844415834, // referralCode false, // disableRFQs true // compact ); console.log('Swap result:', swapResult); res.json({ Approvals: swapResult.Approvals, Calldatas: swapResult.Calldatas, TokensReturn: swapResult.TokensReturn, }); } catch (error) { console.error('Error during swap operation:', error); res.status(500).json({ error: 'Error during swap operation' }); } })); app.post('/route', (req, res) => { const reqBody = req.body; const router = new smart_order_router_1.AlphaRouter({ chainId: reqBody.chainId, provider: new ethers_1.ethers.providers.JsonRpcProvider(constants_1.NETWORKS[reqBody.chainId]), }); const currencyAmount = (0, parseToken_1.parseToken)(reqBody.currencyAmount, reqBody.chainId); const currency = (0, parseToken_1.parseToken)(reqBody.currency, reqBody.chainId); const tradeType = reqBody.tradeType || sdk_1.TradeType.EXACT_INPUT; const SLIPPAGE = new sdk_core_1.Percent(50, 10000); // Correct 15% router .route(smart_order_router_1.CurrencyAmount.fromRawAmount(currencyAmount, reqBody.amount), currency, tradeType, { slippageTolerance: SLIPPAGE, type: smart_order_router_1.SwapType.UNIVERSAL_ROUTER, recipient: ethers_1.ethers.constants.AddressZero, deadlineOrPreviousBlockhash: Math.floor(Date.now() / 1000) + 360, }, { minSplits: 3, }) .then(route => { if (!route) { res.status(404); res.send('No route found'); return; } res.json(route); }) .catch(err => { res.status(500); res.send('Internal server error'); console.log(err); }); }); // HELPER FUNCTIONS function fetchYearnVaultsData(chainId) { return __awaiter(this, void 0, void 0, function* () { try { const apiURL = `https://ydaemon.yearn.fi/${chainId}/vaults/all`; const response = yield fetch(apiURL); const data = yield response.json(); return data; } catch (error) { console.error('Failed to fetch Yearn Finance vaults:', error); return []; } }); } app.listen(port, () => { console.log(`Server running on port ${port}`); });