Skip to content
This repository has been archived by the owner on Jun 3, 2022. It is now read-only.

Commit

Permalink
add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-zynesis committed Mar 21, 2022
1 parent e45f91f commit f53154c
Showing 6 changed files with 245 additions and 11 deletions.
79 changes: 79 additions & 0 deletions src/module.api/cache/defid.cache.spec.ts
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@ import { PoolPairInfo } from '@defichain/jellyfish-api-core/dist/category/poolpa
import { TokenInfo } from '@defichain/jellyfish-api-core/dist/category/token'
import { Cache } from 'cache-manager'
import { CachePrefix } from '@src/module.api/cache/global.cache'
import { Testing } from '@defichain/jellyfish-testing'
import BigNumber from 'bignumber.js'

const container = new MasterNodeRegTestContainer()
let client: JsonRpcClient
@@ -178,3 +180,80 @@ describe('getTokenInfo', () => {
expect(dfi).toBeUndefined()
})
})

describe('getStockLpRewardPct', () => {
beforeAll(async () => {
await container.start()
await container.waitForReady()
await container.waitForWalletCoinbaseMaturity()
client = new JsonRpcClient(await container.getCachedRpcUrl())

testingModule = await Test.createTestingModule({
imports: [CacheModule.register()],
providers: [
{ provide: JsonRpcClient, useValue: client },
DeFiDCache
]
}).compile()

cache = testingModule.get<Cache>(CACHE_MANAGER)
defiCache = testingModule.get(DeFiDCache)

await container.waitForWalletBalanceGTE(110)

await createToken(container, 'BAT') // 1
await container.generate(1)

await createPoolPair(container, 'BAT', 'DFI') // 2
await container.generate(1)

// loan pool pair setup
const testing = Testing.create(container)
const oracleId = await container.call('appointoracle', [await testing.generateAddress(), [
{ token: 'lA', currency: 'USD' }, // 3
{ token: 'lB', currency: 'USD' } // 4
], 1])
await testing.generate(1)

await testing.rpc.oracle.setOracleData(oracleId, Math.floor(new Date().getTime() / 1000), {
prices: [
{ tokenAmount: '1@lA', currency: 'USD' }, // 5
{ tokenAmount: '2@lB', currency: 'USD' } // 6
]
})
await testing.generate(1)

const loanTokens = ['lA', 'lB']
for (const lt of loanTokens) {
await testing.container.call('setloantoken', [{
symbol: lt,
fixedIntervalPriceId: `${lt}/USD`,
mintable: false,
interest: new BigNumber(0.02)
}])
await testing.generate(1)
}

for (const lt of loanTokens) {
await testing.poolpair.create({ tokenA: lt, tokenB: 'DFI' })
await testing.generate(1)
}

await container.call('setgov', [{ LP_LOAN_TOKEN_SPLITS: { 5: 1 } }])
await testing.generate(1)

// calling with non loan token pp returned with assumed zero %
const nonLoanLpPct = await defiCache.getStockLpRewardPct('3')
expect(nonLoanLpPct.toFixed()).toStrictEqual('0')

await container.stop()
})

it('should get from cache via get as container RPC is killed', async () => {
const lA = await defiCache.getStockLpRewardPct('5')
expect(lA.toFixed()).toStrictEqual('1')

const lB = await defiCache.getStockLpRewardPct('6')
expect(lB.toFixed()).toStrictEqual('0') // naturally zero when govvar have no value for this id
})
})
28 changes: 28 additions & 0 deletions src/module.api/cache/defid.cache.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import { TokenInfo, TokenResult } from '@defichain/jellyfish-api-core/dist/categ
import { CachePrefix, GlobalCache } from '@src/module.api/cache/global.cache'
import { PoolPairInfo } from '@defichain/jellyfish-api-core/dist/category/poolpair'
import { GetLoanSchemeResult } from '@defichain/jellyfish-api-core/dist/category/loan'
import BigNumber from 'bignumber.js'

@Injectable()
export class DeFiDCache extends GlobalCache {
@@ -76,4 +77,31 @@ export class DeFiDCache extends GlobalCache {
throw err
}
}

async getStockLpRewardPct (poolId: string): Promise<BigNumber> {
const all = (await this.get<Record<string, BigNumber>>(
CachePrefix.GOVERNANCE,
'LP_LOAN_TOKEN_SPLITS',
this.fetchAllStockLpRewardPct.bind(this))
) as Record<string, BigNumber>

const thisPool = all[poolId]
return thisPool === undefined ? new BigNumber(0) : new BigNumber(thisPool)
}

private async fetchAllStockLpRewardPct (): Promise<Record<string, BigNumber>> {
const { LP_LOAN_TOKEN_SPLITS: rewardPct } = await this.rpcClient.masternode.getGov('LP_LOAN_TOKEN_SPLITS')
if (rewardPct === undefined) {
// unexpected (absolutely existed in prod)
throw new Error('LP_LOAN_TOKEN_SPLITS govvar missing')
}

const tokenIds = Object.keys(rewardPct)
const result: Record<string, BigNumber> = {}
tokenIds.forEach(t => {
result[t] = new BigNumber(rewardPct[t])
})

return result
}
}
3 changes: 2 additions & 1 deletion src/module.api/cache/global.cache.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@ export enum CachePrefix {
TOKEN_INFO = 0,
POOL_PAIR_INFO = 1,
TOKEN_INFO_SYMBOL = 2,
LOAN_SCHEME_INFO = 3
LOAN_SCHEME_INFO = 3,
GOVERNANCE = 4
}

export class GlobalCache {
115 changes: 111 additions & 4 deletions src/module.api/poolpair.controller.e2e.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ import { NestFastifyApplication } from '@nestjs/platform-fastify'
import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '@src/e2e.module'
import { addPoolLiquidity, createPoolPair, createToken, getNewAddress, mintTokens } from '@defichain/testing'
import { NotFoundException } from '@nestjs/common'
import { Testing } from '@defichain/jellyfish-testing'
import BigNumber from 'bignumber.js'

const container = new MasterNodeRegTestContainer()
let app: NestFastifyApplication
@@ -115,6 +117,49 @@ async function setup (): Promise<void> {

await container.call('setgov', [{ LP_SPLITS: { 14: 1.0 } }])
await container.generate(1)

// loan token LP setup
const testing = Testing.create(container)
const loanTokens = ['lA', 'lB', 'lC']
const oracleId = await container.call('appointoracle', [await testing.generateAddress(), [
{ token: 'lA', currency: 'USD' },
{ token: 'lB', currency: 'USD' },
{ token: 'lC', currency: 'USD' }
], 1])
await testing.generate(1)

await testing.rpc.oracle.setOracleData(oracleId, Math.floor(new Date().getTime() / 1000), {
prices: [
{ tokenAmount: '1@lA', currency: 'USD' },
{ tokenAmount: '2@lB', currency: 'USD' },
{ tokenAmount: '3@lC', currency: 'USD' }
]
})
await testing.generate(1)

for (const lt of loanTokens) {
await testing.container.call('setloantoken', [{
symbol: lt,
fixedIntervalPriceId: `${lt}/USD`,
mintable: false,
interest: new BigNumber(0.02)
}])
await testing.generate(1)
}

for (const lt of loanTokens) {
await testing.poolpair.create({ tokenA: lt, tokenB: 'DFI' })
await testing.generate(1)
}

await container.call('setgov', [{
LP_LOAN_TOKEN_SPLITS: {
// 29: 0,
30: 0.4,
31: 0.6
}
}])
await testing.generate(1)
}

describe('list', () => {
@@ -123,7 +168,7 @@ describe('list', () => {
size: 30
})

expect(response.data.length).toStrictEqual(12)
expect(response.data.length).toStrictEqual(15)
expect(response.page).toBeUndefined()

expect(response.data[1]).toStrictEqual({
@@ -173,6 +218,13 @@ describe('list', () => {
h24: 0
}
})

expect(response.data[12].symbol).toStrictEqual('lA-DFI')
expect(response.data[12].rewardPct).toStrictEqual('0')
expect(response.data[13].symbol).toStrictEqual('lB-DFI')
expect(response.data[13].rewardPct).toStrictEqual('0.4')
expect(response.data[14].symbol).toStrictEqual('lC-DFI')
expect(response.data[14].rewardPct).toStrictEqual('0.6')
})

it('should list with pagination', async () => {
@@ -185,11 +237,11 @@ describe('list', () => {
expect(first.data[1].symbol).toStrictEqual('B-DFI')

const next = await controller.list({
size: 11,
size: 14,
next: first.page?.next
})

expect(next.data.length).toStrictEqual(10)
expect(next.data.length).toStrictEqual(13)
expect(next.page?.next).toBeUndefined()
expect(next.data[0].symbol).toStrictEqual('C-DFI')
expect(next.data[1].symbol).toStrictEqual('D-DFI')
@@ -261,11 +313,64 @@ describe('get', () => {
})
})

it('loan token pool "rewardPct" should use gov value', async () => {
const response = await controller.get('31')

expect(response).toStrictEqual({
id: '31',
symbol: 'lC-DFI',
displaySymbol: 'dlC-DFI',
name: '-Default Defi token',
status: true,
tokenA: {
id: expect.any(String),
symbol: 'lC',
reserve: '0',
blockCommission: '0',
displaySymbol: 'dlC'
},
tokenB: {
id: '0',
symbol: 'DFI',
reserve: '0',
blockCommission: '0',
displaySymbol: 'DFI'
},
apr: {
// legit empty pool value
reward: Infinity,
total: NaN,
commission: NaN
},
commission: '0',
totalLiquidity: {
token: '0',
usd: '0'
},
tradeEnabled: false,
ownerAddress: expect.any(String),
priceRatio: {
ab: '0',
ba: '0'
},
rewardPct: '0.6',
customRewards: undefined,
creation: {
tx: expect.any(String),
height: expect.any(Number)
},
volume: {
d30: 0,
h24: 0
}
})
})

it('should throw error while getting non-existent poolpair', async () => {
expect.assertions(2)
try {
await controller.get('999')
} catch (err) {
} catch (err: any) {
expect(err).toBeInstanceOf(NotFoundException)
expect(err.response).toStrictEqual({
statusCode: 404,
@@ -679,6 +784,8 @@ describe('get list swappable tokens', () => {
swappableTokens: [
{ id: '7', symbol: 'G', displaySymbol: 'dG' },
{ id: '0', symbol: 'DFI', displaySymbol: 'DFI' },
{ id: '27', symbol: 'lB', displaySymbol: 'dlB' },
{ id: '26', symbol: 'lA', displaySymbol: 'dlA' },
{ id: '24', symbol: 'USDT', displaySymbol: 'dUSDT' },
{ id: '6', symbol: 'F', displaySymbol: 'dF' },
{ id: '5', symbol: 'E', displaySymbol: 'dE' },
10 changes: 6 additions & 4 deletions src/module.api/poolpair.controller.ts
Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ export class PoolPairController {
const totalLiquidityUsd = await this.poolPairService.getTotalLiquidityUsd(info)
const apr = await this.poolPairService.getAPR(id, info)
const volume = await this.poolPairService.getUSDVolume(id)
items.push(mapPoolPair(id, info, totalLiquidityUsd, apr, volume))
const rewardPct = await this.poolPairService.getRewardPct(id, info)
items.push(mapPoolPair(id, info, totalLiquidityUsd, apr, volume, rewardPct))
}

const response = ApiPagedResponse.of(items, query.size, item => {
@@ -78,7 +79,8 @@ export class PoolPairController {
const totalLiquidityUsd = await this.poolPairService.getTotalLiquidityUsd(info)
const apr = await this.poolPairService.getAPR(id, info)
const volume = await this.poolPairService.getUSDVolume(id)
return mapPoolPair(String(id), info, totalLiquidityUsd, apr, volume)
const rewardPct = await this.poolPairService.getRewardPct(id, info)
return mapPoolPair(String(id), info, totalLiquidityUsd, apr, volume, rewardPct)
}

/**
@@ -184,7 +186,7 @@ export class PoolPairController {
}
}

function mapPoolPair (id: string, info: PoolPairInfo, totalLiquidityUsd?: BigNumber, apr?: PoolPairData['apr'], volume?: PoolPairData['volume']): PoolPairData {
function mapPoolPair (id: string, info: PoolPairInfo, totalLiquidityUsd?: BigNumber, apr?: PoolPairData['apr'], volume?: PoolPairData['volume'], rewardPct?: BigNumber): PoolPairData {
const [symbolA, symbolB] = info.symbol.split('-')

return {
@@ -218,7 +220,7 @@ function mapPoolPair (id: string, info: PoolPairInfo, totalLiquidityUsd?: BigNum
},
tradeEnabled: info.tradeEnabled,
ownerAddress: info.ownerAddress,
rewardPct: info.rewardPct.toFixed(),
rewardPct: rewardPct?.toFixed() ?? info.rewardPct.toFixed(),
customRewards: info.customRewards,
creation: {
tx: info.creationTx,
21 changes: 19 additions & 2 deletions src/module.api/poolpair.service.ts
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ export class PoolPairService {
if (Object.values(result).length > 0) {
return Object.values(result)[0]
}
} catch (err) {
} catch (err: any) {
if (err?.payload?.message !== 'Pool not found') {
throw err
}
@@ -71,7 +71,7 @@ export class PoolPairService {
if (Object.values(result).length > 0) {
return Object.values(result)[0]
}
} catch (err) {
} catch (err: any) {
if (err?.payload?.message !== 'Pool not found') {
throw err
}
@@ -387,6 +387,23 @@ export class PoolPairService {
total: reward.plus(commission).toNumber()
}
}

async getRewardPct (id: string, info: PoolPairInfo): Promise<BigNumber> {
if (!info.rewardPct.isZero()) {
return info.rewardPct
}

const token = await this.deFiDCache.getTokenInfo(info.idTokenA)
if (token === undefined) {
throw new Error(`Pool ${id} not found`)
}

if (!token.isLoanToken) {
return new BigNumber(0)
}

return await this.deFiDCache.getStockLpRewardPct(id)
}
}

function findPoolSwapDfTx (vouts: TransactionVout[]): PoolSwapDfTx | undefined {

0 comments on commit f53154c

Please sign in to comment.