Skip to content

Commit

Permalink
Add blueshift farms and stakings for Milkomeda A1 (DefiLlama#458)
Browse files Browse the repository at this point in the history
* Add blueshift farms and stakings for Milkomeda A1

* Delete unknown function export

* Update package-lock.json
  • Loading branch information
L0stic authored Nov 28, 2022
1 parent 96e7ed6 commit 46699ea
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 87 deletions.
16 changes: 9 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 18 additions & 0 deletions src/adaptors/blueshift/config.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
141 changes: 64 additions & 77 deletions src/adaptors/blueshift/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
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;

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) {
Expand All @@ -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
Expand All @@ -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('.');

Expand All @@ -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];
Expand All @@ -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;
Expand All @@ -155,55 +153,49 @@ 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
});
}

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];
Expand All @@ -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);
Expand All @@ -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])
};
1 change: 1 addition & 0 deletions src/adaptors/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down
Loading

0 comments on commit 46699ea

Please sign in to comment.