Skip to content

Commit

Permalink
fix: logic code and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
semeano committed Dec 12, 2024
1 parent e5560d9 commit dce6c5f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 46 deletions.
70 changes: 38 additions & 32 deletions libs/ledger-live-common/src/families/aptos/logic.test.ts
Original file line number Diff line number Diff line change
@@ -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 ", () => {
Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -87,32 +93,32 @@ 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");
expect(op.recipients).toContain("0x13");
});

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");
expect(op.recipients).toContain("0x12");
});

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");
Expand All @@ -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: {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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";
Expand Down
42 changes: 28 additions & 14 deletions libs/ledger-live-common/src/families/aptos/logic.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
EntryFunctionPayloadResponse,
Event,
TransactionPayloadResponse,
InputEntryFunctionData,
WriteSetChange,
WriteSetChangeWriteResource,
} from "@aptos-labs/ts-sdk";
Expand Down Expand Up @@ -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,
Expand All @@ -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);

Expand Down Expand Up @@ -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());
}
}
}
Expand Down

0 comments on commit dce6c5f

Please sign in to comment.