Commit 6089d38d authored by Jack Short's avatar Jack Short Committed by GitHub

feat: adding price scaling for sudoswap xyk pool (#5804)

* feat: adding price scaling for sudoswap xyk pool

* big number

* updating pricing logic for xyk

* fixing sweep

* removing isnotxykpool

* sudoswap calc refactoring

* refactoring calcpoolprice to include sudoswap

* refactoring calcpoolprice

* not letting asset items equal to 0 to be added

* removing comment
parent 3c6e067e
import { parseEther } from 'ethers/lib/utils' import { parseEther } from 'ethers/lib/utils'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import { GenieAsset, Markets, Trait } from 'nft/types' import { GenieAsset, Markets, Trait } from 'nft/types'
import { isNotXYKPool, wrapScientificNotation } from 'nft/utils' import { wrapScientificNotation } from 'nft/utils'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { import {
...@@ -219,7 +219,7 @@ export function useNftAssets(params: AssetFetcherParams) { ...@@ -219,7 +219,7 @@ export function useNftAssets(params: AssetFetcherParams) {
return useMemo(() => { return useMemo(() => {
return { return {
data: assets?.filter((asset) => isNotXYKPool(asset)), data: assets,
hasNext, hasNext,
loading, loading,
loadMore, loadMore,
...@@ -279,5 +279,5 @@ export function useSweepNftAssets(params: SweepFetcherParams) { ...@@ -279,5 +279,5 @@ export function useSweepNftAssets(params: SweepFetcherParams) {
}), }),
[data?.nftAssets?.edges, data?.nftAssets?.totalCount] [data?.nftAssets?.edges, data?.nftAssets?.totalCount]
) )
return useMemo(() => ({ data: assets?.filter((asset) => isNotXYKPool(asset)), loading }), [assets, loading]) return useMemo(() => ({ data: assets, loading }), [assets, loading])
} }
...@@ -89,7 +89,7 @@ export const CollectionAsset = ({ ...@@ -89,7 +89,7 @@ export const CollectionAsset = ({
}, [asset]) }, [asset])
const handleAddAssetToBag = useCallback(() => { const handleAddAssetToBag = useCallback(() => {
if (BigNumber.from(asset.priceInfo?.ETHPrice ?? 0).gte(0)) { if (BigNumber.from(asset.priceInfo?.ETHPrice ?? 0).gt(0)) {
addAssetsToBag([asset]) addAssetsToBag([asset])
if (!bagExpanded && !isMobile && !bagManuallyClosed) { if (!bagExpanded && !isMobile && !bagManuallyClosed) {
setBagExpanded({ bagExpanded: true }) setBagExpanded({ bagExpanded: true })
......
...@@ -41,7 +41,6 @@ import { ...@@ -41,7 +41,6 @@ import {
} from 'nft/types' } from 'nft/types'
import { import {
calcPoolPrice, calcPoolPrice,
calcSudoSwapPrice,
getRarityStatus, getRarityStatus,
isInSameMarketplaceCollection, isInSameMarketplaceCollection,
isInSameSudoSwapPool, isInSameSudoSwapPool,
...@@ -307,7 +306,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie ...@@ -307,7 +306,6 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
const calculatePrice = useCallback( const calculatePrice = useCallback(
(asset: GenieAsset) => { (asset: GenieAsset) => {
if (asset.marketplace === Markets.Sudoswap) return calcSudoSwapPrice(asset, getPoolPosition(asset))
return calcPoolPrice(asset, getPoolPosition(asset)) return calcPoolPrice(asset, getPoolPosition(asset))
}, },
[getPoolPosition] [getPoolPosition]
......
...@@ -5,7 +5,7 @@ import { formatEther, parseEther } from '@ethersproject/units' ...@@ -5,7 +5,7 @@ import { formatEther, parseEther } from '@ethersproject/units'
import { SweepFetcherParams, useSweepNftAssets } from 'graphql/data/nft/Asset' import { SweepFetcherParams, useSweepNftAssets } from 'graphql/data/nft/Asset'
import { useBag, useCollectionFilters } from 'nft/hooks' import { useBag, useCollectionFilters } from 'nft/hooks'
import { GenieAsset, isPooledMarket, Markets } from 'nft/types' import { GenieAsset, isPooledMarket, Markets } from 'nft/types'
import { calcPoolPrice, calcSudoSwapPrice, formatWeiToDecimal, isInSameSudoSwapPool } from 'nft/utils' import { calcPoolPrice, formatWeiToDecimal, isInSameSudoSwapPool } from 'nft/utils'
import { default as Slider } from 'rc-slider' import { default as Slider } from 'rc-slider'
import { useEffect, useMemo, useReducer, useState } from 'react' import { useEffect, useMemo, useReducer, useState } from 'react'
import styled, { useTheme } from 'styled-components/macro' import styled, { useTheme } from 'styled-components/macro'
...@@ -204,7 +204,7 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { ...@@ -204,7 +204,7 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
jointCollections.forEach((asset) => { jointCollections.forEach((asset) => {
if (!asset.susFlag) { if (!asset.susFlag) {
if (asset.marketplace === Markets.Sudoswap) { if (asset.marketplace === Markets.Sudoswap) {
const poolPrice = calcSudoSwapPrice( const poolPrice = calcPoolPrice(
asset, asset,
sudoSwapAssetsInJointCollections sudoSwapAssetsInJointCollections
.filter((sweepAsset) => isInSameSudoSwapPool(asset, sweepAsset)) .filter((sweepAsset) => isInSameSudoSwapPool(asset, sweepAsset))
...@@ -229,7 +229,7 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => { ...@@ -229,7 +229,7 @@ export const Sweep = ({ contractAddress, minPrice, maxPrice }: SweepProps) => {
}) })
let validAssets = jointCollections.filter( let validAssets = jointCollections.filter(
(asset) => BigNumber.from(asset.priceInfo.ETHPrice).gte(0) && !asset.susFlag (asset) => BigNumber.from(asset.priceInfo.ETHPrice).gt(0) && !asset.susFlag
) )
validAssets = validAssets.slice( validAssets = validAssets.slice(
......
import { DetailsOrigin, GenieAsset, Markets, UpdatedGenieAsset, WalletAsset } from 'nft/types' import { DetailsOrigin, GenieAsset, UpdatedGenieAsset, WalletAsset } from 'nft/types'
import { calcSudoSwapPrice } from './pooledAssets'
export function getRarityStatus( export function getRarityStatus(
rarityStatusCache: Map<string, boolean>, rarityStatusCache: Map<string, boolean>,
...@@ -46,11 +44,3 @@ export const generateTweetForPurchase = (assets: UpdatedGenieAsset[], txHashUrl: ...@@ -46,11 +44,3 @@ export const generateTweetForPurchase = (assets: UpdatedGenieAsset[], txHashUrl:
} with @Uniswap 🦄\n\nhttps://app.uniswap.org/#/nfts/collection/0x60bb1e2aa1c9acafb4d34f71585d7e959f387769\n${txHashUrl}` } with @Uniswap 🦄\n\nhttps://app.uniswap.org/#/nfts/collection/0x60bb1e2aa1c9acafb4d34f71585d7e959f387769\n${txHashUrl}`
return `https://twitter.com/intent/tweet?text=${encodeURIComponent(tweetText)}` return `https://twitter.com/intent/tweet?text=${encodeURIComponent(tweetText)}`
} }
// TODO: remove when BE supports SudoSwap XYK pools
export const isNotXYKPool = (asset: GenieAsset): boolean => {
if (asset.marketplace !== Markets.Sudoswap) return true
if (calcSudoSwapPrice(asset) === undefined) return false
return true
}
...@@ -8,6 +8,7 @@ const PROTOCOL_FEE_MULTIPLIER = BigNumber.from('5000000000000000') ...@@ -8,6 +8,7 @@ const PROTOCOL_FEE_MULTIPLIER = BigNumber.from('5000000000000000')
enum BondingCurve { enum BondingCurve {
Linear = 'LINEAR', Linear = 'LINEAR',
Exponential = 'EXPONENTIAL', Exponential = 'EXPONENTIAL',
Xyk = 'XYK',
} }
interface Pool { interface Pool {
...@@ -32,6 +33,50 @@ const calculateScaledPrice = (currentPrice: BigNumber, poolFee: BigNumber): BigN ...@@ -32,6 +33,50 @@ const calculateScaledPrice = (currentPrice: BigNumber, poolFee: BigNumber): BigN
return currentPrice.add(protocolFee).add(tradeFee) return currentPrice.add(protocolFee).add(tradeFee)
} }
const calcSudoSwapLinearBondingCurve = (currentPrice: BigNumber, delta: BigNumber, position = 0): BigNumber => {
for (let i = 0; i <= position; i++) {
currentPrice = currentPrice.add(delta)
}
return currentPrice
}
const calcSudoSwapExponentialBondingCurve = (currentPrice: BigNumber, delta: BigNumber, position = 0): BigNumber => {
for (let i = 0; i <= position; i++) {
currentPrice = currentPrice.mul(delta).div(BigNumber.from(PRECISION))
}
return currentPrice
}
const calcSudoSwapXykBondingCurve = (
currentPrice: BigNumber,
sudoSwapPool: Pool,
position = 0
): BigNumber | undefined => {
let virtualTokenBalance = BigNumber.from(sudoSwapPool.spotPrice)
let virtualNFTBalance = BigNumber.from(sudoSwapPool.delta)
if (virtualNFTBalance.sub(BigNumber.from(1)).gt(BigNumber.from(0))) {
currentPrice = virtualTokenBalance.div(virtualNFTBalance.sub(BigNumber.from(1)))
} else {
return undefined
}
for (let i = 1; i <= position; i++) {
virtualTokenBalance = virtualTokenBalance.add(currentPrice)
virtualNFTBalance = virtualNFTBalance.sub(BigNumber.from(1))
if (!virtualNFTBalance.sub(BigNumber.from(1)).isZero()) {
currentPrice = virtualTokenBalance.div(virtualNFTBalance.sub(BigNumber.from(1)))
} else {
return undefined
}
}
return currentPrice
}
export const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | undefined => { export const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | undefined => {
if (!asset.sellorders) return undefined if (!asset.sellorders) return undefined
...@@ -45,19 +90,25 @@ export const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | und ...@@ -45,19 +90,25 @@ export const calcSudoSwapPrice = (asset: GenieAsset, position = 0): string | und
const delta = BigNumber.from(sudoSwapPool.delta) const delta = BigNumber.from(sudoSwapPool.delta)
const poolFee = BigNumber.from(sudoSwapPool.fee) const poolFee = BigNumber.from(sudoSwapPool.fee)
for (let i = 0; i <= position; i++) { if (sudoSwapPool.bondingCurve === BondingCurve.Linear) {
if (sudoSwapPool.bondingCurve === BondingCurve.Linear) { currentPrice = calcSudoSwapLinearBondingCurve(currentPrice, delta, position)
currentPrice = currentPrice.add(delta) } else if (sudoSwapPool.bondingCurve === BondingCurve.Exponential) {
} else if (sudoSwapPool.bondingCurve === BondingCurve.Exponential) { currentPrice = calcSudoSwapExponentialBondingCurve(currentPrice, delta, position)
currentPrice = currentPrice.mul(delta).div(BigNumber.from(PRECISION)) } else if (sudoSwapPool.bondingCurve === BondingCurve.Xyk) {
const xykCurrentPrice = calcSudoSwapXykBondingCurve(currentPrice, sudoSwapPool, position)
if (xykCurrentPrice) {
currentPrice = xykCurrentPrice
} else {
return undefined
} }
} else {
return undefined
} }
return calculateScaledPrice(currentPrice, poolFee).toString() return calculateScaledPrice(currentPrice, poolFee).toString()
} }
// TODO: a lot of the below typecasting logic can be simplified when GraphQL migration is complete const calcAmmBasedPoolprice = (asset: GenieAsset, position = 0): string => {
export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
if (!asset.sellorders) return '' if (!asset.sellorders) return ''
let amountToBuy: BigNumber = BigNumber.from(0) let amountToBuy: BigNumber = BigNumber.from(0)
...@@ -120,6 +171,12 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => { ...@@ -120,6 +171,12 @@ export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
return price.toString() return price.toString()
} }
export const calcPoolPrice = (asset: GenieAsset, position = 0): string => {
if (!asset.sellorders) return ''
if (asset.marketplace === Markets.Sudoswap) return calcSudoSwapPrice(asset, position) ?? '0'
return calcAmmBasedPoolprice(asset, position)
}
export const calcAvgGroupPoolPrice = (asset: GenieAsset, numberOfAssets: number) => { export const calcAvgGroupPoolPrice = (asset: GenieAsset, numberOfAssets: number) => {
let total = BigNumber.from(0) let total = BigNumber.from(0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment