From 55eeaa870451f7c1ddb77e14a922eca8dbe080f4 Mon Sep 17 00:00:00 2001 From: Sniezka Date: Tue, 16 Jul 2024 11:13:26 +0200 Subject: [PATCH] Added querying all pools for specified pair --- contracts/collections/pool_keys.ral | 16 +++--- contracts/invariant.ral | 35 ++++++++++-- src/invariant.ts | 14 +++-- src/testUtils.ts | 6 --- src/utils.ts | 52 ++++++++++++++---- ...tion_with_pool_on_removed_fee_tier.test.ts | 5 -- test/query-on-pair.test.ts | 53 +++++++++++++++++++ 7 files changed, 145 insertions(+), 36 deletions(-) create mode 100644 test/query-on-pair.test.ts diff --git a/contracts/collections/pool_keys.ral b/contracts/collections/pool_keys.ral index 2b280b2..6745ca0 100644 --- a/contracts/collections/pool_keys.ral +++ b/contracts/collections/pool_keys.ral @@ -20,14 +20,14 @@ Abstract Contract PoolKeys() { return false } - fn getAllPoolKeys() -> ByteVec { - let mut poolKeysBytes = b`` + // fn getAllPoolKeys() -> ByteVec { + // let mut poolKeysBytes = b`` - for (let mut i = 1; i <= poolKeyCount; i = i + 1) { - let state = poolKeys[i] - poolKeysBytes = poolKeysBytes ++ state.tokenX ++ b`break` ++ state.tokenY ++ b`break` ++ toByteVec!(state.feeTier.fee) ++ b`break` ++ toByteVec!(state.feeTier.tickSpacing) ++ b`break` - } + // for (let mut i = 1; i <= poolKeyCount; i = i + 1) { + // let state = poolKeys[i] + // poolKeysBytes = poolKeysBytes ++ state.tokenX ++ b`break` ++ state.tokenY ++ b`break` ++ toByteVec!(state.feeTier.fee) ++ b`break` ++ toByteVec!(state.feeTier.tickSpacing) ++ b`break` + // } - return poolKeysBytes - } + // return poolKeysBytes + // } } \ No newline at end of file diff --git a/contracts/invariant.ral b/contracts/invariant.ral index 19e9254..1f9f280 100644 --- a/contracts/invariant.ral +++ b/contracts/invariant.ral @@ -168,6 +168,7 @@ Contract Invariant( checkCaller!(caller == config.admin, InvariantError.NotAdmin) for(let mut i = 0; i < feeTierCount; i = i + 1) { + assert!( 1 != 0, 210) if(feeTiers.feeTiers[i].fee == feeTier.fee && feeTiers.feeTiers[i].tickSpacing == feeTier.tickSpacing) { feeTiers.feeTiers[i] = feeTiers.feeTiers[feeTierCount - 1] feeTiers.feeTiers[feeTierCount - 1] = FeeTier{fee: 0, tickSpacing: 0} @@ -187,10 +188,6 @@ Contract Invariant( return false } - pub fn getPools() -> ByteVec { - return getAllPoolKeys() - } - pub fn getTick(poolKey: PoolKey, index: I256) -> (Bool, Tick) { return wrappedGetTick(poolKey, index) } @@ -525,4 +522,34 @@ Contract Invariant( Reserve(pool.reserveY).withdrawSingleAsset(caller, pool.poolKey.tokenY, tokensOwedY) } } + + pub fn getAllPoolsForPair(token0: ByteVec, token1: ByteVec) -> ByteVec { + let mut matchingPools = b`` + + for(let mut i = 0; i < feeTierCount; i = i + 1) { + let poolKey = newPoolKey(token0, token1, feeTiers.feeTiers[i]) + let (exist, pool) = getPool(poolKey) + if(exist) { + matchingPools = matchingPools + ++ poolKey.tokenX ++ b`break` + ++ poolKey.tokenY ++ b`break` + ++ toByteVec!(poolKey.feeTier.fee) ++ b`break` + ++ toByteVec!(poolKey.feeTier.tickSpacing) ++ b`break` + ++ toByteVec!(pool.liquidity) ++ b`break` + ++ toByteVec!(pool.sqrtPrice) ++ b`break` + ++ toByteVec!(pool.currentTickIndex) ++ b`break` + ++ toByteVec!(pool.feeGrowthGlobalX) ++ b`break` + ++ toByteVec!(pool.feeGrowthGlobalY) ++ b`break` + ++ toByteVec!(pool.feeProtocolTokenX) ++ b`break` + ++ toByteVec!(pool.feeProtocolTokenY) ++ b`break` + ++ toByteVec!(pool.startTimestamp) ++ b`break` + ++ toByteVec!(pool.lastTimestamp) ++ b`break` + ++ toByteVec!(pool.feeReceiver) ++ b`break` + ++ pool.reserveX ++ b`break` + ++ pool.reserveY ++ b`break` + } + } + + return matchingPools + } } diff --git a/src/invariant.ts b/src/invariant.ts index bbad9a7..bad061f 100644 --- a/src/invariant.ts +++ b/src/invariant.ts @@ -19,7 +19,6 @@ import { Network } from './network' import { getReserveAddress } from './testUtils' import { balanceOf, - decodeFeeTiers, decodePool, decodePosition, decodeTick, @@ -27,7 +26,8 @@ import { deployCLAMM, deployReserve, MAP_ENTRY_DEPOSIT, - waitTxConfirmed + waitTxConfirmed, + decodePools } from './utils' import { Address, DUST_AMOUNT, SignerProvider } from '@alephium/web3' @@ -324,5 +324,13 @@ export class Invariant { // async getAllLiquidityTicks() {} // async getUserPositionAmount() {} // async getLiquidityTicksAmount() {} - // async getAllPoolsForPair() {} + async getAllPoolsForPair(token0Id: string, token1Id: string) { + return decodePools( + ( + await this.instance.view.getAllPoolsForPair({ + args: { token0: token0Id, token1: token1Id } + }) + ).returns + ) + } } diff --git a/src/testUtils.ts b/src/testUtils.ts index 5b510f4..c31d1d4 100644 --- a/src/testUtils.ts +++ b/src/testUtils.ts @@ -23,8 +23,6 @@ import { import { MAP_ENTRY_DEPOSIT, decodePool, - decodePools, - decodeFeeTiers, decodePosition, deployTokenFaucet, decodeTick, @@ -194,10 +192,6 @@ export async function getPool(invariant: InvariantInstance, poolKey: PoolKey) { ) } -export const getPools = async (invariant: InvariantInstance) => { - return decodePools((await invariant.methods.getPools()).returns) -} - export async function getPosition(invariant: InvariantInstance, owner: Address, index: bigint) { return decodePosition( ( diff --git a/src/utils.ts b/src/utils.ts index cebaa9b..0d7aed8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,12 +5,16 @@ import { SignerProvider, ZERO_ADDRESS, node, - web3 + web3, + Address, + addressFromContractId, + addressFromScript } from '@alephium/web3' import { CLAMM, Invariant, InvariantInstance, Reserve, Utils } from '../artifacts/ts' import { TokenFaucet } from '../artifacts/ts/TokenFaucet' import { FeeTier, FeeTiers, Pool, PoolKey, Position, Tick } from '../artifacts/ts/types' import { MaxFeeTiers } from './consts' +import { ByteVecToAddress } from '@alephium/web3/dist/src/codec' export const MAP_ENTRY_DEPOSIT = ONE_ALPH / 10n @@ -21,6 +25,7 @@ export const EMPTY_FEE_TIERS: FeeTiers = { }) } as FeeTiers +const BREAK_BYTES = '627265616b' function isConfirmed(txStatus: node.TxStatus): txStatus is node.Confirmed { return txStatus.type === 'Confirmed' } @@ -134,23 +139,46 @@ export function decodeFeeTiers(string: string) { } export function decodePools(string: string) { - const parts = string.split('627265616b') + const offset = 16 + const parts = string.split(BREAK_BYTES) const pools: any[] = [] - - for (let i = 0; i < parts.length - 1; i += 4) { + for (let i = 0; i < parts.length - 1; i += offset) { const pool = { - tokenX: parts[i], - tokenY: parts[i + 1], - fee: decodeU256(parts[i + 2]), - tickSpacing: decodeU256(parts[i + 3]) + poolKey: { + tokenX: parts[i], + tokenY: parts[i + 1], + feeTier: { + fee: decodeU256(parts[i + 2]), + tickSpacing: decodeU256(parts[i + 3]) + } + }, + liquidity: decodeU256(parts[i + 4]), + sqrtPrice: decodeU256(parts[i + 5]), + currentTickIndex: decodeI256(parts[i + 6]), + feeGrowthGlobalX: decodeU256(parts[i + 7]), + feeGrowthGlobalY: decodeU256(parts[i + 8]), + feeProtocolTokenX: decodeU256(parts[i + 9]), + feeProtocolTokenY: decodeU256(parts[i + 10]), + startTimestamp: decodeU256(parts[i + 11]), + lastTimestamp: decodeU256(parts[i + 12]), + feeReceiver: addressFromContractId(parts[i + 13]), + reserveX: parts[i + 14], + reserveY: parts[i + 15] } - pools.push(pool) } - return pools } +export const decodePoolKey = (string: string) => { + const parts = string.split(BREAK_BYTES) + return { + token0: addressFromContractId(parts[0]), + token1: addressFromContractId(parts[1]), + feeTier: decodeU256(parts[2]) + } +} + function createEntityProxy(entity: T, exists: boolean) { return new Proxy( { ...entity, exists }, @@ -185,6 +213,10 @@ export function decodeU256(string: string): bigint { return codec.compactUnsignedIntCodec.decodeU256(hexToBytes(string)) } +const decodeI256 = (string: string): bigint => { + return codec.compactSignedIntCodec.decodeI256(hexToBytes(string)) +} + export const newPoolKey = async ( token0: string, token1: string, diff --git a/test/interaction_with_pool_on_removed_fee_tier.test.ts b/test/interaction_with_pool_on_removed_fee_tier.test.ts index b9634d7..fedadf4 100644 --- a/test/interaction_with_pool_on_removed_fee_tier.test.ts +++ b/test/interaction_with_pool_on_removed_fee_tier.test.ts @@ -14,7 +14,6 @@ import { initPosition, initSwap, removePosition, - getPools, getPosition, expectError, getReserveBalances, @@ -190,10 +189,6 @@ describe('interaction with pool on removed fee tiers tests', () => { test('get pool', async () => { await getPool(invariant, poolKey) }) - test('get pools', async () => { - const pools = await getPools(invariant) - expect(pools.length).toBe(1) - }) test('transfer position', async () => { const positionOwner = await getSigner(ONE_ALPH * 1000n, 0) diff --git a/test/query-on-pair.test.ts b/test/query-on-pair.test.ts new file mode 100644 index 0000000..e3abcdd --- /dev/null +++ b/test/query-on-pair.test.ts @@ -0,0 +1,53 @@ +import { ONE_ALPH, web3 } from '@alephium/web3' +import { getSigner } from '@alephium/web3-test' +import { Invariant } from '../src/invariant' +import { Network } from '../src/network' +import { getPool, initTokensXY } from '../src/testUtils' +import { getBasicFeeTickSpacing } from '../src/snippets' +import { newFeeTier, newPoolKey } from '../src/utils' + +web3.setCurrentNodeProvider('http://127.0.0.1:22973') + +describe('query on pair', () => { + test('query on pools works', async () => { + const initialFee = 0n + const [fee] = getBasicFeeTickSpacing() + const deployer = await getSigner(ONE_ALPH * 1000n, 0) + const invariant = await Invariant.deploy(deployer, Network.Local, initialFee) + const supply = 10n ** 10n + const [tokenX, tokenY] = await initTokensXY(deployer, supply) + + const initSqrtPrice = 10n ** 24n + const feeTier10TS = await newFeeTier(fee, 10n) + const feeTier20TS = await newFeeTier(fee, 20n) + + await invariant.addFeeTier(deployer, feeTier10TS) + await invariant.addFeeTier(deployer, feeTier20TS) + + const poolKey0 = await newPoolKey(tokenX.contractId, tokenY.contractId, feeTier10TS) + const poolKey1 = await newPoolKey(tokenX.contractId, tokenY.contractId, feeTier20TS) + + await invariant.createPool( + deployer, + tokenX.contractId, + tokenY.contractId, + feeTier10TS, + initSqrtPrice + ) + + await invariant.createPool( + deployer, + tokenX.contractId, + tokenY.contractId, + feeTier20TS, + initSqrtPrice + ) + + const expectedPool0 = await invariant.getPool(poolKey0) + const expectedPool1 = await invariant.getPool(poolKey1) + console.log('expectedPool0', expectedPool0) + console.log('expectedPool1', expectedPool1) + const query = await invariant.getAllPoolsForPair(tokenX.contractId, tokenY.contractId) + console.log(query) + }) +})