diff --git a/apps/extension/src/background/approvals/service.test.ts b/apps/extension/src/background/approvals/service.test.ts index f8a496cc72..ad85a8e490 100644 --- a/apps/extension/src/background/approvals/service.test.ts +++ b/apps/extension/src/background/approvals/service.test.ts @@ -1,7 +1,21 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import * as borsh from "@dao-xyz/borsh"; +import { TxType } from "@namada/shared"; +import { + AccountType, + EthBridgeTransferMsgValue, + IbcTransferMsgValue, + SubmitBondMsgValue, + SubmitUnbondMsgValue, + SubmitVoteProposalMsgValue, + SubmitWithdrawMsgValue, + TokenInfo, + TransferMsgValue, +} from "@namada/types"; import { KeyRingService, TabStore } from "background/keyring"; import { LedgerService } from "background/ledger"; import { VaultService } from "background/vault"; +import BigNumber from "bignumber.js"; import createMockInstance from "jest-create-mock-instance"; import { KVStoreMock } from "test/init"; import { ApprovalsService } from "./service"; @@ -11,17 +25,24 @@ jest.mock("webextension-polyfill", () => ({ runtime: { getURL: () => "url", }, + windows: { + create: jest.fn(), + }, })); describe.only("approvals service", () => { let service: ApprovalsService; let keyRingService: jest.Mocked; let dataStore: KVStoreMock; + let txStore: KVStoreMock; + + afterEach(() => { + jest.restoreAllMocks(); + }); beforeEach(() => { jest.clearAllMocks(); - - const txStore = new KVStoreMock("TxStore"); + txStore = new KVStoreMock("TxStore"); dataStore = new KVStoreMock("DataStore"); const connectedTabsStore = new KVStoreMock("TabStore"); const approvedOriginsStore = new KVStoreMock( @@ -185,4 +206,288 @@ describe.only("approvals service", () => { expect(service.rejectSignature(tabId, "msgId")).rejects.toBeDefined(); }); }); + + const txTypes = [ + [TxType.Bond, "getParamsBond"], + [TxType.Unbond, "getParamsUnbond"], + [TxType.Withdraw, "getParamsWithdraw"], + [TxType.Transfer, "getParamsTransfer"], + [TxType.IBCTransfer, "getParamsIbcTransfer"], + [TxType.EthBridgeTransfer, "getParamsEthBridgeTransfer"], + [TxType.VoteProposal, "getParamsVoteProposal"], + ] as const; + + describe("approveTx", () => { + it.each(txTypes)("should launch tx", async (type, paramsFn) => { + jest.spyOn(ApprovalsService, paramsFn).mockImplementation(() => ({})); + jest.spyOn(borsh, "deserialize").mockReturnValue({}); + jest.spyOn(service as any, "_launchApprovalWindow"); + + expect( + service.approveTx(type, "", "", AccountType.Mnemonic) + ).resolves.not.toBeDefined(); + }); + }); + + describe("getParamsTransfer", () => { + it("should return transfer params", () => { + const transferMsgValue = new TransferMsgValue({ + source: "source", + target: "target", + token: "token", + amount: BigNumber(100), + nativeToken: "nativeToken", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); + + const params = ApprovalsService.getParamsTransfer( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: transferMsgValue.source, + target: transferMsgValue.target, + tokenAddress: transferMsgValue.token, + amount: transferMsgValue.amount.toString(), + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsIbcTransfer", () => { + it("should return transfer params", () => { + const token: TokenInfo = { + symbol: "symbol", + type: 0, + path: 0, + coin: "coin", + url: "url", + address: "address", + }; + + const transferMsgValue = new IbcTransferMsgValue({ + source: "source", + receiver: "target", + token: token, + amount: BigNumber(100), + portId: "portId", + channelId: "channelId", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); + + const params = ApprovalsService.getParamsIbcTransfer( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: transferMsgValue.source, + target: transferMsgValue.receiver, + tokenAddress: transferMsgValue.token, + amount: transferMsgValue.amount.toString(), + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsEthBridgeTransfer", () => { + it("should return transfer params", () => { + const transferMsgValue = new EthBridgeTransferMsgValue({ + nut: false, + asset: "asset", + recipient: "recipient", + sender: "sender", + amount: BigNumber(100), + feeAmount: BigNumber(0.5), + feeToken: "feeToken", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); + + const params = ApprovalsService.getParamsEthBridgeTransfer( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: transferMsgValue.sender, + target: transferMsgValue.recipient, + tokenAddress: transferMsgValue.asset, + amount: transferMsgValue.amount.toString(), + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsBond", () => { + it("should return bond params", () => { + const bondMsgValue = new SubmitBondMsgValue({ + source: "source", + validator: "validator", + amount: BigNumber(100), + nativeToken: "nativeToken", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(bondMsgValue); + + const params = ApprovalsService.getParamsBond( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: bondMsgValue.source, + tokenAddress: bondMsgValue.nativeToken, + amount: bondMsgValue.amount.toString(), + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsUnbond", () => { + it("should return unbond params", () => { + const unbondMsgValue = new SubmitUnbondMsgValue({ + source: "source", + validator: "validator", + amount: BigNumber(100), + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(unbondMsgValue); + + const params = ApprovalsService.getParamsUnbond( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: unbondMsgValue.source, + amount: unbondMsgValue.amount.toString(), + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsWithdraw", () => { + it("should return withdraw params", () => { + const withdrawMsgValue = new SubmitWithdrawMsgValue({ + source: "source", + validator: "validator", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(withdrawMsgValue); + + const params = ApprovalsService.getParamsWithdraw( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: withdrawMsgValue.source, + validator: withdrawMsgValue.validator, + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("getParamsVoteProposal", () => { + it("should return vote proposal params", () => { + const voteProposalMsgValue = new SubmitVoteProposalMsgValue({ + signer: "singer", + proposalId: BigInt(0), + vote: "yay", + }); + + const txMsgValue = { + token: "token", + feeAmount: BigNumber(0.5), + gasLimit: BigNumber(0.5), + chainId: "chainId", + publicKey: "publicKey", + }; + + jest.spyOn(borsh, "deserialize").mockReturnValue(voteProposalMsgValue); + + const params = ApprovalsService.getParamsVoteProposal( + new Uint8Array([]), + txMsgValue + ); + + expect(params).toEqual({ + source: voteProposalMsgValue.signer, + publicKey: txMsgValue.publicKey, + }); + }); + }); + + describe("rejectTx", () => { + it("should clear pending tx", async () => { + await service.rejectTx("msgId"); + jest.spyOn(service as any, "_clearPendingTx"); + + expect((service as any)._clearPendingTx).toHaveBeenCalledWith("msgId"); + }); + }); + + describe("submitTx", () => { + it("should call submitFn", async () => { + // await txStore.set("msgId", { + // txType: TxType.VoteProposal, + // txMsg: "", + // specificMsg: "", + // }); + + expect((service as any)._clearPendingTx).toHaveBeenCalledWith("msgId"); + }); + }); });