import { WETH_PER_CHAIN_ID } from "../../src/modules/Uniswap/constants";
import { UniswapDecoders } from "../../src/modules/Uniswap/decoders";

describe("Uniswap", () => {
  describe("decoders", () => {
    it("should decode a V2_SWAP_EXACT_IN command input", () => {
      // see tx 0x9d032ce73fb2c10432186087dae1b77f05fdd125982bfd04dfa47a23229dcd7f
      const input =
        "0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000008ef059372e0e255c6f18185b00000000000000000000000000000000000000000000000002520ee13087c56000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000069ee720c120ec7c9c52a625c04414459b3185f23000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
      expect(UniswapDecoders["V2_SWAP_EXACT_IN"](input, 1)).toEqual([
        "0x69ee720c120ec7c9c52a625c04414459b3185f23", // PEEZY
        "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
      ]);
    });

    it("should decode a V2_SWAP_EXACT_OUT command input", () => {
      // see tx 0x6fcd1f97b5c7d365b7b3c3d426c7039f45f40bdb4e7f6ac7b7fbe45c7ffe2846
      const input =
        "0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000060a24181e400000000000000000000000000000000000000000000000000000d0853f8cc9607b000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000036b25341b2ff1bbc1b019b041ec7423a6cb21969000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";
      expect(UniswapDecoders["V2_SWAP_EXACT_OUT"](input, 1)).toEqual([
        "0x36b25341b2ff1bbc1b019b041ec7423a6cb21969", // LAMBEAU
        "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
      ]);
    });

    it("should decode a V3_SWAP_EXACT_IN command input", () => {
      // see tx 0xf70e9fd3397af35a01d99ec33eb2652baf9de4cbe2bc042ddfb693dacb2184f2
      const input =
        "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000274d48fed3e800000000000000000000000000000000000000000000000064e8c5a11639f40000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc200271055747be9f9f5beb232ad59fe7af013b81d95fd5e000000000000000000000000000000000000000000";
      expect(UniswapDecoders["V3_SWAP_EXACT_IN"](input, 1)).toEqual([
        "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
        "0x55747be9f9f5beb232ad59fe7af013b81d95fd5e", // TBO
      ]);
    });

    it("should decode a V3_SWAP_EXACT_OUT command input", () => {
      // see tx 0x12522daaa016979bf86c8732e2d86b975629c99ddacc86ca935d84a48a00988f
      const input =
        "0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000233a3559d9da00000000000000000000000000000000000000000000000062e76d8ff4b926e800000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc200271055747be9f9f5beb232ad59fe7af013b81d95fd5e000000000000000000000000000000000000000000";
      expect(UniswapDecoders["V3_SWAP_EXACT_OUT"](input, 1)).toEqual([
        "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // WETH
        "0x55747be9f9f5beb232ad59fe7af013b81d95fd5e", // TBO
      ]);
    });

    it("should decode a WRAP_ETH command input", () => {
      // see tx 0xf9b0b54a822bae7df4826016661eb213ec934147b7a226ecf88c49cf6ba3ef0d
      const input =
        "0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000032a04cac0ca0000";

      const supportedChainIds = Object.keys(WETH_PER_CHAIN_ID);

      for (const chainId of supportedChainIds) {
        const expectedAddress = WETH_PER_CHAIN_ID[chainId];
        expect(UniswapDecoders["WRAP_ETH"](input, chainId)).toEqual([
          expectedAddress instanceof Error ? undefined : expectedAddress.toLowerCase(),
        ]);
      }
    });

    it("should decode a UNWRAP_ETH command input", () => {
      // see tx 0xd2a99d50c3c2bb70040ec94e10aef6d558f8babc92474cfcc2a1aa29da9afdc5
      const input =
        "0x0000000000000000000000009580d04543fb19860925c649bb3a7741d7ec75d9000000000000000000000000000000000000000000000000011f162a2bc89bc4";

      const supportedChainIds = Object.keys(WETH_PER_CHAIN_ID);

      for (const chainId of supportedChainIds) {
        const expectedAddress = WETH_PER_CHAIN_ID[chainId];
        expect(UniswapDecoders["UNWRAP_ETH"](input, chainId)).toEqual([
          expectedAddress instanceof Error ? undefined : expectedAddress.toLowerCase(),
        ]);
      }
    });

    it("should decode a SWEEP command input", () => {
      // see tx 0xcc3a651b4f962576ed8f2142326271d090dcb701b754429f99e9b77d38cedc30
      const input =
        "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001125ffbea29018485cc228e39aade004a359fe990000000000000000000000000000000000000000000000000000000000000000";
      expect(UniswapDecoders["SWEEP"](input, 1)).toEqual([
        "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
      ]);
    });

    it("should return an empty array for other supported commands", () => {
      const input =
        "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000204fce5e3e2502611000000000000000000000000000000000000000000000000000000001f942ac9a54ae2700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000003ffeea07a27fab7ad1df5297fa75e77a43cb5790000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000ccae1bc46fb018dd396ed4c45565d4cb9d41098";
      const otherCommandDecoders = Object.entries(UniswapDecoders)
        .map(([command, decoder]) => {
          if (
            ![
              "V2_SWAP_EXACT_IN",
              "V2_SWAP_EXACT_OUT",
              "V3_SWAP_EXACT_IN",
              "V3_SWAP_EXACT_OUT",
              "WRAP_ETH",
              "UNWRAP_ETH",
              "SWEEP",
            ].includes(command)
          ) {
            return decoder;
          }
        })
        .filter(Boolean);

      for (const decoder of otherCommandDecoders) {
        expect(decoder!(input, 1)).toEqual([]);
      }
    });
  });
});
