UNPKG

@ledgerhq/coin-ton

Version:
240 lines (218 loc) 8.15 kB
import { Address, toNano } from "@ton/core"; import { setCoinConfig } from "../../config"; import { TOKEN_TRANSFER_FORWARD_AMOUNT, TOKEN_TRANSFER_MAX_FEE, TOKEN_TRANSFER_QUERY_ID, } from "../../constants"; import { TonComment, TonPayloadFormat, TonPayloadJettonTransfer } from "../../types"; import { addressesAreEqual, buildTonTransaction, commentIsValid, getLedgerTonPath, getTransferExpirationTime, isAddressValid, } from "../../utils"; import mockServer, { API_TON_ENDPOINT } from "../fixtures/api.fixtures"; import { account, transaction as baseTransaction, jettonTransaction, } from "../fixtures/common.fixtures"; describe("TON addresses", () => { const addr = { raw: "0:074c7194d64e8218f2cfaab8e79b34201adbed0f8fa7f2773e604dd39969b5ff", rawWrong: "0:074c7194d64e8218f2cfaab8e79b34201adbed0f8fa7f2773e604dd39969b5f", bounceUrl: "EQAHTHGU1k6CGPLPqrjnmzQgGtvtD4-n8nc-YE3TmWm1_1JZ", bounceNoUrl: "EQAHTHGU1k6CGPLPqrjnmzQgGtvtD4+n8nc+YE3TmWm1/1JZ", bounceWrong: "EQAHTHGU1k6CGPLPqrjnmzQgGtvtD4+n8nc+YE3TmWm1/1J", noBounceUrl: "UQAHTHGU1k6CGPLPqrjnmzQgGtvtD4-n8nc-YE3TmWm1_w-c", noBounceNoUrl: "UQAHTHGU1k6CGPLPqrjnmzQgGtvtD4+n8nc+YE3TmWm1/w+c", noBounceWrong: "UQAHTHGU1k6CGPLPqrjnmzQgGtvtD4+n8nc+YE3TmWm1/w+", diff: "UQBjrXgZbYDCpxLKpgMnBe985kYDfUeriuYUafbuKgdBpWuJ", }; test("Check if addresses are valid", () => { expect(isAddressValid(addr.raw)).toBe(true); expect(isAddressValid(addr.bounceUrl)).toBe(true); expect(isAddressValid(addr.bounceNoUrl)).toBe(true); expect(isAddressValid(addr.noBounceUrl)).toBe(true); expect(isAddressValid(addr.noBounceNoUrl)).toBe(true); expect(isAddressValid(addr.rawWrong)).toBe(false); expect(isAddressValid(addr.bounceWrong)).toBe(false); expect(isAddressValid(addr.noBounceWrong)).toBe(false); expect(isAddressValid(addr.diff)).toBe(true); }); test("Compare addresses", () => { expect(addressesAreEqual(addr.raw, addr.bounceUrl)).toBe(true); expect(addressesAreEqual(addr.raw, addr.noBounceUrl)).toBe(true); expect(addressesAreEqual(addr.bounceUrl, addr.noBounceUrl)).toBe(true); expect(addressesAreEqual(addr.rawWrong, addr.noBounceUrl)).toBe(false); expect(addressesAreEqual(addr.noBounceNoUrl, addr.diff)).toBe(false); }); }); test("TON Comments are valid", () => { const msg = (e: boolean, m: string): TonComment => ({ isEncrypted: e, text: m }); expect(commentIsValid(msg(false, ""))).toBe(true); expect(commentIsValid(msg(false, "Hello world!"))).toBe(true); expect( commentIsValid( msg( false, " 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789", // 120 chars ), ), ).toBe(true); expect( commentIsValid( msg( false, " 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ", // 121 chars ), ), ).toBe(false); expect(commentIsValid(msg(false, "😀"))).toBe(false); expect(commentIsValid(msg(true, ""))).toBe(false); }); describe("TON transfers", () => { const commentPayload: TonPayloadFormat = { type: "comment", text: "", }; const transferPayload: TonPayloadFormat = { type: "jetton-transfer", queryId: null, amount: BigInt(0), destination: new Address(0, Buffer.alloc(32)), responseDestination: new Address(0, Buffer.alloc(32)), customPayload: null, forwardAmount: BigInt(0), forwardPayload: null, knownJetton: null, }; const nftPayload: TonPayloadFormat = { type: "nft-transfer", queryId: null, newOwner: new Address(0, Buffer.alloc(32)), responseDestination: new Address(0, Buffer.alloc(32)), customPayload: null, forwardAmount: BigInt(0), forwardPayload: null, }; test("Check if the transaction is jetton transfer", () => { /** * Checks if the given payload is a jetton transfer. */ const isJettonTransfer = (payload: TonPayloadFormat): boolean => payload.type === "jetton-transfer"; expect(isJettonTransfer(commentPayload)).toBe(false); expect(isJettonTransfer(transferPayload)).toBe(true); expect(isJettonTransfer(nftPayload)).toBe(false); }); }); describe("Get TON paths", () => { const correctPath = ["44'/607'/0'/0'/0'/0'", "m/44'/607'/0'/0'/0'/0'"]; const wrongPaths = [ "44'/607'/0'/0'/0'", "44'/607'/0'/0/'/0'", "44'/607'/0'/0'/x'/0'", "44'/607'/0'/-3'/0'/0'", "44'/607'/0'/2147483650'/0'/0'", ]; test("Correct paths return a correct response", () => { correctPath.map((path: string) => { expect(getLedgerTonPath(path)).toStrictEqual([44, 607, 0, 0, 0, 0]); }); }); test("Wrong paths fail", () => { wrongPaths.map((path: string) => { expect(() => getLedgerTonPath(path)).toThrow(/^(\[ton\] Path)/); }); }); }); describe("Build TON transaction", () => { beforeAll(() => { setCoinConfig(() => ({ status: { type: "active", }, infra: { API_TON_ENDPOINT: API_TON_ENDPOINT, KNOWN_JETTONS: [], }, })); mockServer.listen(); }); afterAll(() => { mockServer.close(); }); const seqno = 22; test("Build TON transaction with an specific amount", () => { const tonTransaction = buildTonTransaction(baseTransaction, seqno, account); // Convert the Address to string to compare expect({ ...tonTransaction, to: tonTransaction.to.toString() }).toEqual({ to: Address.parse(baseTransaction.recipient).toString(), seqno, amount: BigInt(baseTransaction.amount.toString()), bounce: false, timeout: getTransferExpirationTime(), sendMode: 3, }); }); test("Build TON transaction when useAllAmount is true and there is a comment", () => { const transaction = { ...baseTransaction, comment: { text: "valid comment", isEncrypted: false }, useAllAmount: true, }; const tonTransaction = buildTonTransaction(transaction, seqno, account); // Convert the Address to string to compare expect({ ...tonTransaction, to: tonTransaction.to.toString() }).toEqual({ to: Address.parse(transaction.recipient).toString(), seqno, amount: BigInt(0), bounce: false, timeout: getTransferExpirationTime(), sendMode: 128, payload: { type: "comment", text: transaction.comment.text }, }); }); test("Build jetton transaction with an specific amount", () => { const jettonTransfer = buildTonTransaction(jettonTransaction, seqno, account); // Convert the Addresses to string to compare expect({ ...jettonTransfer, to: jettonTransfer.to.toString(), payload: undefined, }).toStrictEqual({ to: Address.parse(account.subAccounts?.[0].jettonWallet ?? "").toString(), seqno, amount: toNano(TOKEN_TRANSFER_MAX_FEE), bounce: true, timeout: getTransferExpirationTime(), sendMode: 3, payload: undefined, }); expect(jettonTransfer.payload?.type).toStrictEqual("jetton-transfer"); expect({ ...jettonTransfer.payload, destination: (jettonTransfer.payload as TonPayloadJettonTransfer).destination.toString(), responseDestination: ( jettonTransfer.payload as TonPayloadJettonTransfer ).responseDestination.toString(), queryId: (jettonTransfer.payload as TonPayloadJettonTransfer).queryId?.toString(), amount: (jettonTransfer.payload as TonPayloadJettonTransfer).amount.toString(), forwardAmount: (jettonTransfer.payload as TonPayloadJettonTransfer).forwardAmount.toString(), }).toStrictEqual({ type: "jetton-transfer", queryId: TOKEN_TRANSFER_QUERY_ID.toString(), amount: jettonTransaction.amount.toFixed(), destination: Address.parse(jettonTransaction.recipient).toString(), responseDestination: Address.parse(account.freshAddress).toString(), customPayload: null, forwardAmount: TOKEN_TRANSFER_FORWARD_AMOUNT.toString(), forwardPayload: null, knownJetton: null, }); }); });