diff --git a/integration-tests/contract-increase-paid-storage-operation.spec.ts b/integration-tests/contract-increase-paid-storage-operation.spec.ts index f7e3d32189..de27f26f50 100644 --- a/integration-tests/contract-increase-paid-storage-operation.spec.ts +++ b/integration-tests/contract-increase-paid-storage-operation.spec.ts @@ -2,20 +2,42 @@ import { CONFIGS } from './config'; import { OpKind, Protocols } from '@taquito/taquito'; import { ligoSample } from './data/ligo-simple-contract'; -CONFIGS().forEach(({ lib, rpc, setup, protocol, knownContract }) => { - const kathmandunetAndAlpha = (protocol === Protocols.PtKathman || protocol === Protocols.ProtoALpha) ? test : test.skip; +CONFIGS().forEach(({ lib, rpc, setup, protocol }) => { + const kathmandunet = (protocol === Protocols.PtKathman) ? test : test.skip; + const limanetAndAlpha = (protocol === Protocols.PtLimaPtL || protocol === Protocols.ProtoALpha) ? test : test.skip; + const Tezos = lib; - + let simpleContractAddress: string; describe(`Test Increase Paid Storage using: ${rpc}`, () => { - beforeEach(async (done) => { + beforeAll(async (done) => { await setup(true); + + try { + const op = await Tezos.contract.originate({ + balance: "1", + code: `parameter string; + storage string; + code {CAR; + PUSH string "Hello "; + CONCAT; + NIL operation; PAIR}; + `, + init: `"test"` + }); + + await op.confirmation(); + + simpleContractAddress = op.contractAddress!; + } catch(e) { + console.log(JSON.stringify(e)); + } done(); }); - kathmandunetAndAlpha('should be able to increase the paid storage of a contract successfully', async (done) => { + kathmandunet(`should be able to increase the paid storage of a contract successfully: ${rpc}`, async (done) => { const op = await Tezos.contract.increasePaidStorage({ amount: 1, - destination: knownContract + destination: simpleContractAddress }); await op.confirmation(); @@ -23,8 +45,52 @@ CONFIGS().forEach(({ lib, rpc, setup, protocol, knownContract }) => { expect(op.status).toEqual('applied'); done(); }); + + limanetAndAlpha(`should be able to increase the paid storage of a contract successfully: ${rpc}`, async (done) => { + const paidSpaceBefore = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + + const op = await Tezos.contract.increasePaidStorage({ + amount: 1, + destination: simpleContractAddress + }); + + await op.confirmation(); + expect(op.hash).toBeDefined(); + expect(op.status).toEqual('applied'); + + const paidSpaceAfter = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + + expect(parseInt(paidSpaceAfter)).toEqual(parseInt(paidSpaceBefore) + 1); + done(); + }); + + kathmandunet(`should be able to include increasePaidStorage operation in a batch: ${rpc}`, async (done) => { + const op = await Tezos.contract + .batch() + .withOrigination({ + balance: "1", + code: `parameter string; + storage string; + code {CAR; + PUSH string "Hello "; + CONCAT; + NIL operation; PAIR}; + `, + init: `"test"` + }) + .withIncreasePaidStorage({ + amount: 1, + destination: simpleContractAddress + }) + .send(); + await op.confirmation(); + expect(op.status).toEqual('applied'); + done(); + }); - kathmandunetAndAlpha('should be able to include increasePaidStorage operation in a batch', async (done) => { + limanetAndAlpha(`should be able to include increasePaidStorage operation in a batch: ${rpc}`, async (done) => { + const paidSpaceBefore = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + const op = await Tezos.contract .batch() .withOrigination({ @@ -40,15 +106,42 @@ CONFIGS().forEach(({ lib, rpc, setup, protocol, knownContract }) => { }) .withIncreasePaidStorage({ amount: 1, - destination: knownContract + destination: simpleContractAddress }) .send(); await op.confirmation(); expect(op.status).toEqual('applied'); + + const paidSpaceAfter = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + + expect(parseInt(paidSpaceAfter)).toEqual(parseInt(paidSpaceBefore) + 1); + done(); + }); + + kathmandunet(`should be able to include increasePaidStorage operation in a batch (different batch syntax): ${rpc}`, async (done) => { + const op = await Tezos.contract.batch([ + { + kind: OpKind.ORIGINATION, + balance: '1', + code: ligoSample, + storage: 0 + }, + { + kind: OpKind.INCREASE_PAID_STORAGE, + amount: 1, + destination: simpleContractAddress + } + ]) + .send(); + + await op.confirmation(); + expect(op.status).toEqual('applied'); done(); }); - kathmandunetAndAlpha('should be able to include increasePaidStorage operation in a batch (different batch syntax)', async (done) => { + limanetAndAlpha(`should be able to include increasePaidStorage operation in a batch (different batch syntax): ${rpc}`, async (done) => { + const paidSpaceBefore = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + const op = await Tezos.contract.batch([ { kind: OpKind.ORIGINATION, @@ -59,17 +152,21 @@ CONFIGS().forEach(({ lib, rpc, setup, protocol, knownContract }) => { { kind: OpKind.INCREASE_PAID_STORAGE, amount: 1, - destination: knownContract + destination: simpleContractAddress } ]) .send(); await op.confirmation(); expect(op.status).toEqual('applied'); + + const paidSpaceAfter = await Tezos.rpc.getStoragePaidSpace(simpleContractAddress); + + expect(parseInt(paidSpaceAfter)).toEqual(parseInt(paidSpaceBefore) + 1); done(); }); - kathmandunetAndAlpha('should return error when destination contract address is invalid', async (done) => { + it('should return error when destination contract address is invalid', async (done) => { expect(async () => { const op = await Tezos.contract.increasePaidStorage({ amount: 1, diff --git a/integration-tests/rpc-nodes.spec.ts b/integration-tests/rpc-nodes.spec.ts index ed968539e5..d4fb6e256c 100644 --- a/integration-tests/rpc-nodes.spec.ts +++ b/integration-tests/rpc-nodes.spec.ts @@ -20,7 +20,7 @@ CONFIGS().forEach( }) => { const Tezos = lib; - const limanet = protocol === Protocols.PtLimaPtL ? test : test.skip; + const limanetAndAlpha = protocol === Protocols.PtLimaPtL || protocol === Protocols.ProtoALpha ? test : test.skip; const kathmandunetAndAlpha = protocol === Protocols.PtKathman || protocol === Protocols.ProtoALpha ? test : test.skip; beforeAll(async (done) => { @@ -433,6 +433,17 @@ CONFIGS().forEach( done(); }); + limanetAndAlpha('Verify that rpcClient.getStorageUsedSpace will retrieve the used space of a contract storage', async (done) => { + const usedSpace = await rpcClient.getStorageUsedSpace(knownContract); + expect(usedSpace).toBeDefined(); + done(); + }); + + limanetAndAlpha('Verify that rpcClient.getStoragePaidSpace will retrieve the paid space of a contract storage', async (done) => { + const paidSpace = await rpcClient.getStoragePaidSpace(knownContract); + expect(paidSpace).toBeDefined(); + done(); + }); }); }); } diff --git a/packages/taquito-contracts-library/src/rpc-wrapper.ts b/packages/taquito-contracts-library/src/rpc-wrapper.ts index af3fdd18b3..fa2a7ff411 100644 --- a/packages/taquito-contracts-library/src/rpc-wrapper.ts +++ b/packages/taquito-contracts-library/src/rpc-wrapper.ts @@ -294,4 +294,16 @@ export class RpcWrapperContractsLibrary implements RpcClientInterface { ): Promise { return this.rpc.getTxRollupInbox(txRollupId, blockLevel, { block }); } + async getStorageUsedSpace( + contract: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + return this.rpc.getStorageUsedSpace(contract, { block }); + } + async getStoragePaidSpace( + contract: string, + { block }: RPCOptions = defaultRPCOptions + ): Promise { + return this.rpc.getStoragePaidSpace(contract, { block }); + } } diff --git a/packages/taquito-rpc/src/rpc-client-interface.ts b/packages/taquito-rpc/src/rpc-client-interface.ts index 8f57409817..03efa80fe0 100644 --- a/packages/taquito-rpc/src/rpc-client-interface.ts +++ b/packages/taquito-rpc/src/rpc-client-interface.ts @@ -117,6 +117,8 @@ export interface RpcClientInterface { blockLevel: string, options?: RPCOptions ): Promise; + getStorageUsedSpace(contract: string, options?: RPCOptions): Promise; + getStoragePaidSpace(contract: string, options?: RPCOptions): Promise; } export enum RPCMethodName { @@ -155,4 +157,6 @@ export enum RPCMethodName { GET_TX_ROLLUP_STATE = 'getTxRollupState', GET_VOTES_LISTINGS = 'getVotesListings', PACK_DATA = 'packData', + GET_STORAGE_USED_SPACE = 'getStorageUsedSpace', + GET_STORAGE_PAID_SPACE = 'getStoragePaidSpace', } 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 94d8075706..964051c7d7 100644 --- a/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts +++ b/packages/taquito-rpc/src/rpc-client-modules/rpc-cache.ts @@ -1111,4 +1111,58 @@ export class RpcClientCache implements RpcClientInterface { return response; } } + + /** + * + * @param contract address of the contract we want to retrieve storage information of + * @param options contains generic configuration for rpc calls + * + * @description Access the amount of used space used in a contract's storage + * + * @see https://tezos.gitlab.io/lima/rpc.html#get-block-id-context-contracts-contract-id-storage + */ + async getStorageUsedSpace( + contract: string, + { block }: { block: string } = defaultRPCOptions + ): Promise { + const key = this.formatCacheKey( + this.rpcClient.getRpcUrl(), + RPCMethodName.GET_STORAGE_USED_SPACE, + [block, contract] + ); + if (this.has(key)) { + return this.get(key); + } else { + const response = this.rpcClient.getStorageUsedSpace(contract, { block }); + this.put(key, response); + return response; + } + } + + /** + * + * @param contract address of the contract we want to retrieve storage information of + * @param options contains generic configuration for rpc calls + * + * @description Access the amount of paid space in a contract's storage + * + * @see https://tezos.gitlab.io/lima/rpc.html#get-block-id-context-contracts-contract-id-storage + */ + async getStoragePaidSpace( + contract: string, + { block }: { block: string } = defaultRPCOptions + ): Promise { + const key = this.formatCacheKey( + this.rpcClient.getRpcUrl(), + RPCMethodName.GET_STORAGE_PAID_SPACE, + [block, contract] + ); + if (this.has(key)) { + return this.get(key); + } else { + const response = this.rpcClient.getStoragePaidSpace(contract, { block }); + this.put(key, response); + return response; + } + } } diff --git a/packages/taquito-rpc/src/taquito-rpc.ts b/packages/taquito-rpc/src/taquito-rpc.ts index f542df5576..5c3a6be190 100644 --- a/packages/taquito-rpc/src/taquito-rpc.ts +++ b/packages/taquito-rpc/src/taquito-rpc.ts @@ -1083,4 +1083,46 @@ export class RpcClient implements RpcClientInterface { method: 'GET', }); } + + /** + * + * @param contract address of the contract we want to retrieve storage information of + * @param options contains generic configuration for rpc calls + * + * @description Access the amount of used space in a contract's storage + * + * @see https://tezos.gitlab.io/lima/rpc.html#get-block-id-context-contracts-contract-id-storage + */ + async getStorageUsedSpace( + contract: string, + { block }: { block: string } = defaultRPCOptions + ): Promise { + return this.httpBackend.createRequest({ + url: this.createURL( + `/chains/${this.chain}/blocks/${block}/context/contracts/${contract}/storage/used_space` + ), + method: 'GET', + }); + } + + /** + * + * @param contract address of the contract we want to retrieve storage information of + * @param options contains generic configuration for rpc calls + * + * @description Access the amount of paid space in a contract's storage + * + * @see https://tezos.gitlab.io/lima/rpc.html#get-block-id-context-contracts-contract-id-storage + */ + async getStoragePaidSpace( + contract: string, + { block }: { block: string } = defaultRPCOptions + ): Promise { + return this.httpBackend.createRequest({ + url: this.createURL( + `/chains/${this.chain}/blocks/${block}/context/contracts/${contract}/storage/paid_space` + ), + method: 'GET', + }); + } } diff --git a/packages/taquito-rpc/test/rpc-cache.spec.ts b/packages/taquito-rpc/test/rpc-cache.spec.ts index f74b56b0d9..4199cbf08e 100644 --- a/packages/taquito-rpc/test/rpc-cache.spec.ts +++ b/packages/taquito-rpc/test/rpc-cache.spec.ts @@ -54,6 +54,8 @@ describe('RpcClientCache test', () => { getLiveBlocks: jest.fn(), getBalance: jest.fn(), getStorage: jest.fn(), + getStorageUsedSpace: jest.fn(), + getStoragePaidSpace: jest.fn(), getScript: jest.fn(), getNormalizedScript: jest.fn(), getContract: jest.fn(), @@ -90,6 +92,8 @@ describe('RpcClientCache test', () => { mockRpcClient.getLiveBlocks.mockReturnValue(liveBlocks); mockRpcClient.getBalance.mockReturnValue(balance); mockRpcClient.getStorage.mockReturnValue(storage); + mockRpcClient.getStorageUsedSpace.mockReturnValue('100'); + mockRpcClient.getStoragePaidSpace.mockReturnValue('120'); mockRpcClient.getScript.mockReturnValue(script); mockRpcClient.getNormalizedScript.mockReturnValue(script); mockRpcClient.getContract.mockReturnValue(contract); @@ -117,7 +121,6 @@ describe('RpcClientCache test', () => { mockRpcClient.getProtocols.mockReturnValue(protocols); mockRpcClient.getTxRollupInbox.mockReturnValue(txRollupInbox); mockRpcClient.getTxRollupState.mockReturnValue(txRollupState); - rpcCache = new RpcClientCache(mockRpcClient); }); @@ -132,6 +135,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(); await rpcCache.getBalance(address); await rpcCache.getStorage(contractAddress); + await rpcCache.getStoragePaidSpace(contractAddress); + await rpcCache.getStorageUsedSpace(contractAddress); await rpcCache.getScript(contractAddress); await rpcCache.getNormalizedScript(contractAddress); await rpcCache.getContract(contractAddress); @@ -172,6 +177,12 @@ describe('RpcClientCache test', () => { expect( rpcCache.getAllCachedData()[`rpcTest/getStorage/head/${contractAddress}/`].response ).toEqual(storage); + expect( + rpcCache.getAllCachedData()[`rpcTest/getStoragePaidSpace/head/${contractAddress}/`].response + ).toEqual('120'); + expect( + rpcCache.getAllCachedData()[`rpcTest/getStorageUsedSpace/head/${contractAddress}/`].response + ).toEqual('100'); expect( rpcCache.getAllCachedData()[`rpcTest/getScript/head/${contractAddress}/`].response ).toEqual(script); @@ -256,6 +267,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(block); await rpcCache.getBalance(address, block); await rpcCache.getStorage(contractAddress, block); + await rpcCache.getStoragePaidSpace(contractAddress, block); + await rpcCache.getStorageUsedSpace(contractAddress, block); await rpcCache.getScript(contractAddress, block); await rpcCache.getNormalizedScript(contractAddress, { unparsing_mode: 'Readable' }, block); await rpcCache.getContract(contractAddress, block); @@ -306,6 +319,14 @@ describe('RpcClientCache test', () => { expect( rpcCache.getAllCachedData()[`rpcTest/getStorage/${block.block}/${contractAddress}/`].response ).toEqual(storage); + expect( + rpcCache.getAllCachedData()[`rpcTest/getStoragePaidSpace/${block.block}/${contractAddress}/`] + .response + ).toEqual('120'); + expect( + rpcCache.getAllCachedData()[`rpcTest/getStorageUsedSpace/${block.block}/${contractAddress}/`] + .response + ).toEqual('100'); expect( rpcCache.getAllCachedData()[`rpcTest/getScript/${block.block}/${contractAddress}/`].response ).toEqual(script); @@ -402,6 +423,8 @@ describe('RpcClientCache test', () => { await rpcCache.getLiveBlocks(); await rpcCache.getBalance(address); await rpcCache.getStorage(contractAddress); + await rpcCache.getStoragePaidSpace(contractAddress); + await rpcCache.getStorageUsedSpace(contractAddress); await rpcCache.getScript(contractAddress); await rpcCache.getNormalizedScript(contractAddress); await rpcCache.getContract(contractAddress); diff --git a/packages/taquito-rpc/test/taquito-rpc.spec.ts b/packages/taquito-rpc/test/taquito-rpc.spec.ts index a047720f02..4a8d698b2b 100644 --- a/packages/taquito-rpc/test/taquito-rpc.spec.ts +++ b/packages/taquito-rpc/test/taquito-rpc.spec.ts @@ -129,6 +129,28 @@ describe('RpcClient test', () => { done(); }); + + it('should query used_space url correctly', async (done) => { + await client.getStorageUsedSpace(contractAddress); + + expect(httpBackend.createRequest.mock.calls[0][0]).toEqual({ + method: 'GET', + url: `root/chains/test/blocks/head/context/contracts/${contractAddress}/storage/used_space`, + }); + + done(); + }); + + it('should query used_paid url correctly', async (done) => { + await client.getStoragePaidSpace(contractAddress); + + expect(httpBackend.createRequest.mock.calls[0][0]).toEqual({ + method: 'GET', + url: `root/chains/test/blocks/head/context/contracts/${contractAddress}/storage/paid_space`, + }); + + done(); + }); }); describe('getScript', () => {