Repository: ecadlabs/taquito (ts)

Issue:
Avoid doing POST call to fetch contract script with the RPC
Taquito can query the RPC `context/contracts/{contractAddress}`(GET) to retrieve smart contract code instead of `context/contracts/{contractAddress}/script/normalized`(POST). 

> it is more practical to avoid POST calls when reading from the chain. calling with POST prevents caching using standard HTTP caches and this particular call could be cached with indefinitely below the head level
Additional details: https://tezos-dev.slack.com/archives/CNJJ77B9B/p1649686851745029

The global constants are not expanded in `context/contracts/{contractAddress}/script`, but they are in `context/contracts/{contractAddress}/script/normalized`. This was the rational to use `script/normalized` instead of `script`. 
However, it appears that global constants are also expand in `context/contracts/{contractAddress}`. This latter being a GET call, should be preferred over `script/normalized`.

Pull request:
perf(rpc): use getContract to fetch script
Avoid doing POST call to fetch contract script with the RPC

fix #1532

Thank you for your contribution to Taquito.

Before submitting this PR, please make sure:

- [ ] Your code builds cleanly without any errors or warnings
- [ ] You have added unit tests
- [ ] You have added integration tests (if relevant/appropriate)
- [ ] All public methods or types have TypeDoc coverage with a complete description, and ideally an @example
- [ ] You have added or updated corresponding documentation
- [ ] If relevant, you have written a first draft summary describing the change for inclusion in Release Notes. 

## Release Note Draft Snippet

__If relevant, please write a summary of your change that will be suitable for
inclusion in the Release Notes for the next Taquito release.__


Patch:
diff --git a/packages/taquito-contracts-library/src/rpc-wrapper.ts b/packages/taquito-contracts-library/src/rpc-wrapper.ts
index 248fe988b..d38c9023c 100644
--- a/packages/taquito-contracts-library/src/rpc-wrapper.ts
+++ b/packages/taquito-contracts-library/src/rpc-wrapper.ts
@@ -50,16 +50,15 @@ import { ContractsLibrary } from './taquito-contracts-library';
 export class RpcWrapperContractsLibrary implements RpcClientInterface {
   constructor(private rpc: RpcClientInterface, private contractslibrary: ContractsLibrary) {}
 
-  async getNormalizedScript(
+  async getContract(
     address: string,
-    unparsingMode: UnparsingMode = { unparsing_mode: 'Readable' },
     { block }: RPCOptions = defaultRPCOptions
-  ): Promise<ScriptResponse> {
+  ): Promise<ContractResponse> {
     const contractData = this.contractslibrary.getContract(address);
     if (contractData) {
-      return contractData.script;
+      return { script: contractData.script, balance: new BigNumber(NaN) };
     } else {
-      return this.rpc.getNormalizedScript(address, unparsingMode, { block });
+      return this.rpc.getContract(address, { block });
     }
   }
 
@@ -99,11 +98,12 @@ export class RpcWrapperContractsLibrary implements RpcClientInterface {
   ): Promise<ScriptResponse> {
     return this.rpc.getScript(address, { block });
   }
-  async getContract(
+  async getNormalizedScript(
     address: string,
+    unparsingMode: UnparsingMode = { unparsing_mode: 'Readable' },
     { block }: RPCOptions = defaultRPCOptions
-  ): Promise<ContractResponse> {
-    return this.rpc.getContract(address, { block });
+  ): Promise<ScriptResponse> {
+    return this.rpc.getNormalizedScript(address, unparsingMode, { block });
   }
   async getManagerKey(
     address: string,
diff --git a/packages/taquito-contracts-library/src/taquito-contracts-library.ts b/packages/taquito-contracts-library/src/taquito-contracts-library.ts
index 95eaf8258..62ff580cf 100644
--- a/packages/taquito-contracts-library/src/taquito-contracts-library.ts
+++ b/packages/taquito-contracts-library/src/taquito-contracts-library.ts
@@ -26,7 +26,7 @@ interface ContractsData {
  *
  * contractsLibrary.addContract({
  *      ['contractAddress1']: {
- *          script: script1, // obtained from Tezos.rpc.getNormalizedScript('contractAddress1')
+ *          script: script1, // obtained from Tezos.rpc.getContract('contractAddress1').script
  *          entrypoints: entrypoints1 // obtained from Tezos.rpc.getEntrypoints('contractAddress1')
  *      },
  *      // load more contracts
@@ -44,7 +44,7 @@ export class ContractsLibrary implements Extension {
    *
    * @param contract is an object where the key is a contract address and the value is an object having a script and an entrypoints properties.
    * Note: the expected format for the script and entrypoints properties are the same as the one respectivlely returned by
-   * `TezosToolkit.rpc.getNormalizedScript` and `TezosToolkit.rpc.getEntrypoints`
+   * `TezosToolkit.rpc.getContract('contractAddress').script` and `TezosToolkit.rpc.getEntrypoints`
    *
    */
   addContract(contract: ContractsData) {
diff --git a/packages/taquito/src/contract/rpc-contract-provider.ts b/packages/taquito/src/contract/rpc-contract-provider.ts
index cd50b669c..b7fbbc373 100644
--- a/packages/taquito/src/contract/rpc-contract-provider.ts
+++ b/packages/taquito/src/contract/rpc-contract-provider.ts
@@ -96,7 +96,7 @@ export class RpcContractProvider
       throw new InvalidContractAddressError(contract);
     }
     if (!schema) {
-      schema = await this.rpc.getNormalizedScript(contract);
+      schema = (await this.rpc.getContract(contract)).script;
     }
 
     let contractSchema: Schema;
diff --git a/packages/taquito/src/read-provider/rpc-read-adapter.ts b/packages/taquito/src/read-provider/rpc-read-adapter.ts
index a39b5e5b1..029020ef6 100644
--- a/packages/taquito/src/read-provider/rpc-read-adapter.ts
+++ b/packages/taquito/src/read-provider/rpc-read-adapter.ts
@@ -81,11 +81,8 @@ export class RpcReadAdapter implements TzReadProvider {
    * @returns Note: The code must be in the JSON format and not contain global constant
    */
   async getScript(contract: string, block: BlockIdentifier): Promise<ScriptedContracts> {
-    return this.context.rpc.getNormalizedScript(
-      contract,
-      { unparsing_mode: 'Readable' },
-      { block: String(block) }
-    );
+    const { script } = await this.context.rpc.getContract(contract, { block: String(block) });
+    return script;
   }
 
   /**


Test patch:
diff --git a/packages/taquito-contracts-library/test/rpc-wrapper.spec.ts b/packages/taquito-contracts-library/test/rpc-wrapper.spec.ts
index 4514d07ea..badd87a2a 100644
--- a/packages/taquito-contracts-library/test/rpc-wrapper.spec.ts
+++ b/packages/taquito-contracts-library/test/rpc-wrapper.spec.ts
@@ -49,7 +49,7 @@ describe('RpcWrapperContractsLibrary tests', () => {
     });
 
     const rpcWrapper = new RpcWrapperContractsLibrary(mockRpcClient as any, contractLib);
-    expect(await rpcWrapper.getNormalizedScript(contractAddress)).toEqual(script);
+    expect((await rpcWrapper.getContract(contractAddress)).script).toEqual(script);
     expect(await rpcWrapper.getEntrypoints(contractAddress)).toEqual(entrypoints);
     done();
   });
diff --git a/packages/taquito/test/contract/contract-abstraction-composer.spec.ts b/packages/taquito/test/contract/contract-abstraction-composer.spec.ts
index 01de528b7..e72b80ac4 100644
--- a/packages/taquito/test/contract/contract-abstraction-composer.spec.ts
+++ b/packages/taquito/test/contract/contract-abstraction-composer.spec.ts
@@ -25,12 +25,12 @@ describe('Contract abstraction composer test', () => {
 
   beforeEach(() => {
     mockRpcClient = {
-      getNormalizedScript: jest.fn(),
+      getContract: jest.fn(),
       getEntrypoints: jest.fn(),
       getChainId: jest.fn(),
     };
 
-    mockRpcClient.getNormalizedScript.mockResolvedValue(script);
+    mockRpcClient.getContract.mockResolvedValue({ script });
     mockRpcClient.getEntrypoints.mockResolvedValue({
       entrypoints: {
         mint: { prim: 'pair', args: [{ prim: 'key' }, { prim: 'nat' }] },
diff --git a/packages/taquito/test/contract/contractView.spec.ts b/packages/taquito/test/contract/contractView.spec.ts
index a0d7a6993..794b6ac32 100644
--- a/packages/taquito/test/contract/contractView.spec.ts
+++ b/packages/taquito/test/contract/contractView.spec.ts
@@ -8,7 +8,7 @@ import { ChainIds } from '../../src/constants';
 describe('ContractView test', () => {
   let rpcContractProvider: RpcContractProvider;
   let mockRpcClient: {
-    getNormalizedScript: jest.Mock<any, any>;
+    getContract: jest.Mock<any, any>;
     getStorage: jest.Mock<any, any>;
     getEntrypoints: jest.Mock<any, any>;
     getBlockHeader: jest.Mock<any, any>;
@@ -32,7 +32,7 @@ describe('ContractView test', () => {
   beforeEach(() => {
     mockRpcClient = {
       getEntrypoints: jest.fn(),
-      getNormalizedScript: jest.fn(),
+      getContract: jest.fn(),
       getStorage: jest.fn(),
       getBlockHeader: jest.fn(),
       runView: jest.fn(),
@@ -58,9 +58,11 @@ describe('ContractView test', () => {
     );
 
     mockRpcClient.getChainId.mockResolvedValue('NetXjD3HPJJjmcd');
-    mockRpcClient.getNormalizedScript.mockResolvedValue({
-      code: tokenCode,
-      storage: tokenInit,
+    mockRpcClient.getContract.mockResolvedValue({
+      script: {
+        code: tokenCode,
+        storage: tokenInit,
+      },
     });
     mockSigner.sign.mockResolvedValue({ sbytes: 'test', prefixSig: 'test_sig' });
     mockSigner.publicKey.mockResolvedValue('test_pub_key');
diff --git a/packages/taquito/test/contract/lambda-view-class.spec.ts b/packages/taquito/test/contract/lambda-view-class.spec.ts
index 3073c07b0..9cf179394 100644
--- a/packages/taquito/test/contract/lambda-view-class.spec.ts
+++ b/packages/taquito/test/contract/lambda-view-class.spec.ts
@@ -10,47 +10,49 @@ describe('LambdaView test', () => {
 
   beforeEach(() => {
     mockRpcClientView = {
-      getNormalizedScript: jest.fn(),
+      getContract: jest.fn(),
       getChainId: jest.fn(),
       getEntrypoints: jest.fn(),
     };
 
-    mockRpcClientView.getNormalizedScript.mockResolvedValue(script);
+    mockRpcClientView.getContract.mockResolvedValue({ script });
     mockRpcClientView.getChainId.mockResolvedValue('NetXjD3HPJJjmcd');
 
     toolkitView = new TezosToolkit('url');
     toolkitView['_context'].rpc = mockRpcClientView;
 
     mockRpcClientLambda = {
-      getNormalizedScript: jest.fn(),
+      getContract: jest.fn(),
       getChainId: jest.fn(),
       getEntrypoints: jest.fn(),
     };
 
-    mockRpcClientLambda.getNormalizedScript.mockResolvedValue({
-      code: [
-        {
-          prim: 'parameter',
-          args: [
-            {
-              prim: 'lambda',
-              args: [
-                { prim: 'unit' },
-                {
-                  prim: 'pair',
-                  args: [{ prim: 'list', args: [{ prim: 'operation' }] }, { prim: 'unit' }],
-                },
-              ],
-            },
-          ],
-        },
-        { prim: 'storage', args: [{ prim: 'unit' }] },
-        {
-          prim: 'code',
-          args: [[{ prim: 'CAR' }, { prim: 'UNIT' }, { prim: 'EXEC' }]],
-        },
-      ],
-      storage: { prim: 'Unit' },
+    mockRpcClientLambda.getContract.mockResolvedValue({
+      script: {
+        code: [
+          {
+            prim: 'parameter',
+            args: [
+              {
+                prim: 'lambda',
+                args: [
+                  { prim: 'unit' },
+                  {
+                    prim: 'pair',
+                    args: [{ prim: 'list', args: [{ prim: 'operation' }] }, { prim: 'unit' }],
+                  },
+                ],
+              },
+            ],
+          },
+          { prim: 'storage', args: [{ prim: 'unit' }] },
+          {
+            prim: 'code',
+            args: [[{ prim: 'CAR' }, { prim: 'UNIT' }, { prim: 'EXEC' }]],
+          },
+        ],
+        storage: { prim: 'Unit' },
+      },
     });
     mockRpcClientLambda.getChainId.mockResolvedValue('NetXjD3HPJJjmcd');
     mockRpcClientLambda.getEntrypoints.mockResolvedValue({ entrypoints: {} });
diff --git a/packages/taquito/test/contract/rpc-contract-provider.spec.ts b/packages/taquito/test/contract/rpc-contract-provider.spec.ts
index 9a89c66c4..3b26ba6f3 100644
--- a/packages/taquito/test/contract/rpc-contract-provider.spec.ts
+++ b/packages/taquito/test/contract/rpc-contract-provider.spec.ts
@@ -43,7 +43,6 @@ describe('RpcContractProvider test', () => {
   let rpcContractProvider: RpcContractProvider;
   let mockRpcClient: {
     getScript: jest.Mock<any, any>;
-    getNormalizedScript: jest.Mock<any, any>;
     getStorage: jest.Mock<any, any>;
     getBigMapExpr: jest.Mock<any, any>;
     getBigMapKey: jest.Mock<any, any>;
@@ -97,7 +96,6 @@ describe('RpcContractProvider test', () => {
       getEntrypoints: jest.fn(),
       getBlock: jest.fn(),
       getScript: jest.fn(),
-      getNormalizedScript: jest.fn(),
       getManagerKey: jest.fn(),
       getStorage: jest.fn(),
       getBigMapKey: jest.fn(),
@@ -152,7 +150,13 @@ describe('RpcContractProvider test', () => {
       prim: 'Pair',
       args: [{ int: '100' }, []],
     });
-    mockRpcClient.getContract.mockResolvedValue({ counter: 0 });
+    mockRpcClient.getContract.mockResolvedValue({
+      counter: 0,
+      script: {
+        code: [sample],
+        storage: sampleStorage,
+      },
+    });
     mockRpcClient.getBlockHeader.mockResolvedValue({ hash: 'test' });
     mockRpcClient.getProtocols.mockResolvedValue({ next_protocol: 'test_proto' });
     mockSigner.sign.mockResolvedValue({ sbytes: 'test', prefixSig: 'test_sig' });
@@ -172,10 +176,6 @@ describe('RpcContractProvider test', () => {
 
   describe('getStorage', () => {
     it('should call getStorage', async (done) => {
-      mockRpcClient.getNormalizedScript.mockResolvedValue({
-        code: [sample],
-        storage: sampleStorage,
-      });
       const result = await rpcContractProvider.getStorage('KT1Fe71jyjrxFg9ZrYqtvaX7uQjcLo7svE4D');
       expect(result).toEqual({
         '0': {},
@@ -189,7 +189,6 @@ describe('RpcContractProvider test', () => {
 
   describe('getBigMapKey', () => {
     it('should call getBigMapKey', async (done) => {
-      mockRpcClient.getNormalizedScript.mockResolvedValue({ code: [sample] });
       mockRpcClient.getBigMapKey.mockResolvedValue(sampleBigMapValue);
       const result = await rpcContractProvider.getBigMapKey(
         'KT1Fe71jyjrxFg9ZrYqtvaX7uQjcLo7svE4D',
@@ -1377,7 +1376,6 @@ describe('RpcContractProvider test', () => {
 
   describe('at', () => {
     it('should return contract method', async (done) => {
-      mockRpcClient.getContract.mockResolvedValue({ counter: 0 });
       mockRpcClient.getBlockHeader.mockResolvedValue({ hash: 'test' });
       mockRpcClient.getEntrypoints.mockResolvedValue({
         entrypoints: {
@@ -1385,9 +1383,12 @@ describe('RpcContractProvider test', () => {
         },
       });
       mockRpcClient.preapplyOperations.mockResolvedValue([]);
-      mockRpcClient.getNormalizedScript.mockResolvedValue({
-        code: tokenCode,
-        storage: tokenInit,
+      mockRpcClient.getContract.mockResolvedValue({
+        counter: 0,
+        script: {
+          code: tokenCode,
+          storage: tokenInit,
+        },
       });
       mockRpcClient.getBlockMetadata.mockResolvedValue({
         next_protocol: 'PsBABY5HQTSkA4297zNHfsZNKtxULfL18y95qb3m53QJiXGmrbU',
diff --git a/packages/taquito/test/read-provider/rpc-read-adapter.spec.ts b/packages/taquito/test/read-provider/rpc-read-adapter.spec.ts
index a83368fad..1503a9a04 100644
--- a/packages/taquito/test/read-provider/rpc-read-adapter.spec.ts
+++ b/packages/taquito/test/read-provider/rpc-read-adapter.spec.ts
@@ -250,9 +250,11 @@ describe('RpcReadAdapter test', () => {
     });
 
     it(`should get the code of a smart contract given its address: ${block}`, async (done) => {
-      mockRpcClient.getNormalizedScript.mockResolvedValue({
-        code: contractCodeSample,
-        storage: contractStorage,
+      mockRpcClient.getContract.mockResolvedValue({
+        script: {
+          code: contractCodeSample,
+          storage: contractStorage,
+        },
       });
 
       const result = await readProvider.getScript('KT1NcdpzokZQY4sLmCBUwLnMHQCCQ6rRXYwS', block);
@@ -261,7 +263,7 @@ describe('RpcReadAdapter test', () => {
         storage: contractStorage,
       });
 
-      expect(mockRpcClient.getNormalizedScript.mock.calls[0][0]).toEqual(
+      expect(mockRpcClient.getContract.mock.calls[0][0]).toEqual(
         'KT1NcdpzokZQY4sLmCBUwLnMHQCCQ6rRXYwS'
       );
       done();
diff --git a/packages/taquito/test/wallet/contract-abstraction-composer-wallet.spec.ts b/packages/taquito/test/wallet/contract-abstraction-composer-wallet.spec.ts
index 5bdc46f17..1973690c6 100644
--- a/packages/taquito/test/wallet/contract-abstraction-composer-wallet.spec.ts
+++ b/packages/taquito/test/wallet/contract-abstraction-composer-wallet.spec.ts
@@ -25,12 +25,12 @@ describe('Contract abstraction composer test', () => {
 
   beforeEach(() => {
     mockRpcClient = {
-      getNormalizedScript: jest.fn(),
+      getContract: jest.fn(),
       getEntrypoints: jest.fn(),
       getChainId: jest.fn(),
     };
 
-    mockRpcClient.getNormalizedScript.mockResolvedValue(script);
+    mockRpcClient.getContract.mockResolvedValue({ script });
     mockRpcClient.getEntrypoints.mockResolvedValue({
       entrypoints: {
         mint: { prim: 'pair', args: [{ prim: 'key' }, { prim: 'nat' }] },