Repository: ecadlabs/taquito
Pull request #1840 (2022-08-22 19:12:28)

feat(local-forging): support EMIT instruction
Added support to forge/parse the new EMIT instruction in Kathmandu

re #1742

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-http-utils/src/taquito-http-utils.ts b/packages/taquito-http-utils/src/taquito-http-utils.ts
index 9774c4ba5..e700113f1 100644
--- a/packages/taquito-http-utils/src/taquito-http-utils.ts
+++ b/packages/taquito-http-utils/src/taquito-http-utils.ts
@@ -14,7 +14,7 @@ enum ResponseType {
   JSON = 'json',
 }
 // Z TODO change any type >.>
-type ObjectType = Record<string, any>;
+type ObjectType = Record<string, any>
 
 export interface HttpRequestOptions {
   url: string;
@@ -51,12 +51,8 @@ export class HttpResponseError extends Error {
 export class HttpRequestFailed extends Error {
   public name = 'HttpRequestFailed';
 
-  constructor(
-    public message: string,
-    public url: string,
-    public method: HttpRequestOptions['method']
-  ) {
-    super(message);
+  constructor(public errorDetail: string) {
+    super(errorDetail);
   }
 }
 
@@ -150,7 +146,7 @@ export class HttpBackend {
           url + this.serialize(query)
         );
       } else {
-        throw new HttpRequestFailed(String(err), url + this.serialize(query), method ?? 'GET');
+        throw new HttpRequestFailed(err as string);
       }
     }
   }
diff --git a/packages/taquito-local-forging/src/constants.ts b/packages/taquito-local-forging/src/constants.ts
index 0eab9bd8c..0cd9be033 100644
--- a/packages/taquito-local-forging/src/constants.ts
+++ b/packages/taquito-local-forging/src/constants.ts
@@ -202,6 +202,7 @@ export const opMapping: { [key: string]: string } = {
   '94': 'tx_rollup_l2_address',
   '95': 'MIN_BLOCK_TIME',
   '96': 'sapling_transaction',
+  '97': 'EMIT',
 };
 
 export const opMappingReverse = (() => {


Test patch:
diff --git a/integration-tests/http-backend-request-error-handling.spec.ts b/integration-tests/http-backend-request-error-handling.spec.ts
deleted file mode 100644
index fa04953d1..000000000
--- a/integration-tests/http-backend-request-error-handling.spec.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { HttpBackend } from '@taquito/http-utils';
-
-describe('HttpBackend request', () => {
-    it('will fail with http request url and request method', async (done) => {
-        try {
-            const http: HttpBackend = new HttpBackend(1);
-            await http.createRequest<string>({
-              method: 'GET',
-              url: 'https://mainnet.api.tez.ie/chains/main/blocks/head/hash'
-            });
-        } catch (err: any) {
-            expect(err.message).toEqual('Error: timeout of 1ms exceeded')
-            expect(err.url).toEqual('https://mainnet.api.tez.ie/chains/main/blocks/head/hash')
-            expect(err.method).toEqual('GET')
-        }
-        done()
-      });
-      it('will fail with http request url + query and request method', async (done) => {
-        try {
-            const http: HttpBackend = new HttpBackend(1);
-            await http.createRequest<string>({
-              method: 'GET',
-              url: 'https://mainnet.api.tez.ie/chains/main/blocks/head/helpers/baking_rights',
-              query: {
-                level: 0
-              }
-            });
-        } catch (err: any) {
-            expect(err.message).toEqual('Error: timeout of 1ms exceeded')
-            expect(err.url).toEqual('https://mainnet.api.tez.ie/chains/main/blocks/head/helpers/baking_rights?level=0')
-            expect(err.method).toEqual('GET')
-        }
-        done()
-      });
-})
diff --git a/integration-tests/local-forging.spec.ts b/integration-tests/local-forging.spec.ts
index 66d733f09..140534db6 100644
--- a/integration-tests/local-forging.spec.ts
+++ b/integration-tests/local-forging.spec.ts
@@ -1,10 +1,11 @@
 import { CONFIGS } from "./config";
-import { commonCases } from '../packages/taquito-local-forging/test/allTestsCases';
+import { commonCases, kathmanduCases } from '../packages/taquito-local-forging/test/allTestsCases';
 import { LocalForger, ProtocolsHash } from '@taquito/local-forging'
-import { TezosToolkit } from "@taquito/taquito";
+import { Protocols, TezosToolkit } from "@taquito/taquito";
 
 CONFIGS().forEach(({ rpc, protocol }) => {
     const Tezos = new TezosToolkit(rpc);
+    const kathmandunetAndMondaynet = protocol === Protocols.ProtoALpha || protocol === Protocols.PtKathman ? test: test.skip;
 
     describe(`Test local forger: ${rpc}`, () => {
 
@@ -22,5 +23,19 @@ CONFIGS().forEach(({ rpc, protocol }) => {
                 done();
             });
         });
+
+        kathmanduCases.forEach(({ name, operation, expected }) => {
+
+            kathmandunetAndMondaynet(`Should give the same result as when forging with the rpc: ${name} (${rpc})`, async done => {
+                const localForger = new LocalForger(protocol as unknown as ProtocolsHash);
+
+                const result = await localForger.forge(operation);
+                const rpcResult = await Tezos.rpc.forgeOperations(operation);
+                expect(result).toEqual(rpcResult);
+                expect(await localForger.parse(result)).toEqual(expected || operation);
+
+                done();
+            });
+        });
     });
 })
\ No newline at end of file
diff --git a/packages/taquito-local-forging/test/allTestsCases.ts b/packages/taquito-local-forging/test/allTestsCases.ts
index 2d6749b1f..ff338c5ca 100644
--- a/packages/taquito-local-forging/test/allTestsCases.ts
+++ b/packages/taquito-local-forging/test/allTestsCases.ts
@@ -31,6 +31,7 @@ import {
 import { codeViewsTopLevel, storageViewsTopLevel } from './data/contract_views_top_level';
 import { ForgeParams } from '../src/interface';
 import { MichelsonV1Expression, OpKind } from '@taquito/rpc';
+import { emitCode } from './data/code_with_emit';
 
 function extractOp(
   startIndex: number,
@@ -1365,3 +1366,52 @@ export const commonCases: TestCase[] = [
     },
   },
 ];
+
+export const kathmanduCases: TestCase[] = [
+  ...extractOp(150, 151, opMapping).map((op): TestCase => {
+    return {
+      name: `Origination operation (${op})`,
+      operation: {
+        branch: 'BLzyjjHKEKMULtvkpSHxuZxx6ei6fpntH2BTkYZiLgs8zLVstvX',
+        contents: [
+          {
+            kind: OpKind.ORIGINATION,
+            counter: '1',
+            source: 'tz1QZ6KY7d3BuZDT1d19dUxoQrtFPN2QJ3hn',
+            fee: '10000',
+            gas_limit: '10',
+            storage_limit: '10',
+            balance: '0',
+            script: {
+              code: genericCode(op) as MichelsonV1Expression[],
+              storage: genericStorage,
+            },
+          },
+        ],
+      },
+    };
+  }),
+  {
+    name: `Origination of a contract that contains the instructions EMIT`,
+    operation: {
+      branch: 'BMV9bffK5yjWCJgUJBsoTRifb4SsAYbkCVwVkKbJHffJYn7ePBL',
+      contents: [
+        {
+          kind: OpKind.ORIGINATION,
+          counter: '94141',
+          source: 'tz2WH1zahKo2KiS1gcHBhNFTURPfW1Vk7qpE',
+          fee: '603',
+          gas_limit: '1526',
+          storage_limit: '377',
+          balance: '0',
+          script: {
+            code: emitCode,
+            storage: {
+              prim: 'Unit',
+            },
+          },
+        },
+      ],
+    },
+  },
+];
diff --git a/packages/taquito-local-forging/test/data/code_with_emit.ts b/packages/taquito-local-forging/test/data/code_with_emit.ts
new file mode 100644
index 000000000..b906664cf
--- /dev/null
+++ b/packages/taquito-local-forging/test/data/code_with_emit.ts
@@ -0,0 +1,115 @@
+export const emitCode = [
+  {
+    prim: 'parameter',
+    args: [
+      {
+        prim: 'unit',
+      },
+    ],
+  },
+  {
+    prim: 'storage',
+    args: [
+      {
+        prim: 'unit',
+      },
+    ],
+  },
+  {
+    prim: 'code',
+    args: [
+      [
+        {
+          prim: 'DROP',
+        },
+        {
+          prim: 'UNIT',
+        },
+        {
+          prim: 'PUSH',
+          args: [
+            {
+              prim: 'string',
+            },
+            {
+              string: 'right',
+            },
+          ],
+        },
+        {
+          prim: 'RIGHT',
+          args: [
+            {
+              prim: 'nat',
+            },
+          ],
+        },
+        {
+          prim: 'EMIT',
+          annots: ['%tag1'],
+        },
+        {
+          prim: 'PUSH',
+          args: [
+            {
+              prim: 'nat',
+            },
+            {
+              int: '2',
+            },
+          ],
+        },
+        {
+          prim: 'LEFT',
+          args: [
+            {
+              prim: 'string',
+            },
+          ],
+        },
+        {
+          prim: 'EMIT',
+          args: [
+            {
+              prim: 'or',
+              args: [
+                {
+                  prim: 'nat',
+                  annots: ['%int'],
+                },
+                {
+                  prim: 'string',
+                  annots: ['%str'],
+                },
+              ],
+            },
+          ],
+          annots: ['%tag2'],
+        },
+        {
+          prim: 'NIL',
+          args: [
+            {
+              prim: 'operation',
+            },
+          ],
+        },
+        {
+          prim: 'SWAP',
+        },
+        {
+          prim: 'CONS',
+        },
+        {
+          prim: 'SWAP',
+        },
+        {
+          prim: 'CONS',
+        },
+        {
+          prim: 'PAIR',
+        },
+      ],
+    ],
+  },
+];
diff --git a/packages/taquito-local-forging/test/taquito-local-forging.spec.ts b/packages/taquito-local-forging/test/taquito-local-forging.spec.ts
index e3d4f3de5..9d6668a7e 100644
--- a/packages/taquito-local-forging/test/taquito-local-forging.spec.ts
+++ b/packages/taquito-local-forging/test/taquito-local-forging.spec.ts
@@ -1,6 +1,6 @@
 import { LocalForger } from '../src/taquito-local-forging';
 import { ticketCode3, ticketStorage3 } from './data/code_with_ticket';
-import { commonCases } from './allTestsCases';
+import { commonCases, kathmanduCases } from './allTestsCases';
 import {
   InvalidOperationSchemaError,
   InvalidBlockHashError,
@@ -20,6 +20,17 @@ describe('Forge and parse operations default protocol', () => {
   });
 });
 
+describe('Forge and parse operations kathmandu protocol', () => {
+  const localForger = new LocalForger();
+  kathmanduCases.forEach(({ name, operation, expected }) => {
+    test(`Common test: ${name}`, async (done) => {
+      const result = await localForger.forge(operation);
+      expect(await localForger.parse(result)).toEqual(expected || operation);
+      done();
+    });
+  });
+});
+
 describe('Forge should validate parameters against the schema', () => {
   const localForger = new LocalForger();
   test('Should throw error when operation kind is invalid', async () => {