From 750fe59ea7765956a49a30a651320d737e69061d Mon Sep 17 00:00:00 2001 From: huianyang Date: Mon, 9 Sep 2024 12:06:20 -0700 Subject: [PATCH] feat: add getBalanceAndFrozenBonds and getSpendableAndFrozenBonds rpc endpoint re #3023 --- integration-tests/__tests__/rpc/nodes.spec.ts | 10 ++++ .../src/rpc-wrapper.ts | 12 +++++ .../taquito-rpc/src/rpc-client-interface.ts | 4 ++ .../src/rpc-client-modules/rpc-cache.ts | 48 +++++++++++++++++++ packages/taquito-rpc/src/taquito-rpc.ts | 40 ++++++++++++++++ packages/taquito-rpc/test/rpc-cache.spec.ts | 18 +++++++ packages/taquito-rpc/test/taquito-rpc.spec.ts | 28 +++++++++++ 7 files changed, 160 insertions(+) diff --git a/integration-tests/__tests__/rpc/nodes.spec.ts b/integration-tests/__tests__/rpc/nodes.spec.ts index 31ce129607..71a54bcdee 100644 --- a/integration-tests/__tests__/rpc/nodes.spec.ts +++ b/integration-tests/__tests__/rpc/nodes.spec.ts @@ -71,6 +71,16 @@ CONFIGS().forEach( expect(balance).toBeDefined(); }); + it(`Verify that rpcClient.getBalanceAndFrozenBonds for knownBaker returns the full balance`, async () => { + const balance = await rpcClient.getBalanceAndFrozenBonds(knownBaker); + expect(balance).toBeDefined(); + }); + + betanet(`Verify that rpcClient.getSpendableAndFrozenBonds for knownBaker returns the full balance`, async () => { + const balance = await rpcClient.getSpendableAndFrozenBonds(knownBaker); + expect(balance).toBeDefined(); + }); + it(`Verify that rpcClient.getFullBalance for knownBaker returns the full balance`, async () => { const balance = await rpcClient.getFullBalance(knownBaker); expect(balance).toBeDefined(); diff --git a/packages/taquito-contracts-library/src/rpc-wrapper.ts b/packages/taquito-contracts-library/src/rpc-wrapper.ts index 82fee9af22..7b3ffe930e 100644 --- a/packages/taquito-contracts-library/src/rpc-wrapper.ts +++ b/packages/taquito-contracts-library/src/rpc-wrapper.ts @@ -99,6 +99,18 @@ export class RpcWrapperContractsLibrary implements RpcClientInterface { ): Promise { return this.rpc.getSpendable(address, { block }); } + async getBalanceAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + return this.rpc.getBalanceAndFrozenBonds(address, { block }); + } + async getSpendableAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + return this.rpc.getSpendableAndFrozenBonds(address, { block }); + } async getFullBalance( address: string, { block }: RPCOptions = defaultRPCOptions diff --git a/packages/taquito-rpc/src/rpc-client-interface.ts b/packages/taquito-rpc/src/rpc-client-interface.ts index a7018599e4..10b2337664 100644 --- a/packages/taquito-rpc/src/rpc-client-interface.ts +++ b/packages/taquito-rpc/src/rpc-client-interface.ts @@ -65,6 +65,8 @@ export interface RpcClientInterface { getLiveBlocks(options?: RPCOptions): Promise; getBalance(address: string, options?: RPCOptions): Promise; getSpendable(address: string, options?: RPCOptions): Promise; + getBalanceAndFrozenBonds(address: string, options?: RPCOptions): Promise; + getSpendableAndFrozenBonds(address: string, options?: RPCOptions): Promise; getFullBalance(address: string, options?: RPCOptions): Promise; getStakedBalance(address: string, options?: RPCOptions): Promise; getUnstakedFinalizableBalance(address: string, options?: RPCOptions): Promise; @@ -150,6 +152,8 @@ export enum RPCMethodName { GET_BLOCK_METADATA = 'getBlockMetadata', GET_BALANCE = 'getBalance', GET_SPENDABLE = 'getSpendable', + GET_BALANCE_AND_FROZEN_BONDS = 'getBalanceAndFrozenBonds', + GET_SPENDABLE_AND_FROZEN_BONDS = 'getSpendableAndFrozenBonds', GET_FULL_BALANCE = 'getFullBalance', GET_STAKED_BALANCE = 'getStakedBalance', GET_UNSTAKED_FINALIZABLE_BALANCE = 'getUnstakedFinalizableBalance', diff --git a/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts b/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts index ccd09d75f0..47add1d448 100644 --- a/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts +++ b/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts @@ -246,6 +246,54 @@ export class RpcClientCache implements RpcClientInterface { } } + /** + * @param address address from which we want to retrieve balance and frozen bonds + * @param options contains generic configuration for rpc calls to specified block (default to head) + * @description The sum (in mutez) of the spendable balance and frozen bonds of a contract. Corresponds to the contract's full balance from which staked funds and unstake requests have been excluded. Identical to the 'spendable_and_frozen_bonds' RPC. + */ + async getBalanceAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + this.validateAddress(address); + const key = this.formatCacheKey( + this.rpcClient.getRpcUrl(), + RPCMethodName.GET_BALANCE_AND_FROZEN_BONDS, + [block, address] + ); + if (this.has(key)) { + return this.get(key); + } else { + const response = this.rpcClient.getBalanceAndFrozenBonds(address, { block }); + this.put(key, response); + return response; + } + } + + /** + * @param address address from which we want to retrieve spendable and frozen bonds + * @param options contains generic configuration for rpc calls to specified block (default to head) + * @description The sum (in mutez) of the spendable balance and frozen bonds of a contract. Corresponds to the contract's full balance from which staked funds and unstake requests have been excluded. Identical to the 'balance_and_frozen_bonds' RPC. + */ + async getSpendableAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + this.validateAddress(address); + const key = this.formatCacheKey( + this.rpcClient.getRpcUrl(), + RPCMethodName.GET_SPENDABLE_AND_FROZEN_BONDS, + [block, address] + ); + if (this.has(key)) { + return this.get(key); + } else { + const response = this.rpcClient.getSpendableAndFrozenBonds(address, { block }); + this.put(key, response); + return response; + } + } + /** * @param address address from which we want to retrieve the full balance * @param options contains generic configuration for rpc calls to specified block (default to head) diff --git a/packages/taquito-rpc/src/taquito-rpc.ts b/packages/taquito-rpc/src/taquito-rpc.ts index 43138975b9..d32e5c8770 100644 --- a/packages/taquito-rpc/src/taquito-rpc.ts +++ b/packages/taquito-rpc/src/taquito-rpc.ts @@ -204,6 +204,46 @@ export class RpcClient implements RpcClientInterface { return new BigNumber(balance); } + /** + * @param address address from which we want to retrieve balance and frozen bonds + * @param options contains generic configuration for rpc calls to specified block (default to head) + * @description The sum (in mutez) of the spendable balance and frozen bonds of a contract. Corresponds to the contract's full balance from which staked funds and unstake requests have been excluded. Identical to the 'spendable_and_frozen_bonds' RPC. + * @see https://tezos.gitlab.io/active/rpc.html#get-block-id-context-contracts-contract-id-full-balance + */ + async getBalanceAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + this.validateAddress(address); + const balance = await this.httpBackend.createRequest({ + url: this.createURL( + `/chains/${this.chain}/blocks/${block}/context/contracts/${address}/balance_and_frozen_bonds` + ), + method: 'GET', + }); + return new BigNumber(balance); + } + + /** + * @param address address from which we want to retrieve spendable and frozen bonds + * @param options contains generic configuration for rpc calls to specified block (default to head) + * @description The sum (in mutez) of the spendable balance and frozen bonds of a contract. Corresponds to the contract's full balance from which staked funds and unstake requests have been excluded. Identical to the 'balance_and_frozen_bonds' RPC. + * @see https://tezos.gitlab.io/active/rpc.html#get-block-id-context-contracts-contract-id-full-balance + */ + async getSpendableAndFrozenBonds( + address: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + this.validateAddress(address); + const balance = await this.httpBackend.createRequest({ + url: this.createURL( + `/chains/${this.chain}/blocks/${block}/context/contracts/${address}/spendable_and_frozen_bonds` + ), + method: 'GET', + }); + return new BigNumber(balance); + } + /** * @param address address from which we want to retrieve the full balance * @param options contains generic configuration for rpc calls to specified block (default to head) diff --git a/packages/taquito-rpc/test/rpc-cache.spec.ts b/packages/taquito-rpc/test/rpc-cache.spec.ts index 47eb12a62d..d5c335a57b 100644 --- a/packages/taquito-rpc/test/rpc-cache.spec.ts +++ b/packages/taquito-rpc/test/rpc-cache.spec.ts @@ -59,6 +59,8 @@ describe('RpcClientCache test', () => { getLiveBlocks: jest.fn(), getBalance: jest.fn(), getSpendable: jest.fn(), + getBalanceAndFrozenBonds: jest.fn(), + getSpendableAndFrozenBonds: jest.fn(), getFullBalance: jest.fn(), getStakedBalance: jest.fn(), getUnstakedFinalizableBalance: jest.fn(), @@ -106,6 +108,8 @@ describe('RpcClientCache test', () => { mockRpcClient.getLiveBlocks.mockReturnValue(liveBlocks); mockRpcClient.getBalance.mockReturnValue(balance); mockRpcClient.getSpendable.mockReturnValue(balance); + mockRpcClient.getBalanceAndFrozenBonds.mockReturnValue(balance); + mockRpcClient.getSpendableAndFrozenBonds.mockReturnValue(balance); mockRpcClient.getFullBalance.mockReturnValue(balance); mockRpcClient.getStakedBalance.mockReturnValue(balance); mockRpcClient.getUnstakedFinalizableBalance.mockReturnValue(balance); @@ -158,6 +162,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(); await rpcCache.getBalance(address); await rpcCache.getSpendable(address); + await rpcCache.getBalanceAndFrozenBonds(address); + await rpcCache.getSpendableAndFrozenBonds(address); await rpcCache.getFullBalance(address); await rpcCache.getStakedBalance(address); await rpcCache.getUnstakedFinalizableBalance(address); @@ -330,6 +336,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(block); await rpcCache.getBalance(address, block); await rpcCache.getSpendable(address, block); + await rpcCache.getBalanceAndFrozenBonds(address, block); + await rpcCache.getSpendableAndFrozenBonds(address, block); await rpcCache.getFullBalance(address, block); await rpcCache.getStakedBalance(address, block); await rpcCache.getUnstakedFinalizableBalance(address, block); @@ -398,6 +406,14 @@ describe('RpcClientCache test', () => { expect( rpcCache.getAllCachedData()[`rpcTest/getSpendable/${block.block}/${address}/`].response ).toEqual(balance); + expect( + rpcCache.getAllCachedData()[`rpcTest/getBalanceAndFrozenBonds/${block.block}/${address}/`] + .response + ).toEqual(balance); + expect( + rpcCache.getAllCachedData()[`rpcTest/getSpendableAndFrozenBonds/${block.block}/${address}/`] + .response + ).toEqual(balance); expect( rpcCache.getAllCachedData()[`rpcTest/getFullBalance/${block.block}/${address}/`].response ).toEqual(balance); @@ -528,6 +544,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(); await rpcCache.getBalance(address); await rpcCache.getSpendable(address); + await rpcCache.getBalanceAndFrozenBonds(address); + await rpcCache.getSpendableAndFrozenBonds(address); await rpcCache.getFullBalance(address); await rpcCache.getStakedBalance(address); await rpcCache.getUnstakedFinalizableBalance(address); diff --git a/packages/taquito-rpc/test/taquito-rpc.spec.ts b/packages/taquito-rpc/test/taquito-rpc.spec.ts index 4917e2f99d..3a3847a59c 100644 --- a/packages/taquito-rpc/test/taquito-rpc.spec.ts +++ b/packages/taquito-rpc/test/taquito-rpc.spec.ts @@ -145,6 +145,34 @@ describe('RpcClient test', () => { }); }); + describe('getBalanceAndFrozenBonds', () => { + it('should query the right url and return a string', async () => { + httpBackend.createRequest.mockReturnValue(Promise.resolve('10000')); + const balance = await client.getBalanceAndFrozenBonds(contractAddress); + + expect(httpBackend.createRequest.mock.calls[0][0]).toEqual({ + method: 'GET', + url: `root/chains/test/blocks/head/context/contracts/${contractAddress}/balance_and_frozen_bonds`, + }); + expect(balance).toBeInstanceOf(BigNumber); + expect(balance.toString()).toEqual('10000'); + }); + }); + + describe('getSpendableAndFrozenBonds', () => { + it('should query the right url and return a string', async () => { + httpBackend.createRequest.mockReturnValue(Promise.resolve('10000')); + const balance = await client.getSpendableAndFrozenBonds(contractAddress); + + expect(httpBackend.createRequest.mock.calls[0][0]).toEqual({ + method: 'GET', + url: `root/chains/test/blocks/head/context/contracts/${contractAddress}/spendable_and_frozen_bonds`, + }); + expect(balance).toBeInstanceOf(BigNumber); + expect(balance.toString()).toEqual('10000'); + }); + }); + describe('getFullBalance', () => { it('should query the right url and return a string', async () => { httpBackend.createRequest.mockReturnValue(Promise.resolve('10000'));