@@ -3,11 +3,9 @@ import { ethers } from 'ethers';
33import { bignumber } from 'mathjs' ;
44
55import { Chain } from './networks/chain-config' ;
6- import { getErc20Balance } from './token' ;
76
8- import { SdexQuery } from '~/artifacts/abis/types' ;
7+ import { ERC20__factory , SdexQuery } from '~/artifacts/abis/types' ;
98import {
10- aggregatePositions ,
119 filterPositions ,
1210 netCumulativeLiquidity ,
1311 parseAmbientTokensResult ,
@@ -16,6 +14,7 @@ import {
1614 weightedAverageDuration ,
1715} from '~/utils/aggregationUtils' ;
1816import { calculateAPR } from '~/utils/aprCalculation' ;
17+ import { logger } from '~/utils/logger' ;
1918
2019export enum PositionType {
2120 ambient = 'ambient' ,
@@ -35,118 +34,16 @@ export async function getUserPositions(
3534 const concentratedPositions = filterPositions ( liquidityChanges , poolIdx , base , quote , PositionType . concentrated ) ;
3635 const ambientPositions = filterPositions ( liquidityChanges , poolIdx , base , quote , PositionType . ambient ) ;
3736
38- if ( ! ambientPositions . length || ambientPositions [ 0 ] . liq === '0' ) {
39- // If there are no ambient positions, try checking for LP tokens...
40- const lpTokenAddress = await queryContract . queryPoolLpTokenAddress ( base , quote , poolIdx ) ;
41- const lpTokenBalance = await getErc20Balance ( rpc , lpTokenAddress , user ) . then ( ( balance ) => balance . toString ( ) ) ;
42-
43- if ( bignumber ( lpTokenBalance ) . gt ( 0 ) ) {
44- ambientPositions . push ( {
45- id : '' ,
46- changeType : 'mint' ,
47- transactionHash : '' ,
48- callIndex : 0 ,
49- user,
50- pool : {
51- base,
52- quote,
53- poolIdx : poolIdx . toString ( ) ,
54- } ,
55- block : '' ,
56- time : dayjs ( ) . unix ( ) . toString ( ) ,
57- positionType : PositionType . ambient ,
58- liqChange : lpTokenBalance ,
59- resetRewards : '' ,
60- timeFirstMint : '' ,
61- bidTick : 0 ,
62- askTick : 0 ,
63- isBid : false ,
64- liq : lpTokenBalance ,
65- baseFlow : '0' ,
66- quoteFlow : '0' ,
67- pivotTime : null ,
68- aprDuration : '0' ,
69- aprPostLiq : '0' ,
70- aprContributedLiq : '0' ,
71- aprEst : '0' ,
72- lpTokenAddress,
73- lpTokenBalance,
74- } ) ;
75- }
76- }
77-
78- if ( concentratedPositions . length === 0 && ambientPositions . length === 0 ) {
79- return [ ] ;
80- }
81-
82- let ambientPositionResults = [ ] ;
83- if ( ambientPositions . length > 0 ) {
84- const ambientMints = ambientPositions . shift ( ) ;
85-
86- const ambientMulticallData = [
87- {
88- target : queryContract . getAddress ( ) ,
89- callData : queryContract . interface . encodeFunctionData ( 'queryAmbientTokens' , [ user , base , quote , poolIdx ] ) ,
90- } ,
91- {
92- target : queryContract . getAddress ( ) ,
93- callData : queryContract . interface . encodeFunctionData ( 'queryPoolLpTokenAddress' , [ base , quote , poolIdx ] ) ,
94- } ,
95- ] ;
96-
97- const ambientMulticallResults = await chain . multicall . tryAggregate . staticCall ( true , ambientMulticallData ) ;
98-
99- async function parseAmbientCallResults ( ) {
100- const ambientTokensResult = ambientMulticallResults [ 0 ] ;
101- const lpTokenAddressResult = ambientMulticallResults [ 1 ] ;
102-
103- if ( ambientTokensResult . success && lpTokenAddressResult . success ) {
104- const ambientTokens = parseAmbientTokensResult (
105- queryContract . interface . decodeFunctionResult ( 'queryAmbientTokens' , ambientTokensResult . returnData ) ,
106- ) ;
107- const lpTokenAddress = queryContract . interface . decodeFunctionResult (
108- 'queryPoolLpTokenAddress' ,
109- lpTokenAddressResult . returnData ,
110- ) [ 0 ] ;
111-
112- const lpTokenBalance = await getErc20Balance ( rpc , lpTokenAddress , user ) . then ( ( balance ) => balance . toString ( ) ) ;
113-
114- const ambientLiq = bignumber ( ambientTokens . liq ) . plus ( bignumber ( lpTokenBalance ) ) . toFixed ( 0 ) ;
115-
116- return [
117- {
118- base : base ,
119- quote : quote ,
120- poolIdx : ambientMints . pool . poolIdx ,
121- ambientLiq,
122- time : ambientMints . time ,
123- transactionHash : ambientMints . transactionHash ,
124- concLiq : '0' ,
125- rewardLiq : '0' ,
126- baseQty : ambientTokens . baseQty ,
127- quoteQty : ambientTokens . quoteQty ,
128- aggregatedLiquidity : ambientMints . liq ,
129- aggregatedBaseFlow : ambientMints . baseFlow ,
130- aggregatedQuoteFlow : ambientMints . quoteFlow ,
131- positionType : ambientMints . positionType ,
132- bidTick : ambientMints . bidTick ,
133- askTick : ambientMints . askTick ,
134- aprDuration : '0' ,
135- aprPostLiq : '0' ,
136- aprContributedLiq : '0' ,
137- aprEst : '0' ,
138- lpTokenAddress,
139- lpTokenBalance,
140- } ,
141- ] ;
142- }
143- return [ ] ;
144- }
145-
146- ambientPositionResults = await parseAmbientCallResults ( ) ;
147- }
148-
149- const aggregatedAmbientPosition = aggregatePositions ( ambientPositionResults ) ;
37+ const aggregatedAmbientPosition = await tryAmbientPosition (
38+ queryContract ,
39+ rpc ,
40+ user ,
41+ base ,
42+ quote ,
43+ poolIdx ,
44+ ambientPositions ,
45+ chain ,
46+ ) ;
15047
15148 // Group concentrated positions by (base, quote, poolIdx, bidTick, askTick)
15249 const groupedConcentratedPositions : { [ key : string ] : LiquidityChanges [ ] } = concentratedPositions . reduce (
@@ -249,3 +146,116 @@ export async function getUserPositions(
249146
250147 return result ;
251148}
149+
150+ async function tryAmbientPosition (
151+ queryContract : SdexQuery ,
152+ rpc : ethers . JsonRpcProvider ,
153+ user : string ,
154+ base : string ,
155+ quote : string ,
156+ poolIdx : number ,
157+ liquidityChanges : LiquidityChangesResponse [ 'liquidityChanges' ] ,
158+ chain : Chain ,
159+ ) {
160+ const lpTokenAddress = await queryContract . queryPoolLpTokenAddress ( base , quote , poolIdx ) ;
161+ const tokenContract = ERC20__factory . connect ( lpTokenAddress , rpc ) ;
162+
163+ const multicallData = [
164+ {
165+ target : queryContract . getAddress ( ) ,
166+ callData : queryContract . interface . encodeFunctionData ( 'queryAmbientTokens' , [ user , base , quote , poolIdx ] ) ,
167+ } ,
168+ {
169+ target : queryContract . getAddress ( ) ,
170+ callData : queryContract . interface . encodeFunctionData ( 'queryAmbientTokens' , [
171+ lpTokenAddress ,
172+ base ,
173+ quote ,
174+ poolIdx ,
175+ ] ) ,
176+ } ,
177+ {
178+ target : queryContract . getAddress ( ) ,
179+ callData : queryContract . interface . encodeFunctionData ( 'queryAmbientPosition' , [
180+ lpTokenAddress ,
181+ base ,
182+ quote ,
183+ poolIdx ,
184+ ] ) ,
185+ } ,
186+ {
187+ target : tokenContract . getAddress ( ) ,
188+ callData : tokenContract . interface . encodeFunctionData ( 'balanceOf' , [ user ] ) ,
189+ } ,
190+ {
191+ target : tokenContract . getAddress ( ) ,
192+ callData : tokenContract . interface . encodeFunctionData ( 'totalSupply' ) ,
193+ } ,
194+ ] ;
195+
196+ const results = await chain . multicall . tryAggregate . staticCall ( true , multicallData ) ;
197+
198+ const userAmbientTokens = parseAmbientTokensResult (
199+ queryContract . interface . decodeFunctionResult ( 'queryAmbientTokens' , results [ 0 ] . returnData ) ,
200+ ) ;
201+ const lpAmbientTokens = parseAmbientTokensResult (
202+ queryContract . interface . decodeFunctionResult ( 'queryAmbientTokens' , results [ 1 ] . returnData ) ,
203+ ) ;
204+ const ambientPosition = queryContract . interface . decodeFunctionResult ( 'queryAmbientPosition' , results [ 2 ] . returnData ) ;
205+ const lpTokenBalance = tokenContract . interface . decodeFunctionResult ( 'balanceOf' , results [ 3 ] . returnData ) [ 0 ] . toString ( ) ;
206+ const lpTokenTotalSupply = tokenContract . interface
207+ . decodeFunctionResult ( 'totalSupply' , results [ 4 ] . returnData ) [ 0 ]
208+ . toString ( ) ;
209+
210+ logger . info (
211+ {
212+ userAmbientTokens,
213+ lpAmbientTokens,
214+ lpTokenBalance,
215+ lpTokenTotalSupply,
216+ lpTokenAddress,
217+ ambientPosition,
218+ } ,
219+ `Fetched ambient position data for user ${ user } on pool ${ base } -${ quote } #${ poolIdx } ` ,
220+ ) ;
221+
222+ const ratio = bignumber ( lpTokenBalance ) . dividedBy ( bignumber ( lpTokenTotalSupply ) || 1 ) ;
223+ const ambientLiq = bignumber ( userAmbientTokens . liq ) . plus ( bignumber ( lpAmbientTokens . liq ) . mul ( ratio ) ) . toFixed ( 0 ) ;
224+ const baseQty = bignumber ( userAmbientTokens . baseQty ) . plus ( bignumber ( lpAmbientTokens . baseQty ) . mul ( ratio ) ) . toFixed ( 0 ) ;
225+ const quoteQty = bignumber ( userAmbientTokens . quoteQty )
226+ . plus ( bignumber ( lpAmbientTokens . quoteQty ) . mul ( ratio ) )
227+ . toFixed ( 0 ) ;
228+
229+ if ( bignumber ( ambientLiq ) . gt ( 0 ) ) {
230+ const item = liquidityChanges . shift ( ) ;
231+
232+ return [
233+ {
234+ base : base ,
235+ quote : quote ,
236+ poolIdx : poolIdx . toString ( ) ,
237+ ambientLiq,
238+ time : item ? item . time : dayjs ( ) . unix ( ) . toString ( ) ,
239+ transactionHash : item ? item . transactionHash : '' ,
240+ concLiq : '0' ,
241+ rewardLiq : '0' ,
242+ baseQty : baseQty ,
243+ quoteQty : quoteQty ,
244+ aggregatedLiquidity : ambientLiq ,
245+ aggregatedBaseFlow : '0' ,
246+ aggregatedQuoteFlow : '0' ,
247+ positionType : PositionType . ambient ,
248+ bidTick : 0 ,
249+ askTick : 0 ,
250+ aprDuration : '0' ,
251+ aprPostLiq : '0' ,
252+ aprContributedLiq : '0' ,
253+ aprEst : '0' ,
254+ lpTokenAddress,
255+ lpTokenBalance,
256+ } ,
257+ ] ;
258+ }
259+
260+ return [ ] ;
261+ }
0 commit comments