UNPKG

@ledgerhq/coin-tron

Version:
380 lines (363 loc) 10.9 kB
import BigNumber from "bignumber.js"; import { decode58Check, encode58Check, formatTrongridTrc20TxResponse, formatTrongridTxResponse, } from "./format"; import { Trc20API, TransactionTronAPI } from "./types"; const ownerHex = "41fd49eda0f23ff7ec1d03b52c3a45991c24cd440e"; const toHex = "4198927ffb9f554dc4a453c64b2e553a02d6df514b"; const trc20ContractHex = "4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0"; function baseTransactionTronApi( contract: TransactionTronAPI["raw_data"]["contract"][0], overrides: Partial<TransactionTronAPI> = {}, ): TransactionTronAPI { return { ret: [{ contractRet: "SUCCESS", fee: 1000 }], signature: [], txID: "txId", net_usage: 0, raw_data_hex: "", net_fee: 0, energy_usage: 0, block_timestamp: 1, blockNumber: 42, energy_fee: 0, energy_usage_total: 0, raw_data: { contract: [contract], ref_block_bytes: "", ref_block_hash: "", expiration: 0, }, internal_transactions: [], ...overrides, }; } describe("formatTrongridTrc20TxResponse", () => { it("should return correct TrongridTxInfo for Approval tx type", () => { const tx = { from: "from", to: "to", block_timestamp: 1, detail: { ret: [{ fee: 1 }], }, value: 1, transaction_id: "txId", token_info: { address: "addr" }, type: "Approval", }; const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "ContractApproval", tokenId: undefined, from: "from", to: "to", blockHeight: undefined, value: new BigNumber(1), fee: new BigNumber(1), hasFailed: false, tokenType: "trc20", tokenAddress: "addr", feesPayer: "from", }); }); it("should return correct TrongridTxInfo for Transfer tx type", () => { const tx = { from: "from", to: "to", block_timestamp: 1, detail: { ret: [{ fee: 1 }], }, value: 1, transaction_id: "txId", token_info: { address: "tokenId" }, type: "Transfer", }; const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "TriggerSmartContract", tokenId: "tokenId", from: "from", to: "to", blockHeight: undefined, value: new BigNumber(1), fee: new BigNumber(1), hasFailed: false, tokenType: "trc20", tokenAddress: "tokenId", feesPayer: "from", }); }); it("should fall back to contract_address when token_info.address is missing (unindexed LP contract)", () => { const tx = { from: "from", to: "to", block_timestamp: 1, detail: { ret: [{ fee: 0 }], raw_data: { contract: [ { parameter: { value: { owner_address: "41f1fe9d73ffb3b6ab532858b266c02f63410fbd70", // hex for TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s (unindexed LP contract) contract_address: "41c5f6aa996edd0696a0295b07fd7b20b0dd84c557", }, }, }, ], }, }, value: "20000000000", transaction_id: "txId", token_info: {}, type: "Transfer", }; const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API); expect(result).toMatchObject({ type: "TriggerSmartContract", tokenId: "TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s", tokenAddress: "TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s", }); }); it("should set feesPayer from owner_address when it differs from from (transferFrom case)", () => { // owner_address is the Tron tx initiator (hex); `from` is the TRC20 token source (base58) const tx = { from: "TTokenSourceAddress", to: "to", block_timestamp: 1, detail: { ret: [{ fee: 1 }], raw_data: { contract: [ { parameter: { value: { // hex for TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh owner_address: "41f1fe9d73ffb3b6ab532858b266c02f63410fbd70", }, }, }, ], }, }, value: 100, transaction_id: "txId", token_info: { address: "tokenAddr" }, type: "Transfer", }; const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "TriggerSmartContract", tokenId: "tokenAddr", from: "TTokenSourceAddress", to: "to", blockHeight: undefined, value: new BigNumber(100), fee: new BigNumber(1), hasFailed: false, tokenType: "trc20", tokenAddress: "tokenAddr", feesPayer: "TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh", }); }); }); describe("formatTrongridTxResponse", () => { it("should return correct TrongridTxInfo for TransferContract", async () => { const tx = baseTransactionTronApi({ type: "TransferContract", parameter: { type_url: "", value: { owner_address: ownerHex, to_address: toHex, amount: 1_000_000, }, }, }); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "TransferContract", tokenId: undefined, tokenType: undefined, tokenAddress: undefined, from: encode58Check(ownerHex), to: encode58Check(toHex), value: new BigNumber(1_000_000), fee: new BigNumber(1000), blockHeight: 42, hasFailed: false, feesPayer: encode58Check(ownerHex), }); }); it("should set hasFailed when contract execution did not succeed", async () => { const tx = baseTransactionTronApi( { type: "TransferContract", parameter: { type_url: "", value: { owner_address: ownerHex, to_address: toHex, amount: 100, }, }, }, { ret: [{ contractRet: "REVERT", fee: 0 }] }, ); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result?.hasFailed).toBe(true); }); it("should return correct TrongridTxInfo for TransferAssetContract", async () => { const assetName = "10013004"; const tx = baseTransactionTronApi({ type: "TransferAssetContract", parameter: { type_url: "", value: { owner_address: ownerHex, to_address: toHex, amount: 100, asset_name: assetName, }, }, }); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "TransferAssetContract", tokenId: assetName, tokenType: "trc10", tokenAddress: undefined, from: encode58Check(ownerHex), to: encode58Check(toHex), value: new BigNumber(100), fee: new BigNumber(1000), blockHeight: 42, hasFailed: false, feesPayer: encode58Check(ownerHex), }); }); it("should return correct TrongridTxInfo for TriggerSmartContract", async () => { const tx = baseTransactionTronApi({ type: "TriggerSmartContract", parameter: { type_url: "", value: { owner_address: ownerHex, to_address: toHex, contract_address: trc20ContractHex, amount: 0, }, }, }); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result).toEqual({ txID: "txId", date: new Date(1), type: "TriggerSmartContract", tokenId: encode58Check(trc20ContractHex), tokenType: "trc20", tokenAddress: encode58Check(trc20ContractHex), from: encode58Check(ownerHex), to: encode58Check(toHex), value: new BigNumber(0), fee: new BigNumber(1000), blockHeight: 42, hasFailed: false, feesPayer: encode58Check(ownerHex), }); }); it("should map withdraw amount for WithdrawBalanceContract", async () => { const tx = baseTransactionTronApi( { type: "WithdrawBalanceContract", parameter: { type_url: "", value: { owner_address: ownerHex, }, }, }, { withdraw_amount: 5_000_000 }, ); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result?.value).toEqual(new BigNumber(5_000_000)); }); it("should map quant for ExchangeTransactionContract", async () => { const tx = baseTransactionTronApi({ type: "ExchangeTransactionContract", parameter: { type_url: "", value: { owner_address: ownerHex, quant: 777, }, }, }); const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result?.value).toEqual(new BigNumber(777)); }); it("should attach vote extra info using getValidatorName", async () => { const voteAddressHex = "41b183301d6301fae224c6ab9b28b19b6d1625bf23"; const getValidatorName = jest .fn() .mockImplementation(async (address: string) => address === encode58Check(voteAddressHex) ? "SR-Name" : null, ); const tx = baseTransactionTronApi({ type: "VoteWitnessContract", parameter: { type_url: "", value: { owner_address: ownerHex, votes: [{ vote_address: voteAddressHex, vote_count: 3 }], }, }, }); const result = await formatTrongridTxResponse(tx, getValidatorName); expect(getValidatorName).toHaveBeenCalledWith(encode58Check(voteAddressHex)); expect(result?.extra).toEqual({ votes: [ { name: "SR-Name", address: encode58Check(voteAddressHex), voteCount: 3, }, ], }); }); it("should return undefined when the transaction payload cannot be parsed", async () => { const tx = { txID: "broken", block_timestamp: 1 } as TransactionTronAPI; const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null)); expect(result).toBeUndefined(); }); }); describe("decode58Check", () => { it("decodes correctly Tron address", () => { expect(decode58Check("TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh")).toEqual( "41f1fe9d73ffb3b6ab532858b266c02f63410fbd70", ); }); }); describe("encode58Check", () => { it("encodes correctly Tron address", () => { expect(encode58Check("41f1fe9d73ffb3b6ab532858b266c02f63410fbd70")).toEqual( "TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh", ); }); });