2022-02-16 19:42:35 +01:00
|
|
|
import { approve, Pool, PoolPriceAndFees } from '@oceanprotocol/lib'
|
2022-02-14 17:27:36 +01:00
|
|
|
import Web3 from 'web3'
|
|
|
|
import { getDummyWeb3 } from './web3'
|
|
|
|
import { TransactionReceipt } from 'web3-eth'
|
|
|
|
import Decimal from 'decimal.js'
|
|
|
|
import { AccessDetails } from 'src/@types/Price'
|
2022-04-22 02:38:35 +02:00
|
|
|
import { consumeMarketPoolSwapFee, marketFeeAddress } from '../../app.config'
|
|
|
|
|
2022-02-14 17:27:36 +01:00
|
|
|
/**
|
|
|
|
* This is used to calculate the price to buy one datatoken from a pool, that is different from spot price. You need to pass either a web3 object or a chainId. If you pass a chainId a dummy web3 object will be created
|
|
|
|
* @param {AccessDetails} accessDetails
|
|
|
|
* @param {Web3?} [web3]
|
|
|
|
* @param {number?} [chainId]
|
2022-02-16 19:42:35 +01:00
|
|
|
* @return {Promise<PoolPriceAndFees>}
|
2022-02-14 17:27:36 +01:00
|
|
|
*/
|
|
|
|
export async function calculateBuyPrice(
|
|
|
|
accessDetails: AccessDetails,
|
|
|
|
chainId?: number,
|
|
|
|
web3?: Web3
|
2022-02-16 19:42:35 +01:00
|
|
|
): Promise<PoolPriceAndFees> {
|
2022-02-14 17:27:36 +01:00
|
|
|
if (!web3 && !chainId)
|
|
|
|
throw new Error("web3 and chainId can't be undefined at the same time!")
|
|
|
|
|
|
|
|
if (!web3) {
|
|
|
|
web3 = await getDummyWeb3(chainId)
|
|
|
|
}
|
|
|
|
|
|
|
|
const pool = new Pool(web3)
|
2022-04-22 02:38:35 +02:00
|
|
|
|
2022-02-14 17:27:36 +01:00
|
|
|
const estimatedPrice = await pool.getAmountInExactOut(
|
|
|
|
accessDetails.addressOrId,
|
|
|
|
accessDetails.baseToken.address,
|
|
|
|
accessDetails.datatoken.address,
|
|
|
|
'1',
|
2022-04-22 02:38:35 +02:00
|
|
|
consumeMarketPoolSwapFee
|
2022-02-14 17:27:36 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
return estimatedPrice
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function buyDtFromPool(
|
|
|
|
accessDetails: AccessDetails,
|
|
|
|
accountId: string,
|
|
|
|
web3: Web3
|
|
|
|
): Promise<TransactionReceipt> {
|
|
|
|
const pool = new Pool(web3)
|
|
|
|
// we need to calculate the actual price to buy one datatoken
|
|
|
|
const dtPrice = await calculateBuyPrice(accessDetails, null, web3)
|
|
|
|
const approveTx = await approve(
|
|
|
|
web3,
|
|
|
|
accountId,
|
|
|
|
accessDetails.baseToken.address,
|
|
|
|
accessDetails.addressOrId,
|
2022-02-16 19:42:35 +01:00
|
|
|
dtPrice.tokenAmount,
|
2022-02-14 17:27:36 +01:00
|
|
|
false
|
|
|
|
)
|
2022-03-11 12:25:51 +01:00
|
|
|
if (!approveTx) {
|
|
|
|
return
|
|
|
|
}
|
2022-02-14 17:27:36 +01:00
|
|
|
const result = await pool.swapExactAmountOut(
|
|
|
|
accountId,
|
|
|
|
accessDetails.addressOrId,
|
|
|
|
{
|
2022-04-22 02:38:35 +02:00
|
|
|
marketFeeAddress,
|
2022-02-14 17:27:36 +01:00
|
|
|
tokenIn: accessDetails.baseToken.address,
|
|
|
|
tokenOut: accessDetails.datatoken.address
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// this is just to be safe
|
2022-02-16 19:42:35 +01:00
|
|
|
maxAmountIn: new Decimal(dtPrice.tokenAmount).mul(10).toString(),
|
2022-04-22 02:38:35 +02:00
|
|
|
swapMarketFee: consumeMarketPoolSwapFee,
|
2022-02-14 17:27:36 +01:00
|
|
|
tokenAmountOut: '1'
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2022-03-09 13:58:54 +01:00
|
|
|
|
|
|
|
/**
|
2022-04-22 02:38:35 +02:00
|
|
|
* This is used to calculate the actual price of buying a datatoken, it's a copy of the math in the contracts.
|
|
|
|
* @param params
|
2022-03-09 13:58:54 +01:00
|
|
|
* @returns
|
|
|
|
*/
|
2022-04-22 02:38:35 +02:00
|
|
|
export function calcInGivenOut(params: CalcInGivenOutParams): PoolPriceAndFees {
|
|
|
|
const result = {
|
|
|
|
tokenAmount: '0',
|
|
|
|
liquidityProviderSwapFeeAmount: '0',
|
|
|
|
oceanFeeAmount: '0',
|
|
|
|
publishMarketSwapFeeAmount: '0',
|
|
|
|
consumeMarketSwapFeeAmount: '0'
|
|
|
|
} as PoolPriceAndFees
|
|
|
|
const one = new Decimal(1)
|
|
|
|
const tokenOutLiqudity = new Decimal(params.tokenOutLiquidity)
|
|
|
|
const tokenInLiquidity = new Decimal(params.tokenInLiquidity)
|
|
|
|
const tokenOutAmount = new Decimal(params.tokenOutAmount)
|
|
|
|
const opcFee = new Decimal(params.opcFee)
|
|
|
|
const lpFee = new Decimal(params.lpSwapFee)
|
|
|
|
const publishMarketSwapFee = new Decimal(params.publishMarketSwapFee)
|
|
|
|
const consumeMarketSwapFee = new Decimal(params.consumeMarketSwapFee)
|
|
|
|
|
|
|
|
const diff = tokenOutLiqudity.minus(tokenOutAmount)
|
|
|
|
const y = tokenOutLiqudity.div(diff)
|
|
|
|
let foo = y.pow(one)
|
|
|
|
foo = foo.minus(one)
|
|
|
|
const totalFee = lpFee
|
|
|
|
.plus(opcFee)
|
|
|
|
.plus(publishMarketSwapFee)
|
|
|
|
.plus(consumeMarketSwapFee)
|
|
|
|
|
|
|
|
const tokenAmountIn = tokenInLiquidity.mul(foo).div(one.sub(totalFee))
|
|
|
|
result.tokenAmount = tokenAmountIn.toString()
|
|
|
|
result.oceanFeeAmount = tokenAmountIn
|
|
|
|
.sub(tokenAmountIn.mul(one.sub(opcFee)))
|
|
|
|
.toString()
|
|
|
|
result.publishMarketSwapFeeAmount = tokenAmountIn
|
|
|
|
.sub(tokenAmountIn.mul(one.sub(publishMarketSwapFee)))
|
|
|
|
.toString()
|
|
|
|
result.consumeMarketSwapFeeAmount = tokenAmountIn
|
|
|
|
.sub(tokenAmountIn.mul(one.sub(consumeMarketSwapFee)))
|
|
|
|
.toString()
|
|
|
|
result.liquidityProviderSwapFeeAmount = tokenAmountIn
|
|
|
|
.sub(tokenAmountIn.mul(one.sub(lpFee)))
|
|
|
|
.toString()
|
|
|
|
|
|
|
|
return result
|
2022-03-09 13:58:54 +01:00
|
|
|
}
|
|
|
|
|
2022-04-22 02:38:35 +02:00
|
|
|
/**
|
|
|
|
* Used to calculate swap values, it's a copy of the math in the contracts.
|
|
|
|
* @param tokenLiquidity
|
|
|
|
* @param poolSupply
|
|
|
|
* @param poolShareAmount
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
export function calcSingleOutGivenPoolIn(
|
|
|
|
tokenLiquidity: string,
|
|
|
|
poolSupply: string,
|
|
|
|
poolShareAmount: string
|
2022-03-09 13:58:54 +01:00
|
|
|
): string {
|
2022-04-22 02:38:35 +02:00
|
|
|
const tokenLiquidityD = new Decimal(tokenLiquidity)
|
|
|
|
const poolSupplyD = new Decimal(poolSupply)
|
|
|
|
const poolShareAmountD = new Decimal(poolShareAmount)
|
|
|
|
|
|
|
|
const newPoolSupply = poolSupplyD.sub(poolShareAmountD)
|
|
|
|
const poolRatio = newPoolSupply.div(poolSupplyD)
|
|
|
|
|
|
|
|
const tokenOutRatio = poolRatio.pow(2)
|
|
|
|
const newTokenBalanceOut = tokenLiquidityD.mul(tokenOutRatio)
|
|
|
|
|
|
|
|
const tokensOut = tokenLiquidityD.sub(newTokenBalanceOut)
|
|
|
|
|
|
|
|
return tokensOut.toString()
|
2022-03-09 13:58:54 +01:00
|
|
|
}
|
2022-04-04 15:29:31 +02:00
|
|
|
|
2022-04-22 02:38:35 +02:00
|
|
|
/**
|
|
|
|
* Returns the amount of tokens (based on tokenAddress) that can be withdrawn from the pool
|
|
|
|
* @param {string} poolAddress
|
|
|
|
* @param {string} tokenAddress
|
|
|
|
* @param {string} shares
|
|
|
|
* @param {number} chainId
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
export async function getLiquidityByShares(
|
2022-04-04 15:29:31 +02:00
|
|
|
pool: string,
|
|
|
|
tokenAddress: string,
|
|
|
|
shares: string,
|
2022-04-22 02:38:35 +02:00
|
|
|
chainId: number
|
2022-04-04 15:29:31 +02:00
|
|
|
): Promise<string> {
|
|
|
|
// we only use the dummyWeb3 connection here
|
|
|
|
const web3 = await getDummyWeb3(chainId)
|
|
|
|
|
|
|
|
const poolInstance = new Pool(web3)
|
|
|
|
// get shares VL in ocean
|
2022-04-22 02:38:35 +02:00
|
|
|
const amountBaseToken = await poolInstance.calcSingleOutGivenPoolIn(
|
2022-04-04 15:29:31 +02:00
|
|
|
pool,
|
|
|
|
tokenAddress,
|
|
|
|
shares
|
|
|
|
)
|
|
|
|
|
2022-04-22 02:38:35 +02:00
|
|
|
return amountBaseToken
|
2022-04-04 15:29:31 +02:00
|
|
|
}
|