@ledgerhq/wallet-pnl 0.2.0-nightly.20260513030606
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +28 -0
- package/CHANGELOG.md +15 -0
- package/LICENSE.txt +21 -0
- package/jest.config.js +25 -0
- package/lib/assetPnL.d.ts +6 -0
- package/lib/assetPnL.d.ts.map +1 -0
- package/lib/assetPnL.js +66 -0
- package/lib/assetPnL.js.map +1 -0
- package/lib/classifyOperation.d.ts +29 -0
- package/lib/classifyOperation.d.ts.map +1 -0
- package/lib/classifyOperation.js +49 -0
- package/lib/classifyOperation.js.map +1 -0
- package/lib/costBasis.d.ts +14 -0
- package/lib/costBasis.d.ts.map +1 -0
- package/lib/costBasis.js +139 -0
- package/lib/costBasis.js.map +1 -0
- package/lib/costBasisCache.d.ts +7 -0
- package/lib/costBasisCache.d.ts.map +1 -0
- package/lib/costBasisCache.js +62 -0
- package/lib/costBasisCache.js.map +1 -0
- package/lib/costBasisReconciliation.d.ts +59 -0
- package/lib/costBasisReconciliation.d.ts.map +1 -0
- package/lib/costBasisReconciliation.js +133 -0
- package/lib/costBasisReconciliation.js.map +1 -0
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/index.js +8 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/useAssetPnL.d.ts +6 -0
- package/lib/hooks/useAssetPnL.d.ts.map +1 -0
- package/lib/hooks/useAssetPnL.js +9 -0
- package/lib/hooks/useAssetPnL.js.map +1 -0
- package/lib/hooks/usePortfolioPnL.d.ts +6 -0
- package/lib/hooks/usePortfolioPnL.d.ts.map +1 -0
- package/lib/hooks/usePortfolioPnL.js +9 -0
- package/lib/hooks/usePortfolioPnL.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +25 -0
- package/lib/index.js.map +1 -0
- package/lib/percentage.d.ts +3 -0
- package/lib/percentage.d.ts.map +1 -0
- package/lib/percentage.js +9 -0
- package/lib/percentage.js.map +1 -0
- package/lib/portfolioPnL.d.ts +6 -0
- package/lib/portfolioPnL.d.ts.map +1 -0
- package/lib/portfolioPnL.js +29 -0
- package/lib/portfolioPnL.js.map +1 -0
- package/lib/scenarios/accounts.d.ts +10 -0
- package/lib/scenarios/accounts.d.ts.map +1 -0
- package/lib/scenarios/accounts.js +68 -0
- package/lib/scenarios/accounts.js.map +1 -0
- package/lib/scenarios/countervalues.d.ts +24 -0
- package/lib/scenarios/countervalues.d.ts.map +1 -0
- package/lib/scenarios/countervalues.js +75 -0
- package/lib/scenarios/countervalues.js.map +1 -0
- package/lib/scenarios/currencies.d.ts +11 -0
- package/lib/scenarios/currencies.d.ts.map +1 -0
- package/lib/scenarios/currencies.js +34 -0
- package/lib/scenarios/currencies.js.map +1 -0
- package/lib/scenarios/hodler.d.ts +37 -0
- package/lib/scenarios/hodler.d.ts.map +1 -0
- package/lib/scenarios/hodler.js +93 -0
- package/lib/scenarios/hodler.js.map +1 -0
- package/lib/scenarios/index.d.ts +18 -0
- package/lib/scenarios/index.d.ts.map +1 -0
- package/lib/scenarios/index.js +39 -0
- package/lib/scenarios/index.js.map +1 -0
- package/lib/scenarios/multiAsset.d.ts +48 -0
- package/lib/scenarios/multiAsset.d.ts.map +1 -0
- package/lib/scenarios/multiAsset.js +130 -0
- package/lib/scenarios/multiAsset.js.map +1 -0
- package/lib/scenarios/operations.d.ts +28 -0
- package/lib/scenarios/operations.d.ts.map +1 -0
- package/lib/scenarios/operations.js +54 -0
- package/lib/scenarios/operations.js.map +1 -0
- package/lib/scenarios/singleTrade.d.ts +48 -0
- package/lib/scenarios/singleTrade.d.ts.map +1 -0
- package/lib/scenarios/singleTrade.js +84 -0
- package/lib/scenarios/singleTrade.js.map +1 -0
- package/lib/scenarios/staker.d.ts +33 -0
- package/lib/scenarios/staker.d.ts.map +1 -0
- package/lib/scenarios/staker.js +71 -0
- package/lib/scenarios/staker.js.map +1 -0
- package/lib/scenarios/trader.d.ts +37 -0
- package/lib/scenarios/trader.d.ts.map +1 -0
- package/lib/scenarios/trader.js +105 -0
- package/lib/scenarios/trader.js.map +1 -0
- package/lib/types.d.ts +111 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib-es/assetPnL.d.ts +6 -0
- package/lib-es/assetPnL.d.ts.map +1 -0
- package/lib-es/assetPnL.js +60 -0
- package/lib-es/assetPnL.js.map +1 -0
- package/lib-es/classifyOperation.d.ts +29 -0
- package/lib-es/classifyOperation.d.ts.map +1 -0
- package/lib-es/classifyOperation.js +45 -0
- package/lib-es/classifyOperation.js.map +1 -0
- package/lib-es/costBasis.d.ts +14 -0
- package/lib-es/costBasis.d.ts.map +1 -0
- package/lib-es/costBasis.js +132 -0
- package/lib-es/costBasis.js.map +1 -0
- package/lib-es/costBasisCache.d.ts +7 -0
- package/lib-es/costBasisCache.d.ts.map +1 -0
- package/lib-es/costBasisCache.js +58 -0
- package/lib-es/costBasisCache.js.map +1 -0
- package/lib-es/costBasisReconciliation.d.ts +59 -0
- package/lib-es/costBasisReconciliation.d.ts.map +1 -0
- package/lib-es/costBasisReconciliation.js +125 -0
- package/lib-es/costBasisReconciliation.js.map +1 -0
- package/lib-es/hooks/index.d.ts +3 -0
- package/lib-es/hooks/index.d.ts.map +1 -0
- package/lib-es/hooks/index.js +3 -0
- package/lib-es/hooks/index.js.map +1 -0
- package/lib-es/hooks/useAssetPnL.d.ts +6 -0
- package/lib-es/hooks/useAssetPnL.d.ts.map +1 -0
- package/lib-es/hooks/useAssetPnL.js +6 -0
- package/lib-es/hooks/useAssetPnL.js.map +1 -0
- package/lib-es/hooks/usePortfolioPnL.d.ts +6 -0
- package/lib-es/hooks/usePortfolioPnL.d.ts.map +1 -0
- package/lib-es/hooks/usePortfolioPnL.js +6 -0
- package/lib-es/hooks/usePortfolioPnL.js.map +1 -0
- package/lib-es/index.d.ts +9 -0
- package/lib-es/index.d.ts.map +1 -0
- package/lib-es/index.js +8 -0
- package/lib-es/index.js.map +1 -0
- package/lib-es/percentage.d.ts +3 -0
- package/lib-es/percentage.d.ts.map +1 -0
- package/lib-es/percentage.js +6 -0
- package/lib-es/percentage.js.map +1 -0
- package/lib-es/portfolioPnL.d.ts +6 -0
- package/lib-es/portfolioPnL.d.ts.map +1 -0
- package/lib-es/portfolioPnL.js +23 -0
- package/lib-es/portfolioPnL.js.map +1 -0
- package/lib-es/scenarios/accounts.d.ts +10 -0
- package/lib-es/scenarios/accounts.d.ts.map +1 -0
- package/lib-es/scenarios/accounts.js +60 -0
- package/lib-es/scenarios/accounts.js.map +1 -0
- package/lib-es/scenarios/countervalues.d.ts +24 -0
- package/lib-es/scenarios/countervalues.d.ts.map +1 -0
- package/lib-es/scenarios/countervalues.js +70 -0
- package/lib-es/scenarios/countervalues.js.map +1 -0
- package/lib-es/scenarios/currencies.d.ts +11 -0
- package/lib-es/scenarios/currencies.d.ts.map +1 -0
- package/lib-es/scenarios/currencies.js +28 -0
- package/lib-es/scenarios/currencies.js.map +1 -0
- package/lib-es/scenarios/hodler.d.ts +37 -0
- package/lib-es/scenarios/hodler.d.ts.map +1 -0
- package/lib-es/scenarios/hodler.js +87 -0
- package/lib-es/scenarios/hodler.js.map +1 -0
- package/lib-es/scenarios/index.d.ts +18 -0
- package/lib-es/scenarios/index.d.ts.map +1 -0
- package/lib-es/scenarios/index.js +10 -0
- package/lib-es/scenarios/index.js.map +1 -0
- package/lib-es/scenarios/multiAsset.d.ts +48 -0
- package/lib-es/scenarios/multiAsset.d.ts.map +1 -0
- package/lib-es/scenarios/multiAsset.js +126 -0
- package/lib-es/scenarios/multiAsset.js.map +1 -0
- package/lib-es/scenarios/operations.d.ts +28 -0
- package/lib-es/scenarios/operations.d.ts.map +1 -0
- package/lib-es/scenarios/operations.js +45 -0
- package/lib-es/scenarios/operations.js.map +1 -0
- package/lib-es/scenarios/singleTrade.d.ts +48 -0
- package/lib-es/scenarios/singleTrade.d.ts.map +1 -0
- package/lib-es/scenarios/singleTrade.js +78 -0
- package/lib-es/scenarios/singleTrade.js.map +1 -0
- package/lib-es/scenarios/staker.d.ts +33 -0
- package/lib-es/scenarios/staker.d.ts.map +1 -0
- package/lib-es/scenarios/staker.js +65 -0
- package/lib-es/scenarios/staker.js.map +1 -0
- package/lib-es/scenarios/trader.d.ts +37 -0
- package/lib-es/scenarios/trader.d.ts.map +1 -0
- package/lib-es/scenarios/trader.js +99 -0
- package/lib-es/scenarios/trader.js.map +1 -0
- package/lib-es/types.d.ts +111 -0
- package/lib-es/types.d.ts.map +1 -0
- package/lib-es/types.js +2 -0
- package/lib-es/types.js.map +1 -0
- package/package.json +117 -0
- package/src/__tests__/classifyOperation.test.ts +100 -0
- package/src/__tests__/costBasisCache.test.ts +97 -0
- package/src/__tests__/costBasisReconciliationUnit.test.ts +180 -0
- package/src/__tests__/helpers/bn.ts +42 -0
- package/src/__tests__/helpers/pnl.ts +20 -0
- package/src/__tests__/helpers/testing.ts +8 -0
- package/src/__tests__/hooks.test.ts +206 -0
- package/src/__tests__/percentage.test.ts +38 -0
- package/src/__tests__/reconciliation.test.ts +173 -0
- package/src/__tests__/scenarios.test.ts +337 -0
- package/src/assetPnL.ts +74 -0
- package/src/classifyOperation.ts +53 -0
- package/src/costBasis.ts +156 -0
- package/src/costBasisCache.ts +89 -0
- package/src/costBasisReconciliation.ts +154 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useAssetPnL.ts +18 -0
- package/src/hooks/usePortfolioPnL.ts +18 -0
- package/src/index.ts +19 -0
- package/src/percentage.ts +6 -0
- package/src/portfolioPnL.ts +34 -0
- package/src/scenarios/accounts.ts +86 -0
- package/src/scenarios/countervalues.ts +98 -0
- package/src/scenarios/currencies.ts +32 -0
- package/src/scenarios/hodler.ts +114 -0
- package/src/scenarios/index.ts +25 -0
- package/src/scenarios/multiAsset.ts +150 -0
- package/src/scenarios/operations.ts +82 -0
- package/src/scenarios/singleTrade.ts +108 -0
- package/src/scenarios/staker.ts +88 -0
- package/src/scenarios/trader.ts +124 -0
- package/src/types.ts +117 -0
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +15 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
browser: true,
|
|
4
|
+
es6: true,
|
|
5
|
+
},
|
|
6
|
+
globals: {
|
|
7
|
+
Atomics: "readonly",
|
|
8
|
+
SharedArrayBuffer: "readonly",
|
|
9
|
+
},
|
|
10
|
+
extends: ["plugin:import/typescript"],
|
|
11
|
+
plugins: ["import"],
|
|
12
|
+
rules: {
|
|
13
|
+
"no-console": ["error", { allow: ["warn", "error"] }],
|
|
14
|
+
"linebreak-style": ["error", "unix"],
|
|
15
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
16
|
+
"@typescript-eslint/no-namespace": ["error", { allowDeclarations: true }],
|
|
17
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
18
|
+
},
|
|
19
|
+
overrides: [
|
|
20
|
+
{
|
|
21
|
+
files: ["src/**/*.test.{ts,tsx}"],
|
|
22
|
+
env: {
|
|
23
|
+
"jest/globals": true,
|
|
24
|
+
},
|
|
25
|
+
plugins: ["jest"],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @ledgerhq/wallet-pnl
|
|
2
|
+
|
|
3
|
+
## 0.2.0-nightly.20260513030606
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#17343](https://github.com/LedgerHQ/ledger-live/pull/17343) [`f753ec7`](https://github.com/LedgerHQ/ledger-live/commit/f753ec7f73a870fc4b9f24d213f399773bc50600) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add `@ledgerhq/wallet-pnl`: average cost basis PnL (per-asset and portfolio), operation classification, countervalue-backed cost basis cache.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`f39fede`](https://github.com/LedgerHQ/ledger-live/commit/f39fede0a6eb4e427a15219e5a3c8fbc3302815f), [`ed0dc8a`](https://github.com/LedgerHQ/ledger-live/commit/ed0dc8abc2c8f5054e655c4e12efe6fb433fbaca), [`b812751`](https://github.com/LedgerHQ/ledger-live/commit/b8127519474e63c543b1b937a2d3b11ad162a78e), [`4ddd97a`](https://github.com/LedgerHQ/ledger-live/commit/4ddd97a99bab5b581ad5ccfd36eb420ec4ee6352), [`3b746ee`](https://github.com/LedgerHQ/ledger-live/commit/3b746eea7f3f2be633947e8e9112987457c864a5), [`7fafa10`](https://github.com/LedgerHQ/ledger-live/commit/7fafa10d8af581f4433a60ea908980a726d3a777), [`ac26c8b`](https://github.com/LedgerHQ/ledger-live/commit/ac26c8bffa9b5cc9f28bed5ce3d44e32982d655c), [`1368afd`](https://github.com/LedgerHQ/ledger-live/commit/1368afdc7218a68c803672e6e412f8f9f6e62142), [`fb79639`](https://github.com/LedgerHQ/ledger-live/commit/fb79639eb81258bae4830ed6ffe375ae625054ad), [`0d11df6`](https://github.com/LedgerHQ/ledger-live/commit/0d11df6ef8dc781171071824ad1c39e3beed7730), [`321a0e2`](https://github.com/LedgerHQ/ledger-live/commit/321a0e2ce948fac11f7bdf0e106eb0af57168caa), [`3cd7abb`](https://github.com/LedgerHQ/ledger-live/commit/3cd7abb4d6f6072bad62073108d797faf23f9e8c), [`6e832a0`](https://github.com/LedgerHQ/ledger-live/commit/6e832a044bd7abb704f0a45ea782e55c1b25487c), [`21e69fe`](https://github.com/LedgerHQ/ledger-live/commit/21e69fea49cffc0b1204903e539a64b83e4b28f0), [`2257d43`](https://github.com/LedgerHQ/ledger-live/commit/2257d43630933127549300f39ade1e2b01f94cb8), [`08762c2`](https://github.com/LedgerHQ/ledger-live/commit/08762c286e38136293108c19efa72ae8fbd1286b), [`fb4d165`](https://github.com/LedgerHQ/ledger-live/commit/fb4d1656be8dc8e933e55600970a2e991fbaeebb), [`73bfe05`](https://github.com/LedgerHQ/ledger-live/commit/73bfe055ec23e0d630f2da9f4dbc9731b6fe5190)]:
|
|
12
|
+
- @ledgerhq/types-live@6.107.0-nightly.20260513030606
|
|
13
|
+
- @ledgerhq/ledger-wallet-framework@1.4.0-nightly.20260513030606
|
|
14
|
+
- @ledgerhq/cryptoassets@13.47.0-nightly.20260513030606
|
|
15
|
+
- @ledgerhq/live-countervalues@0.18.3-nightly.20260513030606
|
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-present Ledger https://www.ledger.com/
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
transform: {
|
|
3
|
+
"^.+\\.(ts|tsx)?$": [
|
|
4
|
+
"@swc/jest",
|
|
5
|
+
{
|
|
6
|
+
jsc: {
|
|
7
|
+
target: "esnext",
|
|
8
|
+
transform: {
|
|
9
|
+
react: {
|
|
10
|
+
runtime: "automatic",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
testEnvironment: "jsdom",
|
|
18
|
+
testPathIgnorePatterns: ["lib/", "lib-es/", "helpers/"],
|
|
19
|
+
coverageReporters: ["json", ["lcov", { file: "lcov.info", projectRoot: "../../" }], "text"],
|
|
20
|
+
reporters: [
|
|
21
|
+
"default",
|
|
22
|
+
...(process.env.CI ? ["github-actions"] : []),
|
|
23
|
+
["jest-sonar", { outputName: "sonar-executionTests-report.xml", reportedFilePath: "absolute" }],
|
|
24
|
+
],
|
|
25
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AccountLike } from "@ledgerhq/types-live";
|
|
2
|
+
import type { Currency } from "@ledgerhq/types-cryptoassets";
|
|
3
|
+
import type { CounterValuesState } from "@ledgerhq/live-countervalues/types";
|
|
4
|
+
import type { AssetPnL, ComputePnLOptions } from "./types";
|
|
5
|
+
export declare function computeAssetPnL(account: AccountLike, countervalues: CounterValuesState, fiat: Currency, options?: ComputePnLOptions): AssetPnL | null;
|
|
6
|
+
//# sourceMappingURL=assetPnL.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetPnL.d.ts","sourceRoot":"","sources":["../src/assetPnL.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAI7E,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAkB,MAAM,SAAS,CAAC;AAI3E,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,kBAAkB,EACjC,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE,iBAAiB,GAC1B,QAAQ,GAAG,IAAI,CAwDjB"}
|
package/lib/assetPnL.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeAssetPnL = computeAssetPnL;
|
|
7
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
8
|
+
const logic_1 = require("@ledgerhq/live-countervalues/logic");
|
|
9
|
+
const account_1 = require("@ledgerhq/ledger-wallet-framework/account");
|
|
10
|
+
const costBasisCache_1 = require("./costBasisCache");
|
|
11
|
+
const costBasisReconciliation_1 = require("./costBasisReconciliation");
|
|
12
|
+
const ZERO = new bignumber_js_1.default(0);
|
|
13
|
+
function computeAssetPnL(account, countervalues, fiat, options) {
|
|
14
|
+
const asset = (0, account_1.getAccountCurrency)(account);
|
|
15
|
+
const rawState = (0, costBasisCache_1.getCostBasis)(account, fiat, countervalues, options);
|
|
16
|
+
const hasOps = account.operations.length > 0;
|
|
17
|
+
const hasBalance = account.balance.gt(0);
|
|
18
|
+
if (!hasOps && !hasBalance)
|
|
19
|
+
return null;
|
|
20
|
+
// Reconciliation defaults to ON: if the chain says the wallet holds X and
|
|
21
|
+
// the cost-basis reducer thinks Y, we close the gap so consumers don't see
|
|
22
|
+
// a wildly negative `unrealisedPnL` on tokens whose disposals weren't
|
|
23
|
+
// captured (typical ERC-20 `transferFrom`-after-`APPROVE` flows). Callers
|
|
24
|
+
// that need raw, op-only values can pass `reconcileWithBalance: false`.
|
|
25
|
+
//
|
|
26
|
+
// Detection (`detectBalanceGap`) is pure and always cheap; only the actual
|
|
27
|
+
// repair (`applyBalanceReconciliation`) is gated on the opt-in flag. This
|
|
28
|
+
// keeps the diagnostic available for downstream UIs even when the repair
|
|
29
|
+
// is suppressed.
|
|
30
|
+
const apply = options?.reconcileWithBalance !== false;
|
|
31
|
+
const gap = (0, costBasisReconciliation_1.detectBalanceGap)(rawState, account.balance);
|
|
32
|
+
let state = rawState;
|
|
33
|
+
let applied = false;
|
|
34
|
+
if (apply && !gap.isClean) {
|
|
35
|
+
const result = (0, costBasisReconciliation_1.applyBalanceReconciliation)(rawState, gap, asset, fiat, countervalues);
|
|
36
|
+
state = result.state;
|
|
37
|
+
applied = result.applied;
|
|
38
|
+
}
|
|
39
|
+
const reconciliation = { ...gap, applied };
|
|
40
|
+
const hasHistory = !state.totalAmount.isZero() || !state.realisedPnL.isZero();
|
|
41
|
+
let unrealisedPnL = ZERO;
|
|
42
|
+
if (hasBalance) {
|
|
43
|
+
const latestCV = (0, logic_1.calculate)(countervalues, {
|
|
44
|
+
value: account.balance.toNumber(),
|
|
45
|
+
from: asset,
|
|
46
|
+
to: fiat,
|
|
47
|
+
disableRounding: true,
|
|
48
|
+
});
|
|
49
|
+
if (typeof latestCV === "number") {
|
|
50
|
+
unrealisedPnL = new bignumber_js_1.default(latestCV).minus(state.totalCostInCounterValue);
|
|
51
|
+
}
|
|
52
|
+
else if (!hasHistory) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
unrealisedPnL,
|
|
58
|
+
realisedPnL: state.realisedPnL,
|
|
59
|
+
totalPnL: state.realisedPnL.plus(unrealisedPnL),
|
|
60
|
+
costBasis: state.totalCostInCounterValue,
|
|
61
|
+
lifetimeCost: state.lifetimeCostInCounterValue,
|
|
62
|
+
averageEntryPrice: state.averageEntryPrice,
|
|
63
|
+
reconciliation,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=assetPnL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetPnL.js","sourceRoot":"","sources":["../src/assetPnL.ts"],"names":[],"mappings":";;;;;AAYA,0CA6DC;AAzED,gEAAqC;AAGrC,8DAA+D;AAE/D,uEAA+E;AAC/E,qDAAgD;AAChD,uEAAyF;AAGzF,MAAM,IAAI,GAAG,IAAI,sBAAS,CAAC,CAAC,CAAC,CAAC;AAE9B,SAAgB,eAAe,CAC7B,OAAoB,EACpB,aAAiC,EACjC,IAAc,EACd,OAA2B;IAE3B,MAAM,KAAK,GAAG,IAAA,4BAAkB,EAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAA,6BAAY,EAAC,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;IAErE,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEzC,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAExC,0EAA0E;IAC1E,2EAA2E;IAC3E,sEAAsE;IACtE,0EAA0E;IAC1E,wEAAwE;IACxE,EAAE;IACF,2EAA2E;IAC3E,0EAA0E;IAC1E,yEAAyE;IACzE,iBAAiB;IACjB,MAAM,KAAK,GAAG,OAAO,EAAE,oBAAoB,KAAK,KAAK,CAAC;IACtD,MAAM,GAAG,GAAG,IAAA,0CAAgB,EAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,IAAI,KAAK,GAAG,QAAQ,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAA,oDAA0B,EAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;QACrF,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACrB,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,CAAC;IACD,MAAM,cAAc,GAAmB,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,CAAC;IAE3D,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IAE9E,IAAI,aAAa,GAAG,IAAI,CAAC;IACzB,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,QAAQ,GAAG,IAAA,iBAAS,EAAC,aAAa,EAAE;YACxC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE;YACjC,IAAI,EAAE,KAAK;YACX,EAAE,EAAE,IAAI;YACR,eAAe,EAAE,IAAI;SACtB,CAAC,CAAC;QACH,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,aAAa,GAAG,IAAI,sBAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC/E,CAAC;aAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,aAAa;QACb,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC;QAC/C,SAAS,EAAE,KAAK,CAAC,uBAAuB;QACxC,YAAY,EAAE,KAAK,CAAC,0BAA0B;QAC9C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,cAAc;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Operation, OperationType } from "@ledgerhq/types-live";
|
|
2
|
+
import type { OperationFlow } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Operation types that move asset INTO the account from a cost-basis
|
|
5
|
+
* perspective. Derived from the canonical
|
|
6
|
+
* {@link OPERATION_TYPE_IN_FAMILY} taxonomy of `@ledgerhq/ledger-wallet-framework`,
|
|
7
|
+
* extended with DeFi types not modelled at the framework level
|
|
8
|
+
* (`SUPPLY`, `NFT_IN`).
|
|
9
|
+
*/
|
|
10
|
+
export declare const INFLOWS: ReadonlySet<OperationType | string>;
|
|
11
|
+
/**
|
|
12
|
+
* Operation types that move asset OUT of the account from a cost-basis
|
|
13
|
+
* perspective. Derived from the canonical
|
|
14
|
+
* {@link OPERATION_TYPE_OUT_FAMILY} taxonomy of `@ledgerhq/ledger-wallet-framework`,
|
|
15
|
+
* extended with DeFi types not modelled at the framework level
|
|
16
|
+
* (`REDEEM`, `SELL`, `NFT_OUT`).
|
|
17
|
+
*
|
|
18
|
+
* Note: `OPERATION_TYPE_STAKE_FAMILY` ops (`BOND`, `STAKE`, `APPROVE`,
|
|
19
|
+
* `WITHDRAW_UNBONDED`, ...) are intentionally NOT included — they only move
|
|
20
|
+
* fees, not principal, so they're treated as `"ignored"` by `classifyOperation`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const OUTFLOWS: ReadonlySet<OperationType | string>;
|
|
23
|
+
/**
|
|
24
|
+
* Stake-family ops are exposed for callers (and tests) that need to assert
|
|
25
|
+
* they're treated as no-ops by the cost-basis reducer.
|
|
26
|
+
*/
|
|
27
|
+
export declare const STAKE_FAMILY: ReadonlySet<OperationType | string>;
|
|
28
|
+
export declare function classifyOperation(op: Operation): OperationFlow;
|
|
29
|
+
//# sourceMappingURL=classifyOperation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifyOperation.d.ts","sourceRoot":"","sources":["../src/classifyOperation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAMrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,WAAW,CAAC,aAAa,GAAG,MAAM,CAItD,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,aAAa,GAAG,MAAM,CAKvD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,aAAa,GAAG,MAAM,CAE5D,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAK9D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STAKE_FAMILY = exports.OUTFLOWS = exports.INFLOWS = void 0;
|
|
4
|
+
exports.classifyOperation = classifyOperation;
|
|
5
|
+
const operation_1 = require("@ledgerhq/ledger-wallet-framework/operation");
|
|
6
|
+
/**
|
|
7
|
+
* Operation types that move asset INTO the account from a cost-basis
|
|
8
|
+
* perspective. Derived from the canonical
|
|
9
|
+
* {@link OPERATION_TYPE_IN_FAMILY} taxonomy of `@ledgerhq/ledger-wallet-framework`,
|
|
10
|
+
* extended with DeFi types not modelled at the framework level
|
|
11
|
+
* (`SUPPLY`, `NFT_IN`).
|
|
12
|
+
*/
|
|
13
|
+
exports.INFLOWS = new Set([
|
|
14
|
+
...operation_1.OPERATION_TYPE_IN_FAMILY,
|
|
15
|
+
"NFT_IN",
|
|
16
|
+
"SUPPLY",
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Operation types that move asset OUT of the account from a cost-basis
|
|
20
|
+
* perspective. Derived from the canonical
|
|
21
|
+
* {@link OPERATION_TYPE_OUT_FAMILY} taxonomy of `@ledgerhq/ledger-wallet-framework`,
|
|
22
|
+
* extended with DeFi types not modelled at the framework level
|
|
23
|
+
* (`REDEEM`, `SELL`, `NFT_OUT`).
|
|
24
|
+
*
|
|
25
|
+
* Note: `OPERATION_TYPE_STAKE_FAMILY` ops (`BOND`, `STAKE`, `APPROVE`,
|
|
26
|
+
* `WITHDRAW_UNBONDED`, ...) are intentionally NOT included — they only move
|
|
27
|
+
* fees, not principal, so they're treated as `"ignored"` by `classifyOperation`.
|
|
28
|
+
*/
|
|
29
|
+
exports.OUTFLOWS = new Set([
|
|
30
|
+
...operation_1.OPERATION_TYPE_OUT_FAMILY,
|
|
31
|
+
"NFT_OUT",
|
|
32
|
+
"REDEEM",
|
|
33
|
+
"SELL",
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Stake-family ops are exposed for callers (and tests) that need to assert
|
|
37
|
+
* they're treated as no-ops by the cost-basis reducer.
|
|
38
|
+
*/
|
|
39
|
+
exports.STAKE_FAMILY = new Set(operation_1.OPERATION_TYPE_STAKE_FAMILY);
|
|
40
|
+
function classifyOperation(op) {
|
|
41
|
+
if (op.hasFailed)
|
|
42
|
+
return "ignored";
|
|
43
|
+
if (exports.INFLOWS.has(op.type))
|
|
44
|
+
return "inflow";
|
|
45
|
+
if (exports.OUTFLOWS.has(op.type))
|
|
46
|
+
return "outflow";
|
|
47
|
+
return "ignored";
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=classifyOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifyOperation.js","sourceRoot":"","sources":["../src/classifyOperation.ts"],"names":[],"mappings":";;;AA+CA,8CAKC;AAnDD,2EAIqD;AAGrD;;;;;;GAMG;AACU,QAAA,OAAO,GAAwC,IAAI,GAAG,CAAyB;IAC1F,GAAG,oCAAwB;IAC3B,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACU,QAAA,QAAQ,GAAwC,IAAI,GAAG,CAAyB;IAC3F,GAAG,qCAAyB;IAC5B,SAAS;IACT,QAAQ;IACR,MAAM;CACP,CAAC,CAAC;AAEH;;;GAGG;AACU,QAAA,YAAY,GAAwC,IAAI,GAAG,CACtE,uCAA2B,CAC5B,CAAC;AAEF,SAAgB,iBAAiB,CAAC,EAAa;IAC7C,IAAI,EAAE,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACnC,IAAI,eAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1C,IAAI,gBAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AccountLike, Operation } from "@ledgerhq/types-live";
|
|
2
|
+
import type { Currency } from "@ledgerhq/types-cryptoassets";
|
|
3
|
+
import type { CounterValuesState } from "@ledgerhq/live-countervalues/types";
|
|
4
|
+
import type { ComputePnLOptions, CostBasisState } from "./types";
|
|
5
|
+
export declare const initialCostBasisState: CostBasisState;
|
|
6
|
+
/**
|
|
7
|
+
* Append-only ACB reducer. Folds `newOps` into `prev` and returns a new
|
|
8
|
+
* `CostBasisState`. Reads ONLY historical countervalues at op dates — never
|
|
9
|
+
* `latest` — so the result is stable under price ticks.
|
|
10
|
+
*
|
|
11
|
+
* Returns `prev` (same reference) when nothing new applies.
|
|
12
|
+
*/
|
|
13
|
+
export declare function reduceCostBasis(prev: CostBasisState, newOps: Operation[], account: AccountLike, countervalues: CounterValuesState, fiat: Currency, options?: ComputePnLOptions): CostBasisState;
|
|
14
|
+
//# sourceMappingURL=costBasis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costBasis.d.ts","sourceRoot":"","sources":["../src/costBasis.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAG7E,OAAO,KAAK,EAAE,iBAAiB,EAAgB,cAAc,EAAiB,MAAM,SAAS,CAAC;AAI9F,eAAO,MAAM,qBAAqB,EAAE,cAQnC,CAAC;AA2EF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,SAAS,EAAE,EACnB,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,kBAAkB,EACjC,IAAI,EAAE,QAAQ,EACd,OAAO,CAAC,EAAE,iBAAiB,GAC1B,cAAc,CA+ChB"}
|
package/lib/costBasis.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initialCostBasisState = void 0;
|
|
7
|
+
exports.reduceCostBasis = reduceCostBasis;
|
|
8
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
9
|
+
const logic_1 = require("@ledgerhq/live-countervalues/logic");
|
|
10
|
+
const account_1 = require("@ledgerhq/ledger-wallet-framework/account");
|
|
11
|
+
const classifyOperation_1 = require("./classifyOperation");
|
|
12
|
+
const ZERO = new bignumber_js_1.default(0);
|
|
13
|
+
exports.initialCostBasisState = {
|
|
14
|
+
totalAmount: ZERO,
|
|
15
|
+
totalCostInCounterValue: ZERO,
|
|
16
|
+
lifetimeCostInCounterValue: ZERO,
|
|
17
|
+
realisedPnL: ZERO,
|
|
18
|
+
averageEntryPrice: ZERO,
|
|
19
|
+
lastOperationId: null,
|
|
20
|
+
lastOperationDate: null,
|
|
21
|
+
};
|
|
22
|
+
function compareOps(a, b) {
|
|
23
|
+
const da = a.date.getTime();
|
|
24
|
+
const db = b.date.getTime();
|
|
25
|
+
if (da !== db)
|
|
26
|
+
return da - db;
|
|
27
|
+
if (a.id < b.id)
|
|
28
|
+
return -1;
|
|
29
|
+
if (a.id > b.id)
|
|
30
|
+
return 1;
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
function isAfterBookmark(op, prev) {
|
|
34
|
+
if (prev.lastOperationDate === null)
|
|
35
|
+
return true;
|
|
36
|
+
const opTime = op.date.getTime();
|
|
37
|
+
const bookTime = prev.lastOperationDate.getTime();
|
|
38
|
+
if (opTime > bookTime)
|
|
39
|
+
return true;
|
|
40
|
+
if (opTime < bookTime)
|
|
41
|
+
return false;
|
|
42
|
+
return prev.lastOperationId !== null && op.id > prev.lastOperationId;
|
|
43
|
+
}
|
|
44
|
+
function applyInflow(acc, value, cvBN) {
|
|
45
|
+
const totalCost = acc.totalCost.plus(cvBN);
|
|
46
|
+
const totalAmount = acc.totalAmount.plus(value);
|
|
47
|
+
return {
|
|
48
|
+
totalAmount,
|
|
49
|
+
totalCost,
|
|
50
|
+
lifetimeCost: acc.lifetimeCost.plus(cvBN),
|
|
51
|
+
realised: acc.realised,
|
|
52
|
+
averageEntryPrice: totalAmount.gt(0) ? totalCost.div(totalAmount) : acc.averageEntryPrice,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function applyOutflow(acc, value, cvBN) {
|
|
56
|
+
if (acc.totalAmount.lte(0))
|
|
57
|
+
return acc;
|
|
58
|
+
const sold = bignumber_js_1.default.minimum(value, acc.totalAmount);
|
|
59
|
+
const costOfSale = sold.times(acc.averageEntryPrice);
|
|
60
|
+
// Scale exit CV proportionally when we clamped a sell that exceeded held amount.
|
|
61
|
+
const exitCV = sold.eq(value) ? cvBN : cvBN.times(sold).div(value);
|
|
62
|
+
return {
|
|
63
|
+
totalAmount: acc.totalAmount.minus(sold),
|
|
64
|
+
totalCost: acc.totalCost.minus(costOfSale),
|
|
65
|
+
// `lifetimeCost` is intentionally untouched on sells — it represents
|
|
66
|
+
// "money put in over the lifetime of the position", not the running
|
|
67
|
+
// basis of remaining coins.
|
|
68
|
+
lifetimeCost: acc.lifetimeCost,
|
|
69
|
+
realised: acc.realised.plus(exitCV.minus(costOfSale)),
|
|
70
|
+
averageEntryPrice: acc.averageEntryPrice,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function applyOperation(acc, op, flow, asset, fiat, countervalues) {
|
|
74
|
+
if (op.value.isZero() || op.value.isNegative())
|
|
75
|
+
return acc;
|
|
76
|
+
const cvAtDate = (0, logic_1.calculate)(countervalues, {
|
|
77
|
+
value: op.value.toNumber(),
|
|
78
|
+
from: asset,
|
|
79
|
+
to: fiat,
|
|
80
|
+
date: op.date,
|
|
81
|
+
disableRounding: true,
|
|
82
|
+
});
|
|
83
|
+
if (typeof cvAtDate !== "number")
|
|
84
|
+
return acc;
|
|
85
|
+
const cvBN = new bignumber_js_1.default(cvAtDate);
|
|
86
|
+
return flow === "inflow" ? applyInflow(acc, op.value, cvBN) : applyOutflow(acc, op.value, cvBN);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Append-only ACB reducer. Folds `newOps` into `prev` and returns a new
|
|
90
|
+
* `CostBasisState`. Reads ONLY historical countervalues at op dates — never
|
|
91
|
+
* `latest` — so the result is stable under price ticks.
|
|
92
|
+
*
|
|
93
|
+
* Returns `prev` (same reference) when nothing new applies.
|
|
94
|
+
*/
|
|
95
|
+
function reduceCostBasis(prev, newOps, account, countervalues, fiat, options) {
|
|
96
|
+
if (newOps.length === 0)
|
|
97
|
+
return prev;
|
|
98
|
+
const pending = [];
|
|
99
|
+
for (const op of newOps) {
|
|
100
|
+
if (isAfterBookmark(op, prev))
|
|
101
|
+
pending.push(op);
|
|
102
|
+
}
|
|
103
|
+
if (pending.length === 0)
|
|
104
|
+
return prev;
|
|
105
|
+
pending.sort(compareOps);
|
|
106
|
+
const asset = (0, account_1.getAccountCurrency)(account);
|
|
107
|
+
const isSpam = options?.isSpamOperation;
|
|
108
|
+
let acc = {
|
|
109
|
+
totalAmount: prev.totalAmount,
|
|
110
|
+
totalCost: prev.totalCostInCounterValue,
|
|
111
|
+
lifetimeCost: prev.lifetimeCostInCounterValue,
|
|
112
|
+
realised: prev.realisedPnL,
|
|
113
|
+
averageEntryPrice: prev.averageEntryPrice,
|
|
114
|
+
};
|
|
115
|
+
let lastOperationId = prev.lastOperationId;
|
|
116
|
+
let lastOperationDate = prev.lastOperationDate;
|
|
117
|
+
for (const op of pending) {
|
|
118
|
+
// Advance the bookmark for every seen op (even ignored ones) so that
|
|
119
|
+
// re-passing the same ops is a true no-op.
|
|
120
|
+
lastOperationId = op.id;
|
|
121
|
+
lastOperationDate = op.date;
|
|
122
|
+
if (isSpam?.(op, account))
|
|
123
|
+
continue;
|
|
124
|
+
const flow = (0, classifyOperation_1.classifyOperation)(op);
|
|
125
|
+
if (flow === "ignored")
|
|
126
|
+
continue;
|
|
127
|
+
acc = applyOperation(acc, op, flow, asset, fiat, countervalues);
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
totalAmount: acc.totalAmount,
|
|
131
|
+
totalCostInCounterValue: acc.totalCost,
|
|
132
|
+
lifetimeCostInCounterValue: acc.lifetimeCost,
|
|
133
|
+
realisedPnL: acc.realised,
|
|
134
|
+
averageEntryPrice: acc.averageEntryPrice,
|
|
135
|
+
lastOperationId,
|
|
136
|
+
lastOperationDate,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=costBasis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costBasis.js","sourceRoot":"","sources":["../src/costBasis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AccountLike } from "@ledgerhq/types-live";
|
|
2
|
+
import type { Currency } from "@ledgerhq/types-cryptoassets";
|
|
3
|
+
import type { CounterValuesState } from "@ledgerhq/live-countervalues/types";
|
|
4
|
+
import type { ComputePnLOptions, CostBasisState } from "./types";
|
|
5
|
+
export declare function getCostBasis(account: AccountLike, fiat: Currency, countervalues: CounterValuesState, options?: ComputePnLOptions): CostBasisState;
|
|
6
|
+
export declare function invalidatePnLCache(accountId?: string): void;
|
|
7
|
+
//# sourceMappingURL=costBasisCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costBasisCache.d.ts","sourceRoot":"","sources":["../src/costBasisCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAG7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAiCjE,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,QAAQ,EACd,aAAa,EAAE,kBAAkB,EACjC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,cAAc,CAgChB;AAED,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAS3D"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCostBasis = getCostBasis;
|
|
4
|
+
exports.invalidatePnLCache = invalidatePnLCache;
|
|
5
|
+
const logic_1 = require("@ledgerhq/live-countervalues/logic");
|
|
6
|
+
const helpers_1 = require("@ledgerhq/live-countervalues/helpers");
|
|
7
|
+
const account_1 = require("@ledgerhq/ledger-wallet-framework/account");
|
|
8
|
+
const costBasis_1 = require("./costBasis");
|
|
9
|
+
const cache = new Map();
|
|
10
|
+
function getHistoryKey(state, from, to, lastOpDate) {
|
|
11
|
+
if ((0, helpers_1.inferCurrencyAPIID)(from) === (0, helpers_1.inferCurrencyAPIID)(to))
|
|
12
|
+
return "identity";
|
|
13
|
+
const pairCache = (0, logic_1.lenseRateMap)(state, { from, to });
|
|
14
|
+
if (!pairCache)
|
|
15
|
+
return "noCV";
|
|
16
|
+
const { oldest, earliest, earliestStableDate } = pairCache.stats;
|
|
17
|
+
const bucket = lastOpDate ? (0, helpers_1.formatCounterValueDay)(lastOpDate) : "0";
|
|
18
|
+
const earliestRelevant = earliest && earliest <= bucket ? earliest : "";
|
|
19
|
+
return `${oldest ?? "_"}|${earliestStableDate ?? "_"}|${earliestRelevant}`;
|
|
20
|
+
}
|
|
21
|
+
function getLastOpBookmark(account) {
|
|
22
|
+
const ops = account.operations;
|
|
23
|
+
if (ops.length === 0)
|
|
24
|
+
return { id: "_", date: null };
|
|
25
|
+
let best = ops[0];
|
|
26
|
+
for (let i = 1; i < ops.length; i++) {
|
|
27
|
+
const op = ops[i];
|
|
28
|
+
const opTime = op.date.getTime();
|
|
29
|
+
const bestTime = best.date.getTime();
|
|
30
|
+
if (opTime > bestTime || (opTime === bestTime && op.id > best.id))
|
|
31
|
+
best = op;
|
|
32
|
+
}
|
|
33
|
+
return { id: best.id, date: best.date };
|
|
34
|
+
}
|
|
35
|
+
function getCostBasis(account, fiat, countervalues, options) {
|
|
36
|
+
const asset = (0, account_1.getAccountCurrency)(account);
|
|
37
|
+
if (options?.isSpamOperation) {
|
|
38
|
+
return (0, costBasis_1.reduceCostBasis)(costBasis_1.initialCostBasisState, account.operations, account, countervalues, fiat, options);
|
|
39
|
+
}
|
|
40
|
+
const { id: lastOpId, date: lastOpDate } = getLastOpBookmark(account);
|
|
41
|
+
const historyKey = getHistoryKey(countervalues, asset, fiat, lastOpDate);
|
|
42
|
+
const fiatKey = (0, helpers_1.inferCurrencyAPIID)(fiat);
|
|
43
|
+
const key = `${account.id}|${fiatKey}|${lastOpId}|${historyKey}`;
|
|
44
|
+
const hit = cache.get(key);
|
|
45
|
+
if (hit)
|
|
46
|
+
return hit;
|
|
47
|
+
const fresh = (0, costBasis_1.reduceCostBasis)(costBasis_1.initialCostBasisState, account.operations, account, countervalues, fiat, options);
|
|
48
|
+
cache.set(key, fresh);
|
|
49
|
+
return fresh;
|
|
50
|
+
}
|
|
51
|
+
function invalidatePnLCache(accountId) {
|
|
52
|
+
if (!accountId) {
|
|
53
|
+
cache.clear();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const prefix = `${accountId}|`;
|
|
57
|
+
for (const key of cache.keys()) {
|
|
58
|
+
if (key.startsWith(prefix))
|
|
59
|
+
cache.delete(key);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=costBasisCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costBasisCache.js","sourceRoot":"","sources":["../src/costBasisCache.ts"],"names":[],"mappings":";;AAwCA,oCAqCC;AAED,gDASC;AAtFD,8DAAkE;AAClE,kEAAiG;AAEjG,uEAA+E;AAC/E,2CAAqE;AAGrE,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEhD,SAAS,aAAa,CACpB,KAAyB,EACzB,IAAc,EACd,EAAY,EACZ,UAAuB;IAEvB,IAAI,IAAA,4BAAkB,EAAC,IAAI,CAAC,KAAK,IAAA,4BAAkB,EAAC,EAAE,CAAC;QAAE,OAAO,UAAU,CAAC;IAC3E,MAAM,SAAS,GAAG,IAAA,oBAAY,EAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC;IACjE,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAA,+BAAqB,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACpE,MAAM,gBAAgB,GAAG,QAAQ,IAAI,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,OAAO,GAAG,MAAM,IAAI,GAAG,IAAI,kBAAkB,IAAI,GAAG,IAAI,gBAAgB,EAAE,CAAC;AAC7E,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAoB;IAC7C,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAErD,IAAI,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,MAAM,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YAAE,IAAI,GAAG,EAAE,CAAC;IAC/E,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,SAAgB,YAAY,CAC1B,OAAoB,EACpB,IAAc,EACd,aAAiC,EACjC,OAA2B;IAE3B,MAAM,KAAK,GAAG,IAAA,4BAAkB,EAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;QAC7B,OAAO,IAAA,2BAAe,EACpB,iCAAqB,EACrB,OAAO,CAAC,UAAU,EAClB,OAAO,EACP,aAAa,EACb,IAAI,EACJ,OAAO,CACR,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,IAAA,4BAAkB,EAAC,IAAI,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,OAAO,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;IAEjE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IAEpB,MAAM,KAAK,GAAG,IAAA,2BAAe,EAC3B,iCAAqB,EACrB,OAAO,CAAC,UAAU,EAClB,OAAO,EACP,aAAa,EACb,IAAI,EACJ,OAAO,CACR,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,kBAAkB,CAAC,SAAkB;IACnD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,SAAS,GAAG,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import type { Currency } from "@ledgerhq/types-cryptoassets";
|
|
3
|
+
import type { CounterValuesState } from "@ledgerhq/live-countervalues/types";
|
|
4
|
+
import type { CostBasisState, Reconciliation } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Pure detection: compares the operations-derived `state.totalAmount` to the
|
|
7
|
+
* on-chain `balance` and returns the diagnostic. **Never** does any I/O on
|
|
8
|
+
* countervalues, **never** mutates state, **always** returns `applied: false`.
|
|
9
|
+
*
|
|
10
|
+
* The repair step is a separate concern — see {@link applyBalanceReconciliation}.
|
|
11
|
+
* This split lets callers detect anomalies (UI badges, audit logs) without
|
|
12
|
+
* paying the cost of the heuristic repair, and keeps the reducer pipeline
|
|
13
|
+
* trivially testable.
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectBalanceGap(state: CostBasisState, balance: BigNumber): Reconciliation;
|
|
16
|
+
/**
|
|
17
|
+
* Opinionated repair: when the `gap` shows a non-zero `delta`, folds a
|
|
18
|
+
* synthetic operation into the cost-basis state to close it.
|
|
19
|
+
*
|
|
20
|
+
* - `delta > 0` → synthetic INFLOW valued at the latest counter-value
|
|
21
|
+
* (rebase tokens, missing IN op…). Pushes the average
|
|
22
|
+
* entry price toward the latest market.
|
|
23
|
+
* - `delta < 0` → synthetic OUTFLOW priced at `state.lastOperationDate`
|
|
24
|
+
* (best-effort proxy for the unknown disposal date).
|
|
25
|
+
* The realised gain/loss equals `delta_value − sold × AEP`.
|
|
26
|
+
*
|
|
27
|
+
* `lifetimeCostInCounterValue` is intentionally NEVER touched here, even on
|
|
28
|
+
* a positive delta: rebase yield / silent accruals are not real cash
|
|
29
|
+
* investments, so they would distort a "% vs invested" KPI.
|
|
30
|
+
*
|
|
31
|
+
* Returns `applied: false` (and an unchanged state) when:
|
|
32
|
+
* - the gap is clean,
|
|
33
|
+
* - the counter-value lookup for the delta fails,
|
|
34
|
+
* - or a negative delta hits an empty position.
|
|
35
|
+
*
|
|
36
|
+
* Callers that want the combined detect+repair flow with the legacy signature
|
|
37
|
+
* should use {@link reconcileCostBasisWithBalance}.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyBalanceReconciliation(state: CostBasisState, gap: Reconciliation, asset: Currency, fiat: Currency, countervalues: CounterValuesState): {
|
|
40
|
+
state: CostBasisState;
|
|
41
|
+
applied: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Legacy combined detect+repair entry point, preserved for API stability.
|
|
45
|
+
* New code should prefer composing {@link detectBalanceGap} and
|
|
46
|
+
* {@link applyBalanceReconciliation} explicitly so the conditional mutation
|
|
47
|
+
* is obvious to the reader.
|
|
48
|
+
*
|
|
49
|
+
* Always returns the {@link Reconciliation} diagnostic so callers can flag
|
|
50
|
+
* the result in the UI (e.g. show a warning badge on the asset row).
|
|
51
|
+
*
|
|
52
|
+
* If `apply` is `false`, the gap is detected but no repair is attempted —
|
|
53
|
+
* `applied` will be `false` regardless of the delta.
|
|
54
|
+
*/
|
|
55
|
+
export declare function reconcileCostBasisWithBalance(state: CostBasisState, balance: BigNumber, asset: Currency, fiat: Currency, countervalues: CounterValuesState, apply: boolean): {
|
|
56
|
+
state: CostBasisState;
|
|
57
|
+
reconciliation: Reconciliation;
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=costBasisReconciliation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"costBasisReconciliation.d.ts","sourceRoot":"","sources":["../src/costBasisReconciliation.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9D;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,GAAG,cAAc,CAS1F;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,QAAQ,EACd,aAAa,EAAE,kBAAkB,GAChC;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA8D7C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,SAAS,EAClB,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,QAAQ,EACd,aAAa,EAAE,kBAAkB,EACjC,KAAK,EAAE,OAAO,GACb;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,cAAc,EAAE,cAAc,CAAA;CAAE,CAY3D"}
|