Skip to content

Commit 233d11d

Browse files
authored
TBILL: Only count withdrawal queue entries for the relevant addresses (#3821)
* TBILL: Only count withdrawal queue entries for the relevant addresses * one more test * changeset * test comment
1 parent 9aac776 commit 233d11d

File tree

4 files changed

+253
-5
lines changed

4 files changed

+253
-5
lines changed

.changeset/sharp-sloths-search.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@chainlink/token-balance-adapter': minor
3+
---
4+
5+
Only count TBILL withdrawal queue entries for the relevant addresses

packages/sources/token-balance/src/transport/tbill.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export class TbillTransport extends SubscriptionTransport<BaseEndpointTypes> {
182182
totalSharesUSD += await this.getWithdrawalQueueAum(
183183
queueLength,
184184
contract,
185+
address.wallets,
185186
sharePriceUSD,
186187
sharesDecimals,
187188
)
@@ -212,6 +213,7 @@ export class TbillTransport extends SubscriptionTransport<BaseEndpointTypes> {
212213
async getWithdrawalQueueAum(
213214
queueLength: bigint,
214215
tbillWithrawalQueueContract: GroupedTokenContract,
216+
wallets: string[],
215217
sharePriceUSD: SharePriceType,
216218
sharesDecimals: bigint,
217219
) {
@@ -223,7 +225,11 @@ export class TbillTransport extends SubscriptionTransport<BaseEndpointTypes> {
223225
const results = await Promise.all(
224226
indices.map(async (index) => {
225227
const queueInfo = await tbillWithrawalQueueContract.getWithdrawalQueueInfo(index)
226-
return queueInfo.shares
228+
if (queueInfo.sender === queueInfo.receiver && wallets.includes(queueInfo.sender)) {
229+
return queueInfo.shares
230+
} else {
231+
return 0n
232+
}
227233
}),
228234
)
229235

packages/sources/token-balance/src/transport/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ export class GroupedTokenContract {
5050
return this.runner.run(() => this.contract.getWithdrawalQueueLength())
5151
}
5252

53-
async getWithdrawalQueueInfo(index: number): Promise<{ shares: bigint }> {
53+
async getWithdrawalQueueInfo(index: number): Promise<{
54+
sender: string
55+
receiver: string
56+
shares: bigint
57+
}> {
5458
return this.runner.run(() => this.contract.getWithdrawalQueueInfo(index))
5559
}
5660
}

packages/sources/token-balance/test/unit/tbill.test.ts

Lines changed: 236 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,16 +522,88 @@ describe('TbillTransport', () => {
522522
ethTbillContract.decimals.mockResolvedValue(balanceDecimals)
523523
ethTbillContract.balanceOf.mockResolvedValue(BigInt(balance * 10 ** balanceDecimals))
524524
ethTbillContract.getWithdrawalQueueLength.mockResolvedValue(2)
525-
// TODO: Shouldn't we only count withdrawals from walletAddress?
525+
ethTbillContract.getWithdrawalQueueInfo.mockResolvedValueOnce({
526+
sender: walletAddress,
527+
receiver: walletAddress,
528+
shares: BigInt(withDrawalQueueAmount1 * 10 ** balanceDecimals),
529+
})
530+
ethTbillContract.getWithdrawalQueueInfo.mockResolvedValueOnce({
531+
sender: walletAddress,
532+
receiver: walletAddress,
533+
shares: BigInt(withDrawalQueueAmount2 * 10 ** balanceDecimals),
534+
})
535+
536+
ethTbillPriceContract.decimals.mockResolvedValue(priceDecimals)
537+
ethTbillPriceContract.latestAnswer.mockResolvedValue(BigInt(price * 10 ** priceDecimals))
538+
539+
const param: RequestParams = {
540+
addresses: [
541+
{
542+
chainId: ETHEREUM_RPC_CHAIN_ID,
543+
contractAddress: ETHEREUM_TBILL_CONTRACT_ADDRESS,
544+
priceOracleAddress: ETHEREUM_TBILL_PRICE_ORACLE_ADDRESS,
545+
wallets: [walletAddress],
546+
},
547+
],
548+
} as RequestParams
549+
550+
const now = Date.now()
551+
await transport.handleRequest(context, param)
552+
553+
expect(responseCache.write).toBeCalledWith(transportName, [
554+
{
555+
params: param,
556+
response: {
557+
data: {
558+
decimals: RESULT_DECIMALS,
559+
result,
560+
},
561+
result,
562+
statusCode: 200,
563+
timestamps: {
564+
providerDataRequestedUnixMs: now,
565+
providerDataReceivedUnixMs: now,
566+
},
567+
},
568+
},
569+
])
570+
expect(responseCache.write).toBeCalledTimes(1)
571+
572+
expect(ethTbillContract.getWithdrawalQueueLength).toBeCalledTimes(1)
573+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledWith(0)
574+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledWith(1)
575+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledTimes(2)
576+
})
577+
578+
it('should ignore withdrawal queue entries unless both sender and receiver equal the wallet address', async () => {
579+
const balance = 3
580+
const balanceDecimals = 6
581+
const price = 7
582+
const priceDecimals = 8
583+
const withDrawalQueueAmount1 = 1
584+
const withDrawalQueueAmount2 = 2
585+
const withDrawalQueueAmount3 = 3
586+
587+
const result = String(balance * price * 10 ** RESULT_DECIMALS)
588+
589+
const walletAddress = '0x5EaFF7af80488033Bc845709806D5Fae5291eB88'
590+
ethTbillContract.decimals.mockResolvedValue(balanceDecimals)
591+
ethTbillContract.balanceOf.mockResolvedValue(BigInt(balance * 10 ** balanceDecimals))
592+
ethTbillContract.getWithdrawalQueueLength.mockResolvedValue(3)
526593
ethTbillContract.getWithdrawalQueueInfo.mockResolvedValueOnce({
527594
sender: '0x01',
528-
receiver: '0x02',
595+
receiver: walletAddress,
529596
shares: BigInt(withDrawalQueueAmount1 * 10 ** balanceDecimals),
530597
})
598+
ethTbillContract.getWithdrawalQueueInfo.mockResolvedValueOnce({
599+
sender: walletAddress,
600+
receiver: '0x02',
601+
shares: BigInt(withDrawalQueueAmount2 * 10 ** balanceDecimals),
602+
})
531603
ethTbillContract.getWithdrawalQueueInfo.mockResolvedValueOnce({
532604
sender: '0x03',
533605
receiver: '0x04',
534-
shares: BigInt(withDrawalQueueAmount2 * 10 ** balanceDecimals),
606+
shares: BigInt(withDrawalQueueAmount3 * 10 ** balanceDecimals),
535607
})
536608

537609
ethTbillPriceContract.decimals.mockResolvedValue(priceDecimals)
@@ -573,6 +645,167 @@ describe('TbillTransport', () => {
573645
expect(ethTbillContract.getWithdrawalQueueLength).toBeCalledTimes(1)
574646
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledWith(0)
575647
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledWith(1)
648+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledWith(2)
649+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledTimes(3)
650+
})
651+
652+
it('should not double count withdrawal queue entries for multiple addresses', async () => {
653+
const balance1 = 3
654+
const balance2 = 5
655+
const balanceDecimals = 6
656+
const price = 7
657+
const priceDecimals = 8
658+
const withDrawalQueueAmount1 = 1
659+
const withDrawalQueueAmount2 = 2
660+
661+
const result = String(
662+
(balance1 + balance2 + withDrawalQueueAmount1 + withDrawalQueueAmount2) *
663+
price *
664+
10 ** RESULT_DECIMALS,
665+
)
666+
667+
const walletAddress1 = '0x5EaFF7af80488033Bc845709806D5Fae5291eB88'
668+
const walletAddress2 = '0x1000000000000000000000000000000000000001'
669+
ethTbillContract.decimals.mockResolvedValue(balanceDecimals)
670+
ethTbillContract.balanceOf.mockResolvedValueOnce(BigInt(balance1 * 10 ** balanceDecimals))
671+
ethTbillContract.balanceOf.mockResolvedValueOnce(BigInt(balance2 * 10 ** balanceDecimals))
672+
ethTbillContract.getWithdrawalQueueLength.mockResolvedValue(2)
673+
const withDrawalQueueEntries = [
674+
{
675+
sender: walletAddress1,
676+
receiver: walletAddress1,
677+
shares: BigInt(withDrawalQueueAmount1 * 10 ** balanceDecimals),
678+
},
679+
{
680+
sender: walletAddress2,
681+
receiver: walletAddress2,
682+
shares: BigInt(withDrawalQueueAmount2 * 10 ** balanceDecimals),
683+
},
684+
]
685+
ethTbillContract.getWithdrawalQueueInfo.mockImplementation(
686+
async (index: number) => withDrawalQueueEntries[index],
687+
)
688+
689+
ethTbillPriceContract.decimals.mockResolvedValue(priceDecimals)
690+
ethTbillPriceContract.latestAnswer.mockResolvedValue(BigInt(price * 10 ** priceDecimals))
691+
692+
const param: RequestParams = {
693+
addresses: [walletAddress1, walletAddress2].map((walletAddress) => ({
694+
chainId: ETHEREUM_RPC_CHAIN_ID,
695+
contractAddress: ETHEREUM_TBILL_CONTRACT_ADDRESS,
696+
priceOracleAddress: ETHEREUM_TBILL_PRICE_ORACLE_ADDRESS,
697+
wallets: [walletAddress],
698+
})),
699+
} as RequestParams
700+
701+
const now = Date.now()
702+
await transport.handleRequest(context, param)
703+
704+
expect(responseCache.write).toBeCalledWith(transportName, [
705+
{
706+
params: param,
707+
response: {
708+
data: {
709+
decimals: RESULT_DECIMALS,
710+
result,
711+
},
712+
result,
713+
statusCode: 200,
714+
timestamps: {
715+
providerDataRequestedUnixMs: now,
716+
providerDataReceivedUnixMs: now,
717+
},
718+
},
719+
},
720+
])
721+
expect(responseCache.write).toBeCalledTimes(1)
722+
723+
expect(ethTbillContract.getWithdrawalQueueLength).toBeCalledTimes(2)
724+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(1, 0)
725+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(2, 1)
726+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(3, 0)
727+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(4, 1)
728+
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledTimes(4)
729+
})
730+
731+
// The previous test tests input with multiple address entries with 1 wallet each.
732+
// This test tests input with one address entries with multiple wallets.
733+
it('should not double count withdrawal queue entries for multiple wallets', async () => {
734+
const balance1 = 3
735+
const balance2 = 5
736+
const balanceDecimals = 6
737+
const price = 7
738+
const priceDecimals = 8
739+
const withDrawalQueueAmount1 = 1
740+
const withDrawalQueueAmount2 = 2
741+
742+
const result = String(
743+
(balance1 + balance2 + withDrawalQueueAmount1 + withDrawalQueueAmount2) *
744+
price *
745+
10 ** RESULT_DECIMALS,
746+
)
747+
748+
const walletAddress1 = '0x5EaFF7af80488033Bc845709806D5Fae5291eB88'
749+
const walletAddress2 = '0x1000000000000000000000000000000000000001'
750+
ethTbillContract.decimals.mockResolvedValue(balanceDecimals)
751+
ethTbillContract.balanceOf.mockResolvedValueOnce(BigInt(balance1 * 10 ** balanceDecimals))
752+
ethTbillContract.balanceOf.mockResolvedValueOnce(BigInt(balance2 * 10 ** balanceDecimals))
753+
ethTbillContract.getWithdrawalQueueLength.mockResolvedValue(2)
754+
const withDrawalQueueEntries = [
755+
{
756+
sender: walletAddress1,
757+
receiver: walletAddress1,
758+
shares: BigInt(withDrawalQueueAmount1 * 10 ** balanceDecimals),
759+
},
760+
{
761+
sender: walletAddress2,
762+
receiver: walletAddress2,
763+
shares: BigInt(withDrawalQueueAmount2 * 10 ** balanceDecimals),
764+
},
765+
]
766+
ethTbillContract.getWithdrawalQueueInfo.mockImplementation(
767+
async (index: number) => withDrawalQueueEntries[index],
768+
)
769+
770+
ethTbillPriceContract.decimals.mockResolvedValue(priceDecimals)
771+
ethTbillPriceContract.latestAnswer.mockResolvedValue(BigInt(price * 10 ** priceDecimals))
772+
773+
const param: RequestParams = {
774+
addresses: [
775+
{
776+
chainId: ETHEREUM_RPC_CHAIN_ID,
777+
contractAddress: ETHEREUM_TBILL_CONTRACT_ADDRESS,
778+
priceOracleAddress: ETHEREUM_TBILL_PRICE_ORACLE_ADDRESS,
779+
wallets: [walletAddress1, walletAddress2],
780+
},
781+
],
782+
} as RequestParams
783+
784+
const now = Date.now()
785+
await transport.handleRequest(context, param)
786+
787+
expect(responseCache.write).toBeCalledWith(transportName, [
788+
{
789+
params: param,
790+
response: {
791+
data: {
792+
decimals: RESULT_DECIMALS,
793+
result,
794+
},
795+
result,
796+
statusCode: 200,
797+
timestamps: {
798+
providerDataRequestedUnixMs: now,
799+
providerDataReceivedUnixMs: now,
800+
},
801+
},
802+
},
803+
])
804+
expect(responseCache.write).toBeCalledTimes(1)
805+
806+
expect(ethTbillContract.getWithdrawalQueueLength).toBeCalledTimes(1)
807+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(1, 0)
808+
expect(ethTbillContract.getWithdrawalQueueInfo).toHaveBeenNthCalledWith(2, 1)
576809
expect(ethTbillContract.getWithdrawalQueueInfo).toBeCalledTimes(2)
577810
})
578811

0 commit comments

Comments
 (0)