diff --git a/.changeset/brave-sheep-accept.md b/.changeset/brave-sheep-accept.md new file mode 100644 index 000000000000..33369f97dbb8 --- /dev/null +++ b/.changeset/brave-sheep-accept.md @@ -0,0 +1,9 @@ +--- +"@ledgerhq/hw-app-aptos": minor +"@ledgerhq/coin-aptos": minor +"ledger-live-desktop": minor +"live-mobile": minor +"@ledgerhq/live-common": minor +--- + +support: move aptos to its own coin module diff --git a/apps/ledger-live-desktop/package.json b/apps/ledger-live-desktop/package.json index ba0a02cade97..a44be2aa5b15 100644 --- a/apps/ledger-live-desktop/package.json +++ b/apps/ledger-live-desktop/package.json @@ -54,6 +54,7 @@ "dependencies": { "@braze/web-sdk": "4.10.2", "@ledgerhq/coin-bitcoin": "workspace:^", + "@ledgerhq/coin-aptos": "workspace:^", "@ledgerhq/coin-cosmos": "workspace:^", "@ledgerhq/coin-evm": "workspace:^", "@ledgerhq/coin-filecoin": "workspace:^", diff --git a/apps/ledger-live-desktop/src/renderer/families/aptos/types.ts b/apps/ledger-live-desktop/src/renderer/families/aptos/types.ts index accb07ebf020..2955d6ad05df 100644 --- a/apps/ledger-live-desktop/src/renderer/families/aptos/types.ts +++ b/apps/ledger-live-desktop/src/renderer/families/aptos/types.ts @@ -1,10 +1,6 @@ -import { - AptosAccount, - Transaction, - TransactionStatus, -} from "@ledgerhq/live-common/families/aptos/types"; import { Operation } from "@ledgerhq/types-live"; import { FieldComponentProps, LLDCoinFamily } from "../types"; +import { AptosAccount, TransactionStatus } from "@ledgerhq/coin-aptos/lib/types/index"; export type AptosFamily = LLDCoinFamily; export type AptosFieldComponentProps = FieldComponentProps< diff --git a/libs/coin-modules/coin-aptos/.unimportedrc.json b/libs/coin-modules/coin-aptos/.unimportedrc.json new file mode 100644 index 000000000000..2f34f2149c2c --- /dev/null +++ b/libs/coin-modules/coin-aptos/.unimportedrc.json @@ -0,0 +1,16 @@ +{ + "ignoreUnresolved": ["follow-redirects", "form-data", "proxy-from-env"], + "ignoreUnused": ["@ledgerhq/devices", "invariant", "expect"], + "ignoreUnimported": [ + "src/bridge/deviceTransactionConfig.ts", + "src/bridge/transaction.ts", + "src/bridge/bridge.fixture.ts", + "src/errors.ts", + "src/hw-signMessage.ts", + "src/test/bot-specs.ts", + "src/test/bridgeDatasetTest.ts", + "src/test/cli.ts", + "src/test/index.ts", + "src/test/speculos-deviceActions.ts" + ] +} diff --git a/libs/coin-modules/coin-aptos/jest.config.js b/libs/coin-modules/coin-aptos/jest.config.js new file mode 100644 index 000000000000..f1b2df2b8018 --- /dev/null +++ b/libs/coin-modules/coin-aptos/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ +module.exports = { + collectCoverageFrom: ["src/**/*.ts"], + coverageDirectory: "coverage", + preset: "ts-jest", + testEnvironment: "node", + testPathIgnorePatterns: ["lib/", "lib-es/", ".integration.test.ts"], +}; diff --git a/libs/coin-modules/coin-aptos/package.json b/libs/coin-modules/coin-aptos/package.json new file mode 100644 index 000000000000..2130dafbcd42 --- /dev/null +++ b/libs/coin-modules/coin-aptos/package.json @@ -0,0 +1,124 @@ +{ + "name": "@ledgerhq/coin-aptos", + "version": "1.3.2", + "description": "Ledger Aptos Coin integration", + "keywords": [ + "Ledger", + "LedgerWallet", + "apt", + "Aptos", + "Hardware Wallet" + ], + "repository": { + "type": "git", + "url": "https://github.com/LedgerHQ/ledger-live.git" + }, + "bugs": { + "url": "https://github.com/LedgerHQ/ledger-live/issues" + }, + "homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/coin-modules/coin-aptos", + "publishConfig": { + "access": "public" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib/*" + ], + "lib-es/*": [ + "lib-es/*" + ], + "specs": [ + "lib/test/bot-specs" + ], + "*": [ + "lib/*", + "lib/api/*", + "lib/bridge/*", + "lib/common-logic/*", + "lib/signer/*", + "lib/test/*", + "lib/types/*" + ] + } + }, + "exports": { + "./lib/*": "./lib/*.js", + "./lib-es/*": "./lib-es/*.js", + "./api": { + "require": "./lib/api/index.js", + "default": "./lib-es/api/index.js" + }, + "./deviceTransactionConfig": { + "require": "./lib/bridge/deviceTransactionConfig.js", + "default": "./lib-es/bridge/deviceTransactionConfig.js" + }, + "./signer": { + "require": "./lib/signer/index.js", + "default": "./lib-es/signer/index.js" + }, + "./specs": { + "require": "./lib/test/bot-specs.js", + "default": "./lib-es/test/bot-specs.js" + }, + "./transaction": { + "require": "./lib/bridge/transaction.js", + "default": "./lib-es/bridge/transaction.js" + }, + "./types": { + "require": "./lib/types/index.js", + "default": "./lib-es/types/index.js" + }, + "./*": { + "require": "./lib/*.js", + "default": "./lib-es/*.js" + }, + ".": { + "require": "./lib/index.js", + "default": "./lib-es/index.js" + }, + "./package.json": "./package.json" + }, + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/coin-framework": "workspace:^", + "@ledgerhq/cryptoassets": "workspace:^", + "@ledgerhq/devices": "workspace:*", + "@ledgerhq/errors": "workspace:^", + "@ledgerhq/live-env": "workspace:^", + "@ledgerhq/live-network": "workspace:^", + "@ledgerhq/logs": "workspace:^", + "@ledgerhq/types-live": "workspace:^", + "@aptos-labs/ts-sdk": "^1.33.1", + "@apollo/client": "^3.12.6", + "@noble/hashes": "1.7.0", + "bignumber.js": "^9.1.2", + "graphql": "^16.10.0", + "invariant": "^2.2.4", + "lodash": "^4.17.21", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@faker-js/faker": "^9.4.0", + "@types/invariant": "^2.2.37", + "@types/jest": "^29.5.14", + "@types/lodash": "^4.17.14", + "@types/semver": "^7.5.8", + "jest": "^29.7.0", + "ts-jest": "^29.2.5", + "axios": "^1.7.9", + "react": "^18.3.1" + }, + "scripts": { + "clean": "rimraf lib lib-es", + "build": "tsc && tsc -m ES6 --outDir lib-es", + "coverage": "jest --coverage --testPathIgnorePatterns='/bridge.integration.test.ts|node_modules|lib-es|lib/' --coveragePathIgnorePatterns='src/test|src/types|src/index.ts|src/bridge/bridge.fixture.ts' --passWithNoTests && mv coverage/coverage-final.json coverage/coverage-aptos.json", + "prewatch": "pnpm build", + "watch": "tsc --watch", + "doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts", + "lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx --cache", + "lint:fix": "pnpm lint --fix", + "test": "jest", + "unimported": "unimported" + } +} diff --git a/libs/ledger-live-common/src/families/aptos/api/index.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/api/index.test.ts similarity index 92% rename from libs/ledger-live-common/src/families/aptos/api/index.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/api/index.test.ts index 94a96e35d67e..d10c9bb10d03 100644 --- a/libs/ledger-live-common/src/families/aptos/api/index.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/api/index.test.ts @@ -9,16 +9,15 @@ import { Serializable, post, } from "@aptos-labs/ts-sdk"; -import network from "@ledgerhq/live-network/network"; +import network from "@ledgerhq/live-network"; import BigNumber from "bignumber.js"; -import { AptosAPI } from "."; -import { Account } from "../../../e2e/enum/Account"; +import { AptosAPI } from "../../api"; jest.mock("@aptos-labs/ts-sdk"); jest.mock("@apollo/client"); -let mockedAptos; -let mockedApolloClient; -let mockedPost; +let mockedAptos: jest.Mocked; +let mockedApolloClient: jest.Mocked; +let mockedPost = jest.fn(); jest.mock("@ledgerhq/live-network/network"); const mockedNetwork = jest.mocked(network); @@ -69,19 +68,17 @@ describe("Aptos API", () => { describe("getAccount", () => { it("calls getAccountInfo", async () => { const mockGetAccountInfo = jest.fn(); - mockedAptos.mockImplementation(() => { - return { - getAccountInfo: mockGetAccountInfo, - }; - }); + mockedAptos.mockImplementation(() => ({ + getAccountInfo: mockGetAccountInfo, + })); const mockGetAccountSpy = jest.spyOn({ getAccount: mockGetAccountInfo }, "getAccount"); const api = new AptosAPI("aptos"); - await api.getAccount(Account.APTOS_1.address); + await api.getAccount("address"); expect(mockGetAccountSpy).toHaveBeenCalledWith({ - accountAddress: Account.APTOS_1.address, + accountAddress: "address", }); }); }); @@ -135,7 +132,7 @@ describe("Aptos API", () => { })); const api = new AptosAPI("aptos"); - const accountInfo = await api.getAccountInfo(Account.APTOS_1.address, "1"); + const accountInfo = await api.getAccountInfo("APTOS_1_ADDRESS", "1"); expect(accountInfo.balance).toEqual(new BigNumber(123)); expect(accountInfo.transactions).toEqual([ @@ -201,7 +198,7 @@ describe("Aptos API", () => { })); const api = new AptosAPI("aptos"); - const accountInfo = await api.getAccountInfo(Account.APTOS_1.address, "1"); + const accountInfo = await api.getAccountInfo("APTOS_1_ADDRESS", "1"); expect(accountInfo.balance).toEqual(new BigNumber(0)); expect(accountInfo.transactions).toEqual([ @@ -319,7 +316,7 @@ describe("Aptos API", () => { })); const api = new AptosAPI("aptos"); - const accountInfo = await api.getAccountInfo(Account.APTOS_1.address, "1"); + const accountInfo = await api.getAccountInfo("APTOS_1_ADDRESS", "1"); expect(accountInfo.balance).toEqual(new BigNumber(123)); expect(accountInfo.transactions).toEqual([null]); @@ -367,7 +364,7 @@ describe("Aptos API", () => { const mockSimpleSpy = jest.spyOn({ simple: mockSimple }, "simple"); const api = new AptosAPI("aptos"); - await api.generateTransaction(Account.APTOS_1.address, payload, options); + await api.generateTransaction("APTOS_1_ADDRESS", payload, options); expect(mockSimpleSpy).toHaveBeenCalledWith({ data: payload, @@ -375,7 +372,7 @@ describe("Aptos API", () => { maxGasAmount: Number(options.maxGasAmount), gasUnitPrice: Number(options.gasUnitPrice), }, - sender: Account.APTOS_1.address, + sender: "APTOS_1_ADDRESS", }); }); @@ -403,7 +400,7 @@ describe("Aptos API", () => { const mockSimpleSpy = jest.spyOn({ simple: mockSimple }, "simple"); const api = new AptosAPI("aptos"); - await api.generateTransaction(Account.APTOS_1.address, payload, options); + await api.generateTransaction("APTOS_1_ADDRESS", payload, options); expect(mockSimpleSpy).toHaveBeenCalledWith({ data: payload, @@ -412,7 +409,7 @@ describe("Aptos API", () => { gasUnitPrice: Number(options.gasUnitPrice), expireTimestamp: 120, }, - sender: Account.APTOS_1.address, + sender: "APTOS_1_ADDRESS", }); }); @@ -433,7 +430,7 @@ describe("Aptos API", () => { const api = new AptosAPI("aptos"); expect( - async () => await api.generateTransaction(Account.APTOS_1.address, payload, options), + async () => await api.generateTransaction("APTOS_1_ADDRESS", payload, options), ).rejects.toThrow(); }); }); @@ -454,9 +451,9 @@ describe("Aptos API", () => { const mockSimpleSpy = jest.spyOn({ simple: mockSimple }, "simple"); const api = new AptosAPI("aptos"); - const address = new Ed25519PublicKey(Account.APTOS_1.address); + const address = new Ed25519PublicKey("APTOS_1_ADDRESS"); const tx = new RawTransaction( - new AccountAddress(Uint8Array.from(Buffer.from(Account.APTOS_2.address))), + new AccountAddress(Uint8Array.from(Buffer.from("APTOS_2_ADDRESS"))), BigInt(1), "" as unknown as Serializable, BigInt(100), diff --git a/libs/ledger-live-common/src/families/aptos/broadcast.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/broadcast.test.ts similarity index 91% rename from libs/ledger-live-common/src/families/aptos/broadcast.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/broadcast.test.ts index 7adda4fecfb5..28a5dbf56832 100644 --- a/libs/ledger-live-common/src/families/aptos/broadcast.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/broadcast.test.ts @@ -1,12 +1,11 @@ -import broadcast from "./broadcast"; -import { AptosAPI } from "./api"; -import { patchOperationWithHash } from "./../../operation"; +import broadcast from "../../bridge/broadcast"; +import { AptosAPI } from "../../api"; +import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation"; import type { Account, Operation, SignedOperation } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -jest.mock("./api"); -jest.mock("./../../operation"); -jest.mock("@ledgerhq/logs"); +jest.mock("../../api"); +jest.mock("@ledgerhq/coin-framework/operation"); describe("broadcast", () => { const mockAccount: Account = { diff --git a/libs/ledger-live-common/src/families/aptos/buildTransaction.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/buildTransaction.test.ts similarity index 72% rename from libs/ledger-live-common/src/families/aptos/buildTransaction.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/buildTransaction.test.ts index c65ab1af1b41..e64bb91118c7 100644 --- a/libs/ledger-live-common/src/families/aptos/buildTransaction.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/buildTransaction.test.ts @@ -1,14 +1,13 @@ -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import buildTransaction from "./buildTransaction"; -import { AptosAPI } from "./api"; -import { normalizeTransactionOptions } from "./logic"; +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import buildTransaction from "../../bridge/buildTransaction"; +import { AptosAPI } from "../../api"; +import { normalizeTransactionOptions } from "../../bridge/logic"; import { InputEntryFunctionData } from "@aptos-labs/ts-sdk"; -import { TransactionOptions } from "./types"; +import { TransactionOptions } from "../../types"; const generateTransaction = jest.fn(() => "tx"); -jest.mock("./logic", () => ({ +jest.mock("../../bridge/logic", () => ({ normalizeTransactionOptions: jest.fn(() => ({ maxGasAmount: "100", gasUnitPrice: "200", @@ -17,7 +16,7 @@ jest.mock("./logic", () => ({ DEFAULT_GAS_PRICE: 200, })); -jest.mock("./api", () => { +jest.mock("../../api", () => { return { AptosAPI: function () { return { @@ -30,7 +29,7 @@ jest.mock("./api", () => { describe("buildTransaction Test", () => { it("should return tx", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const aptosClient = new AptosAPI(account.currency.id); const result = await buildTransaction(account, transaction, aptosClient); @@ -47,11 +46,11 @@ describe("buildTransaction Test", () => { generateTransaction.mock.calls[0]; expect(mockedNormalizeTransactionOptions.mock.calls[0][0]).toEqual({ - maxGasAmount: "100", - gasUnitPrice: "200", + maxGasAmount: "0", + gasUnitPrice: "0", }); - expect(generateTransactionArgs[0]).toBe("0x01"); + expect(generateTransactionArgs[0]).toBe("address"); expect(generateTransactionArgs[1]).toEqual({ function: "0x1::aptos_account::transfer_coins", typeArguments: ["0x1::aptos_coin::AptosCoin"], diff --git a/libs/ledger-live-common/src/families/aptos/createTransaction.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/createTransaction.test.ts similarity index 83% rename from libs/ledger-live-common/src/families/aptos/createTransaction.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/createTransaction.test.ts index c3ccf96fe6f0..d9b89d2a5438 100644 --- a/libs/ledger-live-common/src/families/aptos/createTransaction.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/createTransaction.test.ts @@ -1,7 +1,7 @@ import BigNumber from "bignumber.js"; -import createTransaction from "./createTransaction"; +import createTransaction from "../../bridge/createTransaction"; -jest.mock("./logic", () => ({ +jest.mock("../../bridge/logic", () => ({ DEFAULT_GAS: 100, DEFAULT_GAS_PRICE: 200, })); diff --git a/libs/coin-modules/coin-aptos/src/__tests__/bridge/deviceTransactionConfig.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/deviceTransactionConfig.test.ts new file mode 100644 index 000000000000..39b308268b2a --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/deviceTransactionConfig.test.ts @@ -0,0 +1,19 @@ +import getDeviceTransactionConfig, { methodToString } from "../../bridge/deviceTransactionConfig"; + +describe("deviceTransactionConfig", () => { + test("methodToString", () => { + expect(methodToString(0)).toBe("Coin transfer"); + expect(methodToString(1)).toBe("Unknown"); + }); + + test("getDeviceTransactionConfig", () => { + const fields = getDeviceTransactionConfig(); + expect(fields).toMatchObject([ + { + type: "text", + label: "Type", + value: "Coin transfer", + }, + ]); + }); +}); diff --git a/libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/estimateMaxSpendable.test.ts similarity index 87% rename from libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/estimateMaxSpendable.test.ts index 8b1b0ce210b2..b9943bac73ba 100644 --- a/libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/estimateMaxSpendable.test.ts @@ -1,9 +1,8 @@ -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import estimateMaxSpendable from "./estimateMaxSpendable"; +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import estimateMaxSpendable from "../../bridge/estimateMaxSpendable"; import BigNumber from "bignumber.js"; -jest.mock("./getFeesForTransaction", () => ({ +jest.mock("../../bridge/getFeesForTransaction", () => ({ getEstimatedGas: jest.fn(() => ({ fees: new BigNumber(0), estimate: { @@ -54,7 +53,7 @@ describe("estimateMaxSpendable Test", () => { describe("transaction spendable balance is higher than the total gas", () => { it("should return transaction spendable amount minus total gas", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const spendableBalance = new BigNumber(1); @@ -75,7 +74,7 @@ describe("estimateMaxSpendable Test", () => { describe("transaction spendable balance is higher than the total gas", () => { it("should return transaction spendable amount minus total gas", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const spendableBalance = new BigNumber(100000); diff --git a/libs/ledger-live-common/src/families/aptos/getFeesForTransaction.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/getFeesForTransaction.test.ts similarity index 90% rename from libs/ledger-live-common/src/families/aptos/getFeesForTransaction.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/getFeesForTransaction.test.ts index 461e8301350c..84af0edd6d8d 100644 --- a/libs/ledger-live-common/src/families/aptos/getFeesForTransaction.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/getFeesForTransaction.test.ts @@ -1,12 +1,11 @@ import BigNumber from "bignumber.js"; -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import * as getFeesForTransaction from "./getFeesForTransaction"; -import { AptosAPI } from "./api"; +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import * as getFeesForTransaction from "../../bridge/getFeesForTransaction"; +import { AptosAPI } from "../../api"; let simulateTransaction = jest.fn(); -jest.mock("./api", () => { +jest.mock("../../api", () => { return { AptosAPI: function () { return { @@ -25,7 +24,7 @@ jest.mock("@aptos-labs/ts-sdk", () => { }; }); -jest.mock("./logic", () => { +jest.mock("../../bridge/logic", () => { return { DEFAULT_GAS: 201, DEFAULT_GAS_PRICE: 101, @@ -49,7 +48,7 @@ describe("getFeesForTransaction Test", () => { ]); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const aptosClient = new AptosAPI(account.currency.id); transaction.amount = new BigNumber(1); @@ -84,7 +83,7 @@ describe("getFeesForTransaction Test", () => { ]); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const aptosClient = new AptosAPI(account.currency.id); transaction.amount = new BigNumber(1); @@ -112,7 +111,7 @@ describe("getFeesForTransaction Test", () => { ]); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const aptosClient = new AptosAPI(account.currency.id); transaction.amount = new BigNumber(1); @@ -147,7 +146,7 @@ describe("getFeesForTransaction Test", () => { const mocked = jest.spyOn(getFeesForTransaction, "getFee"); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); const aptosClient = new AptosAPI(account.currency.id); transaction.amount = new BigNumber(10); diff --git a/libs/ledger-live-common/src/families/aptos/getTransactionStatus.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/getTransactionStatus.test.ts similarity index 85% rename from libs/ledger-live-common/src/families/aptos/getTransactionStatus.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/getTransactionStatus.test.ts index c9fca25ea84a..eebc71d12c99 100644 --- a/libs/ledger-live-common/src/families/aptos/getTransactionStatus.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/getTransactionStatus.test.ts @@ -1,7 +1,6 @@ import BigNumber from "bignumber.js"; -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import getTransactionStatus from "./getTransactionStatus"; +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import getTransactionStatus from "../../bridge/getTransactionStatus"; import { AmountRequired, FeeNotLoaded, @@ -14,7 +13,7 @@ import { describe("getTransactionStatus Test", () => { it("should return errors for AmountRequired", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.fees = new BigNumber(2); transaction.recipient = "0x" + "0".repeat(64); @@ -36,8 +35,9 @@ describe("getTransactionStatus Test", () => { it("should return errors for FeeNotLoaded", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + account.balance = new BigNumber(10); + const transaction = createFixtureTransaction(); transaction.fees = null; transaction.amount = new BigNumber(2); transaction.recipient = "0x" + "0".repeat(64); @@ -59,9 +59,9 @@ describe("getTransactionStatus Test", () => { it("should return errors for NotEnoughBalance", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); - account.balance = new BigNumber(1); + + const transaction = createFixtureTransaction(); transaction.recipient = "0x" + "0".repeat(64); transaction.amount = new BigNumber(2); transaction.fees = new BigNumber(2); @@ -83,8 +83,9 @@ describe("getTransactionStatus Test", () => { it("should return errors for RecipientRequired", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + account.balance = new BigNumber(10); + const transaction = createFixtureTransaction(); transaction.amount = new BigNumber(2); transaction.fees = new BigNumber(2); @@ -105,7 +106,7 @@ describe("getTransactionStatus Test", () => { it("should return errors for InvalidAddress", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.amount = new BigNumber(2); transaction.fees = new BigNumber(2); @@ -116,6 +117,7 @@ describe("getTransactionStatus Test", () => { const expected = { errors: { recipient: new InvalidAddress(), + amount: new NotEnoughBalance(), }, warnings: {}, estimatedFees: new BigNumber(2), @@ -128,7 +130,7 @@ describe("getTransactionStatus Test", () => { it("should return errors for InvalidAddressBecauseDestinationIsAlsoSource", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.amount = new BigNumber(2); transaction.fees = new BigNumber(2); @@ -140,6 +142,7 @@ describe("getTransactionStatus Test", () => { const expected = { errors: { recipient: new InvalidAddressBecauseDestinationIsAlsoSource(), + amount: new NotEnoughBalance(), }, warnings: {}, estimatedFees: new BigNumber(2), diff --git a/libs/ledger-live-common/src/families/aptos/bridge/js.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/index.test.ts similarity index 97% rename from libs/ledger-live-common/src/families/aptos/bridge/js.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/index.test.ts index 4a80bcea88a4..43dabf15c326 100644 --- a/libs/ledger-live-common/src/families/aptos/bridge/js.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/index.test.ts @@ -1,7 +1,10 @@ import BigNumber from "bignumber.js"; -import bridge from "./js"; +import { createBridges } from "../../bridge"; import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies"; +const signer = jest.fn(); +const bridge = createBridges(signer); + describe("Aptos bridge interface ", () => { describe("currencyBridge", () => { it("should have a preload method that returns a promise", async () => { diff --git a/libs/ledger-live-common/src/families/aptos/logic.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts similarity index 91% rename from libs/ledger-live-common/src/families/aptos/logic.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts index 9339af2405af..5ce766bfe052 100644 --- a/libs/ledger-live-common/src/families/aptos/logic.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts @@ -6,7 +6,7 @@ import { } from "@aptos-labs/ts-sdk"; import type { Operation, OperationType } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { APTOS_ASSET_ID, APTOS_COIN_CHANGE, DIRECTION } from "./constants"; +import { APTOS_ASSET_ID, APTOS_COIN_CHANGE, DIRECTION } from "../../constants"; import { calculateAmount, compareAddress, @@ -19,8 +19,8 @@ import { normalizeTransactionOptions, getBlankOperation, txsToOps, -} from "./logic"; -import type { AptosTransaction, TransactionOptions } from "./types"; +} from "../../bridge/logic"; +import type { AptosTransaction, TransactionOptions } from "../../types"; jest.mock("@ledgerhq/cryptoassets", () => ({ getCryptoCurrencyById: jest.fn(), @@ -111,6 +111,7 @@ describe("Aptos logic ", () => { block: { hash: "0xabc", height: 1 }, timestamp: "1000000", sequence_number: "1", + version: "1", } as unknown as AptosTransaction; const id = "test-id"; @@ -128,6 +129,34 @@ describe("Aptos logic ", () => { recipients: [], accountId: id, date: new Date(1000), + extra: { version: "1" }, + transactionSequenceNumber: 1, + hasFailed: false, + }); + }); + + it("should return a blank operation even when some transaction fields are missing", () => { + const tx: AptosTransaction = { + hash: "0x123", + timestamp: "1000000", + sequence_number: "1", + } as unknown as AptosTransaction; + + const id = "test-id"; + const result = getBlankOperation(tx, id); + + expect(result).toEqual({ + id: "", + hash: "0x123", + type: "", + value: new BigNumber(0), + fee: new BigNumber(0), + blockHash: undefined, + blockHeight: undefined, + senders: [], + recipients: [], + accountId: id, + date: new Date(1000), extra: { version: undefined }, transactionSequenceNumber: 1, hasFailed: false, @@ -344,6 +373,52 @@ describe("Aptos sync logic ", () => { expect(result).toBe(false); }); + it("should return false if no data in WriteSet Change", () => { + const change = { + type: "write_resource", + } as unknown as WriteSetChange; + + const event = { + guid: { + account_address: "0x11", + creation_number: "2", + }, + type: "0x1::coin::WithdrawEvent", + } as Event; + + const result = isChangeOfAptos(change, event, "withdraw_events"); + expect(result).toBe(false); + }); + + it("should return false if no type in change data", () => { + const change = { + type: "write_resource", + data: { + data: { + withdraw_events: { + guid: { + id: { + addr: "0x11", + creation_num: "2", + }, + }, + }, + }, + }, + } as unknown as WriteSetChange; + + const event = { + guid: { + account_address: "0x11", + creation_number: "2", + }, + type: "0x1::coin::WithdrawEvent", + } as Event; + + const result = isChangeOfAptos(change, event, "withdraw_events"); + expect(result).toBe(false); + }); + it("should return false for a change with a different WriteSet Change type", () => { const change = { type: "write_resource", diff --git a/libs/ledger-live-common/src/families/aptos/prepareTransaction.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/prepareTransaction.test.ts similarity index 91% rename from libs/ledger-live-common/src/families/aptos/prepareTransaction.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/prepareTransaction.test.ts index bd0e0500c656..cd6433792c90 100644 --- a/libs/ledger-live-common/src/families/aptos/prepareTransaction.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/prepareTransaction.test.ts @@ -1,14 +1,14 @@ -import prepareTransaction from "./prepareTransaction"; -import { AptosAPI } from "./api"; -import { getEstimatedGas } from "./getFeesForTransaction"; -import { getMaxSendBalance } from "./logic"; +import prepareTransaction from "../../bridge/prepareTransaction"; +import { AptosAPI } from "../../api"; +import { getEstimatedGas } from "../../bridge/getFeesForTransaction"; +import { getMaxSendBalance } from "../../bridge/logic"; import BigNumber from "bignumber.js"; import type { Account } from "@ledgerhq/types-live"; -import type { Transaction } from "./types"; +import type { Transaction } from "../../types"; -jest.mock("./api"); -jest.mock("./getFeesForTransaction"); -jest.mock("./logic"); +jest.mock("../../api"); +jest.mock("../../bridge/getFeesForTransaction"); +jest.mock("../../bridge/logic"); describe("Aptos prepareTransaction", () => { describe("prepareTransaction", () => { diff --git a/libs/ledger-live-common/src/families/aptos/signOperation.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/signOperation.test.ts similarity index 66% rename from libs/ledger-live-common/src/families/aptos/signOperation.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/signOperation.test.ts index e7480585bedc..2d2b40282e0a 100644 --- a/libs/ledger-live-common/src/families/aptos/signOperation.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/signOperation.test.ts @@ -1,10 +1,12 @@ -import { Observable } from "rxjs"; -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import signOperation from "./signOperation"; import BigNumber from "bignumber.js"; +import { Observable } from "rxjs"; +import { SignerContext } from "@ledgerhq/coin-framework/lib/signer"; +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import buildSignOperation, { getAddress } from "../../bridge/signOperation"; +import { AptosSigner } from "../../types"; +import { signTransaction } from "../../network"; -jest.mock("./api", () => { +jest.mock("../../api", () => { return { AptosAPI: function () { return { @@ -14,56 +16,42 @@ jest.mock("./api", () => { }; }); -let signTransaction; - -jest.mock("./LedgerAccount", () => { +jest.mock("../../bridge/buildTransaction", () => { return function () { return { - init: jest.fn(), - signTransaction, + sequence_number: "789", }; }; }); -jest.mock("../../hw/deviceAccess", () => { - return { - withDevice: jest.fn(() => observable => { - return observable(new Observable()); - }), - }; -}); - -jest.mock("../../operation", () => { - return { - encodeOperationId: jest.fn(() => "js:2:aptos:0x000"), - }; -}); +jest.mock("../../network"); +let mockedSignTransaction: jest.Mocked; -jest.mock("./buildTransaction", () => { - return function () { - return { - sequence_number: "789", - }; - }; +describe("getAddress", () => { + it("should return address and derivationPath", () => { + const account = createFixtureAccount(); + expect(getAddress(account)).toEqual({ address: "address", derivationPath: "derivation_path" }); + }); }); -describe("signOperation Test", () => { +describe("buildSignOperation", () => { beforeEach(() => { - signTransaction = jest.fn(() => "tx"); + mockedSignTransaction = jest.mocked(signTransaction); }); + afterEach(() => jest.clearAllMocks()); it("should thrown an error", async () => { - signTransaction = () => { + mockedSignTransaction.mockImplementation(() => { throw new Error("observable-catch-error"); - }; + }); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); account.id = "js:2:aptos:0x000:"; transaction.mode = "send"; - const observable = await signOperation({ + const observable = await buildSignOperation({} as unknown as SignerContext)({ account, deviceId: "1", transaction, @@ -77,16 +65,18 @@ describe("signOperation Test", () => { }); it("should return 3 operations", async () => { + mockedSignTransaction.mockReturnValue("signedTx"); + const date = new Date("2020-01-01"); jest.useFakeTimers().setSystemTime(date); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); account.id = "js:2:aptos:0x000:"; transaction.mode = "send"; - const observable = await signOperation({ + const observable = await buildSignOperation({} as unknown as SignerContext)({ account, deviceId: "1", transaction, @@ -101,7 +91,7 @@ describe("signOperation Test", () => { type: "signed", signedOperation: { operation: { - id: "js:2:aptos:0x000", + id: "js:2:aptos:0x000:--OUT", hash: "", type: "OUT", value: new BigNumber(0), @@ -115,7 +105,7 @@ describe("signOperation Test", () => { date, transactionSequenceNumber: 789, }, - signature: "7478", + signature: "7369676e65645478", }, }, ]; @@ -129,11 +119,13 @@ describe("signOperation Test", () => { }); it("should return 3 operations with all amount", async () => { + mockedSignTransaction.mockReturnValue("signedTx"); + const date = new Date("2020-01-01"); jest.useFakeTimers().setSystemTime(date); const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); account.balance = new BigNumber(40); transaction.fees = new BigNumber(30); @@ -142,7 +134,7 @@ describe("signOperation Test", () => { account.id = "js:2:aptos:0x000:"; transaction.mode = "send"; - const observable = await signOperation({ + const observable = await buildSignOperation({} as unknown as SignerContext)({ account, deviceId: "1", transaction, @@ -157,7 +149,7 @@ describe("signOperation Test", () => { type: "signed", signedOperation: { operation: { - id: "js:2:aptos:0x000", + id: "js:2:aptos:0x000:--OUT", hash: "", type: "OUT", value: new BigNumber(10), @@ -171,7 +163,7 @@ describe("signOperation Test", () => { date, transactionSequenceNumber: 789, }, - signature: "7478", + signature: "7369676e65645478", }, }, ]; diff --git a/libs/ledger-live-common/src/families/aptos/synchronisation.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts similarity index 63% rename from libs/ledger-live-common/src/families/aptos/synchronisation.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts index 84e58dd2a99d..8abda3ab5e50 100644 --- a/libs/ledger-live-common/src/families/aptos/synchronisation.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts @@ -1,45 +1,38 @@ import { AccountShapeInfo } from "@ledgerhq/coin-framework/bridge/jsHelpers"; import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/index"; import { Account, SyncConfig } from "@ledgerhq/types-live"; -import { firstValueFrom } from "rxjs"; -import { decodeAccountId } from "../../account"; -import { makeScanAccounts, makeSync, mergeOps } from "../../bridge/jsHelpers"; -import { AptosAPI } from "./api"; -import { txsToOps } from "./logic"; -import { getAccountShape } from "./synchronisation"; +import { encodeAccountId } from "@ledgerhq/coin-framework/account"; +import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers"; +import { AptosAPI } from "../../api"; +import { getAccountShape } from "../../bridge/synchronisation"; -jest.mock("rxjs"); -let mockedFistValueFrom; - -jest.mock("../../account"); -let mockedDecodeAccountId; +jest.mock("@ledgerhq/coin-framework/account", () => { + const originalModule = jest.requireActual("@ledgerhq/coin-framework/account"); + const partialMockedModule = Object.keys(originalModule).reduce( + (pre: { [key: string]: jest.Mock }, methodName) => { + pre[methodName] = jest.fn(); + return pre; + }, + {} as { [key: string]: jest.Mock }, + ); + return { + ...partialMockedModule, + // mock all except these + decodeAccountId: originalModule.decodeAccountId, + }; +}); -jest.mock("./api"); -let mockedAptosAPI; +const mockedEncodeAccountId = jest.mocked(encodeAccountId); -jest.mock("./logic"); -jest.mocked(txsToOps); +jest.mock("../../api"); +let mockedAptosAPI: jest.Mocked; -jest.mock("../../bridge/jsHelpers"); -jest.mocked(makeScanAccounts); -jest.mocked(makeSync); +jest.mock("@ledgerhq/coin-framework/bridge/jsHelpers"); +jest.mock("invariant", () => jest.fn()); describe("getAccountShape", () => { beforeEach(() => { mockedAptosAPI = jest.mocked(AptosAPI); - - mockedDecodeAccountId = jest.mocked(decodeAccountId).mockReturnValue({ - currencyId: "aptos", - derivationMode: "", - type: "js", - version: "1", - xpubOrAddress: "address", - }); - - mockedFistValueFrom = jest - .mocked(firstValueFrom) - .mockImplementation(async () => ({ publicKey: "publicKey" })); - jest.mocked(mergeOps).mockReturnValue([]); }); @@ -47,7 +40,59 @@ describe("getAccountShape", () => { jest.resetAllMocks(); }); - it("get xpub from device id", async () => { + it("account with xpub", async () => { + const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ + balance: BigInt(0), + transactions: [], + blockHeight: 0, + })); + mockedAptosAPI.mockImplementation(() => ({ + getAccountInfo: mockGetAccountInfo, + })); + const mockGetAccountSpy = jest.spyOn({ getAccount: mockGetAccountInfo }, "getAccount"); + + const account = await getAccountShape( + { + id: "1", + address: "address", + currency: getCryptoCurrencyById("aptos"), + derivationMode: "", + index: 0, + xpub: "address", + derivationPath: "", + deviceId: "1", + initialAccount: { + id: "1:1:1:1:1", + xpub: "address", + seedIdentifier: "1", + derivationMode: "", + index: 0, + freshAddress: "address", + freshAddressPath: "", + used: true, + balance: BigInt(10), + spendableBalance: BigInt(10), + creationDate: new Date(), + blockHeight: 0, + currency: getCryptoCurrencyById("aptos"), + operationsCount: 0, + operations: [], + pendingOperations: [], + lastSyncDate: new Date(), + balanceHistoryCache: {}, + swapHistory: [], + }, + } as unknown as AccountShapeInfo, + {} as SyncConfig, + ); + + expect(account.xpub).toEqual("address"); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); + expect(mockedAptosAPI).toHaveBeenCalledTimes(1); + expect(mockGetAccountSpy).toHaveBeenCalledWith("address", undefined); + }); + + it("account without xpub", async () => { const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ balance: BigInt(0), transactions: [], @@ -70,7 +115,6 @@ describe("getAccountShape", () => { deviceId: "1", initialAccount: { id: "1:1:1:1:1", - // xpub: "address", seedIdentifier: "1", derivationMode: "", index: 0, @@ -93,14 +137,13 @@ describe("getAccountShape", () => { {} as SyncConfig, ); - expect(account.xpub).toEqual("7075626c69634b6579"); - expect(mockedFistValueFrom).toHaveBeenCalledTimes(1); - expect(mockedDecodeAccountId).toHaveBeenCalledTimes(0); + expect(account.xpub).toEqual("1"); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); expect(mockedAptosAPI).toHaveBeenCalledTimes(1); expect(mockGetAccountSpy).toHaveBeenCalledWith("address", undefined); }); - it("get xpub from device id when there is no initial account", async () => { + it("without initialAccount", async () => { const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ balance: BigInt(0), transactions: [], @@ -125,14 +168,13 @@ describe("getAccountShape", () => { {} as SyncConfig, ); - expect(account.xpub).toEqual("7075626c69634b6579"); - expect(mockedFistValueFrom).toHaveBeenCalledTimes(1); - expect(mockedDecodeAccountId).toHaveBeenCalledTimes(0); + expect(account.xpub).toEqual(""); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); expect(mockedAptosAPI).toHaveBeenCalledTimes(1); expect(mockGetAccountSpy).toHaveBeenCalledWith("address", undefined); }); - it("get xpub from initial account id", async () => { + it("initialAccount with operations", async () => { const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ balance: BigInt(0), transactions: [], @@ -152,10 +194,9 @@ describe("getAccountShape", () => { index: 0, xpub: "address", derivationPath: "", - // deviceId: "1", + deviceId: "1", initialAccount: { id: "1:1:1:1:1", - // xpub: "address", seedIdentifier: "1", derivationMode: "", index: 0, @@ -167,8 +208,22 @@ describe("getAccountShape", () => { creationDate: new Date(), blockHeight: 0, currency: getCryptoCurrencyById("aptos"), - operationsCount: 0, - operations: [], + t: 1, + operations: [ + { + id: "1", + hash: "hash", + type: "OUT", + value: BigInt(10), + fee: BigInt(0), + blockHeight: 0, + blockHash: "blockHash", + accountId: "1", + senders: ["sender"], + recipients: ["recipient"], + date: new Date(), + }, + ], pendingOperations: [], lastSyncDate: new Date(), balanceHistoryCache: {}, @@ -178,88 +233,13 @@ describe("getAccountShape", () => { {} as SyncConfig, ); - expect(account.xpub).toEqual("address"); - expect(mockedFistValueFrom).toHaveBeenCalledTimes(0); - expect(mockedDecodeAccountId).toHaveBeenCalledTimes(1); + expect(account.xpub).toEqual("1"); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); expect(mockedAptosAPI).toHaveBeenCalledTimes(1); expect(mockGetAccountSpy).toHaveBeenCalledWith("address", undefined); }); - it("unable to get xpub error is thrown", async () => { - mockedDecodeAccountId = jest.mocked(decodeAccountId).mockReturnValue({ - currencyId: "aptos", - derivationMode: "", - type: "js", - version: "1", - xpubOrAddress: "", - }); - - expect( - async () => - await getAccountShape( - { - id: "1", - address: "address", - currency: getCryptoCurrencyById("aptos"), - derivationMode: "", - index: 0, - xpub: "address", - derivationPath: "", - // deviceId: "1", - initialAccount: { - id: "1:1:1:1:1", - // xpub: "address", - seedIdentifier: "1", - derivationMode: "", - index: 0, - freshAddress: "address", - freshAddressPath: "", - used: true, - balance: BigInt(10), - spendableBalance: BigInt(10), - creationDate: new Date(), - blockHeight: 0, - currency: getCryptoCurrencyById("aptos"), - operationsCount: 0, - operations: [], - pendingOperations: [], - lastSyncDate: new Date(), - balanceHistoryCache: {}, - swapHistory: [], - }, - } as unknown as AccountShapeInfo, - {} as SyncConfig, - ), - ).rejects.toThrow("Unable to retrieve public key"); - }); - - it("unable to get xpub error is thrown when there is no initial account", async () => { - mockedDecodeAccountId = jest.mocked(decodeAccountId).mockReturnValue({ - currencyId: "aptos", - derivationMode: "", - type: "js", - version: "1", - xpubOrAddress: "", - }); - - expect( - async () => - await getAccountShape( - { - id: "1", - address: "address", - currency: getCryptoCurrencyById("aptos"), - derivationMode: "", - index: 0, - xpub: "address", - derivationPath: "", - } as unknown as AccountShapeInfo, - {} as SyncConfig, - ), - ).rejects.toThrow("Unable to retrieve public key"); - }); - - it("get xpub from device id and account has operations history", async () => { + it("initialAccount with operations with extra", async () => { const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ balance: BigInt(0), transactions: [], @@ -282,7 +262,6 @@ describe("getAccountShape", () => { deviceId: "1", initialAccount: { id: "1:1:1:1:1", - // xpub: "address", seedIdentifier: "1", derivationMode: "", index: 0, @@ -294,7 +273,7 @@ describe("getAccountShape", () => { creationDate: new Date(), blockHeight: 0, currency: getCryptoCurrencyById("aptos"), - operationsCount: 1, + t: 1, operations: [ { id: "1", @@ -308,7 +287,7 @@ describe("getAccountShape", () => { senders: ["sender"], recipients: ["recipient"], date: new Date(), - // extra: {}, + extra: { version: 1 }, }, ], pendingOperations: [], @@ -320,14 +299,13 @@ describe("getAccountShape", () => { {} as SyncConfig, ); - expect(account.xpub).toEqual("7075626c69634b6579"); - expect(mockedFistValueFrom).toHaveBeenCalledTimes(1); - expect(mockedDecodeAccountId).toHaveBeenCalledTimes(0); + expect(account.xpub).toEqual("1"); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); expect(mockedAptosAPI).toHaveBeenCalledTimes(1); - expect(mockGetAccountSpy).toHaveBeenCalledWith("address", undefined); + expect(mockGetAccountSpy).toHaveBeenCalledWith("address", 1); }); - it("get xpub from device id and account has operations history with extra", async () => { + it("get publicKey from rest", async () => { const mockGetAccountInfo = jest.fn().mockImplementation(async () => ({ balance: BigInt(0), transactions: [], @@ -350,7 +328,6 @@ describe("getAccountShape", () => { deviceId: "1", initialAccount: { id: "1:1:1:1:1", - // xpub: "address", seedIdentifier: "1", derivationMode: "", index: 0, @@ -362,7 +339,7 @@ describe("getAccountShape", () => { creationDate: new Date(), blockHeight: 0, currency: getCryptoCurrencyById("aptos"), - operationsCount: 1, + t: 1, operations: [ { id: "1", @@ -384,13 +361,13 @@ describe("getAccountShape", () => { balanceHistoryCache: {}, swapHistory: [], }, + rest: { publicKey: "restPublicKey" }, } as unknown as AccountShapeInfo, {} as SyncConfig, ); - expect(account.xpub).toEqual("7075626c69634b6579"); - expect(mockedFistValueFrom).toHaveBeenCalledTimes(1); - expect(mockedDecodeAccountId).toHaveBeenCalledTimes(0); + expect(account.xpub).toEqual("restPublicKey"); + expect(mockedEncodeAccountId).toHaveBeenCalledTimes(1); expect(mockedAptosAPI).toHaveBeenCalledTimes(1); expect(mockGetAccountSpy).toHaveBeenCalledWith("address", 1); }); diff --git a/libs/ledger-live-common/src/families/aptos/transaction.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/transaction.test.ts similarity index 61% rename from libs/ledger-live-common/src/families/aptos/transaction.test.ts rename to libs/coin-modules/coin-aptos/src/__tests__/bridge/transaction.test.ts index d49cc92bc883..1a5a1c4c0315 100644 --- a/libs/ledger-live-common/src/families/aptos/transaction.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/transaction.test.ts @@ -1,20 +1,14 @@ import BigNumber from "bignumber.js"; -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import createTransaction from "./createTransaction"; -import { formatTransaction, fromTransactionRaw, toTransactionRaw } from "./transaction"; -import { Transaction, TransactionRaw } from "./types"; - -jest.mock("./logic", () => ({ - DEFAULT_GAS: 100, - DEFAULT_GAS_PRICE: 200, -})); +import { createFixtureAccount, createFixtureTransaction } from "../../bridge/bridge.fixture"; +import { formatTransaction, fromTransactionRaw, toTransactionRaw } from "../../bridge/transaction"; +import { Transaction, TransactionRaw } from "../../types"; describe("transaction Test", () => { describe("when formatTransaction", () => { describe("when amount is 0 and fee is 0", () => { it("should return a transaction SEND to 0xff00 with fees=?", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.recipient = "0xff00"; const result = formatTransaction(transaction, account); @@ -31,10 +25,10 @@ with fees=?`; describe("when amount is 0 and fee is 0.0001", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("0.0001"); + transaction.fees = BigNumber("0.0001"); const result = formatTransaction(transaction, account); const expected = ` @@ -49,10 +43,10 @@ with fees=0`; describe("when amount is 0 and fee is 0.1", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("0.1"); + transaction.fees = BigNumber("0.1"); const result = formatTransaction(transaction, account); const expected = ` @@ -67,15 +61,15 @@ with fees=0`; describe("when amount is 1 and fee is 0.1", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); - transaction.amount = new BigNumber("1"); + transaction.amount = BigNumber("1"); transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("0.1"); + transaction.fees = BigNumber("0.1"); const result = formatTransaction(transaction, account); const expected = ` -SEND 0 +SEND 0.00000001 TO 0xff00 with fees=0`; @@ -86,17 +80,17 @@ with fees=0`; describe("when amount is 10 and fee is 1", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); - transaction.amount = new BigNumber("10"); + transaction.amount = BigNumber("10"); transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("1"); + transaction.fees = BigNumber("1"); const result = formatTransaction(transaction, account); const expected = ` -SEND 0 +SEND 0.0000001 TO 0xff00 -with fees=0`; +with fees=0.00000001`; expect(result).toBe(expected); }); @@ -105,17 +99,17 @@ with fees=0`; describe("when amount is 1000 and fee is 1", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); - transaction.amount = new BigNumber("1000"); + transaction.amount = BigNumber("1000"); transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("1"); + transaction.fees = BigNumber("1"); const result = formatTransaction(transaction, account); const expected = ` -SEND 0 +SEND 0.00001 TO 0xff00 -with fees=0`; +with fees=0.00000001`; expect(result).toBe(expected); }); @@ -124,18 +118,18 @@ with fees=0`; describe("when using MAX with amount is 1000 and fee is 1", () => { it("should return a transaction SEND to 0xff00 with fees=0", async () => { const account = createFixtureAccount(); - const transaction = createTransaction(); + const transaction = createFixtureTransaction(); - transaction.amount = new BigNumber("1000"); + transaction.amount = BigNumber("1000"); transaction.useAllAmount = true; transaction.recipient = "0xff00"; - transaction.fees = new BigNumber("1"); + transaction.fees = BigNumber("1"); const result = formatTransaction(transaction, account); const expected = ` SEND MAX TO 0xff00 -with fees=0`; +with fees=0.00000001`; expect(result).toBe(expected); }); @@ -147,7 +141,6 @@ with fees=0`; const txRaw = { family: "aptos", mode: "send", - fees: null, options: "{}", amount: "0.5", recipient: "0xff00", @@ -160,7 +153,39 @@ with fees=0`; const expected = { family: "aptos", - amount: new BigNumber("0.5"), + amount: BigNumber("0.5"), + options: {}, + mode: "send", + recipient: "0xff00", + recipientDomain: {}, + subAccountId: "0xff01", + useAllAmount: false, + }; + + expect(result).toEqual(expected); + }); + + it("should return the transaction object with fees and errors", () => { + const txRaw = { + family: "aptos", + mode: "send", + fees: "50", + errors: '{ "errors": "error" }', + options: "{}", + amount: "0.5", + recipient: "0xff00", + useAllAmount: false, + subAccountId: "0xff01", + recipientDomain: {}, + } as TransactionRaw; + + const result = fromTransactionRaw(txRaw); + + const expected = { + family: "aptos", + amount: BigNumber("0.5"), + fees: BigNumber(50), + errors: { errors: "error" }, options: {}, mode: "send", recipient: "0xff00", @@ -177,7 +202,7 @@ with fees=0`; it("should return the raw transaction object", () => { const tx = { family: "aptos", - amount: new BigNumber("0.5"), + amount: BigNumber("0.5"), options: {}, mode: "send", recipient: "0xff00", @@ -202,5 +227,35 @@ with fees=0`; expect(result).toEqual(expected); }); + + it("should return the raw transaction object with fees", () => { + const tx = { + family: "aptos", + amount: BigNumber("0.5"), + options: {}, + fees: BigNumber("0.1"), + mode: "send", + recipient: "0xff00", + recipientDomain: {}, + subAccountId: "0xff01", + useAllAmount: false, + } as Transaction; + + const result = toTransactionRaw(tx); + + const expected = { + family: "aptos", + mode: "send", + fees: "0.1", + options: "{}", + amount: "0.5", + recipient: "0xff00", + useAllAmount: false, + subAccountId: "0xff01", + recipientDomain: {}, + } as TransactionRaw; + + expect(result).toEqual(expected); + }); }); }); diff --git a/libs/coin-modules/coin-aptos/src/__tests__/errors.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/errors.test.ts new file mode 100644 index 000000000000..b99a3b713b70 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/__tests__/errors.test.ts @@ -0,0 +1,25 @@ +import { + SequenceNumberTooOldError, + SequenceNumberTooNewError, + TransactionExpiredError, +} from "../errors"; + +describe("APTOS errors", () => { + it("should create the SequenceNumberTooOldError error", () => { + const error = new SequenceNumberTooOldError(); + + expect(error).toBeInstanceOf(Error); + }); + + it("should create the SequenceNumberTooNewError error", () => { + const error = new SequenceNumberTooNewError(); + + expect(error).toBeInstanceOf(Error); + }); + + it("should create the TransactionExpiredError error", () => { + const error = new TransactionExpiredError(); + + expect(error).toBeInstanceOf(Error); + }); +}); diff --git a/libs/coin-modules/coin-aptos/src/__tests__/index.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/index.test.ts new file mode 100644 index 000000000000..2744437136b2 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/__tests__/index.test.ts @@ -0,0 +1,26 @@ +jest.mock("@ledgerhq/coin-framework/bridge/getAddressWrapper", () => jest.fn()); +jest.mock("@ledgerhq/coin-framework/signer", () => jest.fn()); +jest.mock("@ledgerhq/types-live", () => jest.fn()); +jest.mock("@ledgerhq/coin-framework/bridge/jsHelpers", () => ({ + makeAccountBridgeReceive: jest.fn(), + makeScanAccounts: jest.fn(), + getSerializedAddressParameters: jest.fn(), + makeSync: jest.fn(), +})); +jest.mock("../signer", () => jest.fn()); +jest.mock("../types", () => jest.fn()); +jest.mock("../bridge/getTransactionStatus", () => jest.fn()); +jest.mock("../bridge/estimateMaxSpendable", () => jest.fn()); +jest.mock("../bridge/prepareTransaction", () => jest.fn()); +jest.mock("../bridge/createTransaction", () => jest.fn()); +jest.mock("../bridge/synchronisation", () => jest.fn()); +jest.mock("../bridge/signOperation", () => jest.fn()); +jest.mock("../bridge/broadcast", () => jest.fn()); + +import { createBridges } from "../bridge"; + +describe("APTOS index", () => { + it("should export a function createBridges", () => { + expect(typeof createBridges).toBe("function"); + }); +}); diff --git a/libs/coin-modules/coin-aptos/src/__tests__/network/index.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/network/index.test.ts new file mode 100644 index 000000000000..1e9f7e7b2e4f --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/__tests__/network/index.test.ts @@ -0,0 +1,95 @@ +import { signTransaction } from "../../network"; +import { createFixtureAccount } from "../../bridge/bridge.fixture"; +import { + AccountAddress, + ChainId, + RawTransaction, + Serializable, + generateSigningMessageForTransaction, + generateSignedTransaction, +} from "@aptos-labs/ts-sdk"; + +jest.mock("@aptos-labs/ts-sdk", () => { + const originalModule = jest.requireActual("@aptos-labs/ts-sdk"); + const partialMockedModule = Object.keys(originalModule).reduce( + (pre: { [key: string]: jest.Mock }, methodName) => { + pre[methodName] = jest.fn(); + return pre; + }, + {} as { [key: string]: jest.Mock }, + ); + return { + ...partialMockedModule, + // mock all except these + AccountAddress: originalModule.AccountAddress, + Hex: originalModule.Hex, + }; +}); +let mockedGenerateSigningMessageForTransaction: jest.Mocked; +let mockedGenerateSignedTransaction: jest.Mocked; + +describe("signTransaction", () => { + beforeAll(() => { + mockedGenerateSigningMessageForTransaction = jest.mocked(generateSigningMessageForTransaction); + mockedGenerateSignedTransaction = jest.mocked(generateSignedTransaction); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("should throw an error", async () => { + mockedGenerateSigningMessageForTransaction.mockReturnValue("signingMessage"); + + const mockGenerateSignedTransactionSpy = jest.spyOn( + { generateSignedTransaction: mockedGenerateSignedTransaction }, + "generateSignedTransaction", + ); + + const signerContext = jest.fn().mockImplementation(() => ({ signature: "0x7aa193705193f4" })); + const account = createFixtureAccount(); + const deviceId = "nanoX"; + const rawTxn = new RawTransaction( + new AccountAddress(Uint8Array.from(Buffer.from("thisaddressmustbe32byteslooooong"))), + BigInt(1), + "" as unknown as Serializable, + BigInt(100), + BigInt(50), + BigInt(1), + { chainId: 1 } as ChainId, + ); + + expect(signTransaction(signerContext, account, deviceId, rawTxn)).rejects.toThrow( + "Account must have a public signing key", + ); + + expect(mockGenerateSignedTransactionSpy).toHaveBeenCalledTimes(0); + }); + + it("should sign a transaction", async () => { + mockedGenerateSigningMessageForTransaction.mockReturnValue("signingMessage"); + + const mockGenerateSignedTransactionSpy = jest.spyOn( + { generateSignedTransaction: mockedGenerateSignedTransaction }, + "generateSignedTransaction", + ); + + const signerContext = jest.fn().mockImplementation(() => ({ signature: "0x7aa193705193f4" })); + const account = createFixtureAccount(); + account.xpub = "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390"; + const deviceId = "nanoX"; + const rawTxn = new RawTransaction( + AccountAddress.fromString(account.xpub), + BigInt(1), + "" as unknown as Serializable, + BigInt(100), + BigInt(50), + BigInt(1), + { chainId: 1 } as ChainId, + ); + + await signTransaction(signerContext, account, deviceId, rawTxn); + + expect(mockGenerateSignedTransactionSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/libs/coin-modules/coin-aptos/src/__tests__/signer/index.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/signer/index.test.ts new file mode 100644 index 000000000000..5b90a2851bb2 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/__tests__/signer/index.test.ts @@ -0,0 +1,24 @@ +import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies"; +import resolver from "../../signer"; + +describe("aptos signer", () => { + test("getAddress", async () => { + const getAddress = resolver( + async () => + ({ + address: "address", + publicKey: Buffer.from("publicKey"), + }) as any, + ); + const result = await getAddress("deviceId", { + path: "path", + currency: getCryptoCurrencyById("aptos"), + derivationMode: "", + }); + expect(result).toMatchObject({ + address: "address", + publicKey: "7075626c69634b6579", + path: "path", + }); + }); +}); diff --git a/libs/ledger-live-common/src/families/aptos/api/graphql/queries.ts b/libs/coin-modules/coin-aptos/src/api/graphql/queries.ts similarity index 100% rename from libs/ledger-live-common/src/families/aptos/api/graphql/queries.ts rename to libs/coin-modules/coin-aptos/src/api/graphql/queries.ts diff --git a/libs/ledger-live-common/src/families/aptos/api/graphql/types.ts b/libs/coin-modules/coin-aptos/src/api/graphql/types.ts similarity index 100% rename from libs/ledger-live-common/src/families/aptos/api/graphql/types.ts rename to libs/coin-modules/coin-aptos/src/api/graphql/types.ts diff --git a/libs/ledger-live-common/src/families/aptos/api/index.ts b/libs/coin-modules/coin-aptos/src/api/index.ts similarity index 97% rename from libs/ledger-live-common/src/families/aptos/api/index.ts rename to libs/coin-modules/coin-aptos/src/api/index.ts index 3f7aa5bf2704..ca3d53da896c 100644 --- a/libs/ledger-live-common/src/families/aptos/api/index.ts +++ b/libs/coin-modules/coin-aptos/src/api/index.ts @@ -15,13 +15,14 @@ import { TransactionResponse, UserTransactionResponse, PostRequestOptions, + Block, } from "@aptos-labs/ts-sdk"; import { getEnv } from "@ledgerhq/live-env"; -import network from "@ledgerhq/live-network/network"; +import network from "@ledgerhq/live-network"; import BigNumber from "bignumber.js"; import isUndefined from "lodash/isUndefined"; import { APTOS_ASSET_ID } from "../constants"; -import { isTestnet } from "../logic"; +import { isTestnet } from "../bridge/logic"; import type { AptosTransaction, TransactionOptions } from "../types"; import { GetAccountTransactionsData, GetAccountTransactionsDataGt } from "./graphql/queries"; import { @@ -99,7 +100,7 @@ export class AptosAPI { try { const { ledger_timestamp } = await this.aptosClient.getLedgerInfo(); opts.expireTimestamp = Number(Math.ceil(+ledger_timestamp / 1_000_000 + 2 * 60)); // in milliseconds - } catch (_) { + } catch { // skip } @@ -110,7 +111,7 @@ export class AptosAPI { options: opts, }) .then(t => t.rawTransaction) - .catch((error: any) => { + .catch(error => { throw error; }); } @@ -155,7 +156,7 @@ export class AptosAPI { }); const balance = parseInt(balanceStr, 10); return new BigNumber(balance); - } catch (e: any) { + } catch (_) { return new BigNumber(0); } } @@ -206,7 +207,7 @@ export class AptosAPI { } private async getHeight(): Promise { - const { data } = await network({ + const { data } = await network({ method: "GET", url: this.apiUrl, }); diff --git a/libs/coin-modules/coin-aptos/src/bridge/bridge.fixture.ts b/libs/coin-modules/coin-aptos/src/bridge/bridge.fixture.ts new file mode 100644 index 000000000000..324a6a7003c5 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/bridge/bridge.fixture.ts @@ -0,0 +1,53 @@ +import BigNumber from "bignumber.js"; +import { faker } from "@faker-js/faker"; +import type { AptosAccount, Transaction } from "../types/index"; +import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies"; +import { emptyHistoryCache } from "@ledgerhq/coin-framework/account/index"; + +const currency = getCryptoCurrencyById("aptos"); + +export function createFixtureAccount(account?: Partial): AptosAccount { + const freshAddress = { + address: "address", + derivationPath: "derivation_path", + }; + + return { + type: "Account", + id: faker.string.uuid(), + seedIdentifier: faker.string.uuid(), + derivationMode: "", + index: faker.number.int(), + freshAddress: account?.freshAddress || freshAddress.address, + freshAddressPath: account?.freshAddressPath || freshAddress.derivationPath, + used: true, + balance: account?.balance || new BigNumber(0), + spendableBalance: account?.spendableBalance || new BigNumber(0), + creationDate: faker.date.past(), + blockHeight: faker.number.int({ min: 100_000, max: 200_000 }), + currency, + operationsCount: account?.operationsCount || 0, + operations: account?.operations || [], + pendingOperations: account?.pendingOperations || [], + lastSyncDate: new Date(), + balanceHistoryCache: emptyHistoryCache, + swapHistory: [], + }; +} + +export function createFixtureTransaction(tx?: Partial): Transaction { + const transaction: Transaction = { + amount: tx?.amount || new BigNumber(0), + recipient: tx?.recipient || "", + useAllAmount: tx?.useAllAmount || false, + family: "aptos", + mode: tx?.mode || "send", + fees: tx?.fees || null, + options: { + maxGasAmount: BigNumber(0).toString(), + gasUnitPrice: BigNumber(0).toString(), + }, + }; + + return transaction; +} diff --git a/libs/ledger-live-common/src/families/aptos/broadcast.ts b/libs/coin-modules/coin-aptos/src/bridge/broadcast.ts similarity index 79% rename from libs/ledger-live-common/src/families/aptos/broadcast.ts rename to libs/coin-modules/coin-aptos/src/bridge/broadcast.ts index 3a2e14b6c93f..0c93dd43288d 100644 --- a/libs/ledger-live-common/src/families/aptos/broadcast.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/broadcast.ts @@ -1,6 +1,6 @@ import type { Account, Operation, SignedOperation } from "@ledgerhq/types-live"; -import { patchOperationWithHash } from "./../../operation"; -import { AptosAPI } from "./api"; +import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation"; +import { AptosAPI } from "../api"; const broadcast = async ({ signedOperation, diff --git a/libs/ledger-live-common/src/families/aptos/buildTransaction.ts b/libs/coin-modules/coin-aptos/src/bridge/buildTransaction.ts similarity index 87% rename from libs/ledger-live-common/src/families/aptos/buildTransaction.ts rename to libs/coin-modules/coin-aptos/src/bridge/buildTransaction.ts index b0cc76af3249..83f43e5c0367 100644 --- a/libs/ledger-live-common/src/families/aptos/buildTransaction.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/buildTransaction.ts @@ -1,10 +1,10 @@ import { InputEntryFunctionData, RawTransaction } from "@aptos-labs/ts-sdk"; import type { Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { AptosAPI } from "./api"; -import { APTOS_ASSET_ID } from "./constants"; +import { AptosAPI } from "../api"; +import { APTOS_ASSET_ID } from "../constants"; import { normalizeTransactionOptions } from "./logic"; -import type { Transaction } from "./types"; +import type { Transaction } from "../types"; const buildTransaction = async ( account: Account, diff --git a/libs/ledger-live-common/src/families/aptos/createTransaction.ts b/libs/coin-modules/coin-aptos/src/bridge/createTransaction.ts similarity index 89% rename from libs/ledger-live-common/src/families/aptos/createTransaction.ts rename to libs/coin-modules/coin-aptos/src/bridge/createTransaction.ts index d694c317c7c3..781d61dec66c 100644 --- a/libs/ledger-live-common/src/families/aptos/createTransaction.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/createTransaction.ts @@ -1,5 +1,5 @@ import BigNumber from "bignumber.js"; -import type { Transaction } from "./types"; +import type { Transaction } from "../types"; import { DEFAULT_GAS, DEFAULT_GAS_PRICE } from "./logic"; const createTransaction = (): Transaction => ({ diff --git a/libs/ledger-live-common/src/families/aptos/deviceTransactionConfig.ts b/libs/coin-modules/coin-aptos/src/bridge/deviceTransactionConfig.ts similarity index 83% rename from libs/ledger-live-common/src/families/aptos/deviceTransactionConfig.ts rename to libs/coin-modules/coin-aptos/src/bridge/deviceTransactionConfig.ts index c5168a827f89..73633053e1ec 100644 --- a/libs/ledger-live-common/src/families/aptos/deviceTransactionConfig.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/deviceTransactionConfig.ts @@ -1,4 +1,4 @@ -import type { DeviceTransactionField } from "../../transaction"; +import type { CommonDeviceTransactionField as DeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common"; import BigNumber from "bignumber.js"; export const methodToString = (method: number): string => { diff --git a/libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.ts b/libs/coin-modules/coin-aptos/src/bridge/estimateMaxSpendable.ts similarity index 86% rename from libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.ts rename to libs/coin-modules/coin-aptos/src/bridge/estimateMaxSpendable.ts index 808634d0b729..e1ce2712f18f 100644 --- a/libs/ledger-live-common/src/families/aptos/estimateMaxSpendable.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/estimateMaxSpendable.ts @@ -1,10 +1,10 @@ import type { Account, AccountLike } from "@ledgerhq/types-live"; import { BigNumber } from "bignumber.js"; -import { getMainAccount } from "../../account"; -import { AptosAPI } from "./api"; +import { getMainAccount } from "@ledgerhq/coin-framework/account/index"; +import { AptosAPI } from "../api"; import { getEstimatedGas } from "./getFeesForTransaction"; import { DEFAULT_GAS, DEFAULT_GAS_PRICE, getMaxSendBalance } from "./logic"; -import type { Transaction } from "./types"; +import type { Transaction } from "../types"; const estimateMaxSpendable = async ({ account, diff --git a/libs/ledger-live-common/src/families/aptos/getFeesForTransaction.ts b/libs/coin-modules/coin-aptos/src/bridge/getFeesForTransaction.ts similarity index 97% rename from libs/ledger-live-common/src/families/aptos/getFeesForTransaction.ts rename to libs/coin-modules/coin-aptos/src/bridge/getFeesForTransaction.ts index 8013e7c33bb1..4d74b79b9266 100644 --- a/libs/ledger-live-common/src/families/aptos/getFeesForTransaction.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/getFeesForTransaction.ts @@ -2,10 +2,10 @@ import { Ed25519PublicKey } from "@aptos-labs/ts-sdk"; import { log } from "@ledgerhq/logs"; import type { Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { AptosAPI } from "./api"; +import { AptosAPI } from "../api"; import buildTransaction from "./buildTransaction"; import { DEFAULT_GAS, DEFAULT_GAS_PRICE, ESTIMATE_GAS_MUL } from "./logic"; -import type { Transaction, TransactionErrors } from "./types"; +import type { Transaction, TransactionErrors } from "../types"; type IGetEstimatedGasReturnType = { fees: BigNumber; diff --git a/libs/ledger-live-common/src/families/aptos/getTransactionStatus.ts b/libs/coin-modules/coin-aptos/src/bridge/getTransactionStatus.ts similarity index 80% rename from libs/ledger-live-common/src/families/aptos/getTransactionStatus.ts rename to libs/coin-modules/coin-aptos/src/bridge/getTransactionStatus.ts index 27456ce8bb73..6f1a1ee10b81 100644 --- a/libs/ledger-live-common/src/families/aptos/getTransactionStatus.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/getTransactionStatus.ts @@ -8,14 +8,13 @@ import { AmountRequired, } from "@ledgerhq/errors"; import type { Account } from "@ledgerhq/types-live"; -import type { TransactionStatus } from "../..//generated/types"; -import type { Transaction } from "./types"; +import type { Transaction, TransactionStatus } from "../types"; import { AccountAddress } from "@aptos-labs/ts-sdk"; const getTransactionStatus = async (a: Account, t: Transaction): Promise => { - const errors: Record = {}; - const warnings: Record = {}; + const errors: Record = {}; + const warnings = {}; if (!t.fees) { errors.fees = new FeeNotLoaded(); @@ -31,15 +30,15 @@ const getTransactionStatus = async (a: Account, t: Transaction): Promise): CurrencyBridge { + const getAddress = resolver(signerContext); + + const scanAccounts = makeScanAccounts({ + getAccountShape, + getAddressFn: getAddressWrapper(getAddress), + }); + + return { + preload: () => Promise.resolve({}), + hydrate: () => {}, + scanAccounts, + }; +} + +const sync = makeSync({ getAccountShape }); + +function buildAccountBridge( + signerContext: SignerContext, +): AccountBridge { + const getAddress = resolver(signerContext); + + const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress)); + const signOperation = buildSignOperation(signerContext); + + return { + estimateMaxSpendable, + createTransaction, + updateTransaction, + getTransactionStatus, + getSerializedAddressParameters, + prepareTransaction, + sync, + receive, + signOperation, + broadcast, + }; +} + +export function createBridges(signerContext: SignerContext) { + return { + currencyBridge: buildCurrencyBridge(signerContext), + accountBridge: buildAccountBridge(signerContext), + }; +} diff --git a/libs/ledger-live-common/src/families/aptos/logic.ts b/libs/coin-modules/coin-aptos/src/bridge/logic.ts similarity index 84% rename from libs/ledger-live-common/src/families/aptos/logic.ts rename to libs/coin-modules/coin-aptos/src/bridge/logic.ts index 307c661031e6..cd2c90d6bfd6 100644 --- a/libs/ledger-live-common/src/families/aptos/logic.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/logic.ts @@ -2,21 +2,22 @@ import { EntryFunctionPayloadResponse, Event, InputEntryFunctionData, + MoveResource, WriteSetChange, - WriteSetChangeWriteResource, } from "@aptos-labs/ts-sdk"; import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies"; import type { Operation, OperationType } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { encodeOperationId } from "../../operation"; +import { encodeOperationId } from "@ledgerhq/coin-framework/operation"; import { APTOS_COIN_CHANGE, BATCH_TRANSFER_TYPES, DELEGATION_POOL_TYPES, DIRECTION, TRANSFER_TYPES, -} from "./constants"; -import type { AptosTransaction, TransactionOptions } from "./types"; + WRITE_RESOURCE, +} from "../constants"; +import type { AptosMoveResource, AptosTransaction, TransactionOptions } from "../types"; export const DEFAULT_GAS = new BigNumber(200); export const DEFAULT_GAS_PRICE = new BigNumber(100); @@ -39,6 +40,15 @@ export const getMaxSendBalance = ( }; export function normalizeTransactionOptions(options: TransactionOptions): TransactionOptions { + // FIXME: this is wrong. TransactionOptions is + // { + // maxGasAmount: string; + // gasUnitPrice: string; + // sequenceNumber?: string; + // expirationTimestampSecs?: string; + // } + // meaning we can't return undefined in check method. + // This method is useless, not deleting as it breaks code and this iteration is coin modularisation. const check = (v: any) => ((v ?? "").toString().trim() ? v : undefined); return { maxGasAmount: check(options.maxGasAmount), @@ -61,7 +71,7 @@ export const getBlankOperation = ( recipients: [] as string[], accountId: id, date: new Date(parseInt(tx.timestamp) / 1000), - extra: { version: tx?.version }, + extra: { version: tx.version }, transactionSequenceNumber: parseInt(tx.sequence_number), hasFailed: false, }); @@ -175,23 +185,39 @@ function checkWriteSets(tx: AptosTransaction, event: Event, event_name: string): }); } -export function isChangeOfAptos(change: WriteSetChange, event: Event, event_name: string): boolean { +export function isChangeOfAptos( + writeSetChange: WriteSetChange, + event: Event, + event_name: string, +): boolean { // to validate the event is related to Aptos Tokens we need to find change of type "write_resource" // with the same guid as event - if (change.type == "write_resource") { - const change_data = (change as WriteSetChangeWriteResource).data; - if (change_data.type === APTOS_COIN_CHANGE) { - const change_event_data = change_data.data[event_name]; - if ( - change_event_data && - change_event_data.guid.id.addr === event.guid.account_address && - change_event_data.guid.id.creation_num === event.guid.creation_number - ) { - return true; - } - } + if (writeSetChange.type !== WRITE_RESOURCE) { + return false; + } + + if (!("data" in writeSetChange)) { + return false; + } + + const change_data = writeSetChange.data; + + if (!("type" in change_data)) { + return false; } - return false; + + const mr = change_data as MoveResource; + + if (mr.type !== APTOS_COIN_CHANGE) { + return false; + } + + const change_event_data = mr.data[event_name]; + + return ( + change_event_data.guid.id.addr === event.guid.account_address && + change_event_data.guid.id.creation_num === event.guid.creation_number + ); } export function getAptosAmounts( diff --git a/libs/ledger-live-common/src/families/aptos/prepareTransaction.ts b/libs/coin-modules/coin-aptos/src/bridge/prepareTransaction.ts similarity index 95% rename from libs/ledger-live-common/src/families/aptos/prepareTransaction.ts rename to libs/coin-modules/coin-aptos/src/bridge/prepareTransaction.ts index 37479f0f57d5..f498a78e9e54 100644 --- a/libs/ledger-live-common/src/families/aptos/prepareTransaction.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/prepareTransaction.ts @@ -1,9 +1,9 @@ import type { Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; -import { AptosAPI } from "./api"; +import { AptosAPI } from "../api"; import { getEstimatedGas } from "./getFeesForTransaction"; -import type { Transaction } from "./types"; +import type { Transaction } from "../types"; import { DEFAULT_GAS, DEFAULT_GAS_PRICE, getMaxSendBalance } from "./logic"; const prepareTransaction = async ( diff --git a/libs/coin-modules/coin-aptos/src/bridge/signOperation.ts b/libs/coin-modules/coin-aptos/src/bridge/signOperation.ts new file mode 100644 index 000000000000..986c3964cd26 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/bridge/signOperation.ts @@ -0,0 +1,82 @@ +import type { AptosAccount, Transaction } from "../types"; +import { Observable } from "rxjs"; +import { encodeOperationId } from "@ledgerhq/coin-framework/operation"; +import buildTransaction from "./buildTransaction"; +import BigNumber from "bignumber.js"; +import type { Account, AccountBridge, Operation, OperationType } from "@ledgerhq/types-live"; +import { AptosAPI } from "../api"; + +import { SignerContext } from "@ledgerhq/coin-framework/signer"; +import { AptosSigner } from "../types"; +import { signTransaction } from "../network"; + +export const getAddress = (a: Account) => ({ + address: a.freshAddress, + derivationPath: a.freshAddressPath, +}); + +const buildSignOperation = + ( + signerContext: SignerContext, + ): AccountBridge["signOperation"] => + ({ account, transaction, deviceId }) => + new Observable(o => { + async function main() { + o.next({ type: "device-signature-requested" }); + + const aptosClient = new AptosAPI(account.currency.id); + + const rawTx = await buildTransaction(account, transaction, aptosClient); + const txBytes = await signTransaction(signerContext, account, deviceId, rawTx); + const signature = Buffer.from(txBytes).toString("hex"); + + o.next({ type: "device-signature-granted" }); + + const accountId = account.id; + const hash = ""; + const type: OperationType = "OUT"; + const fee = transaction.fees || new BigNumber(0); + const extra = {}; + const senders: string[] = []; + const recipients: string[] = []; + + if (transaction.mode === "send") { + senders.push(account.freshAddress); + recipients.push(transaction.recipient); + } + + // build optimistic operation + const operation: Operation = { + id: encodeOperationId(accountId, hash, type), + hash, + type, + value: transaction.useAllAmount + ? account.balance.minus(fee) + : transaction.amount.plus(fee), + fee, + extra, + blockHash: null, + blockHeight: null, + senders, + recipients, + accountId, + date: new Date(), + transactionSequenceNumber: Number(rawTx.sequence_number), + }; + + o.next({ + type: "signed", + signedOperation: { + operation, + signature, + }, + }); + } + + main().then( + () => o.complete(), + e => o.error(e), + ); + }); + +export default buildSignOperation; diff --git a/libs/coin-modules/coin-aptos/src/bridge/synchronisation.ts b/libs/coin-modules/coin-aptos/src/bridge/synchronisation.ts new file mode 100644 index 000000000000..cc5e2d3bd89b --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/bridge/synchronisation.ts @@ -0,0 +1,50 @@ +import { decodeAccountId, encodeAccountId } from "@ledgerhq/coin-framework/account"; +import type { GetAccountShape } from "@ledgerhq/coin-framework/bridge/jsHelpers"; +import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers"; +import { AptosAPI } from "../api"; +import { txsToOps } from "./logic"; +import type { AptosAccount } from "../types"; + +export const getAccountShape: GetAccountShape = async info => { + const { address, initialAccount, currency, derivationMode, rest } = info; + + const publicKey = + rest?.publicKey || (initialAccount && decodeAccountId(initialAccount.id).xpubOrAddress); + + const accountId = encodeAccountId({ + type: "js", + version: "2", + currencyId: currency.id, + xpubOrAddress: publicKey || address, + derivationMode, + }); + + // "xpub" field is used to store publicKey to simulate transaction during sending tokens. + // We can't get access to the Nano X via bluetooth on the step of simulation + // but we need public key to simulate transaction. + // "xpub" field is used because this field exists in ledger operation type + const xpub = initialAccount?.xpub || publicKey || ""; + + const oldOperations = initialAccount?.operations || []; + const startAt = (oldOperations[0]?.extra as any)?.version; + + const aptosClient = new AptosAPI(currency.id); + const { balance, transactions, blockHeight } = await aptosClient.getAccountInfo(address, startAt); + + const newOperations = txsToOps(info, accountId, transactions); + const operations = mergeOps(oldOperations, newOperations); + + const shape: Partial = { + type: "Account", + id: accountId, + xpub, + balance: balance, + spendableBalance: balance, + operations, + operationsCount: operations.length, + blockHeight, + lastSyncDate: new Date(), + }; + + return shape; +}; diff --git a/libs/ledger-live-common/src/families/aptos/transaction.ts b/libs/coin-modules/coin-aptos/src/bridge/transaction.ts similarity index 87% rename from libs/ledger-live-common/src/families/aptos/transaction.ts rename to libs/coin-modules/coin-aptos/src/bridge/transaction.ts index d0f484eb1603..6e3444e7a8c2 100644 --- a/libs/ledger-live-common/src/families/aptos/transaction.ts +++ b/libs/coin-modules/coin-aptos/src/bridge/transaction.ts @@ -1,7 +1,7 @@ import { BigNumber } from "bignumber.js"; -import type { Transaction, TransactionRaw } from "./types"; +import type { Transaction, TransactionRaw } from "../types"; -import { formatTransactionStatus } from "@ledgerhq/coin-bitcoin/transaction"; +import { formatTransactionStatus } from "@ledgerhq/coin-framework/formatters"; import { fromTransactionCommonRaw, fromTransactionStatusRawCommon as fromTransactionStatusRaw, @@ -9,7 +9,7 @@ import { toTransactionStatusRawCommon as toTransactionStatusRaw, } from "@ledgerhq/coin-framework/serialization"; import { Account } from "@ledgerhq/types-live"; -import { formatCurrencyUnit } from "../../currencies"; +import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index"; export const formatTransaction = ( { mode, amount, fees, recipient, useAllAmount }: Transaction, diff --git a/libs/ledger-live-common/src/families/aptos/constants.ts b/libs/coin-modules/coin-aptos/src/constants.ts similarity index 52% rename from libs/ledger-live-common/src/families/aptos/constants.ts rename to libs/coin-modules/coin-aptos/src/constants.ts index e97564afa963..4348d368d5ae 100644 --- a/libs/ledger-live-common/src/families/aptos/constants.ts +++ b/libs/coin-modules/coin-aptos/src/constants.ts @@ -1,3 +1,5 @@ +import { MoveStructId } from "@aptos-labs/ts-sdk"; + export const LOAD_LIMIT = 10; export enum TX_STATUS { @@ -6,22 +8,24 @@ export enum TX_STATUS { SUCCESS = "success", } -export const TRANSFER_TYPES = [ +export const WRITE_RESOURCE = "write_resource"; + +export const TRANSFER_TYPES: MoveStructId[] = [ "0x1::aptos_account::transfer", "0x1::aptos_account::transfer_coins", "0x1::coin::transfer", ]; -export const BATCH_TRANSFER_TYPES = [ +export const BATCH_TRANSFER_TYPES: MoveStructId[] = [ "0x1::aptos_account::batch_transfer", "0x1::aptos_account::batch_transfer_coins", ]; -export const DELEGATION_POOL_TYPES = [ +export const DELEGATION_POOL_TYPES: MoveStructId[] = [ "0x1::delegation_pool::add_stake", "0x1::delegation_pool::withdraw", ]; -export const APTOS_ASSET_ID = "0x1::aptos_coin::AptosCoin"; -export const APTOS_COIN_CHANGE = `0x1::coin::CoinStore<${APTOS_ASSET_ID}>`; +export const APTOS_ASSET_ID: MoveStructId = "0x1::aptos_coin::AptosCoin"; +export const APTOS_COIN_CHANGE: MoveStructId = `0x1::coin::CoinStore<${APTOS_ASSET_ID}>`; export enum DIRECTION { IN = "IN", diff --git a/libs/coin-modules/coin-aptos/src/errors.ts b/libs/coin-modules/coin-aptos/src/errors.ts new file mode 100644 index 000000000000..50f0279260ea --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/errors.ts @@ -0,0 +1,7 @@ +import { createCustomErrorClass } from "@ledgerhq/errors"; + +export const SequenceNumberTooOldError = createCustomErrorClass("SequenceNumberTooOld"); + +export const SequenceNumberTooNewError = createCustomErrorClass("SequenceNumberTooNew"); + +export const TransactionExpiredError = createCustomErrorClass("TransactionExpired"); diff --git a/libs/coin-modules/coin-aptos/src/index.ts b/libs/coin-modules/coin-aptos/src/index.ts new file mode 100644 index 000000000000..ef822ba96a7b --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/index.ts @@ -0,0 +1,3 @@ +export * from "./types"; + +export { createBridges } from "./bridge/index"; diff --git a/libs/coin-modules/coin-aptos/src/network/index.ts b/libs/coin-modules/coin-aptos/src/network/index.ts new file mode 100644 index 000000000000..fe444257a0f6 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/network/index.ts @@ -0,0 +1,54 @@ +import { + AccountAddress, + AccountAuthenticatorEd25519, + Ed25519PublicKey, + Ed25519Signature, + generateSignedTransaction, + generateSigningMessageForTransaction, + Hex, + RawTransaction, + SimpleTransaction, +} from "@aptos-labs/ts-sdk"; +import { SignerContext } from "@ledgerhq/coin-framework/lib/signer"; +import { Account } from "@ledgerhq/types-live"; +import { AptosSigner } from "../types"; +import { sha3_256 as sha3Hash } from "@noble/hashes/sha3"; + +export async function signTransaction( + signerContext: SignerContext, + account: Account, + deviceId: string, + rawTxn: RawTransaction, +): Promise { + const { freshAddressPath: derivationPath } = account; + + if (!account.xpub) { + throw Error("Account must have a public signing key"); + } + + const publicKey = Buffer.from(AccountAddress.from(account.xpub).toUint8Array()); + const hash = sha3Hash.create(); + hash.update(publicKey.toString("hex")); + hash.update("\x00"); + + const signingMessage = generateSigningMessageForTransaction({ + rawTransaction: rawTxn, + } as SimpleTransaction); + + const response = await signerContext( + deviceId, + async signer => await signer.signTransaction(derivationPath, Buffer.from(signingMessage)), + ); + + const sigHexStr = Hex.fromHexString(response.signature.toString("hex")); + const signature = new Ed25519Signature(sigHexStr.toUint8Array()); + const authenticator = new AccountAuthenticatorEd25519( + new Ed25519PublicKey(publicKey.toString("hex")), + signature, + ); + + return generateSignedTransaction({ + transaction: { rawTransaction: rawTxn } as SimpleTransaction, + senderAuthenticator: authenticator, + }); +} diff --git a/libs/coin-modules/coin-aptos/src/signer/index.ts b/libs/coin-modules/coin-aptos/src/signer/index.ts new file mode 100644 index 000000000000..ca421d015d05 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/signer/index.ts @@ -0,0 +1,17 @@ +import { GetAddressFn } from "@ledgerhq/coin-framework/bridge/getAddressWrapper"; +import { SignerContext } from "@ledgerhq/coin-framework/signer"; +import { GetAddressOptions } from "@ledgerhq/coin-framework/derivation"; +import { AptosSigner } from "../types"; + +const resolver = (signerContext: SignerContext): GetAddressFn => { + return async (deviceId: string, { path, verify }: GetAddressOptions) => { + const r = await signerContext(deviceId, signer => signer.getAddress(path, verify || false)); + return { + address: r.address, + publicKey: r.publicKey.toString("hex"), + path, + }; + }; +}; + +export default resolver; diff --git a/libs/ledger-live-common/src/families/aptos/specs.ts b/libs/coin-modules/coin-aptos/src/test/bot-specs.ts similarity index 65% rename from libs/ledger-live-common/src/families/aptos/specs.ts rename to libs/coin-modules/coin-aptos/src/test/bot-specs.ts index 1e9be968c1df..3d5ec56e61f3 100644 --- a/libs/ledger-live-common/src/families/aptos/specs.ts +++ b/libs/coin-modules/coin-aptos/src/test/bot-specs.ts @@ -1,12 +1,11 @@ import invariant from "invariant"; -import expect from "expect"; import { DeviceModelId } from "@ledgerhq/devices"; import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies"; import { parseCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index"; -import { genericTestDestination, pickSiblings, botTest } from "../../bot/specs"; -import type { AppSpec } from "../../bot/types"; +import { botTest, genericTestDestination, pickSiblings } from "@ledgerhq/coin-framework/bot/specs"; +import type { AppSpec } from "@ledgerhq/coin-framework/bot/types"; import { acceptTransaction } from "./speculos-deviceActions"; -import type { Transaction } from "./types"; +import type { Transaction } from "../types"; const currency = getCryptoCurrencyById("aptos"); const minBalanceNewAccount = parseCurrencyUnit(currency.units[0], "0.0001"); @@ -20,8 +19,7 @@ const aptos: AppSpec = { appName: "Aptos", }, genericDeviceAction: acceptTransaction, - testTimeout: 1000, - // testTimeout: 5 * 60 * 1000, + testTimeout: 5 * 60 * 1000, minViableAmount: minBalanceNewAccount, transactionCheck: ({ maxSpendable }) => { invariant(maxSpendable.gt(minBalanceNewAccount), "balance is too low"); @@ -60,6 +58,28 @@ const aptos: AppSpec = { ); }, }, + { + name: "Send max", + maxRun: 2, + testDestination: genericTestDestination, + transaction: ({ account, siblings, bridge }) => { + const sibling = pickSiblings(siblings, 4); + const recipient = sibling.freshAddress; + const transaction = bridge.createTransaction(account); + + return { + transaction, + updates: [{ recipient }, { useAllAmount: true }], + }; + }, + test: ({ account, accountBeforeTransaction, operation }) => { + botTest("Account balance should have decreased", () => { + expect(account.balance.toNumber()).toEqual( + accountBeforeTransaction.balance.minus(operation.value).toNumber(), + ); + }); + }, + }, ], }; diff --git a/libs/coin-modules/coin-aptos/src/test/bridgeDatasetTest.ts b/libs/coin-modules/coin-aptos/src/test/bridgeDatasetTest.ts new file mode 100644 index 000000000000..4308ba21523e --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/test/bridgeDatasetTest.ts @@ -0,0 +1,82 @@ +import { CurrenciesData, DatasetTest } from "@ledgerhq/types-live"; +import BigNumber from "bignumber.js"; +import { fromTransactionRaw } from "../bridge/transaction"; +import { Transaction } from "../types"; + +const aptos: CurrenciesData = { + scanAccounts: [ + { + name: "aptos seed 1", + apdus: ` + => 5b0500000d038000002c8000027d80000000 + <= 210430cfd94a543eca9ba9d26eafe07f6c28e1e43e4768f3c0bad32efeced8662f8720b44227ab88ddefa2ff5deb5e366c70e8b703aec381de39b103dd50eabf8d9d119000 + => 5b05000015058000002c8000027d800000008000000080000000 + <= 21044b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b20ba21e074c2bd6b307a35c85afd6ad40dc8319af9ec11660c588ffd3e413773259000 + => 5b05000015058000002c8000027d800000018000000080000000 + <= 21049aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e207fa1d1caa1209d35fafe59393bc820bb7b0b81f3a808dd3728e0b1347bfff40e9000 + => 5b05000015058000002c8000027d800000028000000080000000 + <= 21041fb77263c646810574525025561e4559c338b571f57f1b513d75b1609d5fa5f6205e9117d152b467fac631d742ddbc31ea3cbcaac51273c1e931058a56e983d9f59000 + `, + }, + ], + accounts: [ + { + raw: { + id: "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", + seedIdentifier: "d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583", + used: true, + derivationMode: "", + index: 0, + freshAddress: "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + freshAddressPath: "44'/637'/0'/0/0", + blockHeight: 266360751, + creationDate: "2024-12-18T12:26:31.070Z", + operationsCount: 5, + operations: [], + pendingOperations: [], + currencyId: "aptos", + lastSyncDate: "2024-12-18T15:20:55.097Z", + balance: "30100", + spendableBalance: "30100", + balanceHistoryCache: { + HOUR: { balances: [0, 50000, 50000, 30100], latestDate: 1734534000000 }, + DAY: { balances: [0], latestDate: 1734480000000 }, + WEEK: { balances: [0], latestDate: 1734220800000 }, + }, + xpub: "d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956", + swapHistory: [], + }, + transactions: [ + { + name: "NO_NAME", + transaction: fromTransactionRaw({ + amount: "20000", + recipient: "0xd20fa44192f94ba086ab16bfdf57e43ff118ada69b4c66fa9b9a9223cbc068c1", + useAllAmount: false, + family: "aptos", + mode: "send", + fees: "1100", + options: '{ "maxGasAmount": "11", "gasUnitPrice": "100" }', + errors: "{}", + }), + expectedStatus: () => + // you can use account and transaction for smart logic. drop the =>fn otherwise + ({ + errors: {}, + warnings: {}, + estimatedFees: BigNumber("900"), + amount: BigNumber("20000"), + totalSpent: BigNumber("20900"), + }), + }, + ], + }, + ], +}; + +export const dataset: DatasetTest = { + implementations: ["js"], + currencies: { + aptos, + }, +}; diff --git a/libs/coin-modules/coin-aptos/src/test/cli.ts b/libs/coin-modules/coin-aptos/src/test/cli.ts new file mode 100644 index 000000000000..069c26f7c916 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/test/cli.ts @@ -0,0 +1,80 @@ +import type { Account, AccountLike, AccountLikeArray } from "@ledgerhq/types-live"; +import invariant from "invariant"; +import flatMap from "lodash/flatMap"; +import type { Transaction } from "../types"; +import { getAccountCurrency } from "@ledgerhq/coin-framework/account/index"; +import { AccountType } from "../types"; + +const options = [ + { + name: "token", + alias: "t", + type: String, + desc: "use an token account children of the account", + }, +]; + +function inferAccounts(account: Account, opts: Record): AccountLikeArray { + invariant(account.currency.family === "aptos", "aptos family"); + + if (!opts.token) { + const accounts: Account[] = [account]; + return accounts; + } + + const token = opts.token; + + const subAccounts = account.subAccounts || []; + + if (token) { + const subAccount = subAccounts.find(t => { + const currency = getAccountCurrency(t); + return ( + token.toLowerCase() === currency.ticker.toLowerCase() || token.toLowerCase() === currency.id + ); + }); + + if (!subAccount) { + throw new Error( + "token account '" + + token + + "' not found. Available: " + + subAccounts.map(t => getAccountCurrency(t).ticker).join(", "), + ); + } + + return [subAccount]; + } + + return []; +} + +function inferTransactions( + transactions: Array<{ + account: AccountLike; + transaction: Transaction; + }>, +): Transaction[] { + return flatMap(transactions, ({ transaction, account }) => { + invariant(transaction.family === "aptos", "aptos family"); + + if (account.type === AccountType.TokenAccount) { + const isDelisted = account.token.delisted === true; + invariant(!isDelisted, "token is delisted"); + } + + return { + ...transaction, + family: "aptos", + subAccountId: account.type === AccountType.TokenAccount ? account.id : null, + } as Transaction; + }); +} + +export default function makeCliTools() { + return { + options, + inferAccounts, + inferTransactions, + }; +} diff --git a/libs/coin-modules/coin-aptos/src/test/index.ts b/libs/coin-modules/coin-aptos/src/test/index.ts new file mode 100644 index 000000000000..5f9103148614 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/test/index.ts @@ -0,0 +1,3 @@ +export * from "./bridgeDatasetTest"; +export * from "./bot-specs"; +export * from "./speculos-deviceActions"; diff --git a/libs/ledger-live-common/src/families/aptos/speculos-deviceActions.ts b/libs/coin-modules/coin-aptos/src/test/speculos-deviceActions.ts similarity index 68% rename from libs/ledger-live-common/src/families/aptos/speculos-deviceActions.ts rename to libs/coin-modules/coin-aptos/src/test/speculos-deviceActions.ts index 8fe4ff03b500..b59f298cb0c8 100644 --- a/libs/ledger-live-common/src/families/aptos/speculos-deviceActions.ts +++ b/libs/coin-modules/coin-aptos/src/test/speculos-deviceActions.ts @@ -1,6 +1,10 @@ -import type { DeviceAction } from "../../bot/types"; -import type { Transaction } from "./types"; -import { deviceActionFlow, formatDeviceAmount, SpeculosButton } from "../../bot/specs"; +import type { DeviceAction } from "@ledgerhq/coin-framework/bot/types"; +import type { Transaction } from "../types"; +import { + deviceActionFlow, + formatDeviceAmount, + SpeculosButton, +} from "@ledgerhq/coin-framework/bot/specs"; import { State } from "@ledgerhq/coin-framework/bot/types"; const typeWording = { @@ -20,6 +24,13 @@ export const acceptTransaction: DeviceAction> = title: "Review", button: SpeculosButton.RIGHT, }, + { + title: "Type", + button: SpeculosButton.RIGHT, + expectedValue: ({ transaction }) => { + return typeWording[transaction.mode as keyof typeof typeWording]; + }, + }, { title: "Amount", button: SpeculosButton.RIGHT, @@ -33,25 +44,6 @@ export const acceptTransaction: DeviceAction> = button: SpeculosButton.RIGHT, expectedValue: ({ transaction }) => transaction.recipient, }, - { - title: "Max Fees", - button: SpeculosButton.RIGHT, - }, - { - title: "No Gateway Fee", - button: SpeculosButton.RIGHT, - }, - { - title: "Validator", - button: SpeculosButton.RIGHT, - }, - { - title: "Type", - button: SpeculosButton.RIGHT, - expectedValue: ({ transaction }) => { - return typeWording[transaction.mode]; - }, - }, { title: "Accept", button: SpeculosButton.BOTH, diff --git a/libs/coin-modules/coin-aptos/src/types/bridge.ts b/libs/coin-modules/coin-aptos/src/types/bridge.ts new file mode 100644 index 000000000000..36a046ad51b1 --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/types/bridge.ts @@ -0,0 +1,4 @@ +export enum AccountType { + Account = "Account", + TokenAccount = "TokenAccount", +} diff --git a/libs/ledger-live-common/src/families/aptos/types.ts b/libs/coin-modules/coin-aptos/src/types/index.ts similarity index 85% rename from libs/ledger-live-common/src/families/aptos/types.ts rename to libs/coin-modules/coin-aptos/src/types/index.ts index e7b7143329ca..9a82757b2546 100644 --- a/libs/ledger-live-common/src/families/aptos/types.ts +++ b/libs/coin-modules/coin-aptos/src/types/index.ts @@ -1,12 +1,15 @@ import type { UserTransactionResponse } from "@aptos-labs/ts-sdk"; import type { Account, + Operation, TransactionCommon, TransactionCommonRaw, TransactionStatusCommon, TransactionStatusCommonRaw, } from "@ledgerhq/types-live"; import type { BigNumber } from "bignumber.js"; +export * from "./signer"; +export * from "./bridge"; export type AptosTransaction = UserTransactionResponse & { block: { @@ -15,6 +18,8 @@ export type AptosTransaction = UserTransactionResponse & { }; }; +export type AptosOperation = Operation; + export type AptosAccount = Account; export type TransactionStatus = TransactionStatusCommon; @@ -63,3 +68,7 @@ export type TransactionRaw = TransactionCommonRaw & { options: string; errors?: string; }; + +export type AptosMoveResource = { + [key: string]: { guid: { id: { addr: string; creation_num: string } } }; +}; diff --git a/libs/coin-modules/coin-aptos/src/types/signer.ts b/libs/coin-modules/coin-aptos/src/types/signer.ts new file mode 100644 index 000000000000..ef5c7a970a7d --- /dev/null +++ b/libs/coin-modules/coin-aptos/src/types/signer.ts @@ -0,0 +1,26 @@ +export interface AptosAddress { + publicKey: Buffer; + chainCode: Buffer; + address: string; +} + +export interface AptosSigner { + getAddress(path: string, display: boolean): Promise; + signTransaction(path: string, txBuffer: Buffer): Promise<{ signature: Buffer }>; +} + +export type AptosSignature = { + signature: null | Buffer; + return_code: number; + error_message: string; + signature_der: Uint8Array; + signature_compact: Uint8Array; +}; + +export type AptosGetAddrResponse = { + addrByte: Uint8Array; + addrString: string; + compressed_pk: Uint8Array; + return_code: number; + error_message: string; +}; diff --git a/libs/coin-modules/coin-aptos/tsconfig.json b/libs/coin-modules/coin-aptos/tsconfig.json new file mode 100644 index 000000000000..ef29ef154772 --- /dev/null +++ b/libs/coin-modules/coin-aptos/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.base", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "module": "commonjs", + "downlevelIteration": true, + "lib": ["es2020", "dom"], + "rootDir": "./src", + "outDir": "lib", + "exactOptionalPropertyTypes": true + }, + "include": ["src/**/*", "deviceTransactionConfig.ts", "transaction.ts"] +} diff --git a/libs/ledger-live-common/package.json b/libs/ledger-live-common/package.json index 82637b963d98..beec6f98c89e 100644 --- a/libs/ledger-live-common/package.json +++ b/libs/ledger-live-common/package.json @@ -120,8 +120,6 @@ "https": false }, "dependencies": { - "@apollo/client": "^3.8.7", - "@aptos-labs/ts-sdk": "^1.33.1", "@blooo/hw-app-acre": "^1.1.1", "@cardano-foundation/ledgerjs-hw-app-cardano": "^7.1.2", "@celo/connect": "^6.0.2", @@ -133,6 +131,7 @@ "@dfinity/candid": "^0.21.0", "@dfinity/principal": "^0.15.6", "@ledgerhq/coin-algorand": "workspace:^", + "@ledgerhq/coin-aptos": "workspace:^", "@ledgerhq/coin-bitcoin": "workspace:^", "@ledgerhq/coin-cardano": "workspace:^", "@ledgerhq/coin-cosmos": "workspace:^", @@ -195,7 +194,6 @@ "@ledgerhq/wallet-api-core": "^1.13.0", "@ledgerhq/wallet-api-exchange-module": "workspace:^", "@ledgerhq/wallet-api-server": "^1.7.0", - "@noble/hashes": "1.6.1", "@stricahq/typhonjs": "^2.0.0", "@taquito/ledger-signer": "^20.0.0", "@ton-community/ton-ledger": "^7.0.1", @@ -223,7 +221,6 @@ "date-fns": "^2.23.0", "expect": "^27.4.6", "fuse.js": "^6.6.2", - "graphql": "^16.8.1", "invariant": "^2.2.2", "isomorphic-ws": "^4.0.1", "jotai": "^2.10.1", diff --git a/libs/ledger-live-common/scripts/sync-families-dispatch.mjs b/libs/ledger-live-common/scripts/sync-families-dispatch.mjs index 57f264837dff..2b089a76e207 100644 --- a/libs/ledger-live-common/scripts/sync-families-dispatch.mjs +++ b/libs/ledger-live-common/scripts/sync-families-dispatch.mjs @@ -22,6 +22,7 @@ const targets = [ // Coins using coin-framework const familiesWPackage = [ "algorand", + "aptos", "bitcoin", "cardano", "cosmos", @@ -166,7 +167,7 @@ async function getDeviceTransactionConfig(families) { const libsDir = path.join(__dirname, "../.."); const target = "deviceTransactionConfig.ts"; - for (const family of ["filecoin", "stacks", "polkadot", "tron"]) { + for (const family of ["aptos", "filecoin", "stacks", "polkadot", "tron"]) { if (fs.existsSync(path.join(libsDir, `coin-modules/coin-${family}/src/bridge`, target))) { imports += `import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_${family} } from "@ledgerhq/coin-${family}/bridge/deviceTransactionConfig";\n`; exprts += `\n | ExtraDeviceTransactionField_${family}`; diff --git a/libs/ledger-live-common/src/errors.ts b/libs/ledger-live-common/src/errors.ts index 29ad131885f1..af47cdae9040 100644 --- a/libs/ledger-live-common/src/errors.ts +++ b/libs/ledger-live-common/src/errors.ts @@ -122,6 +122,7 @@ export const EConnResetError = createCustomErrorClass("EConnReset"); export { ClaimRewardsFeesWarning } from "@ledgerhq/errors"; export * from "@ledgerhq/coin-framework/errors"; export * from "@ledgerhq/coin-algorand/errors"; +export * from "@ledgerhq/coin-aptos/errors"; export * from "@ledgerhq/coin-bitcoin/errors"; export * from "@ledgerhq/coin-cardano/errors"; export * from "@ledgerhq/coin-cosmos/errors"; diff --git a/libs/ledger-live-common/src/families/aptos/LedgerAccount.test.ts b/libs/ledger-live-common/src/families/aptos/LedgerAccount.test.ts deleted file mode 100644 index 39490f9019a3..000000000000 --- a/libs/ledger-live-common/src/families/aptos/LedgerAccount.test.ts +++ /dev/null @@ -1,144 +0,0 @@ -import LedgerAccount from "./LedgerAccount"; -import { createFixtureAccount } from "../../mock/fixtures/cryptoCurrencies"; -import { AccountAddress, Hex, InputEntryFunctionData } from "@aptos-labs/ts-sdk"; -import HwAptos from "@ledgerhq/hw-app-aptos"; -import Transport from "@ledgerhq/hw-transport"; -import { AptosAPI } from "./api"; -import { APTOS_ASSET_ID } from "./constants"; -import { Account } from "../../e2e/enum/Account"; - -jest.mock("@ledgerhq/hw-app-aptos"); - -describe("LedgerAccount Test", () => { - it("Testing constructor", async () => { - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath); - const expected = { - hdPath: account.freshAddressPath, - publicKey: Buffer.from([]), - accountAddress: new AccountAddress(new Uint8Array(AccountAddress.LENGTH)), - }; - expect(ledger_account).toEqual(expected); - }); - - it("Testing init method", async () => { - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath); - const transport = {} as Transport; - const mockGetAddress = jest.fn().mockResolvedValue({ - address: account.freshAddress, - publicKey: Buffer.from("publicKey"), - }); - (HwAptos as jest.Mock).mockImplementation(() => { - return { - getAddress: mockGetAddress, - }; - }); - - await ledger_account.init(transport); - - expect(mockGetAddress).toHaveBeenCalledWith(account.freshAddressPath, false); - expect(ledger_account["publicKey"]).toEqual(Buffer.from("publicKey")); - expect(ledger_account["accountAddress"]).toEqual(AccountAddress.from(account.freshAddress)); - }); - - it("Testing authKey method", () => { - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath, account.freshAddress); - const authKey = ledger_account.authKey(); - - expect(authKey).toBeInstanceOf(AccountAddress); - }); - - it("Account needs init before asyncSignBuffer method", async () => { - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath); - - const mockSignTransaction = jest.fn().mockResolvedValue({ - signature: Buffer.from("signature"), - }); - const mockGetAddress = jest.fn().mockResolvedValue({ - address: account.freshAddress, - publicKey: Buffer.from("publicKey"), - }); - (HwAptos as jest.Mock).mockImplementation(() => { - return { - signTransaction: mockSignTransaction, - getAddress: mockGetAddress, - }; - }); - const buffer = new Uint8Array([1, 2, 3]); - expect(ledger_account.asyncSignBuffer(buffer)).rejects.toThrow(); - }); - - it("Testing asyncSignBuffer method", async () => { - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath); - const transport = {} as Transport; - const mockSignTransaction = jest.fn().mockResolvedValue({ - signature: Buffer.from("signature"), - }); - const mockGetAddress = jest.fn().mockResolvedValue({ - address: account.freshAddress, - publicKey: Buffer.from("publicKey"), - }); - (HwAptos as jest.Mock).mockImplementation(() => { - return { - signTransaction: mockSignTransaction, - getAddress: mockGetAddress, - }; - }); - - await ledger_account.init(transport); - const buffer = new Uint8Array([1, 2, 3]); - const signature = await ledger_account.asyncSignBuffer(buffer); - - expect(mockSignTransaction).toHaveBeenCalledWith(account.freshAddressPath, Buffer.from(buffer)); - expect(signature).toEqual(new Hex(new Uint8Array(Buffer.from("signature")))); - }); - - it("Testing signTransaction method", async () => { - const api = new AptosAPI("aptos"); - const account = createFixtureAccount(); - const ledger_account = new LedgerAccount(account.freshAddressPath); - const transport = {} as Transport; - - const mockSignTransaction = jest.fn().mockResolvedValue({ - signature: Buffer.from("0x13321ab5d9da6ea27ff47a89f55bb384f0cc0b04a755d5098fc5e0653179a1"), // random hex to fulfill expectation of 64 length - }); - const mockGetAddress = jest.fn().mockResolvedValue({ - address: account.freshAddress, - publicKey: Buffer.from("0x13321ab5d9da6ea27ff47a89f55bb8"), // random hex to fulfill expectations of 32 length - chainCode: Buffer.from(""), - }); - - (HwAptos as jest.Mock).mockImplementation(() => { - return { - signTransaction: mockSignTransaction, - getAddress: mockGetAddress, - }; - }); - - await ledger_account.init(transport); - const payload = { - function: "0x1::aptos_account::transfer_coins", - typeArguments: [APTOS_ASSET_ID], - functionArguments: [Account.APTOS_1.address, BigInt(1).toString()], - }; - const options = { - maxGasAmount: "100", - gasUnitPrice: "50", - sequenceNumber: "1", - expirationTimestampSecs: "1735639799486", - }; - - const rawTxn = await api.generateTransaction( - account.freshAddress, - payload as InputEntryFunctionData, - options, - ); - const signedTxn = await ledger_account.signTransaction(rawTxn); - - expect(signedTxn).toBeInstanceOf(Uint8Array); - }); -}); diff --git a/libs/ledger-live-common/src/families/aptos/LedgerAccount.ts b/libs/ledger-live-common/src/families/aptos/LedgerAccount.ts deleted file mode 100644 index 83ee820c844c..000000000000 --- a/libs/ledger-live-common/src/families/aptos/LedgerAccount.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { - AccountAddress, - AccountAuthenticatorEd25519, - Ed25519PublicKey, - Ed25519Signature, - Hex, - RawTransaction, - SimpleTransaction, - generateSignedTransaction, - generateSigningMessageForTransaction, -} from "@aptos-labs/ts-sdk"; -import HwAptos from "@ledgerhq/hw-app-aptos"; -import Transport from "@ledgerhq/hw-transport"; -import { sha3_256 as sha3Hash } from "@noble/hashes/sha3"; - -export default class LedgerAccount { - private readonly hdPath: string; - - private client?: HwAptos; - private publicKey: Buffer = Buffer.from([]); - private accountAddress: AccountAddress = new AccountAddress( - new Uint8Array(AccountAddress.LENGTH), - ); - - constructor(path: string, pubKey?: string) { - this.hdPath = path; - if (pubKey) { - this.publicKey = Buffer.from(AccountAddress.from(pubKey).toUint8Array()); - this.accountAddress = this.authKey(); - } - } - - async init(transport: Transport, display = false): Promise { - this.client = new HwAptos(transport); - if (!this.publicKey.length && !display) { - const response = await this.client.getAddress(this.hdPath, display); - this.accountAddress = AccountAddress.from(response.address); - this.publicKey = response.publicKey; - } - } - - authKey(): AccountAddress { - const hash = sha3Hash.create(); - hash.update(this.publicKey.toString("hex")); - hash.update("\x00"); - return AccountAddress.from(hash.digest()); - } - - async asyncSignBuffer(buffer: Uint8Array): Promise { - if (!this.client) { - throw new Error("LedgerAccount not initialized"); - } - const response = await this.client.signTransaction(this.hdPath, Buffer.from(buffer)); - return new Hex(new Uint8Array(response.signature)); - } - - async signTransaction(rawTxn: RawTransaction): Promise { - const signingMessage = generateSigningMessageForTransaction({ - rawTransaction: rawTxn, - } as SimpleTransaction); - const sigHexStr = await this.asyncSignBuffer(signingMessage); - const signature = new Ed25519Signature(sigHexStr.toUint8Array()); - const authenticator = new AccountAuthenticatorEd25519( - new Ed25519PublicKey(this.publicKey.toString("hex")), - signature, - ); - - return generateSignedTransaction({ - transaction: { rawTransaction: rawTxn } as SimpleTransaction, - senderAuthenticator: authenticator, - }); - } -} diff --git a/libs/ledger-live-common/src/families/aptos/__snapshots__/bridge.integration.test.ts.snap b/libs/ledger-live-common/src/families/aptos/__snapshots__/bridge.integration.test.ts.snap index d7e264eba4a1..e644391bce53 100644 --- a/libs/ledger-live-common/src/families/aptos/__snapshots__/bridge.integration.test.ts.snap +++ b/libs/ledger-live-common/src/families/aptos/__snapshots__/bridge.integration.test.ts.snap @@ -3,55 +3,55 @@ exports[`aptos currency bridge scanAccounts aptos seed 1 1`] = ` [ { - "balance": "30100", + "balance": "9593900", "currencyId": "aptos", "derivationMode": "", - "freshAddress": "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "freshAddress": "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", "freshAddressPath": "44'/637'/0'/0/0", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", "index": 0, - "operationsCount": 5, + "operationsCount": 30, "pendingOperations": [], - "seedIdentifier": "d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583", - "spendableBalance": "30100", + "seedIdentifier": "30cfd94a543eca9ba9d26eafe07f6c28e1e43e4768f3c0bad32efeced8662f87", + "spendableBalance": "9593900", "swapHistory": [], "syncHash": undefined, "used": true, - "xpub": "d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956", + "xpub": "4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b", }, { - "balance": "20000", + "balance": "81000", "currencyId": "aptos", "derivationMode": "", - "freshAddress": "0xd20fa44192f94ba086ab16bfdf57e43ff118ada69b4c66fa9b9a9223cbc068c1", + "freshAddress": "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", "freshAddressPath": "44'/637'/1'/0/0", - "id": "js:2:aptos:6a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e:", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", "index": 1, - "operationsCount": 1, + "operationsCount": 9, "pendingOperations": [], - "seedIdentifier": "d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583", - "spendableBalance": "20000", + "seedIdentifier": "30cfd94a543eca9ba9d26eafe07f6c28e1e43e4768f3c0bad32efeced8662f87", + "spendableBalance": "81000", "swapHistory": [], "syncHash": undefined, "used": true, - "xpub": "6a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e", + "xpub": "9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e", }, { "balance": "0", "currencyId": "aptos", "derivationMode": "", - "freshAddress": "0xf4bf78be42e07959793c98c7e8345bb948bf10b8e6baac5e368eab66d09a9671", + "freshAddress": "0x6f77c3db5bf0f3997586ffe14e7ecc1722ea30ef2654415a0d31ceea396a490e", "freshAddressPath": "44'/637'/2'/0/0", - "id": "js:2:aptos:8ffc0c2e141ead220f05b30fa01ce9a3783c5a157219f922b02ec194308b1b45:", + "id": "js:2:aptos:1fb77263c646810574525025561e4559c338b571f57f1b513d75b1609d5fa5f6:", "index": 2, "operationsCount": 0, "pendingOperations": [], - "seedIdentifier": "d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583", + "seedIdentifier": "30cfd94a543eca9ba9d26eafe07f6c28e1e43e4768f3c0bad32efeced8662f87", "spendableBalance": "0", "swapHistory": [], "syncHash": undefined, "used": false, - "xpub": "8ffc0c2e141ead220f05b30fa01ce9a3783c5a157219f922b02ec194308b1b45", + "xpub": "1fb77263c646810574525025561e4559c338b571f57f1b513d75b1609d5fa5f6", }, ] `; @@ -60,132 +60,825 @@ exports[`aptos currency bridge scanAccounts aptos seed 1 2`] = ` [ [ { - "accountId": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - "blockHash": "0x4c000b55c435dc0d1040d26a7ee782fb7e151748d41ea9126ebe6bbbf2e95111", - "blockHeight": 266342014, + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xece235905ecb0018aceb92d017c974f4d2fe1cc78621732bbc3a99ea6b39975a", + "blockHeight": 273956152, "extra": { - "version": "2066042051", + "version": "2162247463", }, "fee": "900", "hasFailed": false, - "hash": "0x1e85342da3a81f9c3a30c585677d3e50101d5731dcaf31cc157a3c694e6aece8", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:-0x1e85342da3a81f9c3a30c585677d3e50101d5731dcaf31cc157a3c694e6aece8-IN", + "hash": "0x0c4dff2ceccebad1ec992941b41888563dd557e576635131e077116d7b71df16", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x0c4dff2ceccebad1ec992941b41888563dd557e576635131e077116d7b71df16-OUT", "recipients": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", ], "senders": [ - "0xa0d8abc262e3321f87d745bd5d687e8f3fb14c87d48f840b6b56867df0026ec8", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], - "transactionSequenceNumber": 10, - "type": "IN", - "value": "100000", + "transactionSequenceNumber": 6, + "type": "OUT", + "value": "10900", }, { - "accountId": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - "blockHash": "0x46de657932759f16ffcda6ef6ace41996f263287e538d3e0f5cbf85994695247", - "blockHeight": 266316843, + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x3acc16b06e118fc7724d8f06cc26b61ec779762f4357885b70416753022f6bed", + "blockHeight": 274252362, "extra": { - "version": "2065700142", + "version": "2166011393", }, "fee": "900", "hasFailed": false, - "hash": "0x3c586d8c15c76848fbd3c84ddfbf11a1a07c92734da4dd8d530c9f23a0e7744c", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:-0x3c586d8c15c76848fbd3c84ddfbf11a1a07c92734da4dd8d530c9f23a0e7744c-IN", + "hash": "0x0d415c4de1815ec852f4c91afdb4adde7728186058375c206d50ab68a97d4f25", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x0d415c4de1815ec852f4c91afdb4adde7728186058375c206d50ab68a97d4f25-OUT", "recipients": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", ], "senders": [ - "0xa0d8abc262e3321f87d745bd5d687e8f3fb14c87d48f840b6b56867df0026ec8", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], - "transactionSequenceNumber": 9, - "type": "IN", - "value": "20000", + "transactionSequenceNumber": 14, + "type": "OUT", + "value": "10900", }, { - "accountId": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - "blockHash": "0xc546b75fd87fb75a2f328bebffade4ccf3345844eec4d2b6cf82e042fe9a7661", - "blockHeight": 266313878, + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xc2ec96838ae4aa4272987f7480315d22234e1c14de5f50da3854ba2b7f11c371", + "blockHeight": 255135504, "extra": { - "version": "2065659252", + "version": "1948860343", }, "fee": "99900", "hasFailed": false, - "hash": "0x5f2c2f597ab912dff9fe413b503036edbcc5488c03a4606f11eef868ed68258e", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:-0x5f2c2f597ab912dff9fe413b503036edbcc5488c03a4606f11eef868ed68258e-IN", + "hash": "0x12113c74d6896e36c752fcf76eab1321edbfa4798e33c06602355feefcf65d47", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x12113c74d6896e36c752fcf76eab1321edbfa4798e33c06602355feefcf65d47-IN", "recipients": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], "senders": [ - "0xa0d8abc262e3321f87d745bd5d687e8f3fb14c87d48f840b6b56867df0026ec8", + "0xaf0de7650b37343774f7863bba89c3356c28bed3c4e5e2a911b4d1d91e67a026", ], - "transactionSequenceNumber": 7, + "transactionSequenceNumber": 0, "type": "IN", - "value": "20000", + "value": "10000000", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x847a1006f41d37ab42c86ba2dadbc7e33212376359a5ab9e0153b382fb27121b", + "blockHeight": 274264802, + "extra": { + "version": "2166216504", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x12a9c3d76dc4addd3f966274c9400d554556ae30fece663d7c6b04e60be4cdd2", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x12a9c3d76dc4addd3f966274c9400d554556ae30fece663d7c6b04e60be4cdd2-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 18, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x36fb6a647421ede650f41b8105a9b137156b1dc2bf30393a3fd6d91c8230ecf3", + "blockHeight": 274251349, + "extra": { + "version": "2165996780", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x197e50a359e8dfd5023fc4216e3801ab54af82b691132b84fb6dac3f3c25280f", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x197e50a359e8dfd5023fc4216e3801ab54af82b691132b84fb6dac3f3c25280f-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 12, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x2649266f6fe57c753a7b71770587d3f28665f52a0ce8812038c52cd581085b9e", + "blockHeight": 276965591, + "extra": { + "version": "2199745699", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x1d6064f3bf30635f6cac94c96964737bf4ea602568fc76a1f0e6cd1693ca7347", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x1d6064f3bf30635f6cac94c96964737bf4ea602568fc76a1f0e6cd1693ca7347-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 27, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x182f7eeec19f2b5680aab3bd9c627aa490fed37e5d8c9ad87d45f5eea7c5d459", + "blockHeight": 272765848, + "extra": { + "version": "2148065947", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x1e1ad4377edf063f061a502130996b3fa808630383c406736887cdf219b3c844", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x1e1ad4377edf063f061a502130996b3fa808630383c406736887cdf219b3c844-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 2, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x13fe93cbb618816f468856ed424cd575638c332c0b618e8f57bfd78668147250", + "blockHeight": 274263702, + "extra": { + "version": "2166198757", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x24454a50bd1903d3c4589579ff28f935e7769d659e15f90f723ad15b04fd2223", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x24454a50bd1903d3c4589579ff28f935e7769d659e15f90f723ad15b04fd2223-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 17, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x930844bfae8abbc2b22041cd93511e595d9b30d862c4c3f9bbee176547d6f25e", + "blockHeight": 274252748, + "extra": { + "version": "2166016929", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x2ed969c5e279c59c218f698d7a47d13f18377b96d6aa00151277fe430bca1a92", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x2ed969c5e279c59c218f698d7a47d13f18377b96d6aa00151277fe430bca1a92-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 15, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xee1451f3ad1322e5faccd21f01f1a179b1e6da11b877bcb65d41da2fe26af8d6", + "blockHeight": 274253791, + "extra": { + "version": "2166031915", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x2f2803020328b57f0964b6af91ae4aad692b7aea2baed2bff152c9a4cb74722a", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x2f2803020328b57f0964b6af91ae4aad692b7aea2baed2bff152c9a4cb74722a-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 16, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x846338bfd20d6f1d19b9fa2d90586b733f7b57ae53385f809e5fd68ea818755c", + "blockHeight": 274637459, + "extra": { + "version": "2171300249", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x354a08c39bfe5130879c306d6a7b9f14d472639083013e3138e5ffbbbdc0e9ea", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x354a08c39bfe5130879c306d6a7b9f14d472639083013e3138e5ffbbbdc0e9ea-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 21, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x5e303773c909a74bd98ca07f934de699084c63b3cc87d54a2c61f0115eb5aa55", + "blockHeight": 275151233, + "extra": { + "version": "2177714422", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x3a83dd74795d433bf092e9dc2728f78477011208a14cd782e2e8ec7cc24ec72a", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x3a83dd74795d433bf092e9dc2728f78477011208a14cd782e2e8ec7cc24ec72a-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 24, + "type": "OUT", + "value": "10900", }, { - "accountId": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - "blockHash": "0x1bbe17059abba7dc500aca2eb174c217e71f3dcd7486cd4b27dc6136cce8a60a", - "blockHeight": 266315762, + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x8f5180c1d05e07a231674ac9e073eada15eab880c784e1bb9b218a2a3e2d9528", + "blockHeight": 273957210, "extra": { - "version": "2065684418", + "version": "2162262245", }, "fee": "900", "hasFailed": false, - "hash": "0xb74e3ab13f7a00faeb51c0e251602f53d387a64ac9fea7c76a8be3d0bf6f7a19", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:-0xb74e3ab13f7a00faeb51c0e251602f53d387a64ac9fea7c76a8be3d0bf6f7a19-IN", + "hash": "0x4559a08c7e7c0a6da05436636161d6dcc3d56cbb6bf388cb7068ac7c6c3ccf76", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x4559a08c7e7c0a6da05436636161d6dcc3d56cbb6bf388cb7068ac7c6c3ccf76-OUT", "recipients": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", ], "senders": [ - "0xa0d8abc262e3321f87d745bd5d687e8f3fb14c87d48f840b6b56867df0026ec8", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], "transactionSequenceNumber": 8, - "type": "IN", - "value": "10000", + "type": "OUT", + "value": "10900", }, { - "accountId": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - "blockHash": "0xf37ce698cf2e6d9e4a0048cd6d09fb3f19f417ab8251a3cc1f19b8d0e503538f", - "blockHeight": 266342506, + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x1b616ff9efb544248c599020fc7f5f48731f5a519895c23835f6b5cd2ea72eb0", + "blockHeight": 274268701, "extra": { - "version": "2066048548", + "version": "2166268639", }, - "fee": "99900", + "fee": "900", + "hasFailed": false, + "hash": "0x4587e36eccc1e25e28e934960676b826aad3224a884c9caa4c514016abf7620d", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x4587e36eccc1e25e28e934960676b826aad3224a884c9caa4c514016abf7620d-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 20, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x11092feb90640eb6dcd52b19682fac3c5641c1b87a2b99221d67d21d5a2a2152", + "blockHeight": 273961478, + "extra": { + "version": "2162324620", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x4843bc0597d8a594c827f84703ed6c0c509d65b5442dd6468e43a022a2a9f62f", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x4843bc0597d8a594c827f84703ed6c0c509d65b5442dd6468e43a022a2a9f62f-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 9, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x375cf7f4774203b182f862c802c3f361dd59a440f8aeb545f9879641079cdf59", + "blockHeight": 274637663, + "extra": { + "version": "2171303618", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x5cb25e49b437aa668add732e25f8b7f9cdc97d4c08f2398fe1eb820388850e02", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x5cb25e49b437aa668add732e25f8b7f9cdc97d4c08f2398fe1eb820388850e02-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 22, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xb401ed6e35281417d39232da2f93d81dd3016ecd25e4c35afa122410458872b4", + "blockHeight": 273962615, + "extra": { + "version": "2162341006", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x7eac94a074ed8d8e7fed10277e2284cb7eb9931a973302bfabc48856516b9a07", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x7eac94a074ed8d8e7fed10277e2284cb7eb9931a973302bfabc48856516b9a07-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 10, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xe014bd75045d58a433f438b18bc9eb7027706e21fc7d61621d45d075f55ef491", + "blockHeight": 274268237, + "extra": { + "version": "2166262611", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x97dfb6cf853a24c9ec04c6c953ae0fbebd114e6adea0900c6935bb194eef9f87", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x97dfb6cf853a24c9ec04c6c953ae0fbebd114e6adea0900c6935bb194eef9f87-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 19, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xb949089a48ab43eb96c83b1dbadf9f40905f396bce52a5b3d6e5e5df8b14bff5", + "blockHeight": 273956720, + "extra": { + "version": "2162255510", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x9d9ab9000a9d5ceadc755959da723781bcc1787fec0d92d6f22d54efd909e1f7", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0x9d9ab9000a9d5ceadc755959da723781bcc1787fec0d92d6f22d54efd909e1f7-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 7, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x4252a39a7b8295171e90c81c40e044a9b4b3a4178ef986c17dc97161aeea17fd", + "blockHeight": 273949985, + "extra": { + "version": "2162159703", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xa1c75b968e777ef4d2e53d5beafe32252f3eb0a642c68ef1e873919a402f0f1d", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xa1c75b968e777ef4d2e53d5beafe32252f3eb0a642c68ef1e873919a402f0f1d-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 4, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x94ad47763b53fd9e1c8667f3d3819d72844cc328b4bdc765dfd749007a4af163", + "blockHeight": 275453413, + "extra": { + "version": "2181349814", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xa6440f36bb8050e5c8e173886969e99440ac211178877cf1879b285bfd83045e", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xa6440f36bb8050e5c8e173886969e99440ac211178877cf1879b285bfd83045e-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 25, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x84fc8939d6d3b1ba6d6ee22ef00ca6fdc72823544561199da56ab082ee4e7914", + "blockHeight": 261398871, + "extra": { + "version": "2014010375", + }, + "fee": "900", "hasFailed": false, - "hash": "0xf980601fe40ad1dab0cc68fe08d2bc95c73e2a21c6d257475e0879394638058e", - "id": "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:-0xf980601fe40ad1dab0cc68fe08d2bc95c73e2a21c6d257475e0879394638058e-OUT", + "hash": "0xb1051c4496cd2f2871e4efc3645685cd9632984cd15f1226b5ec5e2232e353fd", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xb1051c4496cd2f2871e4efc3645685cd9632984cd15f1226b5ec5e2232e353fd-OUT", "recipients": [ - "0xd20fa44192f94ba086ab16bfdf57e43ff118ada69b4c66fa9b9a9223cbc068c1", + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", ], "senders": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], "transactionSequenceNumber": 0, "type": "OUT", - "value": "119900", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xe8d5d389146e09689b57af156ddae67c0496b971db923bd50dd0a4562334328f", + "blockHeight": 274641986, + "extra": { + "version": "2171367550", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xbbfc526a4a355e007fa14d9d0b0e1e5ea8f27265e40ec232d26d070ed757fc47", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xbbfc526a4a355e007fa14d9d0b0e1e5ea8f27265e40ec232d26d070ed757fc47-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 23, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x4d14177a2f5f4f557e781aefb1d03fe7cd43f15931a22491a0c0ed3bae331045", + "blockHeight": 274251949, + "extra": { + "version": "2166005585", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xc3ac40ad860070744b5554508fd215f566a828144d718a1cf07ef1fba89c1016", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xc3ac40ad860070744b5554508fd215f566a828144d718a1cf07ef1fba89c1016-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 13, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x2d2ab86a115539ed35c356130d2c3a4ec3fda2e46da9a4276f5ae5fb347b2df1", + "blockHeight": 272766647, + "extra": { + "version": "2148076098", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xd6a30fa7a9e2fb78777e979bf0be87857ca737d5037546352334afbd90a729d4", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xd6a30fa7a9e2fb78777e979bf0be87857ca737d5037546352334afbd90a729d4-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 3, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0xd13466efd8e22cb364c5c51f9160912ab47f621ac96e8da2f3cf01d02cbbf4c6", + "blockHeight": 280949630, + "extra": { + "version": "2245923990", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xd7dc53cf183fe1558b35eaf084135b297598d0c406cf1273c7b76836aa99c900", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xd7dc53cf183fe1558b35eaf084135b297598d0c406cf1273c7b76836aa99c900-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 28, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x321829c14b11a90a3c4037b697f646516e0ca5058decaeeafcba00a7b526c42f", + "blockHeight": 273954853, + "extra": { + "version": "2162228874", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xe74cf1491d353e510a6c2362de11eefd7179913b74d14d9310abbaf70b656caa", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xe74cf1491d353e510a6c2362de11eefd7179913b74d14d9310abbaf70b656caa-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 5, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x953fa3dbab1b503abfa673fce9f1202f319605e8c02270f75ce27f1dfa57771a", + "blockHeight": 273964656, + "extra": { + "version": "2162369921", + }, + "fee": "99900", + "hasFailed": false, + "hash": "0xf543e0ec9634ea5449e85d47a6e0f6110d39599535e7cd623ccebeac6fec011c", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xf543e0ec9634ea5449e85d47a6e0f6110d39599535e7cd623ccebeac6fec011c-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 11, + "type": "OUT", + "value": "100900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x4c64a1bea89bfb2db0596057c8a07002f8df826cf460b65ffb52ae24a1b5d870", + "blockHeight": 272765025, + "extra": { + "version": "2148055516", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xf63cb3b4a8c71a1aff8d6e21d4babb8c263b4d3bf68f72066118d8c91773424c", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xf63cb3b4a8c71a1aff8d6e21d4babb8c263b4d3bf68f72066118d8c91773424c-OUT", + "recipients": [ + "0x6c0e2e27005620ea8e0f11762687b0e5483b721c8407dc855c6f7127f8881371", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 1, + "type": "OUT", + "value": "10900", + }, + { + "accountId": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:", + "blockHash": "0x26d756aa919bc58b7bda8f3eb48f91690dc791c0ba4e7795f71d4ac20225bab9", + "blockHeight": 276963274, + "extra": { + "version": "2199716907", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xffdd90a772d8a5f540f8af6617b9bf994c120499338c9e50106af140f288a30b", + "id": "js:2:aptos:4b16bdc2f72ea4502a8c4879c72e71d4d1a8ec46c43620e00a6f46e0b7569c6b:-0xffdd90a772d8a5f540f8af6617b9bf994c120499338c9e50106af140f288a30b-OUT", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 26, + "type": "OUT", + "value": "10900", }, ], [ { - "accountId": "js:2:aptos:6a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e:", - "blockHash": "0xf37ce698cf2e6d9e4a0048cd6d09fb3f19f417ab8251a3cc1f19b8d0e503538f", - "blockHeight": 266342506, + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x2649266f6fe57c753a7b71770587d3f28665f52a0ce8812038c52cd581085b9e", + "blockHeight": 276965591, "extra": { - "version": "2066048548", + "version": "2199745699", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x1d6064f3bf30635f6cac94c96964737bf4ea602568fc76a1f0e6cd1693ca7347", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0x1d6064f3bf30635f6cac94c96964737bf4ea602568fc76a1f0e6cd1693ca7347-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 27, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x846338bfd20d6f1d19b9fa2d90586b733f7b57ae53385f809e5fd68ea818755c", + "blockHeight": 274637459, + "extra": { + "version": "2171300249", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x354a08c39bfe5130879c306d6a7b9f14d472639083013e3138e5ffbbbdc0e9ea", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0x354a08c39bfe5130879c306d6a7b9f14d472639083013e3138e5ffbbbdc0e9ea-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 21, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x5e303773c909a74bd98ca07f934de699084c63b3cc87d54a2c61f0115eb5aa55", + "blockHeight": 275151233, + "extra": { + "version": "2177714422", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x3a83dd74795d433bf092e9dc2728f78477011208a14cd782e2e8ec7cc24ec72a", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0x3a83dd74795d433bf092e9dc2728f78477011208a14cd782e2e8ec7cc24ec72a-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 24, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x375cf7f4774203b182f862c802c3f361dd59a440f8aeb545f9879641079cdf59", + "blockHeight": 274637663, + "extra": { + "version": "2171303618", + }, + "fee": "900", + "hasFailed": false, + "hash": "0x5cb25e49b437aa668add732e25f8b7f9cdc97d4c08f2398fe1eb820388850e02", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0x5cb25e49b437aa668add732e25f8b7f9cdc97d4c08f2398fe1eb820388850e02-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 22, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x94ad47763b53fd9e1c8667f3d3819d72844cc328b4bdc765dfd749007a4af163", + "blockHeight": 275453413, + "extra": { + "version": "2181349814", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xa6440f36bb8050e5c8e173886969e99440ac211178877cf1879b285bfd83045e", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0xa6440f36bb8050e5c8e173886969e99440ac211178877cf1879b285bfd83045e-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 25, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0xe8d5d389146e09689b57af156ddae67c0496b971db923bd50dd0a4562334328f", + "blockHeight": 274641986, + "extra": { + "version": "2171367550", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xbbfc526a4a355e007fa14d9d0b0e1e5ea8f27265e40ec232d26d070ed757fc47", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0xbbfc526a4a355e007fa14d9d0b0e1e5ea8f27265e40ec232d26d070ed757fc47-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 23, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0xd13466efd8e22cb364c5c51f9160912ab47f621ac96e8da2f3cf01d02cbbf4c6", + "blockHeight": 280949630, + "extra": { + "version": "2245923990", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xd7dc53cf183fe1558b35eaf084135b297598d0c406cf1273c7b76836aa99c900", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0xd7dc53cf183fe1558b35eaf084135b297598d0c406cf1273c7b76836aa99c900-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 28, + "type": "IN", + "value": "10000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x953fa3dbab1b503abfa673fce9f1202f319605e8c02270f75ce27f1dfa57771a", + "blockHeight": 273964656, + "extra": { + "version": "2162369921", }, "fee": "99900", "hasFailed": false, - "hash": "0xf980601fe40ad1dab0cc68fe08d2bc95c73e2a21c6d257475e0879394638058e", - "id": "js:2:aptos:6a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e:-0xf980601fe40ad1dab0cc68fe08d2bc95c73e2a21c6d257475e0879394638058e-IN", + "hash": "0xf543e0ec9634ea5449e85d47a6e0f6110d39599535e7cd623ccebeac6fec011c", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0xf543e0ec9634ea5449e85d47a6e0f6110d39599535e7cd623ccebeac6fec011c-IN", "recipients": [ - "0xd20fa44192f94ba086ab16bfdf57e43ff118ada69b4c66fa9b9a9223cbc068c1", + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", ], "senders": [ - "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", ], - "transactionSequenceNumber": 0, + "transactionSequenceNumber": 11, "type": "IN", - "value": "20000", + "value": "1000", + }, + { + "accountId": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:", + "blockHash": "0x26d756aa919bc58b7bda8f3eb48f91690dc791c0ba4e7795f71d4ac20225bab9", + "blockHeight": 276963274, + "extra": { + "version": "2199716907", + }, + "fee": "900", + "hasFailed": false, + "hash": "0xffdd90a772d8a5f540f8af6617b9bf994c120499338c9e50106af140f288a30b", + "id": "js:2:aptos:9aec773c4b645bba274924e2e8aeea525ba37051c94bfd922b60c87b1692091e:-0xffdd90a772d8a5f540f8af6617b9bf994c120499338c9e50106af140f288a30b-IN", + "recipients": [ + "0x98739115d8ba968aa0870a1ce6a988a0cb5aeb2e5f0cb5a0f346c7a1bb7e4a27", + ], + "senders": [ + "0xb69a68cc64f7aa193705193f4dd598320a0a74baf7e4b50c9980c5bd60a82390", + ], + "transactionSequenceNumber": 26, + "type": "IN", + "value": "10000", }, ], [], diff --git a/libs/ledger-live-common/src/families/aptos/bridge.integration.test.ts b/libs/ledger-live-common/src/families/aptos/bridge.integration.test.ts index fe4667c907e3..1086f718269f 100644 --- a/libs/ledger-live-common/src/families/aptos/bridge.integration.test.ts +++ b/libs/ledger-live-common/src/families/aptos/bridge.integration.test.ts @@ -1,92 +1,5 @@ -import { CurrenciesData, DatasetTest } from "@ledgerhq/types-live"; -import BigNumber from "bignumber.js"; -import { testBridge } from "../../__tests__/test-helpers/bridge"; import "../../__tests__/test-helpers/setup"; -import { fromTransactionRaw } from "./transaction"; -import { Transaction } from "./types"; - -const aptos: CurrenciesData = { - scanAccounts: [ - { - name: "aptos seed 1", - apdus: ` - => 5b0500000d038000002c8000027d80000000 - <= 2104d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583204bb135642f160c72c323d57ad509b904ff44d9f2b983e8b90468e19b6f431ea79000 - => 5b05000015058000002c8000027d800000008000000080000000 - <= 2104d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956200d8d6cf19a090a8080768d07a848acc333775e5327d2da8a4022301f7dbb88ff9000 - => 5b05000015058000002c8000027d800000008000000080000000 - <= 2104d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956200d8d6cf19a090a8080768d07a848acc333775e5327d2da8a4022301f7dbb88ff9000 - => 5b05000015058000002c8000027d800000018000000080000000 - <= 21046a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e208e72477f799c2d3b2899b32b114988ab3d1af02dd0d3562196eccded2936f8449000 - => 5b05000015058000002c8000027d800000018000000080000000 - <= 21046a7712fdac0cb4ed27076c707e7798be52cf6c93a2d43d5cf9b874d0a45a111e208e72477f799c2d3b2899b32b114988ab3d1af02dd0d3562196eccded2936f8449000 - => 5b05000015058000002c8000027d800000028000000080000000 - <= 21048ffc0c2e141ead220f05b30fa01ce9a3783c5a157219f922b02ec194308b1b452084cf4bdff7814f8c3d08bfceb9d2615bf8c6850b208477528f8376c4250e4b5a9000 - => 5b05000015058000002c8000027d800000028000000080000000 - <= 21048ffc0c2e141ead220f05b30fa01ce9a3783c5a157219f922b02ec194308b1b452084cf4bdff7814f8c3d08bfceb9d2615bf8c6850b208477528f8376c4250e4b5a9000 - `, - }, - ], - accounts: [ - { - raw: { - id: "js:2:aptos:d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956:", - seedIdentifier: "d6816f4f22f867b56cf9304b776f452a16d107835d73ee8a33c4ced210300583", - used: true, - derivationMode: "", - index: 0, - freshAddress: "0x445fa0013887abd1a0c14acdec6e48090e0ad3fed3e08202aac15ca14f3be26b", - freshAddressPath: "44'/637'/0'/0/0", - blockHeight: 266360751, - creationDate: "2024-12-18T12:26:31.070Z", - operationsCount: 5, - operations: [], - pendingOperations: [], - currencyId: "aptos", - lastSyncDate: "2024-12-18T15:20:55.097Z", - balance: "30100", - spendableBalance: "30100", - balanceHistoryCache: { - HOUR: { balances: [0, 50000, 50000, 30100], latestDate: 1734534000000 }, - DAY: { balances: [0], latestDate: 1734480000000 }, - WEEK: { balances: [0], latestDate: 1734220800000 }, - }, - xpub: "d1a8c6a1cdd52dd40c7ea61ee4571fb51fcae440a594c1eca18636928f1d3956", - swapHistory: [], - }, - transactions: [ - { - name: "NO_NAME", - transaction: fromTransactionRaw({ - amount: "20000", - recipient: "0xd20fa44192f94ba086ab16bfdf57e43ff118ada69b4c66fa9b9a9223cbc068c1", - useAllAmount: false, - family: "aptos", - mode: "send", - fees: "1100", - options: '{ "maxGasAmount": "11", "gasUnitPrice": "100"}', - errors: "{}", - }), - expectedStatus: () => - // you can use account and transaction for smart logic. drop the =>fn otherwise - ({ - errors: {}, - warnings: {}, - estimatedFees: BigNumber("900"), - amount: BigNumber("20000"), - totalSpent: BigNumber("20900"), - }), - }, - ], - }, - ], -}; - -const dataset: DatasetTest = { - implementations: ["js"], - currencies: { - aptos, - }, -}; +import { testBridge } from "../../__tests__/test-helpers/bridge"; +import { dataset } from "@ledgerhq/coin-aptos/test/index"; testBridge(dataset); diff --git a/libs/ledger-live-common/src/families/aptos/bridge/js.ts b/libs/ledger-live-common/src/families/aptos/bridge/js.ts deleted file mode 100644 index 634ce39005f8..000000000000 --- a/libs/ledger-live-common/src/families/aptos/bridge/js.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { AccountBridge, CurrencyBridge } from "@ledgerhq/types-live"; -import { getSerializedAddressParameters } from "@ledgerhq/coin-framework/bridge/jsHelpers"; -import { updateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers"; -import type { Transaction } from "../types"; -import { makeAccountBridgeReceive } from "../../../bridge/jsHelpers"; -import { sync, scanAccounts } from "../synchronisation"; -import getTransactionStatus from "../getTransactionStatus"; -import prepareTransaction from "../prepareTransaction"; -import createTransaction from "../createTransaction"; -import estimateMaxSpendable from "../estimateMaxSpendable"; -import signOperation from "../signOperation"; -import broadcast from "../broadcast"; - -const currencyBridge: CurrencyBridge = { - preload: () => Promise.resolve({}), - hydrate: () => {}, - scanAccounts, -}; - -const receive = makeAccountBridgeReceive(); - -const accountBridge: AccountBridge = { - estimateMaxSpendable, - createTransaction, - updateTransaction, - getTransactionStatus, - getSerializedAddressParameters, - prepareTransaction, - sync, - receive, - signOperation, - broadcast, -}; - -export default { currencyBridge, accountBridge }; diff --git a/libs/ledger-live-common/src/families/aptos/bridge/mock.ts b/libs/ledger-live-common/src/families/aptos/bridge/mock.ts deleted file mode 100644 index 36d7907358be..000000000000 --- a/libs/ledger-live-common/src/families/aptos/bridge/mock.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { getSerializedAddressParameters } from "@ledgerhq/coin-framework/bridge/jsHelpers"; -import { BigNumber } from "bignumber.js"; -import { - AmountRequired, - NotEnoughBalance, - RecipientRequired, - InvalidAddress, - InvalidAddressBecauseDestinationIsAlsoSource, -} from "@ledgerhq/errors"; -import type { Account, AccountBridge, AccountLike, CurrencyBridge } from "@ledgerhq/types-live"; -import type { Transaction, TransactionStatus } from "../types"; -import { DEFAULT_GAS, DEFAULT_GAS_PRICE } from "../logic"; -import { - scanAccounts, - signOperation, - broadcast, - sync, - makeAccountBridgeReceive, -} from "../../../bridge/mockHelpers"; -import { updateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers"; -import { getMainAccount } from "../../../account"; - -const receive = makeAccountBridgeReceive(); - -const createTransaction = (): Transaction => ({ - family: "aptos", - mode: "send", - amount: BigNumber(0), - recipient: "", - useAllAmount: false, - fees: new BigNumber(0.0001), - options: { - maxGasAmount: DEFAULT_GAS.toString(), - gasUnitPrice: DEFAULT_GAS_PRICE.toString(), - }, -}); - -const getTransactionStatus = async (a: Account, t: Transaction): Promise => { - const errors: TransactionStatus["errors"] = {}; - const warnings: TransactionStatus["warnings"] = {}; - - const { balance } = a; - const { address } = getAddress(a); - const { recipient, useAllAmount } = t; - let { amount } = t; - - if (!recipient) errors.recipient = new RecipientRequired(); - else if (!isAddressValid()) - errors.recipient = new InvalidAddress("", { - currencyName: a.currency.name, - }); - else if (recipient.toLowerCase() === address.toLowerCase()) - errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource(); - - if (!isAddressValid()) - errors.sender = new InvalidAddress("", { - currencyName: a.currency.name, - }); - - let estimatedFees = t.fees; - - if (!estimatedFees) estimatedFees = new BigNumber(0); - - let totalSpent = BigNumber(0); - - if (useAllAmount) { - totalSpent = a.spendableBalance; - amount = totalSpent.minus(estimatedFees); - if (amount.lte(0) || totalSpent.gt(balance)) { - errors.amount = new NotEnoughBalance(); - } - } - - if (!useAllAmount) { - totalSpent = amount.plus(estimatedFees); - if (amount.eq(0)) { - errors.amount = new AmountRequired(); - } - - if (totalSpent.gt(a.spendableBalance)) { - errors.amount = new NotEnoughBalance(); - } - } - - return { - errors, - warnings, - estimatedFees, - amount, - totalSpent, - }; -}; - -const prepareTransaction = async (a: Account, t: Transaction): Promise => { - const { address } = getAddress(a); - const { recipient } = t; - - if (recipient && address) { - if (t.useAllAmount) { - const amount = a.spendableBalance.minus(t.fees ? t.fees : new BigNumber(0)); - return { ...t, amount }; - } - } - - return t; -}; - -const estimateMaxSpendable = async ({ - account, - parentAccount, - transaction, -}: { - account: AccountLike; - parentAccount?: Account | null | undefined; - transaction?: Transaction | null | undefined; -}): Promise => { - const a = getMainAccount(account, parentAccount); - let balance = a.spendableBalance; - - if (balance.eq(0)) return balance; - - const estimatedFees = transaction?.fees ?? getEstimatedFees(); - - if (balance.lte(estimatedFees)) return new BigNumber(0); - - balance = balance.minus(estimatedFees); - - return balance; -}; - -const preload = async () => ({}); - -const hydrate = () => {}; - -const getAddress = ( - a: Account, -): { - address: string; - derivationPath: string; -} => ({ address: a.freshAddress, derivationPath: a.freshAddressPath }); - -const isAddressValid = (): boolean => { - try { - return true; - } catch (err) { - return false; - } -}; - -const getEstimatedFees = (): BigNumber => { - return new BigNumber(0); -}; - -const currencyBridge: CurrencyBridge = { - preload, - hydrate, - scanAccounts, -}; - -const accountBridge: AccountBridge = { - getSerializedAddressParameters, - createTransaction, - updateTransaction, - prepareTransaction, - getTransactionStatus, - sync, - receive, - signOperation, - broadcast, - estimateMaxSpendable, -}; - -export default { - currencyBridge, - accountBridge, -}; diff --git a/libs/ledger-live-common/src/families/aptos/hw-getAddress.ts b/libs/ledger-live-common/src/families/aptos/hw-getAddress.ts deleted file mode 100644 index 46349e337de9..000000000000 --- a/libs/ledger-live-common/src/families/aptos/hw-getAddress.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Aptos from "@ledgerhq/hw-app-aptos"; -import type { Resolver } from "../../hw/getAddress/types"; -import type { AptosAddress } from "./types"; - -const resolver: Resolver = async (transport, { path, verify }): Promise => { - const aptos = new Aptos(transport); - - const r = await aptos.getAddress(path, verify || false); - - return { - address: r.address, - publicKey: r.publicKey.toString("hex"), - path, - }; -}; - -export default resolver; diff --git a/libs/ledger-live-common/src/families/aptos/setup.ts b/libs/ledger-live-common/src/families/aptos/setup.ts new file mode 100644 index 000000000000..1b8d37046986 --- /dev/null +++ b/libs/ledger-live-common/src/families/aptos/setup.ts @@ -0,0 +1,29 @@ +// Goal of this file is to inject all necessary device/signer dependency to coin-modules + +import { + AptosAccount, + TransactionStatus, + createBridges, + type Transaction, +} from "@ledgerhq/coin-aptos"; +import Transport from "@ledgerhq/hw-transport"; +import Aptos from "@ledgerhq/hw-app-aptos"; +import type { Bridge } from "@ledgerhq/types-live"; +import aptosResolver from "@ledgerhq/coin-aptos/signer/index"; +import makeCliTools from "@ledgerhq/coin-aptos/test/cli"; +import { CreateSigner, createResolver, executeWithSigner } from "../../bridge/setup"; +import { Resolver } from "../../hw/getAddress/types"; + +const createSigner: CreateSigner = (transport: Transport) => { + return new Aptos(transport); +}; + +const bridge: Bridge = createBridges( + executeWithSigner(createSigner), +); + +const resolver: Resolver = createResolver(createSigner, aptosResolver); + +const cliTools = makeCliTools(); + +export { bridge, cliTools, resolver }; diff --git a/libs/ledger-live-common/src/families/aptos/signOperation.ts b/libs/ledger-live-common/src/families/aptos/signOperation.ts deleted file mode 100644 index c0d62db60ead..000000000000 --- a/libs/ledger-live-common/src/families/aptos/signOperation.ts +++ /dev/null @@ -1,91 +0,0 @@ -import type { Transaction } from "./types"; -import { Observable } from "rxjs"; -import { withDevice } from "../../hw/deviceAccess"; -import { encodeOperationId } from "../../operation"; -import buildTransaction from "./buildTransaction"; -import BigNumber from "bignumber.js"; - -import type { - Account, - Operation, - OperationType, - SignOperationFnSignature, -} from "@ledgerhq/types-live"; -import { AptosAPI } from "./api"; -import LedgerAccount from "./LedgerAccount"; - -const signOperation: SignOperationFnSignature = ({ - account, - deviceId, - transaction, -}: { - account: Account; - deviceId: any; - transaction: Transaction; -}) => - withDevice(deviceId)( - transport => - new Observable(o => { - async function main() { - const aptosClient = new AptosAPI(account.currency.id); - - o.next({ type: "device-signature-requested" }); - - const ledgerAccount = new LedgerAccount(account.freshAddressPath, account.xpub as string); - await ledgerAccount.init(transport); - - const rawTx = await buildTransaction(account, transaction, aptosClient); - const txBytes = await ledgerAccount.signTransaction(rawTx); - const signed = Buffer.from(txBytes).toString("hex"); - - o.next({ type: "device-signature-granted" }); - - const hash = ""; - const accountId = account.id; - const fee = transaction.fees || new BigNumber(0); - const extra = {}; - const type: OperationType = "OUT"; - const senders: string[] = []; - const recipients: string[] = []; - - if (transaction.mode === "send") { - senders.push(account.freshAddress); - recipients.push(transaction.recipient); - } - - // build optimistic operation - const operation: Operation = { - id: encodeOperationId(accountId, hash, type), - hash, - type, - value: transaction.useAllAmount - ? account.balance.minus(fee) - : transaction.amount.plus(fee), - fee, - extra, - blockHash: null, - blockHeight: null, - senders, - recipients, - accountId, - date: new Date(), - transactionSequenceNumber: Number(rawTx.sequence_number), - }; - - o.next({ - type: "signed", - signedOperation: { - operation, - signature: signed, - }, - }); - } - - main().then( - () => o.complete(), - e => o.error(e), - ); - }), - ); - -export default signOperation; diff --git a/libs/ledger-live-common/src/families/aptos/synchronisation.ts b/libs/ledger-live-common/src/families/aptos/synchronisation.ts deleted file mode 100644 index 2e692a3dce1a..000000000000 --- a/libs/ledger-live-common/src/families/aptos/synchronisation.ts +++ /dev/null @@ -1,67 +0,0 @@ -import Aptos from "@ledgerhq/hw-app-aptos"; -import { firstValueFrom, from } from "rxjs"; -import { decodeAccountId, encodeAccountId } from "../../account"; -import type { GetAccountShape } from "../../bridge/jsHelpers"; -import { makeScanAccounts, makeSync, mergeOps } from "../../bridge/jsHelpers"; -import { withDevice } from "../../hw/deviceAccess"; -import { AptosAPI } from "./api"; -import { txsToOps } from "./logic"; -import type { AptosAccount } from "./types"; - -export const getAccountShape: GetAccountShape = async info => { - const { address, initialAccount, derivationMode, currency, deviceId, derivationPath } = info; - - // "xpub" field is used to store publicKey to simulate transaction during sending tokens. - // We can't get access to the Nano X via bluetooth on the step of simulation - // but we need public key to simulate transaction. - // "xpub" field is used because this field exists in ledger operation type - let xpub = initialAccount?.xpub; - if (!initialAccount?.xpub && typeof deviceId === "string") { - const result = await firstValueFrom( - withDevice(deviceId)(transport => from(new Aptos(transport).getAddress(derivationPath))), - ); - xpub = Buffer.from(result.publicKey).toString("hex"); - } - if (!xpub && initialAccount?.id) { - const { xpubOrAddress } = decodeAccountId(initialAccount.id); - xpub = xpubOrAddress; - } - if (!xpub) { - // This is the corner case. We don't expect this happens - throw new Error("Unable to retrieve public key"); - } - - const oldOperations = initialAccount?.operations || []; - const startAt = (oldOperations[0]?.extra as any)?.version; - - const accountId = encodeAccountId({ - type: "js", - version: "2", - currencyId: currency.id, - xpubOrAddress: xpub as string, - derivationMode, - }); - - const aptosClient = new AptosAPI(currency.id); - const { balance, transactions, blockHeight } = await aptosClient.getAccountInfo(address, startAt); - - const newOperations = txsToOps(info, accountId, transactions); - const operations = mergeOps(oldOperations, newOperations); - - const shape: Partial = { - type: "Account", - id: accountId, - xpub, - balance: balance, - spendableBalance: balance, - operations, - operationsCount: operations.length, - blockHeight, - lastSyncDate: new Date(), - }; - - return shape; -}; - -export const scanAccounts = makeScanAccounts({ getAccountShape }); -export const sync = makeSync({ getAccountShape, shouldMergeOps: false }); diff --git a/libs/ledger-live-common/src/generated/bridge/js.ts b/libs/ledger-live-common/src/generated/bridge/js.ts index 7c6be6699d05..d16d53670a68 100644 --- a/libs/ledger-live-common/src/generated/bridge/js.ts +++ b/libs/ledger-live-common/src/generated/bridge/js.ts @@ -1,7 +1,7 @@ -import aptos from "../../families/aptos/bridge/js"; import casper from "../../families/casper/bridge/js"; import celo from "../../families/celo/bridge/js"; import { bridge as algorand } from "../../families/algorand/setup"; +import { bridge as aptos } from "../../families/aptos/setup"; import { bridge as bitcoin } from "../../families/bitcoin/setup"; import { bridge as cardano } from "../../families/cardano/setup"; import { bridge as cosmos } from "../../families/cosmos/setup"; @@ -23,10 +23,10 @@ import { bridge as vechain } from "../../families/vechain/setup"; import { bridge as xrp } from "../../families/xrp/setup"; export default { - aptos, casper, celo, algorand, + aptos, bitcoin, cardano, cosmos, diff --git a/libs/ledger-live-common/src/generated/bridge/mock.ts b/libs/ledger-live-common/src/generated/bridge/mock.ts index 9e1541f46899..a4b5ae66cce5 100644 --- a/libs/ledger-live-common/src/generated/bridge/mock.ts +++ b/libs/ledger-live-common/src/generated/bridge/mock.ts @@ -1,5 +1,4 @@ import algorand from "../../families/algorand/bridge/mock"; -import aptos from "../../families/aptos/bridge/mock"; import bitcoin from "../../families/bitcoin/bridge/mock"; import cardano from "../../families/cardano/bridge/mock"; import casper from "../../families/casper/bridge/mock"; @@ -16,7 +15,6 @@ import xrp from "../../families/xrp/bridge/mock"; export default { algorand, - aptos, bitcoin, cardano, casper, diff --git a/libs/ledger-live-common/src/generated/cli-transaction.ts b/libs/ledger-live-common/src/generated/cli-transaction.ts index 6257f528b8e7..3bbd0cb1f22e 100644 --- a/libs/ledger-live-common/src/generated/cli-transaction.ts +++ b/libs/ledger-live-common/src/generated/cli-transaction.ts @@ -1,5 +1,6 @@ import celo from "../families/celo/cli-transaction"; import { cliTools as algorand } from "../families/algorand/setup"; +import { cliTools as aptos } from "../families/aptos/setup"; import { cliTools as bitcoin } from "../families/bitcoin/setup"; import { cliTools as cardano } from "../families/cardano/setup"; import { cliTools as cosmos } from "../families/cosmos/setup"; @@ -23,6 +24,7 @@ import { cliTools as xrp } from "../families/xrp/setup"; export default { celo, algorand, + aptos, bitcoin, cardano, cosmos, diff --git a/libs/ledger-live-common/src/generated/deviceTransactionConfig.ts b/libs/ledger-live-common/src/generated/deviceTransactionConfig.ts index 87cd3a74dc6a..566ba39b78f3 100644 --- a/libs/ledger-live-common/src/generated/deviceTransactionConfig.ts +++ b/libs/ledger-live-common/src/generated/deviceTransactionConfig.ts @@ -1,7 +1,7 @@ -import aptos from "../families/aptos/deviceTransactionConfig"; import casper from "../families/casper/deviceTransactionConfig"; import celo from "../families/celo/deviceTransactionConfig"; import algorand from "@ledgerhq/coin-algorand/deviceTransactionConfig"; +import aptos from "@ledgerhq/coin-aptos/deviceTransactionConfig"; import bitcoin from "@ledgerhq/coin-bitcoin/deviceTransactionConfig"; import cardano from "@ledgerhq/coin-cardano/deviceTransactionConfig"; import cosmos from "@ledgerhq/coin-cosmos/deviceTransactionConfig"; @@ -22,10 +22,10 @@ import tron from "@ledgerhq/coin-tron/deviceTransactionConfig"; import xrp from "@ledgerhq/coin-xrp/deviceTransactionConfig"; export default { - aptos, casper, celo, algorand, + aptos, bitcoin, cardano, cosmos, @@ -45,16 +45,16 @@ export default { tron, xrp, }; -import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_aptos } from "../families/aptos/deviceTransactionConfig"; import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_casper } from "../families/casper/deviceTransactionConfig"; +import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_aptos } from "@ledgerhq/coin-aptos/bridge/deviceTransactionConfig"; import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_filecoin } from "@ledgerhq/coin-filecoin/bridge/deviceTransactionConfig"; import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_stacks } from "@ledgerhq/coin-stacks/bridge/deviceTransactionConfig"; import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_polkadot } from "@ledgerhq/coin-polkadot/bridge/deviceTransactionConfig"; import { ExtraDeviceTransactionField as ExtraDeviceTransactionField_tron } from "@ledgerhq/coin-tron/bridge/deviceTransactionConfig"; export type ExtraDeviceTransactionField = - | ExtraDeviceTransactionField_aptos | ExtraDeviceTransactionField_casper + | ExtraDeviceTransactionField_aptos | ExtraDeviceTransactionField_filecoin | ExtraDeviceTransactionField_stacks | ExtraDeviceTransactionField_polkadot diff --git a/libs/ledger-live-common/src/generated/hw-getAddress.ts b/libs/ledger-live-common/src/generated/hw-getAddress.ts index ee8b677a5e42..fcc34eee6bd4 100644 --- a/libs/ledger-live-common/src/generated/hw-getAddress.ts +++ b/libs/ledger-live-common/src/generated/hw-getAddress.ts @@ -1,7 +1,7 @@ -import aptos from "../families/aptos/hw-getAddress"; import casper from "../families/casper/hw-getAddress"; import celo from "../families/celo/hw-getAddress"; import { resolver as algorand } from "../families/algorand/setup"; +import { resolver as aptos } from "../families/aptos/setup"; import { resolver as bitcoin } from "../families/bitcoin/setup"; import { resolver as cardano } from "../families/cardano/setup"; import { resolver as cosmos } from "../families/cosmos/setup"; @@ -23,10 +23,10 @@ import { resolver as vechain } from "../families/vechain/setup"; import { resolver as xrp } from "../families/xrp/setup"; export default { - aptos, casper, celo, algorand, + aptos, bitcoin, cardano, cosmos, diff --git a/libs/ledger-live-common/src/generated/specs.ts b/libs/ledger-live-common/src/generated/specs.ts index fb59f365268a..6254e8ab22bd 100644 --- a/libs/ledger-live-common/src/generated/specs.ts +++ b/libs/ledger-live-common/src/generated/specs.ts @@ -1,7 +1,7 @@ -import aptos from "../families/aptos/specs"; import casper from "../families/casper/specs"; import celo from "../families/celo/specs"; import algorand from "@ledgerhq/coin-algorand/specs"; +import aptos from "@ledgerhq/coin-aptos/specs"; import bitcoin from "@ledgerhq/coin-bitcoin/specs"; import cardano from "@ledgerhq/coin-cardano/specs"; import cosmos from "@ledgerhq/coin-cosmos/specs"; @@ -23,10 +23,10 @@ import vechain from "@ledgerhq/coin-vechain/specs"; import xrp from "@ledgerhq/coin-xrp/specs"; export default { - aptos, casper, celo, algorand, + aptos, bitcoin, cardano, cosmos, diff --git a/libs/ledger-live-common/src/generated/transaction.ts b/libs/ledger-live-common/src/generated/transaction.ts index 5142554bb78d..a3f3c673d46e 100644 --- a/libs/ledger-live-common/src/generated/transaction.ts +++ b/libs/ledger-live-common/src/generated/transaction.ts @@ -1,7 +1,7 @@ -import aptos from "../families/aptos/transaction"; import casper from "../families/casper/transaction"; import celo from "../families/celo/transaction"; import algorand from "@ledgerhq/coin-algorand/transaction"; +import aptos from "@ledgerhq/coin-aptos/transaction"; import bitcoin from "@ledgerhq/coin-bitcoin/transaction"; import cardano from "@ledgerhq/coin-cardano/transaction"; import cosmos from "@ledgerhq/coin-cosmos/transaction"; @@ -23,10 +23,10 @@ import vechain from "@ledgerhq/coin-vechain/transaction"; import xrp from "@ledgerhq/coin-xrp/transaction"; export default { - aptos, casper, celo, algorand, + aptos, bitcoin, cardano, cosmos, diff --git a/libs/ledger-live-common/src/generated/types.ts b/libs/ledger-live-common/src/generated/types.ts index 904293ddf23e..87a609fa1bf3 100644 --- a/libs/ledger-live-common/src/generated/types.ts +++ b/libs/ledger-live-common/src/generated/types.ts @@ -9,7 +9,7 @@ import type { TransactionRaw as aptosTransactionRaw, TransactionStatus as aptosTransactionStatus, TransactionStatusRaw as aptosTransactionStatusRaw, -} from "../families/aptos/types"; +} from "@ledgerhq/coin-aptos/types/index"; import type { Transaction as bitcoinTransaction, TransactionRaw as bitcoinTransactionRaw, diff --git a/libs/ledgerjs/packages/hw-app-aptos/src/Aptos.ts b/libs/ledgerjs/packages/hw-app-aptos/src/Aptos.ts index c58eaf97f886..24b73fc07ace 100644 --- a/libs/ledgerjs/packages/hw-app-aptos/src/Aptos.ts +++ b/libs/ledgerjs/packages/hw-app-aptos/src/Aptos.ts @@ -77,7 +77,6 @@ export interface AddressData { * .then(signature => console.log(`Signature: ${signature}`)) * .catch(e => console.log(`An error occurred (${e.message})`)); */ - export default class Aptos { transport: Transport; diff --git a/package.json b/package.json index 66f17775e238..ea2e56f4222f 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "coin:coverage": "pnpm turbo coverage --filter=\"@ledgerhq/coin-*\" --concurrency=2 && mkdir -p coverage && mv libs/coin-modules/**/coverage/*.json coverage && pnpm exec nyc merge coverage coverage/coverage-final.json && pnpm exec nyc report -t coverage --report-dir coverage --reporter=html-spa", "coin:coverage:clean": "rm -rf coverage && rm -rf libs/coin-modules/**/coverage", "coin:algorand": "pnpm --filter coin-algorand", + "coin:aptos": "pnpm --filter coin-aptos", "coin:bitcoin": "pnpm --filter coin-bitcoin", "coin:cardano": "pnpm --filter coin-cardano", "coin:cosmos": "pnpm --filter coin-cosmos", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1e8f330d6d4..6dc96f176c5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -303,6 +303,9 @@ importers: '@braze/web-sdk': specifier: 4.10.2 version: 4.10.2 + '@ledgerhq/coin-aptos': + specifier: workspace:^ + version: link:../../libs/coin-modules/coin-aptos '@ledgerhq/coin-bitcoin': specifier: workspace:^ version: link:../../libs/coin-modules/coin-bitcoin @@ -1872,6 +1875,85 @@ importers: specifier: ^29.1.1 version: 29.1.5(jest@29.7.0)(typescript@5.4.3) + libs/coin-modules/coin-aptos: + dependencies: + '@apollo/client': + specifier: ^3.12.6 + version: 3.12.6(graphql@16.10.0)(react@18.3.1) + '@aptos-labs/ts-sdk': + specifier: ^1.33.1 + version: 1.33.1 + '@ledgerhq/coin-framework': + specifier: workspace:^ + version: link:../../coin-framework + '@ledgerhq/cryptoassets': + specifier: workspace:^ + version: link:../../ledgerjs/packages/cryptoassets + '@ledgerhq/devices': + specifier: workspace:* + version: link:../../ledgerjs/packages/devices + '@ledgerhq/errors': + specifier: workspace:^ + version: link:../../ledgerjs/packages/errors + '@ledgerhq/live-env': + specifier: workspace:^ + version: link:../../env + '@ledgerhq/live-network': + specifier: workspace:^ + version: link:../../live-network + '@ledgerhq/logs': + specifier: workspace:^ + version: link:../../ledgerjs/packages/logs + '@ledgerhq/types-live': + specifier: workspace:^ + version: link:../../ledgerjs/packages/types-live + '@noble/hashes': + specifier: 1.7.0 + version: 1.7.0 + bignumber.js: + specifier: ^9.1.2 + version: 9.1.2 + graphql: + specifier: ^16.10.0 + version: 16.10.0 + invariant: + specifier: ^2.2.4 + version: 2.2.4 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + rxjs: + specifier: ^7.8.1 + version: 7.8.1 + devDependencies: + '@faker-js/faker': + specifier: ^9.4.0 + version: 9.4.0 + '@types/invariant': + specifier: ^2.2.37 + version: 2.2.37 + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + '@types/lodash': + specifier: ^4.17.14 + version: 4.17.14 + '@types/semver': + specifier: ^7.5.8 + version: 7.5.8 + axios: + specifier: ^1.7.9 + version: 1.7.9 + jest: + specifier: ^29.7.0 + version: 29.7.0 + react: + specifier: ^18.3.1 + version: 18.3.1 + ts-jest: + specifier: ^29.2.5 + version: 29.2.5(jest@29.7.0)(typescript@5.4.3) + libs/coin-modules/coin-bitcoin: dependencies: '@ledgerhq/coin-framework': @@ -3917,12 +3999,6 @@ importers: libs/ledger-live-common: dependencies: - '@apollo/client': - specifier: ^3.8.7 - version: 3.12.4(@types/react@18.2.73)(graphql@16.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@aptos-labs/ts-sdk': - specifier: ^1.33.1 - version: 1.33.1 '@blooo/hw-app-acre': specifier: ^1.1.1 version: 1.1.1 @@ -3956,6 +4032,9 @@ importers: '@ledgerhq/coin-algorand': specifier: workspace:^ version: link:../coin-modules/coin-algorand + '@ledgerhq/coin-aptos': + specifier: workspace:^ + version: link:../coin-modules/coin-aptos '@ledgerhq/coin-bitcoin': specifier: workspace:^ version: link:../coin-modules/coin-bitcoin @@ -4142,9 +4221,6 @@ importers: '@ledgerhq/wallet-api-server': specifier: ^1.7.0 version: 1.7.0(react@18.3.1)(rxjs@7.8.1) - '@noble/hashes': - specifier: 1.6.1 - version: 1.6.1 '@stricahq/typhonjs': specifier: ^2.0.0 version: 2.0.0 @@ -4226,9 +4302,6 @@ importers: fuse.js: specifier: ^6.6.2 version: 6.6.2 - graphql: - specifier: ^16.8.1 - version: 16.8.1 invariant: specifier: ^2.2.2 version: 2.2.4 @@ -8160,8 +8233,8 @@ packages: peerDependencies: ajv: '>=8' - '@apollo/client@3.12.4': - resolution: {integrity: sha512-S/eC9jxEW9Jg1BjD6AZonE1fHxYuvC3gFHop8FRQkUdeK63MmBD5r0DOrN2WlJbwha1MSD6A97OwXwjaujEQpA==} + '@apollo/client@3.12.6': + resolution: {integrity: sha512-MOEtkojZagMKB7nxlwQ426eaBYwEs/Xfn+JeLOd81wv6j7toKo57eEGAbJdZwyXGRgtiqDkX5gx3EzE7qtarXA==} peerDependencies: graphql: ^15.0.0 || ^16.0.0 graphql-ws: ^5.5.5 @@ -10959,6 +11032,10 @@ packages: resolution: {integrity: sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} + '@faker-js/faker@9.4.0': + resolution: {integrity: sha512-85+k0AxaZSTowL0gXp8zYWDIrWclTbRPg/pm/V0dSFZ6W6D4lhcG3uuZl4zLsEKfEvs69xDbLN2cHQudwp95JA==} + engines: {node: '>=18.0.0', npm: '>=9.0.0'} + '@fal-works/esbuild-plugin-global-externals@2.1.2': resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} @@ -11998,6 +12075,10 @@ packages: resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.7.0': + resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} + engines: {node: ^14.21.3 || >=16} + '@noble/secp256k1@1.7.1': resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} @@ -15974,6 +16055,9 @@ packages: '@types/lodash@4.17.0': resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==} + '@types/lodash@4.17.14': + resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==} + '@types/lodash@4.17.7': resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==} @@ -17381,6 +17465,9 @@ packages: axios@1.7.7: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} + axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} @@ -21535,6 +21622,10 @@ packages: resolution: {integrity: sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==} engines: {node: '>= 10.x'} + graphql@16.10.0: + resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + graphql@16.8.1: resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -30857,18 +30948,18 @@ snapshots: jsonpointer: 5.0.1 leven: 3.1.0 - '@apollo/client@3.12.4(@types/react@18.2.73)(graphql@16.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@apollo/client@3.12.6(graphql@16.10.0)(react@18.3.1)': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.10.0) '@wry/caches': 1.0.1 '@wry/equality': 0.5.7 '@wry/trie': 0.5.0 - graphql: 16.8.1 - graphql-tag: 2.12.6(graphql@16.8.1) + graphql: 16.10.0 + graphql-tag: 2.12.6(graphql@16.10.0) hoist-non-react-statics: 3.3.2 optimism: 0.18.1 prop-types: 15.8.1 - rehackt: 0.1.0(@types/react@18.2.73)(react@18.3.1) + rehackt: 0.1.0(react@18.3.1) response-iterator: 0.2.11 symbol-observable: 4.0.0 ts-invariant: 0.10.3 @@ -30876,7 +30967,6 @@ snapshots: zen-observable-ts: 1.2.5 optionalDependencies: react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - '@types/react' @@ -30894,7 +30984,7 @@ snapshots: '@aptos-labs/aptos-cli': 1.0.2 '@aptos-labs/aptos-client': 0.1.1 '@noble/curves': 1.6.0 - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 eventemitter3: 5.0.1 @@ -33902,7 +33992,7 @@ snapshots: '@ethereumjs/rlp': 5.0.2 '@ethereumjs/util': 8.0.5 '@noble/curves': 1.6.0 - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 '@types/debug': 4.1.12 bignumber.js: 9.1.2 debug: 4.3.4 @@ -34345,7 +34435,7 @@ snapshots: '@confio/ics23@0.6.8': dependencies: - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 protobufjs: 6.11.4 '@cosmjs/amino@0.26.8': @@ -34382,7 +34472,7 @@ snapshots: '@cosmjs/encoding': 0.26.8 '@cosmjs/math': 0.26.8 '@cosmjs/utils': 0.26.8 - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 bn.js: 5.2.1 elliptic: 6.5.5 libsodium-wrappers: 0.7.13 @@ -34392,7 +34482,7 @@ snapshots: '@cosmjs/encoding': 0.31.3 '@cosmjs/math': 0.31.3 '@cosmjs/utils': 0.31.3 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 bn.js: 5.2.1 elliptic: 6.5.5 libsodium-wrappers-sumo: 0.7.13 @@ -34632,7 +34722,7 @@ snapshots: '@dfinity/candid': 0.21.4(@dfinity/principal@0.15.7(@types/node@20.12.12)(typescript@5.1.3)) '@dfinity/principal': 0.15.7(@types/node@20.12.12)(typescript@5.1.3) '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 base64-arraybuffer: 0.2.0 borc: 2.1.2 buffer: 6.0.3(patch_hash=2xnca52oxhztvr7iaoovwclcze) @@ -34643,7 +34733,7 @@ snapshots: '@dfinity/candid': 0.21.4(@dfinity/principal@0.15.7(typescript@5.4.3)) '@dfinity/principal': 0.15.7(typescript@5.4.3) '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 base64-arraybuffer: 0.2.0 borc: 2.1.2 buffer: 6.0.3(patch_hash=2xnca52oxhztvr7iaoovwclcze) @@ -36204,6 +36294,8 @@ snapshots: '@faker-js/faker@8.4.1': {} + '@faker-js/faker@9.4.0': {} + '@fal-works/esbuild-plugin-global-externals@2.1.2': {} '@fastify/busboy@2.1.1': {} @@ -36597,9 +36689,9 @@ snapshots: dependencies: graphql: 15.8.0 - '@graphql-typed-document-node/core@3.2.0(graphql@16.8.1)': + '@graphql-typed-document-node/core@3.2.0(graphql@16.10.0)': dependencies: - graphql: 16.8.1 + graphql: 16.10.0 '@grpc/grpc-js@1.6.7': dependencies: @@ -37716,7 +37808,7 @@ snapshots: '@ledgerhq/device-transport-kit-mock-client': 1.1.0 '@sentry/minimal': 6.19.7 '@statelyai/inspect': 0.4.0(xstate@5.19.0) - axios: 1.7.7 + axios: 1.7.9 inversify: 6.1.4(reflect-metadata@0.2.2) inversify-logger-middleware: 3.1.0 purify-ts: 2.1.0 @@ -38196,6 +38288,8 @@ snapshots: '@noble/hashes@1.6.1': {} + '@noble/hashes@1.7.0': {} + '@noble/secp256k1@1.7.1': {} '@node-ipc/js-queue@2.0.3': @@ -38771,7 +38865,7 @@ snapshots: '@polkadot-api/substrate-bindings@0.0.1': dependencies: - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 '@polkadot-api/utils': 0.0.1 '@scure/base': 1.1.6 scale-ts: 1.6.0 @@ -38955,7 +39049,7 @@ snapshots: '@polkadot/util-crypto@12.6.2(@polkadot/util@12.6.2)': dependencies: '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@polkadot/networks': 12.6.2 '@polkadot/util': 12.6.2 '@polkadot/wasm-crypto': 7.3.2(@polkadot/util@12.6.2)(@polkadot/x-randomvalues@12.6.2(@polkadot/util@12.6.2)(@polkadot/wasm-util@7.3.2(@polkadot/util@12.6.2))) @@ -41993,7 +42087,7 @@ snapshots: dependencies: '@babel/runtime': 7.25.0 '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.5.0 bigint-buffer: 1.1.5 @@ -42071,7 +42165,7 @@ snapshots: '@stacks/transactions@4.3.8': dependencies: - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 '@noble/secp256k1': 1.7.1 '@stacks/common': 4.3.5 '@stacks/network': 4.3.5 @@ -42742,7 +42836,7 @@ snapshots: '@stellar/stellar-sdk@11.3.0': dependencies: '@stellar/stellar-base': 11.0.1 - axios: 1.7.7 + axios: 1.7.9 bignumber.js: 9.1.2 eventsource: 2.0.2 randombytes: 2.1.0 @@ -43060,7 +43154,7 @@ snapshots: '@storybook/preview-api': 7.6.20 '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/types': 7.6.20 - '@types/lodash': 4.17.7 + '@types/lodash': 4.17.14 color-convert: 2.0.1 dequal: 2.0.3 lodash: 4.17.21 @@ -43093,7 +43187,7 @@ snapshots: '@storybook/preview-api': 7.6.20 '@storybook/theming': 7.6.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/types': 7.6.20 - '@types/lodash': 4.17.7 + '@types/lodash': 4.17.14 color-convert: 2.0.1 dequal: 2.0.3 lodash: 4.17.21 @@ -44704,7 +44798,7 @@ snapshots: dependencies: '@ton/core': 0.56.3(@ton/crypto@3.3.0) '@ton/crypto': 3.3.0 - axios: 1.7.7 + axios: 1.7.9 dataloader: 2.2.2 symbol.inspect: 1.0.1 teslabot: 1.5.0 @@ -44744,7 +44838,7 @@ snapshots: '@types/axios@0.14.0': dependencies: - axios: 1.7.7 + axios: 1.7.9 '@types/babel__core@7.20.5': dependencies: @@ -45073,6 +45167,8 @@ snapshots: '@types/lodash@4.17.0': {} + '@types/lodash@4.17.14': {} + '@types/lodash@4.17.7': {} '@types/long@4.0.2': {} @@ -45433,7 +45529,7 @@ snapshots: '@types/testing-library__jest-dom@5.14.9': dependencies: - '@types/jest': 29.5.12 + '@types/jest': 29.5.14 '@types/tough-cookie@4.0.5': {} @@ -46338,7 +46434,7 @@ snapshots: '@xrplf/isomorphic@1.0.0': dependencies: - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 eventemitter3: 5.0.1 ws: 8.17.1 transitivePeerDependencies: @@ -46509,7 +46605,7 @@ snapshots: dependencies: '@ledgerhq/hw-transport': 6.30.6 '@zondax/ledger-js': 0.8.2 - axios: 1.7.7 + axios: 1.7.9 JSONStream@1.3.5: dependencies: @@ -47104,6 +47200,12 @@ snapshots: form-data: 4.0.0 proxy-from-env: 1.1.0 + axios@1.7.9: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + axobject-query@3.2.1: dependencies: dequal: 2.0.3 @@ -47707,7 +47809,7 @@ snapshots: bip32@4.0.0: dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@scure/base': 1.1.6 typeforce: 1.18.0 wif: 2.0.6 @@ -47977,7 +48079,7 @@ snapshots: bs58check@3.0.1: dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 bs58: 5.0.0 bser@2.1.1: @@ -48147,7 +48249,7 @@ snapshots: c32check@2.0.0: dependencies: - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 base-x: 4.0.0 cac@6.7.14: {} @@ -48287,7 +48389,7 @@ snapshots: '@ethersproject/constants': 5.7.0 '@noble/curves': 1.6.0 '@noble/ed25519': 1.7.3 - '@noble/hashes': 1.6.1 + '@noble/hashes': 1.7.0 '@noble/secp256k1': 1.7.1 '@open-rpc/client-js': 1.8.1 '@scure/bip32': 1.4.0 @@ -52775,13 +52877,15 @@ snapshots: graphql: 15.8.0 tslib: 2.6.2 - graphql-tag@2.12.6(graphql@16.8.1): + graphql-tag@2.12.6(graphql@16.10.0): dependencies: - graphql: 16.8.1 + graphql: 16.10.0 tslib: 2.6.2 graphql@15.8.0: {} + graphql@16.10.0: {} + graphql@16.8.1: {} gunzip-maybe@1.4.2: @@ -53793,7 +53897,7 @@ snapshots: dependencies: '@ipld/dag-cbor': 9.2.1 '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 bignumber.js: 9.1.2 @@ -61601,9 +61705,8 @@ snapshots: dependencies: jsesc: 0.5.0 - rehackt@0.1.0(@types/react@18.2.73)(react@18.3.1): + rehackt@0.1.0(react@18.3.1): optionalDependencies: - '@types/react': 18.2.73 react: 18.3.1 relateurl@0.2.7: {} @@ -63845,11 +63948,11 @@ snapshots: '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.7.0 '@noble/secp256k1': 1.7.1 '@tronweb3/google-protobuf': 3.21.2 aes-js: 3.1.2 - axios: 1.7.7 + axios: 1.7.9 bignumber.js: 9.1.2 ethereum-cryptography: 2.1.3 ethers: 6.12.1 @@ -64138,7 +64241,7 @@ snapshots: chalk: 4.1.2 enhanced-resolve: 5.17.1 micromatch: 4.0.7 - semver: 7.6.3 + semver: 7.5.4 source-map: 0.7.4 typescript: 5.1.3 webpack: 5.94.0