diff --git a/libs/ledger-live-common/src/families/aptos/logic.test.ts b/libs/ledger-live-common/src/families/aptos/logic.test.ts index beaaadc8f5ff..af64d55b625f 100644 --- a/libs/ledger-live-common/src/families/aptos/logic.test.ts +++ b/libs/ledger-live-common/src/families/aptos/logic.test.ts @@ -1,8 +1,15 @@ -import { Event, EntryFunctionPayloadResponse, WriteSetChange } from "@aptos-labs/ts-sdk"; +import { Event, InputEntryFunctionData, WriteSetChange } from "@aptos-labs/ts-sdk"; import type { Operation, OperationType } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { calculateAmount, getAptosAmounts, getFunctionAddress, isChangeOfAptos } from "./logic"; -import { processRecipients, compareAddress } from "./logic"; +import { APTOS_ASSET_ID, APTOS_COIN_CHANGE } from "./constants"; +import { + calculateAmount, + compareAddress, + getAptosAmounts, + getFunctionAddress, + isChangeOfAptos, + processRecipients, +} from "./logic"; import type { AptosTransaction } from "./types"; describe("Aptos sync logic ", () => { @@ -32,13 +39,12 @@ describe("Aptos sync logic ", () => { }); }); - /////////////////////////////////////////// describe("getFunctionAddress", () => { it("should return the function address when payload contains a function", () => { - const payload: EntryFunctionPayloadResponse = { + const payload: InputEntryFunctionData = { function: "0x1::coin::transfer", - type_arguments: [], - arguments: [], + typeArguments: [], + functionArguments: [], }; const result = getFunctionAddress(payload); @@ -47,23 +53,23 @@ describe("Aptos sync logic ", () => { it("should return undefined when payload does not contain a function", () => { const payload = { - function: "", - type_arguments: [], - arguments: [], - } as EntryFunctionPayload; + function: "::::", + typeArguments: [], + functionArguments: [], + } as InputEntryFunctionData; const result = getFunctionAddress(payload); expect(result).toBeUndefined(); }); it("should return undefined when payload is empty", () => { - const payload = {} as EntryFunctionPayloadResponse; + const payload = {} as InputEntryFunctionData; const result = getFunctionAddress(payload); expect(result).toBeUndefined(); }); }); - /////////////////////////////////////////// + describe("processRecipients", () => { let op: Operation; @@ -87,10 +93,10 @@ describe("Aptos sync logic ", () => { }); it("should add recipient for transfer-like functions from LL account", () => { - const payload: EntryFunctionPayloadResponse = { + const payload: InputEntryFunctionData = { function: "0x1::coin::transfer", - type_arguments: [], - arguments: ["0x12", "0x13", 1], //from: &signer, to: address, amount: u64 + typeArguments: [], + functionArguments: ["0x12", "0x13", 1], // from: &signer, to: address, amount: u64 }; processRecipients(payload, "0x13", op, "0x1"); @@ -98,10 +104,10 @@ describe("Aptos sync logic ", () => { }); it("should add recipient for transfer-like functions from external account", () => { - const payload: EntryFunctionPayloadResponse = { + const payload: InputEntryFunctionData = { function: "0x1::coin::transfer", - type_arguments: [], - arguments: ["0x13", "0x12", 1], //from: &signer, to: address, amount: u64 + typeArguments: [], + functionArguments: ["0x13", "0x12", 1], // from: &signer, to: address, amount: u64 }; processRecipients(payload, "0x13", op, "0x1"); @@ -109,10 +115,10 @@ describe("Aptos sync logic ", () => { }); it("should add recipients for batch transfer functions", () => { - const payload: EntryFunctionPayloadResponse = { + const payload: InputEntryFunctionData = { function: "0x1::aptos_account::batch_transfer_coins", - type_arguments: ["0x1::aptos_coin::AptosCoin"], - arguments: ["0x11", ["0x12", "0x13"], [1, 2]], + typeArguments: [APTOS_ASSET_ID], + functionArguments: ["0x11", ["0x12", "0x13"], [1, 2]], }; op.senders.push("0x11"); @@ -121,23 +127,23 @@ describe("Aptos sync logic ", () => { }); it("should add function address as recipient for other smart contracts", () => { - const payload: PayloadResponse = { + const payload: InputEntryFunctionData = { function: "0x2::other::contract", - type_arguments: [], - arguments: ["0x11", ["0x12"], [1]], + typeArguments: [], + functionArguments: ["0x11", ["0x12"], [1]], }; processRecipients(payload, "0x11", op, "0x2"); expect(op.recipients).toContain("0x2"); }); }); - /////////////////////////////////////////// + describe("isChangeOfAptos", () => { it("should return true for a valid change of Aptos", () => { const change = { type: "write_resource", data: { - type: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", + type: APTOS_COIN_CHANGE, data: { withdraw_events: { guid: { @@ -167,7 +173,7 @@ describe("Aptos sync logic ", () => { const change = { type: "write_resource", data: { - type: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", + type: APTOS_COIN_CHANGE, data: { withdraw_events: { guid: { @@ -241,7 +247,7 @@ describe("Aptos sync logic ", () => { expect(result).toBe(false); }); }); - /////////////////////////////////////////// + describe("getAptosAmounts", () => { it("should calculate the correct amounts for withdraw and deposit events", () => { const tx = { @@ -271,7 +277,7 @@ describe("Aptos sync logic ", () => { { type: "write_resource", data: { - type: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", + type: APTOS_COIN_CHANGE, data: { withdraw_events: { guid: { @@ -330,7 +336,7 @@ describe("Aptos sync logic ", () => { { type: "write_resource", data: { - type: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", + type: APTOS_COIN_CHANGE, data: { withdraw_events: { guid: { @@ -384,7 +390,7 @@ describe("Aptos sync logic ", () => { expect(result.amount_out).toEqual(new BigNumber(0)); }); }); - /////////////////////////////////////////// + describe("calculateAmount", () => { it("should calculate the correct amount when the address is the sender", () => { const address = "0x11"; diff --git a/libs/ledger-live-common/src/families/aptos/logic.ts b/libs/ledger-live-common/src/families/aptos/logic.ts index c4d3be0fb1e2..ae08f974abf1 100644 --- a/libs/ledger-live-common/src/families/aptos/logic.ts +++ b/libs/ledger-live-common/src/families/aptos/logic.ts @@ -1,7 +1,7 @@ import { EntryFunctionPayloadResponse, Event, - TransactionPayloadResponse, + InputEntryFunctionData, WriteSetChange, WriteSetChangeWriteResource, } from "@aptos-labs/ts-sdk"; @@ -93,6 +93,14 @@ const getBlankOperation = ( hasFailed: false, }); +const convertFunctionPayloadResponseToInputEntryFunctionData = ( + payload: EntryFunctionPayloadResponse, +): InputEntryFunctionData => ({ + function: payload.function, + typeArguments: payload.type_arguments, + functionArguments: payload.arguments, +}); + export const txsToOps = ( info: { address: string }, id: string, @@ -106,7 +114,9 @@ export const txsToOps = ( const op: Operation = getBlankOperation(tx, id); op.fee = new BigNumber(tx.gas_used).multipliedBy(new BigNumber(tx.gas_unit_price)); - const payload = tx.payload; + const payload = convertFunctionPayloadResponseToInputEntryFunctionData( + tx.payload as EntryFunctionPayloadResponse, + ); const function_address = getFunctionAddress(payload); @@ -142,37 +152,41 @@ export function compareAddress(addressA: string, addressB: string) { ); } -export function getFunctionAddress(payload: TransactionPayloadResponse): string | undefined { +export function getFunctionAddress(payload: InputEntryFunctionData): string | undefined { if ("function" in payload) { const parts = payload.function.split("::"); - return parts.length === 3 ? parts[0] : undefined; + return parts.length === 3 && parts[0].length ? parts[0] : undefined; } return undefined; } export function processRecipients( - payload: TransactionPayloadResponse, + payload: InputEntryFunctionData, address: string, op: Operation, function_address: string, ): void { // get recipients buy 3 groups if ( - (TRANSFER_TYPES.includes((payload as EntryFunctionPayloadResponse).function) || - DELEGATION_POOL_TYPES.includes((payload as EntryFunctionPayloadResponse).function)) && - "arguments" in payload + (TRANSFER_TYPES.includes(payload.function) || + DELEGATION_POOL_TYPES.includes(payload.function)) && + payload.functionArguments && + payload.functionArguments.length > 1 && + typeof payload.functionArguments[1] === "string" ) { // 1. Transfer like functions (includes some delegation pool functions) - op.recipients.push(payload.arguments[1]); + op.recipients.push(payload.functionArguments[1].toString()); } else if ( - BATCH_TRANSFER_TYPES.includes((payload as EntryFunctionPayloadResponse).function) && - "arguments" in payload + BATCH_TRANSFER_TYPES.includes(payload.function) && + payload.functionArguments && + payload.functionArguments.length > 1 && + Array.isArray(payload.functionArguments[1]) ) { // 2. Batch function, to validate we are in the recipients list if (!compareAddress(op.senders[0], address)) { - for (const recipient of payload.arguments[1]) { - if (compareAddress(recipient, address)) { - op.recipients.push(recipient); + for (const recipient of payload.functionArguments[1]) { + if (recipient && compareAddress(recipient.toString(), address)) { + op.recipients.push(recipient.toString()); } } }