-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3974486
commit 492654c
Showing
10 changed files
with
1,383 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Network } from '../../constants'; | ||
import { DexConfigMap } from '../../types'; | ||
import { DexParams } from './types'; | ||
|
||
export const Config: DexConfigMap<DexParams> = { | ||
UsualPP: { | ||
[Network.MAINNET]: { | ||
USD0: { | ||
address: '0x73a15fed60bf67631dc6cd7bc5b6e8da8190acf5', | ||
decimals: 18, | ||
}, | ||
USD0PP: { | ||
address: '0x35d8949372d46b7a3d5a56006ae77b215fc69bc0', | ||
decimals: 18, | ||
}, | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import _ from 'lodash'; | ||
import { Interface } from '@ethersproject/abi'; | ||
import { IDexHelper } from '../../dex-helper'; | ||
import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; | ||
import { Address, Log, Logger } from '../../types'; | ||
import { AsyncOrSync, DeepReadonly } from 'ts-essentials'; | ||
import { PoolState } from './types'; | ||
import { getOnChainState } from './utils'; | ||
|
||
export class UsualPool extends StatefulEventSubscriber<PoolState> { | ||
decoder = (log: Log) => this.poolInterface.parseLog(log); | ||
|
||
constructor( | ||
parentName: string, | ||
protected dexHelper: IDexHelper, | ||
private poolAddress: Address, | ||
private poolInterface: Interface, | ||
logger: Logger, | ||
) { | ||
super(parentName, 'UsualPool', dexHelper, logger); | ||
this.addressesSubscribed = [poolAddress]; | ||
} | ||
|
||
protected processLog( | ||
state: DeepReadonly<PoolState>, | ||
log: Readonly<Log>, | ||
): AsyncOrSync<DeepReadonly<PoolState> | null> { | ||
const event = this.decoder(log); | ||
const _state: PoolState = _.cloneDeep(state); | ||
if (event.name === 'FloorPriceUpdated') { | ||
_state.price = BigInt(event.args.newFloorPrice); | ||
return _state; | ||
} | ||
return null; | ||
} | ||
|
||
async generateState( | ||
blockNumber: number | 'latest' = 'latest', | ||
): Promise<DeepReadonly<PoolState>> { | ||
const state = await getOnChainState( | ||
this.dexHelper.multiContract, | ||
this.poolAddress, | ||
this.poolInterface, | ||
blockNumber, | ||
); | ||
return state; | ||
} | ||
|
||
async getPrice(blockNumber: number): Promise<bigint> { | ||
const state = await this.getOrGenerateState(blockNumber); | ||
if (!state) throw new Error('Cannot compute state'); | ||
return state.price; | ||
} | ||
|
||
async getOrGenerateState( | ||
blockNumber: number, | ||
): Promise<DeepReadonly<PoolState> | null> { | ||
const state = this.getState(blockNumber); | ||
if (state) { | ||
return state; | ||
} | ||
|
||
this.logger.debug( | ||
`No state found for ${this.addressesSubscribed[0]}, generating new one`, | ||
); | ||
const newState = await this.generateState(blockNumber); | ||
|
||
if (!newState) { | ||
this.logger.debug( | ||
`Could not regenerate state for ${this.addressesSubscribed[0]}`, | ||
); | ||
return null; | ||
} | ||
this.setState(newState, blockNumber); | ||
return newState; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Address } from '../../types'; | ||
|
||
export type PoolState = { | ||
price: bigint; | ||
}; | ||
|
||
export type UsualPPData = {}; | ||
|
||
export type DexParams = { | ||
USD0: { address: Address; decimals: number }; | ||
USD0PP: { address: Address; decimals: number }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import dotenv from 'dotenv'; | ||
dotenv.config(); | ||
|
||
import { Network } from '../../constants'; | ||
import { DummyDexHelper } from '../../dex-helper/index'; | ||
import { testEventSubscriber } from '../../../tests/utils-events'; | ||
import { PoolState } from './types'; | ||
import { Config } from './config'; | ||
import { UsualPool } from './pool'; | ||
import { PoolConfig } from '../curve-v1/types'; | ||
import UsualPoolAbi from '../../abi/usual-pp/abi.json'; | ||
import { Interface } from '@ethersproject/abi'; | ||
|
||
jest.setTimeout(50 * 1000); | ||
const dexKey = 'UsualPP'; | ||
const network = Network.MAINNET; | ||
const config = Config[dexKey][network]; | ||
const dexHelper = new DummyDexHelper(network); | ||
const logger = dexHelper.getLogger(dexKey); | ||
|
||
async function fetchPoolState( | ||
usualPool: UsualPool, | ||
blockNumber: number, | ||
): Promise<PoolState> { | ||
return usualPool.generateState(blockNumber); | ||
} | ||
|
||
function compareState(state: PoolState, expectedState: PoolState) { | ||
expect(state).toEqual(expectedState); | ||
} | ||
|
||
describe('UsualPP Event', function () { | ||
const blockNumbers: { [eventName: string]: number[] } = { | ||
FloorPriceUpdated: [21589702], | ||
}; | ||
|
||
describe('UsualPool', function () { | ||
let usualPool: UsualPool; | ||
let blockNumber: number; | ||
|
||
const usualPoolIface = new Interface(UsualPoolAbi); | ||
|
||
beforeAll(async function () { | ||
blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); | ||
}); | ||
|
||
Object.keys(blockNumbers).forEach((event: string) => { | ||
blockNumbers[event].forEach((blockNumber: number) => { | ||
it(`Should return the correct state after the ${blockNumber}:${event}`, async function () { | ||
usualPool = new UsualPool( | ||
dexKey, | ||
dexHelper, | ||
config.USD0PP.address, | ||
usualPoolIface, | ||
logger, | ||
); | ||
await testEventSubscriber( | ||
usualPool, | ||
usualPool.addressesSubscribed, | ||
(_blockNumber: number) => fetchPoolState(usualPool, _blockNumber), | ||
blockNumber, | ||
`${dexKey}_${config.USD0PP.address}`, | ||
dexHelper.provider, | ||
compareState, | ||
); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* eslint-disable no-console */ | ||
import dotenv from 'dotenv'; | ||
dotenv.config(); | ||
|
||
import { Interface } from '@ethersproject/abi'; | ||
import { DummyDexHelper } from '../../dex-helper/index'; | ||
import { Network, SwapSide } from '../../constants'; | ||
import { BI_POWS } from '../../bigint-constants'; | ||
import { | ||
checkPoolPrices, | ||
checkConstantPoolPrices, | ||
checkPoolsLiquidity, | ||
} from '../../../tests/utils'; | ||
import { Tokens } from '../../../tests/constants-e2e'; | ||
import { UsualPP } from './usual-pp'; | ||
|
||
async function testPricingOnNetwork( | ||
usual: UsualPP, | ||
network: Network, | ||
dexKey: string, | ||
blockNumber: number, | ||
srcTokenSymbol: string, | ||
destTokenSymbol: string, | ||
side: SwapSide, | ||
amounts: bigint[], | ||
funcNameToCheck: string, | ||
) { | ||
const networkTokens = Tokens[network]; | ||
|
||
console.log(amounts); | ||
|
||
const pools = await usual.getPoolIdentifiers( | ||
networkTokens[srcTokenSymbol], | ||
networkTokens[destTokenSymbol], | ||
side, | ||
blockNumber, | ||
); | ||
console.log( | ||
`${srcTokenSymbol} <> ${destTokenSymbol} Pool Identifiers: `, | ||
pools, | ||
); | ||
|
||
expect(pools.length).toBeGreaterThan(0); | ||
|
||
const poolPrices = await usual.getPricesVolume( | ||
networkTokens[srcTokenSymbol], | ||
networkTokens[destTokenSymbol], | ||
amounts, | ||
side, | ||
blockNumber, | ||
pools, | ||
); | ||
console.log( | ||
`${srcTokenSymbol} <> ${destTokenSymbol} Pool Prices: `, | ||
poolPrices, | ||
); | ||
|
||
expect(poolPrices).not.toBeNull(); | ||
// Check if onchain pricing equals to calculated ones | ||
} | ||
|
||
describe('UsualPP', function () { | ||
const dexKey = 'UsualPP'; | ||
let blockNumber: number; | ||
let usualPP: UsualPP; | ||
|
||
describe('Mainnet', () => { | ||
const network = Network.MAINNET; | ||
const dexHelper = new DummyDexHelper(network); | ||
|
||
// Don't forget to update relevant tokens in constant-e2e.ts | ||
|
||
const amountsForSell = [ | ||
0n, | ||
1n * BI_POWS[18], | ||
2n * BI_POWS[18], | ||
3n * BI_POWS[18], | ||
4n * BI_POWS[18], | ||
5n * BI_POWS[18], | ||
6n * BI_POWS[18], | ||
7n * BI_POWS[18], | ||
8n * BI_POWS[18], | ||
9n * BI_POWS[18], | ||
10n * BI_POWS[18], | ||
]; | ||
|
||
beforeAll(async () => { | ||
blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); | ||
usualPP = new UsualPP(network, dexKey, dexHelper); | ||
if (usualPP.initializePricing) { | ||
await usualPP.initializePricing(blockNumber); | ||
} | ||
}); | ||
|
||
it('getPoolIdentifiers and getPricesVolume SELL', async function () { | ||
await testPricingOnNetwork( | ||
usualPP, | ||
network, | ||
dexKey, | ||
blockNumber, | ||
'USD0++', | ||
'USD0', | ||
SwapSide.SELL, | ||
amountsForSell, | ||
'', | ||
); | ||
}); | ||
|
||
it('getTopPoolsForToken: USD0', async function () { | ||
const tokenA = Tokens[network]['USD0']; | ||
const dexHelper = new DummyDexHelper(network); | ||
const usualPP = new UsualPP(network, dexKey, dexHelper); | ||
|
||
const poolLiquidity = await usualPP.getTopPoolsForToken( | ||
tokenA.address, | ||
10, | ||
); | ||
console.log( | ||
`${tokenA.symbol} Top Pools:`, | ||
JSON.stringify(poolLiquidity, null, 2), | ||
); | ||
|
||
checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); | ||
}); | ||
|
||
it('getTopPoolsForToken: USD0++', async function () { | ||
const tokenA = Tokens[network]['USD0++']; | ||
const dexHelper = new DummyDexHelper(network); | ||
const usualPP = new UsualPP(network, dexKey, dexHelper); | ||
|
||
const poolLiquidity = await usualPP.getTopPoolsForToken( | ||
tokenA.address, | ||
10, | ||
); | ||
console.log( | ||
`${tokenA.symbol} Top Pools:`, | ||
JSON.stringify(poolLiquidity, null, 2), | ||
); | ||
|
||
checkPoolsLiquidity(poolLiquidity, tokenA.address, dexKey); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.