diff --git a/packages/address-book/address-book/polygon/tokens/tokens.ts b/packages/address-book/address-book/polygon/tokens/tokens.ts index 3e419c674..236998902 100644 --- a/packages/address-book/address-book/polygon/tokens/tokens.ts +++ b/packages/address-book/address-book/polygon/tokens/tokens.ts @@ -1920,6 +1920,18 @@ const _tokens = { description: 'Axelar Bridged USDC', documentation: 'https://docs.axelar.dev/', }, + BETS: { + name: 'BetSwirl Token', + symbol: 'BETS', + address: '0x9246a5F10A79a5a939b0C2a75A3AD196aAfDB43b', + chainId: 137, + decimals: 18, + logoURI: '', + website: 'https://www.betswirl.com/', + description: + 'BetSwirl is a fully decentralized online cryptocurrency gaming platform, where everyone will be able to enjoy a fair play, a fun time and an innovative gamer experience.', + documentation: 'https://documentation.betswirl.com/', + }, } as const; export const tokens: ConstRecord = _tokens; diff --git a/src/abis/BetSwirlSingleStaking.json b/src/abis/BetSwirlSingleStaking.json new file mode 100644 index 000000000..8d086a82e --- /dev/null +++ b/src/abis/BetSwirlSingleStaking.json @@ -0,0 +1,834 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_stakingToken", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardDuration", + "type": "uint256" + } + ], + "name": "AddRewardToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Recovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "rewardsToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newDuration", + "type": "uint256" + } + ], + "name": "RewardsDurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SetStakingToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_rewardsDistributor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_rewardsDuration", + "type": "uint256" + } + ], + "name": "addReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + } + ], + "name": "earned", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "exit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "__totalSupply", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + } + ], + "internalType": "struct SingleStaking.Token", + "name": "_stakingToken", + "type": "tuple" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + } + ], + "internalType": "struct SingleStaking.Token", + "name": "token", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "rewardsDistributor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "rewardsDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "periodFinish", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastUpdateTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardPerTokenStored", + "type": "uint256" + } + ], + "internalType": "struct SingleStaking.Reward", + "name": "rewardData", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "lastTimeRewardApplicable", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardPerToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardForDuration", + "type": "uint256" + } + ], + "internalType": "struct SingleStaking.RewardToken[]", + "name": "_rewardTokens", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + } + ], + "name": "getRewardForDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getToken", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals", + "type": "uint8" + } + ], + "internalType": "struct SingleStaking.Token", + "name": "_token", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + } + ], + "name": "lastTimeRewardApplicable", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "notifyRewardAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenAmount", + "type": "uint256" + } + ], + "name": "recoverERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardData", + "outputs": [ + { + "internalType": "address", + "name": "rewardsDistributor", + "type": "address" + }, + { + "internalType": "uint256", + "name": "rewardsDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "periodFinish", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardRate", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastUpdateTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardPerTokenStored", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + } + ], + "name": "rewardPerToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "rewardTokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_rewardsDistributor", + "type": "address" + } + ], + "name": "setRewardsDistributor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_rewardsToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_rewardsDuration", + "type": "uint256" + } + ], + "name": "setRewardsDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stakingToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "userRewardPerTokenPaid", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/api/stats/getAmmPrices.ts b/src/api/stats/getAmmPrices.ts index 6f6b24779..cfa23d218 100644 --- a/src/api/stats/getAmmPrices.ts +++ b/src/api/stats/getAmmPrices.ts @@ -578,6 +578,7 @@ const coinGeckoCoins: Record = { axlusdc: ['axlUSDC'], 'mimo-parallel-governance-token': ['MIMO'], olympus: ['OHM'], + betswirl: ['BETS'], }; /** diff --git a/src/api/stats/matic/getBetSwirlSingleApy.js b/src/api/stats/matic/getBetSwirlSingleApy.js new file mode 100644 index 000000000..874706694 --- /dev/null +++ b/src/api/stats/matic/getBetSwirlSingleApy.js @@ -0,0 +1,82 @@ +const BigNumber = require('bignumber.js'); +const { MultiCall } = require('eth-multicall'); +const { polygonWeb3: web3, multicallAddress } = require('../../../utils/web3'); + +const ISingleStaking = require('../../../abis/BetSwirlSingleStaking.json'); +const fetchPrice = require('../../../utils/fetchPrice'); +const { POLYGON_CHAIN_ID: chainId } = require('../../../constants'); +import { getContract } from '../../../utils/contractHelper'; +import getApyBreakdown from '../common/getApyBreakdown'; +import { addressBook } from '../../../../packages/address-book/address-book'; +const { + polygon: { + tokens: { BETS, MATIC }, + }, +} = addressBook; + +const pools = [ + { + name: 'betswirl-poly-bets', + address: BETS.address, + rewardPool: '0xa184468972c71209BC31a5eF39b7321d2A839225', + oracle: 'tokens', + oracleId: 'BETS', + decimals: '1e18', + }, +]; + +const getBetSwirlSingleApy = async () => { + let apys = []; + + apys = await getFarmApys(pools); + + return getApyBreakdown(pools, 0, apys, 0); +}; + +const getFarmApys = async pools => { + const apys = []; + const tokenPrice = await fetchPrice({ oracle: 'tokens', id: 'MATIC' }); + const { balances, rewardRates, finishes } = await getPoolsData(pools); + for (let i = 0; i < pools.length; i++) { + let yearlyRewardsInUsd = new BigNumber(0); + const pool = pools[i]; + + const stakedPrice = await fetchPrice({ oracle: pool.oracle, id: pool.oracleId }); + const totalStakedInUsd = balances[i].times(stakedPrice).dividedBy(pool.decimals); + + if (new BigNumber(finishes[i]).gte(Date.now() / 1000)) { + const secondsPerYear = 31536000; + const yearlyRewards = rewardRates[i].times(secondsPerYear); + yearlyRewardsInUsd = yearlyRewards.times(tokenPrice).dividedBy('1e18'); + } + + const apy = yearlyRewardsInUsd.dividedBy(totalStakedInUsd); + apys.push(apy); + //console.log(pool.name, apy.toNumber(), yearlyRewardsInUsd.toNumber(), totalStakedInUsd.toNumber()); + } + return apys; +}; + +const getPoolsData = async pools => { + const multicall = new MultiCall(web3, multicallAddress(chainId)); + const balanceCalls = []; + const rewardRateCalls = []; + pools.forEach(pool => { + const rewarder = getContract(ISingleStaking, pool.rewardPool); + balanceCalls.push({ + balance: rewarder.methods.totalSupply(), + }); + rewardRateCalls.push({ + rewardRate: rewarder.methods.rewardData(MATIC.address), + }); + }); + + const res = await multicall.all([balanceCalls, rewardRateCalls]); + + const balances = res[0].map(v => new BigNumber(v.balance)); + const rewardRates = res[1].map(v => new BigNumber(v.rewardRate[3])); + const finishes = res[1].map(v => new BigNumber(v.rewardRate[2])); + return { balances, rewardRates, finishes }; +}; + +module.exports = getBetSwirlSingleApy; diff --git a/src/api/stats/matic/index.js b/src/api/stats/matic/index.js index 8fe016b11..b548a76a2 100644 --- a/src/api/stats/matic/index.js +++ b/src/api/stats/matic/index.js @@ -29,6 +29,7 @@ const getKyberPolygonApys = require('./getKyberPolygonApys'); const getOvixApys = require('./getOvixApys'); const { getPearlApys } = require('./getPearlApys'); const { getQuickGammaApys } = require('./getQuickGammaApys'); +const getBetSwirlSingleApy = require('./getBetSwirlSingleApy'); const getApys = [ getbeQiApy, @@ -62,6 +63,7 @@ const getApys = [ getKyberPolygonApys, getOvixApys, getPearlApys, + getBetSwirlSingleApy, ]; const BATCH_SIZE = 15;