Add blueshift farms and stakings for Milkomeda A1 (#458)

* Add blueshift farms and stakings for Milkomeda A1

* Delete unknown function export

* Update package-lock.json
This commit is contained in:
Dmitriy Kondratev
2022-11-28 11:19:50 +03:00
committed by GitHub
parent 96e7ed651d
commit 46699ea4e1
6 changed files with 125 additions and 87 deletions

16
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@defillama/sdk": "^2.3.98",
"@defillama/sdk": "^2.3.126",
"@types/jest": "^28.1.6",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/smart-order-router": "^2.8.0",
@@ -738,11 +738,12 @@
}
},
"node_modules/@defillama/sdk": {
"version": "2.3.102",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-2.3.102.tgz",
"integrity": "sha512-qvteOAHPtxDKfqdrIoEdgMKDnEEMnv5e8g1i3uZcN0UsPE7CYzebLzPFK99+iH+dbUXvPOxgVtAEKYgz7s8WMg==",
"version": "2.3.126",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-2.3.126.tgz",
"integrity": "sha512-vPK2o75d4wiRcsf1Osx9Kan/fPNhuNRU5wJ8BxaWkV3hEIXiFOmZ5Vse8s5NtvINnTg3HVPNN7L6fRk//koV3Q==",
"dependencies": {
"@supercharge/promise-pool": "^2.1.0",
"bignumber.js": "^9.1.0",
"ethers": "^5.4.5",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
@@ -20353,11 +20354,12 @@
}
},
"@defillama/sdk": {
"version": "2.3.102",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-2.3.102.tgz",
"integrity": "sha512-qvteOAHPtxDKfqdrIoEdgMKDnEEMnv5e8g1i3uZcN0UsPE7CYzebLzPFK99+iH+dbUXvPOxgVtAEKYgz7s8WMg==",
"version": "2.3.126",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-2.3.126.tgz",
"integrity": "sha512-vPK2o75d4wiRcsf1Osx9Kan/fPNhuNRU5wJ8BxaWkV3hEIXiFOmZ5Vse8s5NtvINnTg3HVPNN7L6fRk//koV3Q==",
"requires": {
"@supercharge/promise-pool": "^2.1.0",
"bignumber.js": "^9.1.0",
"ethers": "^5.4.5",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",

View File

@@ -12,7 +12,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@defillama/sdk": "^2.3.98",
"@defillama/sdk": "^2.3.126",
"@types/jest": "^28.1.6",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/smart-order-router": "^2.8.0",

View File

@@ -0,0 +1,18 @@
{
"network": {
"milkomeda": "Cardano",
"milkomeda_a1": "Algorand"
},
"apiUrl": {
"milkomeda": "https://api.blueshift.fi/api",
"milkomeda_a1": "https://a1.api.blueshift.fi/api"
},
"registry": {
"milkomeda": "0x83E384d119adA05195Caca26396B8f56fdDA1c91",
"milkomeda_a1": "0xa2f7a17872C5A02097970De636EDa8a088aeC9ab"
},
"minter": {
"milkomeda": "0xdE6AB15d0786a0034B28Ed7e6B21ed95099CF48B",
"milkomeda_a1": "0x6455b3FE3cB9815d71D296f0CFFEfc1d591A91f3"
}
}

View File

@@ -1,16 +1,11 @@
const sdk = require('@defillama/sdk');
const utils = require('../utils');
const { BigNumber } = require('ethers');
// const { default: BigNumber } = require('bignumber.js');
const { transformMilkomedaAddress } = require('../../helper/transform');
const { AddressZero } = require('@ethersproject/constants');
const { getChainTransform, getFixBalances } = require('../../helper/transform');
const abi = require('./abi.json');
const API_URL = 'https://api.blueshift.fi/api/portfolio/fee';
const REGISTRY_CONTRACT = '0x83E384d119adA05195Caca26396B8f56fdDA1c91';
const MINTER_CONTRACT = '0xdE6AB15d0786a0034B28Ed7e6B21ed95099CF48B';
const MANUAL_POOL_CONTRACT = '0xA4f0e3C80C77b347250B9D3999478E305FF814A4';
const config = require("./config.json");
const BLOCKS_PER_YEAR = 8e6;
@@ -18,6 +13,9 @@ const MONTHS_IN_YEAR = 12;
const DAYS_IN_YEAR = 365;
const NUMBER_OF_PERIODS = DAYS_IN_YEAR;
const ONE = (decimals) => BigNumber.from(10).pow(decimals);
const TRANSFORM_TO_PERCENTS = (num) => num * 100;
function formatBigNumber(num, decimals) {
if (num.length > decimals) {
@@ -27,11 +25,11 @@ function formatBigNumber(num, decimals) {
}
}
async function getFees(portfolios) {
async function getFees(chain, portfolios) {
const res = {};
const fees = (await utils.getData(
API_URL,
`${config.apiUrl[chain]}/portfolio/fee`,
{
portfolio: portfolios,
period: 30
@@ -45,10 +43,10 @@ async function getFees(portfolios) {
return res;
}
async function getBluesPrice() {
async function getTokenVsUsdPrice(token) {
const bluesPrice = (await utils.getData(
'https://api.coingecko.com/api/v3/simple/price?ids=blueshift&vs_currencies=usd'
)).blueshift.usd;
`https://api.coingecko.com/api/v3/simple/price?ids=${token}&vs_currencies=usd`
))[token].usd;
const [i, f] = bluesPrice.toString().split('.');
@@ -75,38 +73,37 @@ function apy(apr, aprWeights) {
return apy1 + apr2 / apr1 * (apy1 - 1) - 1;
}
async function farming(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
async function farming(chain, aprWeights, rewardToken, BLUES_PRICE, portfolios) {
const res = [];
const transform = await transformMilkomedaAddress();
const transform = await getChainTransform(chain);
const fixBalances = await getFixBalances(chain);
const fees = await getFees(portfolios.map(portfolio => portfolio.contractAddress));
const fees = await getFees(chain, portfolios.map(portfolio => portfolio.contractAddress));
const farms = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.getFarms,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [],
// block: chainBlocks['milkomeda'],
})).output;
const farmInfos = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.getStatusFarms,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [
"0x0000000000000000000000000000000000000000",
(await sdk.api.util.getLatestBlock("milkomeda")).timestamp
AddressZero,
(await sdk.api.util.getLatestBlock(chain)).timestamp
],
// block: chainBlocks['milkomeda'],
})).output;
for (let farm of farms) {
const receivedToken = (await sdk.api.abi.call({
abi: abi.BlueshiftEarning.getToken,
chain: 'milkomeda',
chain: chain,
target: farm,
params: [],
// block: chainBlocks['milkomeda'],
})).output;
const portfolioInfo = portfolios.filter(portfolio => portfolio.lpTokenAddress === receivedToken)[0];
@@ -123,24 +120,25 @@ async function farming(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
const tokensSymbols = (await sdk.api.abi.multiCall({
abi: abi.ERC20.symbol,
chain: 'milkomeda',
chain: chain,
calls: tokensAddresses.map(tokenAddress => ({
target: tokenAddress,
params: []
})),
// block: chainBlocks['milkomeda'],
requery: true,
})).output.map(s => s.output);
const rewardedFee = Number(formatBigNumber(BigNumber.from(fees[portfolioInfo.contractAddress]).mul(MONTHS_IN_YEAR).toString(), 6));
const rewardedStake = Number(formatBigNumber(BigNumber.from(farmInfo.rewardPerBlock).mul(BLOCKS_PER_YEAR).mul(BLUES_PRICE).div(BigNumber.from(10).pow(18)).toString(), 6));
const rewardedStake = Number(formatBigNumber(BigNumber.from(farmInfo.rewardPerBlock).mul(BLOCKS_PER_YEAR).mul(BLUES_PRICE).div(ONE(18)).toString(), 6));
let tvl = farmInfo.accDeposited;
tvl = BigNumber.from(tvl).mul(BigNumber.from(portfolioInfo.lpTokenPrice)).div(BigNumber.from(10).pow(18));
tvl = BigNumber.from(tvl).mul(BigNumber.from(portfolioInfo.lpTokenPrice)).div(ONE(18));
const balances = {};
await sdk.util.sumSingleBalance(balances, transform(portfolioInfo.baseTokenAddress), tvl.toString());
const tvlUsd = (await sdk.util.computeTVL(balances, "now")).usdTvl;
let balances = {};
let tvlUsd = 0;
sdk.util.sumSingleBalance(balances, transform(portfolioInfo.baseTokenAddress), tvl.toString());
fixBalances(balances);
tvlUsd = (await sdk.util.computeTVL(balances, "now")).usdTvl;
const aprBase = rewardedFee / tvlUsd;
const aprReward = rewardedStake / tvlUsd;
@@ -155,16 +153,16 @@ async function farming(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
// console.log("apyReward:", apyReward.toString());
res.push({
pool: `${farm}`.toLowerCase(),
chain: utils.formatChain('milkomeda'),
pool: farm.toLowerCase(),
chain: utils.formatChain(chain),
project: 'blueshift',
symbol: tokensSymbols.join('-'),
apyBase: aprBase * 100,
apyReward: aprReward * 100,
apyBase: TRANSFORM_TO_PERCENTS(apyBase),
apyReward: TRANSFORM_TO_PERCENTS(apyReward),
tvlUsd: tvlUsd,
rewardTokens: [rewardToken],
underlyingTokens: tokensAddresses,
url: 'https://app.blueshift.fi/#/farming',
url: `https://app.blueshift.fi/#/farming?network=${config.network[chain]}`,
poolMeta: portfolioInfo.name
});
}
@@ -172,38 +170,32 @@ async function farming(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
return res;
}
async function staking(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
async function staking(chain, aprWeights, rewardToken, BLUES_PRICE, portfolios) {
const res = [];
const transform = await transformMilkomedaAddress();
const stakings = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.getStakings,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [],
// block: chainBlocks['milkomeda'],
})).output;
// console.log(stakings);
const stakingInfos = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.getStatusStaking,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [
"0x0000000000000000000000000000000000000000",
(await sdk.api.util.getLatestBlock("milkomeda")).timestamp
AddressZero,
(await sdk.api.util.getLatestBlock(chain)).timestamp
],
// block: chainBlocks['milkomeda'],
})).output;
for (let staking of stakings) {
const receivedToken = (await sdk.api.abi.call({
abi: abi.BlueshiftEarning.getToken,
chain: 'milkomeda',
chain: chain,
target: staking,
params: [],
// block: chainBlocks['milkomeda'],
})).output;
const stakingInfo = stakingInfos.filter(stakingInfo => stakingInfo.farm === staking)[0];
@@ -212,7 +204,7 @@ async function staking(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
}
let tvl = stakingInfo.accDeposited;
const tvlUsd = BigNumber.from(tvl).mul(BLUES_PRICE).div(BigNumber.from(10).pow(18)).toString();
const tvlUsd = BigNumber.from(tvl).mul(BLUES_PRICE).div(ONE(18)).toString();
const aprReward = BigNumber.from(stakingInfo.rewardPerBlock).mul(BLOCKS_PER_YEAR).mul(10000).div(tvl);
const apyReward = apy(Number(formatBigNumber(aprReward.toString(), 4)), aprWeights);
@@ -222,61 +214,56 @@ async function staking(aprWeights, rewardToken, BLUES_PRICE, portfolios) {
res.push({
pool: `${staking}`.toLowerCase(),
chain: utils.formatChain('milkomeda'),
chain: utils.formatChain(chain),
project: 'blueshift',
symbol: 'BLUES',
apyBase: null,
apyReward: apyReward * 100,
apyReward: TRANSFORM_TO_PERCENTS(apyReward),
tvlUsd: Number(formatBigNumber(tvlUsd.toString(), 6)),
rewardTokens: [rewardToken],
underlyingTokens: [rewardToken],
url: 'https://app.blueshift.fi/#/staking'
url: `https://app.blueshift.fi/#/staking?network=${config.network[chain]}`
});
}
return res;
}
async function poolsApy(timestamp, block, chainBlocks) {
const res = [];
const transform = await transformMilkomedaAddress();
const BLUES_PRICE = await getBluesPrice();
async function poolsApy(chain) {
const BLUES_PRICE = await getTokenVsUsdPrice("blueshift");
const portfolios = (await sdk.api.abi.call({
abi: abi.BlueshiftRegistry.getPortfolios,
chain: 'milkomeda',
target: REGISTRY_CONTRACT,
chain: chain,
target: config.registry[chain],
params: [],
// block: chainBlocks['milkomeda'],
})).output;
const rewardToken = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.token,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [],
// block: chainBlocks['milkomeda'],
})).output;
const aprWeights = (await sdk.api.abi.call({
abi: abi.BlueshiftMinter.getAprWeights,
chain: 'milkomeda',
target: MINTER_CONTRACT,
chain: chain,
target: config.minter[chain],
params: [],
// block: chainBlocks['milkomeda'],
})).output;
(await farming(aprWeights, rewardToken, BLUES_PRICE, portfolios))
.map(elem => res.push(elem));
const farmingPools = await farming(chain, aprWeights, rewardToken, BLUES_PRICE, portfolios);
const stakingPools = await staking(chain, aprWeights, rewardToken, BLUES_PRICE, portfolios);
(await staking(aprWeights, rewardToken, BLUES_PRICE, portfolios))
.map(elem => res.push(elem));
return res;
return [...farmingPools, ...stakingPools];
}
module.exports = {
timetravel: false,
apy: poolsApy
apy: async () => (await Promise.all([
"milkomeda",
"milkomeda_a1"
].map(async chain => await poolsApy(chain))))
.reduce((a, b) => [...a, ...b])
};

View File

@@ -10,6 +10,7 @@ exports.formatChain = (chain) => {
if (chain && chain.toLowerCase() === 'okexchain') return 'OKExChain';
if (chain && chain.toLowerCase() === 'bsc') return 'Binance';
if (chain && chain.toLowerCase() === 'milkomeda') return 'Milkomeda C1';
if (chain && chain.toLowerCase() === 'milkomeda_a1') return 'Milkomeda A1';
return chain.charAt(0).toUpperCase() + chain.slice(1);
};

View File

@@ -994,6 +994,25 @@ const energiFixMapping = {
'0xa55f26319462355474a9f2c8790860776a329aa4': { coingeckoId: 'energi', decimals: 18, },
}
const milkomedaFixMapping = {
"0x0000000000000000000000000000000000000000": { coingeckoId: "cardano", decimals: 18 },
"0xAE83571000aF4499798d1e3b0fA0070EB3A3E3F9": { coingeckoId: "cardano", decimals: 18 },
"0x4bf769b05e832fcdc9053fffbc78ca889acb5e1e": { coingeckoId: "binance-usd", decimals: 18 },
'0x41eAFC40CD5Cb904157A10158F73fF2824dC1339': { coingeckoId: "dai", decimals: 6 },
'0xab58DA63DFDd6B97EAaB3C94165Ef6f43d951fb2': { coingeckoId: "tether", decimals: 6 },
'0x5a955FDdF055F2dE3281d99718f5f1531744B102': { coingeckoId: "usd-coin", decimals: 6 },
"0x8c008BBA2Dd56b99f4A6aB276bE3a478cB075F0C": { coingeckoId: "blueshift", decimals: 18 }
}
const milkomeda_a1FixMapping = {
"0x0000000000000000000000000000000000000000": { coingeckoId: "algorand", decimals: 18 },
"0xaF86E6c5Fd9dAf53e5100ed38BaB2572609fCA27": { coingeckoId: "algorand", decimals: 18 },
"0xBc31960A049Fe10297Ed8432Fb61DD734fEAd4ea": { coingeckoId: "usd-coin", decimals: 6 },
"0x32564ae38E5DBf316958CE25A6aD2A2249EbCc2D": { coingeckoId: "tether", decimals: 6 },
"0x522B61755b5FF8176B2931DA7bF1a5F9414Eb710": { coingeckoId: "tether", decimals: 6 },
"0xc9BAA8cfdDe8E328787E29b4B078abf2DaDc2055": { coingeckoId: "blueshift", decimals: 18 }
}
const fixBalancesMapping = {
avax: fixAvaxBalances,
@@ -1014,6 +1033,8 @@ const fixBalancesMapping = {
oasis: fixOasisBalances,
bittorrent: b => fixBalances(b, bittorrentFixMapping, { removeUnmapped: false }),
syscoin: b => fixBalances(b, syscoinFixMapping, { removeUnmapped: true }),
milkomeda: b => fixBalances(b, milkomedaFixMapping, { removeUnmapped: false }),
milkomeda_a1: b => fixBalances(b, milkomeda_a1FixMapping, { removeUnmapped: false }),
}
const chainTransforms = {
@@ -1034,6 +1055,7 @@ const chainTransforms = {
optimism: transformOptimismAddress,
moonriver: transformMoonriverAddress,
milkomeda: transformMilkomedaAddress,
milkomeda_a1: transformMilkomedaAddress,
okex: transformOkexAddress,
kcc: transformKccAddress,
arbitrum: transformArbitrumAddress,
@@ -1102,14 +1124,21 @@ async function transformMilkomedaAddress() {
// '0x0000000000000000000000000000000000000000': '' // MilkADA
'0x5950F9B6EF36f3127Ea66799e64D0ea1f5fdb9D1': '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH
'0x41eAFC40CD5Cb904157A10158F73fF2824dC1339': '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
'0xab58DA63DFDd6B97EAaB3C94165Ef6f43d951fb2': '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
'0x5a955FDdF055F2dE3281d99718f5f1531744B102': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
'0x3795C36e7D12A8c252A20C5a7B455f7c57b60283': '0xdac17f958d2ee523a2206206994597c13d831ec7', // Celer USDT -> USDT
'0xab58DA63DFDd6B97EAaB3C94165Ef6f43d951fb2': '0xdac17f958d2ee523a2206206994597c13d831ec7', // Nomad USDT -> USDT
'0x5a955FDdF055F2dE3281d99718f5f1531744B102': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // Nomad USDC -> USDC
'0x48AEB7584BA26D3791f06fBA360dB435B3d7A174': '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', // WBTC
}
return transformChainAddress(mapping, 'milkomeda')
}
async function transformMilkomedaA1Address() {
const mapping = {}
return transformChainAddress(mapping, 'milkomeda_a1')
}
async function transformFindoraAddress() {
const mapping = {
'0xABc979788c7089B516B8F2f1b5cEaBd2E27Fd78b': 'bsc:0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', // BNB token
@@ -1174,6 +1203,7 @@ module.exports = {
transformOasisAddress,
transformOasisAddressBase,
transformMilkomedaAddress,
transformMilkomedaA1Address,
transformDfkAddress,
transformFindoraAddress,
wavesMapping,