@gearbox-protocol/sdk 15.1.0-next.10 → 15.1.0-next.11

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.
Files changed (36) hide show
  1. package/dist/cjs/dev/compareOpportunities.js +45 -126
  2. package/dist/cjs/dev/comparePositions.js +183 -0
  3. package/dist/cjs/dev/fieldDiff.js +241 -0
  4. package/dist/cjs/sdk/market/math.js +8 -1
  5. package/dist/cjs/sdk/pools/PoolService.js +1 -1
  6. package/dist/cjs/sdk/positions/PositionsService.js +6 -1
  7. package/dist/esm/dev/AccountOpener.js +1 -1
  8. package/dist/esm/dev/compareOpportunities.js +44 -125
  9. package/dist/esm/dev/comparePositions.js +181 -0
  10. package/dist/esm/dev/fieldDiff.js +224 -0
  11. package/dist/esm/dev/withdrawalUtils.js +1 -1
  12. package/dist/esm/plugins/adapters/contracts/ERC4626AdapterContract.js +1 -1
  13. package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
  14. package/dist/esm/preview/trace/extractTransfers.js +1 -1
  15. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +2 -2
  16. package/dist/esm/sdk/accounts/liquidations/LiquidationsService.js +1 -1
  17. package/dist/esm/sdk/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  18. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  19. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  20. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  21. package/dist/esm/sdk/base/TokensMeta.js +3 -3
  22. package/dist/esm/sdk/chain/detectNetwork.js +1 -1
  23. package/dist/esm/sdk/core/createAddressProvider.js +1 -1
  24. package/dist/esm/sdk/market/credit/CreditFacadeV310BaseContract.js +1 -1
  25. package/dist/esm/sdk/market/math.js +8 -1
  26. package/dist/esm/sdk/market/pool/PoolV310Contract.js +1 -1
  27. package/dist/esm/sdk/market/zapper/IETHZapperContract.js +1 -1
  28. package/dist/esm/sdk/market/zapper/ZapperContract.js +1 -1
  29. package/dist/esm/sdk/pools/PoolService.js +2 -2
  30. package/dist/esm/sdk/positions/PositionsService.js +6 -1
  31. package/dist/esm/sdk/utils/viem/simulateWithPriceUpdates.js +1 -1
  32. package/dist/types/dev/compareOpportunities.d.ts +13 -61
  33. package/dist/types/dev/comparePositions.d.ts +149 -0
  34. package/dist/types/dev/fieldDiff.d.ts +167 -0
  35. package/dist/types/sdk/market/math.d.ts +2 -0
  36. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { iCreditFacadeV310Abi } from "../../abi/310/generated.js";
3
2
  import { AddressMap } from "../../sdk/utils/AddressMap.js";
3
+ import { ierc20Abi } from "../../abi/iERC20.js";
4
4
  import "../../sdk/index.js";
5
5
  import { UnexpectedFacadeEventOrderError } from "./errors.js";
6
6
  import { getAddress, isAddressEqual, parseEventLogs } from "viem";
@@ -1,5 +1,3 @@
1
- import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
2
- import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
3
1
  import { AP_REWARDS_COMPRESSOR } from "../constants/address-provider.js";
4
2
  import { ADDRESS_0X0 } from "../constants/addresses.js";
5
3
  import { MAX_UINT256 } from "../constants/math.js";
@@ -10,6 +8,8 @@ import "../base/index.js";
10
8
  import { AccountBotsService } from "./bots/AccountBotsService.js";
11
9
  import "./bots/index.js";
12
10
  import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
11
+ import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
12
+ import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
13
13
  import { expectedBalanceDeltas } from "../market/credit/expectedBalanceDeltas.js";
14
14
  import "../market/index.js";
15
15
  import { CreditAccountCompressor } from "./credit-account-compressor/CreditAccountCompressor.js";
@@ -1,4 +1,3 @@
1
- import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
2
1
  import { AddressSet } from "../../utils/AddressSet.js";
3
2
  import { bytes32ToString } from "../../utils/bytes32ToString.js";
4
3
  import { ADDRESS_0X0 } from "../../constants/addresses.js";
@@ -20,6 +19,7 @@ import { SecuritizeLiquidatorContract } from "../../market/rwa/securitize/Securi
20
19
  import "../../market/rwa/securitize/index.js";
21
20
  import "../../market/index.js";
22
21
  import { LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./constants.js";
22
+ import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
23
23
  //#region src/sdk/accounts/liquidations/LiquidationsService.ts
24
24
  /**
25
25
  * Service for discovering liquidatable credit accounts and previewing manual
@@ -1,7 +1,7 @@
1
- import { iRedemptionLoggerV310Abi } from "../../../abi/iRedemptionLoggerV310.js";
2
1
  import { BaseContract } from "../../base/BaseContract.js";
3
2
  import "../../base/index.js";
4
3
  import { decodeDelayedIntent } from "./intent-codec.js";
4
+ import { iRedemptionLoggerV310Abi } from "../../../abi/iRedemptionLoggerV310.js";
5
5
  import { InvalidDelayedIntentError } from "./errors.js";
6
6
  //#region src/sdk/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.ts
7
7
  const abi = iRedemptionLoggerV310Abi;
@@ -1,5 +1,5 @@
1
- import { iWithdrawalCompressorV310Abi } from "../../../abi/IWithdrawalCompressorV310.js";
2
1
  import { AbstractWithdrawalCompressorContract } from "./AbstractWithdrawalCompressorContract.js";
2
+ import { iWithdrawalCompressorV310Abi } from "../../../abi/IWithdrawalCompressorV310.js";
3
3
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.ts
4
4
  const abi = iWithdrawalCompressorV310Abi;
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { iWithdrawalCompressorV311Abi } from "../../../abi/IWithdrawalCompressorV311.js";
2
1
  import { AbstractWithdrawalCompressorContract } from "./AbstractWithdrawalCompressorContract.js";
2
+ import { iWithdrawalCompressorV311Abi } from "../../../abi/IWithdrawalCompressorV311.js";
3
3
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.ts
4
4
  const abi = iWithdrawalCompressorV311Abi;
5
5
  /**
@@ -1,6 +1,6 @@
1
- import { iWithdrawalCompressorV313Abi } from "../../../abi/IWithdrawalCompressorV313.js";
2
1
  import { encodeDelayedIntent } from "./intent-codec.js";
3
2
  import { AbstractWithdrawalCompressorContract, iCreditAccountAbi, toClaimableWithdrawal, toPendingWithdrawal, toRequestableWithdrawal } from "./AbstractWithdrawalCompressorContract.js";
3
+ import { iWithdrawalCompressorV313Abi } from "../../../abi/IWithdrawalCompressorV313.js";
4
4
  import { toWithdrawalStatus } from "./types.js";
5
5
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.ts
6
6
  const abi = iWithdrawalCompressorV313Abi;
@@ -1,12 +1,12 @@
1
- import { iExpirableAbi } from "../../abi/iExpirable.js";
2
- import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
3
- import { iVersionAbi } from "../../abi/iVersion.js";
4
1
  import { AddressMap } from "../utils/AddressMap.js";
5
2
  import { AddressSet } from "../utils/AddressSet.js";
6
3
  import { bytes32ToString } from "../utils/bytes32ToString.js";
7
4
  import { getAssetType } from "../chain/chains.js";
8
5
  import { formatBN } from "../utils/formatter.js";
9
6
  import "../utils/index.js";
7
+ import { iExpirableAbi } from "../../abi/iExpirable.js";
8
+ import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
9
+ import { iVersionAbi } from "../../abi/iVersion.js";
10
10
  import { executeMulticallBatches } from "../utils/viem/executeMulticallBatches.js";
11
11
  //#region src/sdk/base/TokensMeta.ts
12
12
  /**
@@ -1,5 +1,5 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { chains } from "./chains.js";
2
+ import { ierc20Abi } from "../../abi/iERC20.js";
3
3
  //#region src/sdk/chain/detectNetwork.ts
4
4
  /**
5
5
  * Detects the network type from the given client.
@@ -1,8 +1,8 @@
1
- import { iVersionAbi } from "../../abi/iVersion.js";
2
1
  import { AP_MARKET_COMPRESSOR, AP_PRICE_FEED_COMPRESSOR } from "../constants/address-provider.js";
3
2
  import { isV310 } from "../constants/versions.js";
4
3
  import "../constants/index.js";
5
4
  import { hexEq } from "../utils/hex.js";
5
+ import { iVersionAbi } from "../../abi/iVersion.js";
6
6
  import { AddressProviderV310Contract } from "./AddressProviderV310Contract.js";
7
7
  //#region src/sdk/core/createAddressProvider.ts
8
8
  const OVERRIDE_ADDRESSES = { Mainnet: {
@@ -1,7 +1,7 @@
1
- import { iPausableAbi } from "../../../abi/iPausable.js";
2
1
  import { iCreditFacadeMulticallV310Abi, iCreditFacadeV310Abi } from "../../../abi/310/generated.js";
3
2
  import { BaseContract } from "../../base/BaseContract.js";
4
3
  import "../../base/index.js";
4
+ import { iPausableAbi } from "../../../abi/iPausable.js";
5
5
  //#region src/sdk/market/credit/CreditFacadeV310BaseContract.ts
6
6
  const abi = [
7
7
  ...iCreditFacadeV310Abi,
@@ -23,8 +23,15 @@ function rayToBps(ray) {
23
23
  return Number(ray * PERCENTAGE_FACTOR / RAY);
24
24
  }
25
25
  /**
26
+ * Raw 8-decimal USD values below this are compressor leftover dust (typically
27
+ * 1-wei balances on empty accounts) and report as `0`.
28
+ **/
29
+ const USD_DUST_THRESHOLD = 1000n;
30
+ /**
26
31
  * Converts a USD value in the oracle's 8-decimal fixed point to a float.
27
32
  *
33
+ * Values below {@link USD_DUST_THRESHOLD} report as `0`.
34
+ *
28
35
  * @example
29
36
  * ```ts
30
37
  * // usd: $1500.50 in 8-decimal fixed point
@@ -32,7 +39,7 @@ function rayToBps(ray) {
32
39
  * ```
33
40
  **/
34
41
  function usdToNumber(usd) {
35
- return Number(usd) / Number(PRICE_DECIMALS);
42
+ return usd < USD_DUST_THRESHOLD ? 0 : Number(usd) / Number(PRICE_DECIMALS);
36
43
  }
37
44
  /**
38
45
  * Share of capital currently borrowed, in basis points. Returns `0` when there
@@ -1,4 +1,3 @@
1
- import { iPausableAbi } from "../../../abi/iPausable.js";
2
1
  import { iPoolV310Abi } from "../../../abi/310/generated.js";
3
2
  import { AddressMap } from "../../utils/AddressMap.js";
4
3
  import { RAY } from "../../constants/math.js";
@@ -7,6 +6,7 @@ import { formatBN, formatBNvalue, percentFmt } from "../../utils/formatter.js";
7
6
  import "../../utils/index.js";
8
7
  import { BaseContract } from "../../base/BaseContract.js";
9
8
  import "../../base/index.js";
9
+ import { iPausableAbi } from "../../../abi/iPausable.js";
10
10
  import { calcUtilization } from "../math.js";
11
11
  //#region src/sdk/market/pool/PoolV310Contract.ts
12
12
  const abi = [...iPoolV310Abi, ...iPausableAbi];
@@ -1,5 +1,5 @@
1
- import { iethZapperAbi } from "../../../abi/iETHZapper.js";
2
1
  import { ZapperContract } from "./ZapperContract.js";
2
+ import { iethZapperAbi } from "../../../abi/iETHZapper.js";
3
3
  //#region src/sdk/market/zapper/IETHZapperContract.ts
4
4
  const abi = iethZapperAbi;
5
5
  var IETHZapperContract = class extends ZapperContract {
@@ -1,6 +1,6 @@
1
- import { iZapperAbi } from "../../../abi/iZapper.js";
2
1
  import { BaseContract } from "../../base/BaseContract.js";
3
2
  import "../../base/index.js";
3
+ import { iZapperAbi } from "../../../abi/iZapper.js";
4
4
  import { UnsupportedZapperFunctionError } from "./errors.js";
5
5
  //#region src/sdk/market/zapper/ZapperContract.ts
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { AddressSet } from "../utils/AddressSet.js";
2
+ import { ierc20Abi } from "../../abi/iERC20.js";
3
3
  import "../constants/addresses.js";
4
4
  import { PERCENTAGE_FACTOR, RAY } from "../constants/math.js";
5
5
  import "../constants/index.js";
@@ -414,7 +414,7 @@ var PoolService = class extends SDKConstruct {
414
414
  const { pool } = market.pool;
415
415
  return {
416
416
  kind: "pool",
417
- name: market.poolName,
417
+ name: this.sdk.tokensMeta.mustGetToken(pool.address).name,
418
418
  chainId: this.chainId,
419
419
  pool: pool.address,
420
420
  netValue: {
@@ -1,6 +1,7 @@
1
1
  import { AddressMap } from "../utils/AddressMap.js";
2
2
  import "../constants/math.js";
3
3
  import "../constants/index.js";
4
+ import { hexEq } from "../utils/hex.js";
4
5
  import "../utils/index.js";
5
6
  import { SDKConstruct } from "../base/SDKConstruct.js";
6
7
  import "../base/index.js";
@@ -146,7 +147,11 @@ var PositionsService = class extends SDKConstruct {
146
147
  const { pool } = market.pool;
147
148
  const token = this.sdk.tokensMeta.mustGetToken(market.unwrappedUnderlying);
148
149
  const totalDebtValue = ca.debt + ca.accruedInterest + ca.accruedFees;
149
- const collateral = dominantCollateral(ca, market);
150
+ let collateral = dominantCollateral(ca, market);
151
+ if (collateral) {
152
+ const source = this.sdk.withdrawalCompressor?.getWithdrawalSourceToken(collateral);
153
+ if (source) collateral = hexEq(source, market.underlying) ? void 0 : source;
154
+ }
150
155
  const snapshot = accountSnapshotFromCreditAccountData(ca);
151
156
  const borrowRate = this.borrowRate(snapshot);
152
157
  const timeToLiquidation = this.timeToLiquidation(snapshot);
@@ -1,6 +1,6 @@
1
1
  import { errorAbis } from "../../../abi/errors.js";
2
- import { iUpdatablePriceFeedAbi } from "../../../abi/iUpdatablePriceFeed.js";
3
2
  import { generateCastTraceCall } from "./cast.js";
3
+ import { iUpdatablePriceFeedAbi } from "../../../abi/iUpdatablePriceFeed.js";
4
4
  import { simulateMulticall } from "./simulateMulticall.js";
5
5
  import { BaseError, CallExecutionError, ContractFunctionRevertedError, decodeFunctionData, decodeFunctionResult, encodeFunctionData, parseAbi } from "viem";
6
6
  import { getAction, parseAccount } from "viem/utils";
@@ -2,37 +2,9 @@ import { ChainId } from "../model/primitives.js";
2
2
  import { Opportunity, OpportunityId, OpportunityKind } from "../model/opportunities.js";
3
3
  import { ChainMetadata, DataResponse } from "../model/response.js";
4
4
  import "../model/index.js";
5
+ import { ChainCompareCounts, CompareCounts, DiffKind, DiffPathCount, ExpectedDiffReason, FieldDiff } from "./fieldDiff.js";
5
6
  import { Address } from "viem";
6
7
  //#region src/dev/compareOpportunities.d.ts
7
- /**
8
- * What kind of disagreement a {@link FieldDiff} describes, so that a reader can
9
- * bucket the report without re-deriving it from the values.
10
- *
11
- * - `"presence"` — one side has no value at all (`undefined` or `null`).
12
- * - `"usd"` — an {@link Amount.valueUsd}, i.e. a price-derived float.
13
- * - `"numeric"` — any other number or bigint.
14
- * - `"other"` — everything else: strings, booleans, array shapes.
15
- **/
16
- type DiffKind = "presence" | "usd" | "numeric" | "other";
17
- /**
18
- * One field of one opportunity where the two sources disagree.
19
- **/
20
- interface FieldDiff {
21
- /**
22
- * Dotted path into the row, with array elements keyed by their own identity
23
- * rather than by index, e.g. `collateralTokens[0xa0b8...].symbol`.
24
- **/
25
- path: string;
26
- /**
27
- * Value the chain reported, `undefined` when it has no such field.
28
- **/
29
- onchain: unknown;
30
- /**
31
- * Value the backend reported, see {@link onchain}.
32
- **/
33
- offchain: unknown;
34
- kind: DiffKind;
35
- }
36
8
  /**
37
9
  * Enough of an opportunity to identify it in a report without carrying the
38
10
  * whole row.
@@ -64,36 +36,16 @@ interface OpportunityMatch {
64
36
  **/
65
37
  onchainName: string;
66
38
  offchainName: string;
39
+ /**
40
+ * No diffs at all, including the documented offchain-only ones.
41
+ **/
67
42
  identical: boolean;
43
+ /**
44
+ * No unexpected diffs: every disagreement is mode-scoped or within tolerance.
45
+ **/
46
+ clean: boolean;
68
47
  diffs: FieldDiff[];
69
48
  }
70
- /**
71
- * How often one field disagreed across all matched rows, with array keys
72
- * collapsed, e.g. `collateralTokens[].symbol`.
73
- **/
74
- interface DiffPathCount {
75
- path: string;
76
- kinds: DiffKind[];
77
- count: number;
78
- }
79
- /**
80
- * Counts of one chain, or of the whole report when `chainId` is absent.
81
- **/
82
- interface CompareCounts {
83
- onchainRows: number;
84
- offchainRows: number;
85
- matched: number;
86
- identical: number;
87
- differing: number;
88
- onlyOnchain: number;
89
- onlyOffchain: number;
90
- }
91
- /**
92
- * Counts of one chain.
93
- **/
94
- interface ChainCompareCounts extends CompareCounts {
95
- chainId: ChainId;
96
- }
97
49
  /**
98
50
  * Totals of the comparison plus the fields that differed most often.
99
51
  **/
@@ -139,10 +91,10 @@ interface CompareOpportunitiesInput {
139
91
  * Matches two opportunity listings by {@link opportunityId} and reports every
140
92
  * field the two sources disagree on.
141
93
  *
142
- * Nothing is filtered out: a diff that is expected — a field only the backend
143
- * can fill, a formula the two sides define differently, a USD value smoothed on
144
- * one side — is reported like any other, tagged by {@link DiffKind} so that a
145
- * reader can bucket it afterwards.
94
+ * Nothing is filtered out. A field only the backend can fill, or a USD value
95
+ * that drifted within snapshot-lag noise, is still reported — tagged
96
+ * {@link FieldDiff.expected} so that {@link CompareCounts.clean} can ignore it
97
+ * while {@link CompareCounts.identical} stays strict.
146
98
  **/
147
99
  declare function compareOpportunities(input: CompareOpportunitiesInput): OpportunityCompareReport;
148
100
  /**
@@ -150,4 +102,4 @@ declare function compareOpportunities(input: CompareOpportunitiesInput): Opportu
150
102
  **/
151
103
  declare function diffOpportunity(onchain: Opportunity, offchain: Opportunity): FieldDiff[];
152
104
  //#endregion
153
- export { ChainCompareCounts, CompareCounts, CompareOpportunitiesInput, CompareSummary, DiffKind, DiffPathCount, FieldDiff, OpportunityCompareReport, OpportunityMatch, OpportunityRef, compareOpportunities, diffOpportunity };
105
+ export { type ChainCompareCounts, type CompareCounts, CompareOpportunitiesInput, CompareSummary, type DiffKind, type DiffPathCount, type ExpectedDiffReason, type FieldDiff, OpportunityCompareReport, OpportunityMatch, OpportunityRef, compareOpportunities, diffOpportunity };
@@ -0,0 +1,149 @@
1
+ import { ChainId } from "../model/primitives.js";
2
+ import { Position, PositionId, PositionKind } from "../model/positions.js";
3
+ import { ChainMetadata, DataResponse } from "../model/response.js";
4
+ import "../model/index.js";
5
+ import { ChainCompareCounts, CompareCounts, DiffPathCount, FieldDiff } from "./fieldDiff.js";
6
+ import { Address } from "viem";
7
+ //#region src/dev/comparePositions.d.ts
8
+ /**
9
+ * Enough of a position to identify it in a report without carrying the whole
10
+ * row.
11
+ **/
12
+ interface PositionRef {
13
+ id: PositionId;
14
+ kind: PositionKind;
15
+ chainId: ChainId;
16
+ name: string;
17
+ /**
18
+ * Set on a pool position.
19
+ **/
20
+ pool?: Address;
21
+ /**
22
+ * Set on a strategy position.
23
+ **/
24
+ creditAccount?: Address;
25
+ creditManager?: Address;
26
+ }
27
+ /**
28
+ * One position both sources listed for a wallet, and everything they disagree
29
+ * on.
30
+ **/
31
+ interface PositionMatch {
32
+ id: PositionId;
33
+ kind: PositionKind;
34
+ chainId: ChainId;
35
+ onchainName: string;
36
+ offchainName: string;
37
+ /**
38
+ * No diffs at all, including the documented mode-scoped ones.
39
+ **/
40
+ identical: boolean;
41
+ /**
42
+ * No unexpected diffs: every disagreement is mode-scoped or within tolerance.
43
+ **/
44
+ clean: boolean;
45
+ diffs: FieldDiff[];
46
+ }
47
+ /**
48
+ * One wallet's comparison, or the error that stopped it.
49
+ **/
50
+ interface WalletComparison {
51
+ wallet: Address;
52
+ /**
53
+ * Why both listings of this wallet could not be read. When set, the rest of
54
+ * the fields are empty.
55
+ **/
56
+ error?: string;
57
+ onlyOnchain: PositionRef[];
58
+ onlyOffchain: PositionRef[];
59
+ matched: PositionMatch[];
60
+ }
61
+ /**
62
+ * Counts of one wallet.
63
+ **/
64
+ interface WalletCompareCounts extends CompareCounts {
65
+ wallet: Address;
66
+ /**
67
+ * Present when the wallet's listings could not be read.
68
+ **/
69
+ error?: string;
70
+ }
71
+ /**
72
+ * Totals of the comparison plus the fields that differed most often.
73
+ **/
74
+ interface PositionsCompareSummary extends CompareCounts {
75
+ wallets: number;
76
+ /**
77
+ * Wallets whose listings were read and that have no membership gaps and no
78
+ * unexpected field diffs.
79
+ **/
80
+ walletsClean: number;
81
+ walletsFailed: number;
82
+ byChain: ChainCompareCounts[];
83
+ byWallet: WalletCompareCounts[];
84
+ diffsByPath: DiffPathCount[];
85
+ }
86
+ /**
87
+ * Everything one comparison run produced, ready to be written out as JSON.
88
+ **/
89
+ interface PositionsCompareReport {
90
+ generatedAt: string;
91
+ backendUrl: string;
92
+ networks: string[];
93
+ /**
94
+ * Per-chain metadata collected from the on-chain reads, which says which
95
+ * block each chain answered from. Taken from the first successful wallet
96
+ * listing of each chain.
97
+ **/
98
+ onchainChains: ChainMetadata[];
99
+ /**
100
+ * Per-chain metadata of the backend reads, see {@link onchainChains}.
101
+ **/
102
+ offchainChains: ChainMetadata[];
103
+ summary: PositionsCompareSummary;
104
+ wallets: WalletComparison[];
105
+ }
106
+ /**
107
+ * Both listings of one wallet.
108
+ **/
109
+ interface WalletPositions {
110
+ wallet: Address;
111
+ onchain: DataResponse<Position[]>;
112
+ offchain: DataResponse<Position[]>;
113
+ }
114
+ /**
115
+ * A wallet whose listings could not be read from one or both sources.
116
+ **/
117
+ interface WalletPositionsFailure {
118
+ wallet: Address;
119
+ error: string;
120
+ }
121
+ /**
122
+ * The per-wallet listings to compare, plus what the run was pointed at.
123
+ **/
124
+ interface ComparePositionsInput {
125
+ wallets: WalletPositions[];
126
+ failures?: WalletPositionsFailure[];
127
+ backendUrl: string;
128
+ networks: string[];
129
+ /**
130
+ * ISO timestamp stamped onto the report, defaulting to now. Pinned by tests.
131
+ **/
132
+ generatedAt?: string;
133
+ }
134
+ /**
135
+ * Matches two position listings per wallet by {@link positionId} and reports
136
+ * every field the two sources disagree on.
137
+ *
138
+ * Nothing is filtered out. A field only one mode can fill, or a USD value that
139
+ * drifted within snapshot-lag noise, is still reported — tagged
140
+ * {@link FieldDiff.expected} so that {@link CompareCounts.clean} can ignore it
141
+ * while {@link CompareCounts.identical} stays strict.
142
+ **/
143
+ declare function comparePositions(input: ComparePositionsInput): PositionsCompareReport;
144
+ /**
145
+ * Every field two versions of one position disagree on.
146
+ **/
147
+ declare function diffPosition(onchain: Position, offchain: Position): FieldDiff[];
148
+ //#endregion
149
+ export { ComparePositionsInput, PositionMatch, PositionRef, PositionsCompareReport, PositionsCompareSummary, WalletCompareCounts, WalletComparison, WalletPositions, WalletPositionsFailure, comparePositions, diffPosition };
@@ -0,0 +1,167 @@
1
+ import { ChainId } from "../model/primitives.js";
2
+ import "../model/index.js";
3
+ //#region src/dev/fieldDiff.d.ts
4
+ /**
5
+ * What kind of disagreement a {@link FieldDiff} describes, so that a reader can
6
+ * bucket the report without re-deriving it from the values.
7
+ *
8
+ * - `"presence"` — one side has no value at all (`undefined` or `null`).
9
+ * - `"usd"` — an {@link Amount.valueUsd}, i.e. a price-derived float.
10
+ * - `"numeric"` — any other number or bigint.
11
+ * - `"other"` — everything else: strings, booleans, array shapes.
12
+ **/
13
+ type DiffKind = "presence" | "usd" | "numeric" | "other";
14
+ /**
15
+ * Why a {@link FieldDiff} is expected rather than a real disagreement.
16
+ *
17
+ * - `"mode-scoped"` — a field documented `@mode offchain` or `@mode onchain`,
18
+ * so the other source has nothing to put there.
19
+ * - `"tolerance"` — snapshot lag or float-path noise within the thresholds
20
+ * below, not a formula or membership mismatch.
21
+ **/
22
+ type ExpectedDiffReason = "mode-scoped" | "tolerance";
23
+ /**
24
+ * One field of one row where the two sources disagree.
25
+ **/
26
+ interface FieldDiff {
27
+ /**
28
+ * Dotted path into the row, with array elements keyed by their own identity
29
+ * rather than by index, e.g. `collateralTokens[0xa0b8...].symbol`.
30
+ **/
31
+ path: string;
32
+ /**
33
+ * Value the chain reported, `undefined` when it has no such field.
34
+ **/
35
+ onchain: unknown;
36
+ /**
37
+ * Value the backend reported, see {@link onchain}.
38
+ **/
39
+ offchain: unknown;
40
+ kind: DiffKind;
41
+ /**
42
+ * Present when this disagreement is documented or within snapshot-lag noise,
43
+ * so it does not keep the row from being counted as clean.
44
+ **/
45
+ expected?: true;
46
+ reason?: ExpectedDiffReason;
47
+ }
48
+ /**
49
+ * How often one field disagreed across all matched rows, with array keys
50
+ * collapsed, e.g. `collateralTokens[].symbol`.
51
+ **/
52
+ interface DiffPathCount {
53
+ path: string;
54
+ kinds: DiffKind[];
55
+ count: number;
56
+ expected: number;
57
+ unexpected: number;
58
+ }
59
+ /**
60
+ * Counts of one chain, one wallet, or of the whole report when those ids are
61
+ * absent.
62
+ **/
63
+ interface CompareCounts {
64
+ onchainRows: number;
65
+ offchainRows: number;
66
+ matched: number;
67
+ identical: number;
68
+ /**
69
+ * Matched rows with no unexpected diffs, including the identical ones.
70
+ **/
71
+ clean: number;
72
+ differing: number;
73
+ onlyOnchain: number;
74
+ onlyOffchain: number;
75
+ }
76
+ /**
77
+ * Counts of one chain.
78
+ **/
79
+ interface ChainCompareCounts extends CompareCounts {
80
+ chainId: ChainId;
81
+ }
82
+ /**
83
+ * Identity of an array element, used so a token present on one side only is
84
+ * reported as such rather than shifting every later element into a diff.
85
+ *
86
+ * Return a string to key the element; `undefined` falls back to the default
87
+ * (`address`, `id`, `token`, or nested `token.address`).
88
+ **/
89
+ type ArrayElementKey = (path: string, value: unknown) => string | undefined;
90
+ /**
91
+ * How to walk two values. Callers that need identity-bearing arrays whose
92
+ * key is not one of the defaults pass {@link DiffOptions.keyOf}.
93
+ **/
94
+ interface DiffOptions {
95
+ keyOf?: ArrayElementKey;
96
+ }
97
+ /**
98
+ * Relative drift allowed on {@link Amount.valueUsd} before a USD float is a
99
+ * real disagreement: 0.1%.
100
+ **/
101
+ declare const USD_RELATIVE_EPSILON = 0.001;
102
+ /**
103
+ * Relative drift allowed on lag-bounded bigint amounts: 0.05%.
104
+ **/
105
+ declare const AMOUNT_RELATIVE_EPSILON = 0.0005;
106
+ /**
107
+ * Absolute drift allowed on bps rates before rounding and a one-block lag are
108
+ * no longer enough to explain it.
109
+ **/
110
+ declare const BPS_ABSOLUTE_EPSILON = 1;
111
+ /**
112
+ * Every field two versions of one value disagree on. Nothing is filtered or
113
+ * tagged: the caller marks expected diffs afterwards.
114
+ **/
115
+ declare function diffValue(path: string, onchain: unknown, offchain: unknown, out: FieldDiff[], options?: DiffOptions): void;
116
+ /**
117
+ * Deep-diff two values and return the disagreements, in path order of
118
+ * discovery.
119
+ **/
120
+ declare function diffObjects(onchain: unknown, offchain: unknown, options?: DiffOptions): FieldDiff[];
121
+ /**
122
+ * Mark a diff expected, so a later `clean` count can ignore it.
123
+ **/
124
+ declare function withExpected(diff: FieldDiff, reason: ExpectedDiffReason): FieldDiff;
125
+ /**
126
+ * How often each field differed, with array keys collapsed so that the same
127
+ * field of a hundred collateral tokens counts as one path. Sorted so the
128
+ * unexpected disagreements come first.
129
+ **/
130
+ declare function countPaths(diffs: Iterable<FieldDiff>): DiffPathCount[];
131
+ /**
132
+ * Collapse `collateralTokens[0xa0b8...].symbol` to `collateralTokens[].symbol`.
133
+ **/
134
+ declare function collapseArrayKeys(path: string): string;
135
+ /**
136
+ * Membership and match totals of one comparison, from already-built lists.
137
+ **/
138
+ declare function toCompareCounts(onchainRows: number, offchainRows: number, onlyOnchain: number, onlyOffchain: number, matched: ReadonlyArray<{
139
+ identical: boolean;
140
+ clean: boolean;
141
+ }>): CompareCounts;
142
+ /**
143
+ * USD floats within {@link USD_RELATIVE_EPSILON}.
144
+ **/
145
+ declare function isUsdWithinTolerance(onchain: unknown, offchain: unknown): boolean;
146
+ /**
147
+ * Bps rates that differ by at most {@link BPS_ABSOLUTE_EPSILON}.
148
+ **/
149
+ declare function isBpsWithinTolerance(onchain: unknown, offchain: unknown): boolean;
150
+ /**
151
+ * Bigint amounts within {@link AMOUNT_RELATIVE_EPSILON}.
152
+ **/
153
+ declare function isAmountWithinTolerance(onchain: unknown, offchain: unknown): boolean;
154
+ /**
155
+ * Finite numbers within a relative epsilon of each other.
156
+ **/
157
+ declare function withinRelative(onchain: number | undefined, offchain: number | undefined, epsilon: number): boolean;
158
+ /**
159
+ * `diff / max(|a|, |b|) <= epsilon`, computed in integer arithmetic so a
160
+ * 1e18-scale amount does not round through `Number`.
161
+ **/
162
+ declare function withinRelativeBigint(onchain: bigint, offchain: bigint, epsilon: number): boolean;
163
+ declare function asFiniteNumber(value: unknown): number | undefined;
164
+ declare function union(left: string[], right: string[]): string[];
165
+ declare function isRecord(value: unknown): value is Record<string, unknown>;
166
+ //#endregion
167
+ export { AMOUNT_RELATIVE_EPSILON, ArrayElementKey, BPS_ABSOLUTE_EPSILON, ChainCompareCounts, CompareCounts, DiffKind, DiffOptions, DiffPathCount, ExpectedDiffReason, FieldDiff, USD_RELATIVE_EPSILON, asFiniteNumber, collapseArrayKeys, countPaths, diffObjects, diffValue, isAmountWithinTolerance, isBpsWithinTolerance, isRecord, isUsdWithinTolerance, toCompareCounts, union, withExpected, withinRelative, withinRelativeBigint };
@@ -15,6 +15,8 @@ declare function rayToBps(ray: bigint): Bps;
15
15
  /**
16
16
  * Converts a USD value in the oracle's 8-decimal fixed point to a float.
17
17
  *
18
+ * Values below {@link USD_DUST_THRESHOLD} report as `0`.
19
+ *
18
20
  * @example
19
21
  * ```ts
20
22
  * // usd: $1500.50 in 8-decimal fixed point
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "15.1.0-next.10",
3
+ "version": "15.1.0-next.11",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {