Skip to content

Commit

Permalink
Merge pull request #8163 from LedgerHQ/support/coin-stacks-module
Browse files Browse the repository at this point in the history
LIVE-13681 chore: move stacks to its own module
  • Loading branch information
Wozacosta authored Nov 14, 2024
2 parents 5fdee2a + b3721ca commit 0b5ef53
Show file tree
Hide file tree
Showing 64 changed files with 984 additions and 616 deletions.
7 changes: 7 additions & 0 deletions .changeset/ten-pigs-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ledgerhq/coin-stacks": patch
"live-mobile": patch
"@ledgerhq/live-common": patch
---

support: move stacks to its own coin module
1 change: 1 addition & 0 deletions apps/ledger-live-mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"@ledgerhq/coin-evm": "workspace:^",
"@ledgerhq/coin-filecoin": "workspace:^",
"@ledgerhq/coin-framework": "workspace:^",
"@ledgerhq/coin-stacks": "workspace:^",
"@ledgerhq/devices": "workspace:*",
"@ledgerhq/domain-service": "workspace:^",
"@ledgerhq/errors": "workspace:^",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import invariant from "invariant";
import React from "react";
import { StyleSheet } from "react-native";
import type { Transaction } from "@ledgerhq/live-common/generated/types";
import { ExtraDeviceTransactionField } from "@ledgerhq/live-common/families/stacks/deviceTransactionConfig";
import { DeviceTransactionField } from "@ledgerhq/live-common/transaction/index";
import { ExtraDeviceTransactionField } from "@ledgerhq/coin-stacks/deviceTransactionConfig";
import LText from "~/components/LText";
import { DataRow } from "~/components/ValidateOnDeviceDataRow";

Expand Down
20 changes: 20 additions & 0 deletions libs/coin-modules/coin-stacks/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
env: {
browser: true,
es6: true,
},
overrides: [
{
files: ["src/**/*.test.{ts,tsx}"],
env: {
"jest/globals": true,
},
plugins: ["jest"],
},
],
rules: {
"no-console": ["error", { allow: ["warn", "error"] }],
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "warn",
},
};
31 changes: 31 additions & 0 deletions libs/coin-modules/coin-stacks/.unimportedrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"entry": [
"src/api/index.ts",
"src/bridge/index.ts",
"src/bridge/deviceTransactionConfig.ts",
"src/datasets/dataset-1.ts",
"src/signer/index.ts",
"src/test/index.ts",
"src/index.ts"
],
"ignorePatterns": [
"**/node_modules/**",
"**/*.fixture.ts",
"**/*.mock.ts",
"**/*.test.{js,jsx,ts,tsx}"
],
"ignoreUnresolved": [
"jest-get-type",
"jest-matcher-utils",
"jest-message-util"
],
"ignoreUnimported": [
"src/network/index.ts",
"src/signer/signMessage.ts"
],
"ignoreUnused": [
"@ledgerhq/types-cryptoassets",
"ripple-address-codec",
"ripple-binary-codec"
]
}
8 changes: 8 additions & 0 deletions libs/coin-modules/coin-stacks/jest.config.js
Original file line number Diff line number Diff line change
@@ -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"]
};
136 changes: 136 additions & 0 deletions libs/coin-modules/coin-stacks/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
{
"name": "@ledgerhq/coin-stacks",
"version": "0.1.0",
"description": "Ledger Stacks Coin integration",
"keywords": [
"Ledger",
"LedgerWallet",
"stacks",
"stx",
"Bitcoin layer2",
"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-stacks",
"publishConfig": {
"access": "public"
},
"typesVersions": {
"*": {
"lib/*": [
"lib/*"
],
"lib-es/*": [
"lib-es/*"
],
"deviceTransactionConfig": [
"lib/bridge/deviceTransactionConfig"
],
"specs": [
"lib/test/bot-specs"
],
"transaction": [
"lib/bridge/transaction"
],
"*": [
"lib/*"
]
}
},
"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"
},
"./hw-signMessage": {
"require": "./lib/signer/signMessage.js",
"default": "./lib-es/signer/signMessage.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-cryptoassets": "workspace:^",
"@ledgerhq/types-live": "workspace:^",
"axios": "1.7.7",
"bignumber.js": "^9.1.2",
"c32check": "1.1.3",
"invariant": "^2.2.4",
"lodash": "^4.17.21",
"ripple-address-codec": "^5.0.0",
"ripple-binary-codec": "^1.3.0",
"rxjs": "^7.8.1",
"@stacks/network": "6.10.0",
"@stacks/transactions": "6.11.0",
"@zondax/ledger-stacks": "^1.0.2"
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@types/invariant": "^2.2.37",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.14.191",
"dotenv": "^16.4.5",
"expect": "^27.4.6",
"jest": "^29.7.0",
"ripple-keypairs": "^2.0.0",
"ts-jest": "^29.1.1",
"typescript": "^5.4.5"
},
"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/' --passWithNoTests && mv coverage/coverage-final.json coverage/coverage-stacks.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",
"test-integ": "DOTENV_CONFIG_PATH=.env.integ.test jest --config=jest.integ.config.js",
"typecheck": "tsc --noEmit",
"unimported": "unimported"
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import invariant from "invariant";
import { AccountBridge } from "@ledgerhq/types-live";
import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation";
import { StacksOperation, Transaction } from "./types";
import { getTxToBroadcast } from "./bridge/utils/misc";
import { broadcastTx } from "./bridge/utils/api";
import { AccountBridge } from "@ledgerhq/types-live";
import invariant from "invariant";
import { broadcastTx } from "../network/api";
import { StacksOperation, Transaction } from "../types";
import { getTxToBroadcast } from "./utils/misc";

export const broadcast: AccountBridge<Transaction>["broadcast"] = async ({
signedOperation: { operation, signature, rawData },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import BigNumber from "bignumber.js";
import { Account, OperationType } from "@ledgerhq/types-live";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import { StacksOperation, Transaction } from "./types";
import { getAddress } from "./bridge/utils/misc";
import { Account, OperationType } from "@ledgerhq/types-live";
import BigNumber from "bignumber.js";
import { StacksOperation, Transaction } from "../types";
import { getAddress } from "./utils/misc";

export const buildOptimisticOperation = (
account: Account,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AccountBridge } from "@ledgerhq/types-live";
import { Transaction } from "./types";
import BigNumber from "bignumber.js";
import { AnchorMode } from "@stacks/transactions";
import BigNumber from "bignumber.js";
import { Transaction } from "../types";

export const createTransaction: AccountBridge<Transaction>["createTransaction"] = () => ({
family: "stacks",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BigNumber } from "bignumber.js";
import type { CommonDeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
import type { Account, AccountLike } from "@ledgerhq/types-live";
import type { DeviceTransactionField } from "../../transaction";
import type { Transaction, TransactionStatus } from "./types";
import { BigNumber } from "bignumber.js";
import type { Transaction, TransactionStatus } from "../types";

export type ExtraDeviceTransactionField =
| {
Expand All @@ -15,6 +15,8 @@ export type ExtraDeviceTransactionField =
value: BigNumber;
};

export type DeviceTransactionField = CommonDeviceTransactionField | ExtraDeviceTransactionField;

function getDeviceTransactionConfig(input: {
account: AccountLike;
parentAccount: Account | null | undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets/abandonseed";
import { AccountBridge } from "@ledgerhq/types-live";
import { StacksMainnet } from "@stacks/network";
import {
UnsignedTokenTransferOptions,
estimateTransaction,
makeUnsignedSTXTokenTransfer,
} from "@stacks/transactions";
import invariant from "invariant";
import BigNumber from "bignumber.js";
import { StacksMainnet } from "@stacks/network";
import { AccountBridge } from "@ledgerhq/types-live";
import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets/abandonseed";
import invariant from "invariant";
import { StacksNetwork } from "../network/api.types";
import { Transaction } from "../types";
import { createTransaction } from "./createTransaction";
import { StacksNetwork } from "./bridge/utils/api.types";
import { Transaction } from "./types";

export const estimateMaxSpendable: AccountBridge<Transaction>["estimateMaxSpendable"] = async ({
account,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {
NotEnoughBalance,
RecipientRequired,
} from "@ledgerhq/errors";
import BigNumber from "bignumber.js";
import { AccountBridge } from "@ledgerhq/types-live";
import { Transaction, TransactionStatus } from "./types";
import { validateAddress } from "./bridge/utils/addresses";
import { getAddress } from "./bridge/utils/misc";
import { StacksMemoTooLong } from "./errors";
import BigNumber from "bignumber.js";
import { StacksMemoTooLong } from "../errors";
import { Transaction, TransactionStatus } from "../types";
import { validateAddress } from "./utils/addresses";
import { getAddress } from "./utils/misc";

export const getTransactionStatus: AccountBridge<Transaction>["getTransactionStatus"] = async (
account,
Expand Down
64 changes: 64 additions & 0 deletions libs/coin-modules/coin-stacks/src/bridge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
makeAccountBridgeReceive,
makeScanAccounts,
makeSync,
} from "@ledgerhq/coin-framework/bridge/jsHelpers";
import resolver from "../signer/index";
import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
import { SignerContext } from "@ledgerhq/coin-framework/signer";
import type { Account, AccountBridge, CurrencyBridge } from "@ledgerhq/types-live";
import { defaultUpdateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import type { Transaction, TransactionStatus, StacksSigner } from "../types";
import { getTransactionStatus } from "./getTransactionStatus";
import { estimateMaxSpendable } from "./estimateMaxSpendable";
import { prepareTransaction } from "./prepareTransaction";
import { createTransaction } from "./createTransaction";
import { getAccountShape } from "./synchronization";
import { buildSignOperation } from "./signOperation";
import { broadcast } from "./broadcast";

function buildCurrencyBridge(signerContext: SignerContext<StacksSigner>): 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<StacksSigner>,
): AccountBridge<Transaction, Account, TransactionStatus> {
const getAddress = resolver(signerContext);
const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));

const signOperation = buildSignOperation(signerContext);

return {
estimateMaxSpendable,
createTransaction,
updateTransaction: defaultUpdateTransaction,
getTransactionStatus,
prepareTransaction,
sync,
receive,
signOperation,
broadcast,
};
}

export function createBridges(signerContext: SignerContext<StacksSigner>) {
return {
currencyBridge: buildCurrencyBridge(signerContext),
accountBridge: buildAccountBridge(signerContext),
};
}
export { prepareTransaction, estimateMaxSpendable };
Loading

0 comments on commit 0b5ef53

Please sign in to comment.