@gearbox-protocol/sdk 15.1.0-next.4 → 15.1.0-next.5

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.
@@ -0,0 +1,218 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_model_opportunities = require("../model/opportunities.js");
3
+ require("../model/index.js");
4
+ //#region src/dev/compareOpportunities.ts
5
+ /**
6
+ * Matches two opportunity listings by {@link opportunityId} and reports every
7
+ * field the two sources disagree on.
8
+ *
9
+ * Nothing is filtered out: a diff that is expected — a field only the backend
10
+ * can fill, a formula the two sides define differently, a USD value smoothed on
11
+ * one side — is reported like any other, tagged by {@link DiffKind} so that a
12
+ * reader can bucket it afterwards.
13
+ **/
14
+ function compareOpportunities(input) {
15
+ const onchainRows = indexById(input.onchain.data);
16
+ const offchainRows = indexById(input.offchain.data);
17
+ const onlyOnchain = [];
18
+ const onlyOffchain = [];
19
+ const matched = [];
20
+ for (const [id, row] of onchainRows) {
21
+ const counterpart = offchainRows.get(id);
22
+ if (!counterpart) {
23
+ onlyOnchain.push(toRef(row));
24
+ continue;
25
+ }
26
+ const diffs = diffOpportunity(row, counterpart);
27
+ matched.push({
28
+ id,
29
+ kind: row.kind,
30
+ chainId: row.chainId,
31
+ onchainName: row.name,
32
+ offchainName: counterpart.name,
33
+ identical: diffs.length === 0,
34
+ diffs
35
+ });
36
+ }
37
+ for (const [id, row] of offchainRows) if (!onchainRows.has(id)) onlyOffchain.push(toRef(row));
38
+ byId(onlyOnchain);
39
+ byId(onlyOffchain);
40
+ matched.sort((a, b) => a.id.localeCompare(b.id));
41
+ return {
42
+ generatedAt: input.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
43
+ backendUrl: input.backendUrl,
44
+ networks: [...input.networks],
45
+ onchainChains: input.onchain.meta.chains,
46
+ offchainChains: input.offchain.meta.chains,
47
+ summary: summarize(input.onchain.data, input.offchain.data, onlyOnchain, onlyOffchain, matched),
48
+ onlyOnchain,
49
+ onlyOffchain,
50
+ matched
51
+ };
52
+ }
53
+ function indexById(rows) {
54
+ return new Map(rows.map((row) => [require_model_opportunities.opportunityId(row), row]));
55
+ }
56
+ function byId(refs) {
57
+ refs.sort((a, b) => a.id.localeCompare(b.id));
58
+ }
59
+ function toRef(row) {
60
+ const base = {
61
+ id: require_model_opportunities.opportunityId(row),
62
+ kind: row.kind,
63
+ chainId: row.chainId,
64
+ name: row.name
65
+ };
66
+ return row.kind === "pool" ? {
67
+ ...base,
68
+ pool: row.pool
69
+ } : {
70
+ ...base,
71
+ creditManager: row.creditManager,
72
+ targetCollateral: row.targetCollateral.address
73
+ };
74
+ }
75
+ /**
76
+ * Every field two versions of one opportunity disagree on.
77
+ **/
78
+ function diffOpportunity(onchain, offchain) {
79
+ const diffs = [];
80
+ diffValue("", onchain, offchain, diffs);
81
+ return diffs;
82
+ }
83
+ function diffValue(path, onchain, offchain, out) {
84
+ if (isAbsent(onchain) && isAbsent(offchain)) return;
85
+ if (isAbsent(onchain) || isAbsent(offchain)) {
86
+ out.push({
87
+ path,
88
+ onchain,
89
+ offchain,
90
+ kind: "presence"
91
+ });
92
+ return;
93
+ }
94
+ if (Array.isArray(onchain) && Array.isArray(offchain)) {
95
+ diffArray(path, onchain, offchain, out);
96
+ return;
97
+ }
98
+ if (isRecord(onchain) && isRecord(offchain)) {
99
+ for (const key of union(Object.keys(onchain), Object.keys(offchain))) diffValue(join(path, key), onchain[key], offchain[key], out);
100
+ return;
101
+ }
102
+ if (!sameScalar(onchain, offchain)) out.push({
103
+ path,
104
+ onchain,
105
+ offchain,
106
+ kind: scalarKind(path, onchain)
107
+ });
108
+ }
109
+ /**
110
+ * Arrays whose elements identify themselves — collateral tokens, points
111
+ * programs — are matched by that identity, so a token present on one side only
112
+ * is reported as such rather than shifting every later element into a diff.
113
+ **/
114
+ function diffArray(path, onchain, offchain, out) {
115
+ const onchainKeyed = keyElements(onchain);
116
+ const offchainKeyed = keyElements(offchain);
117
+ if (!onchainKeyed || !offchainKeyed) {
118
+ if (onchain.length !== offchain.length) {
119
+ out.push({
120
+ path,
121
+ onchain,
122
+ offchain,
123
+ kind: "other"
124
+ });
125
+ return;
126
+ }
127
+ onchain.forEach((element, index) => {
128
+ diffValue(`${path}[${index}]`, element, offchain[index], out);
129
+ });
130
+ return;
131
+ }
132
+ for (const key of union([...onchainKeyed.keys()], [...offchainKeyed.keys()])) diffValue(`${path}[${key}]`, onchainKeyed.get(key), offchainKeyed.get(key), out);
133
+ }
134
+ /**
135
+ * The array indexed by each element's own identity, or `undefined` when its
136
+ * elements have none and order is all there is to go by.
137
+ **/
138
+ function keyElements(values) {
139
+ const keyed = /* @__PURE__ */ new Map();
140
+ for (const value of values) {
141
+ if (!isRecord(value)) return;
142
+ const identity = value.address ?? value.id ?? value.token;
143
+ if (typeof identity !== "string") return;
144
+ keyed.set(identity.toLowerCase(), value);
145
+ }
146
+ return keyed.size === values.length ? keyed : void 0;
147
+ }
148
+ const ADDRESS = /^0x[0-9a-f]{40}$/i;
149
+ /**
150
+ * Only addresses are compared case-insensitively: the backend lowercases them
151
+ * while the chain hands out checksummed ones, which is not a disagreement. A
152
+ * symbol or a name spelled differently is.
153
+ **/
154
+ function sameScalar(onchain, offchain) {
155
+ if (typeof onchain === "string" && typeof offchain === "string" && ADDRESS.test(onchain) && ADDRESS.test(offchain)) return onchain.toLowerCase() === offchain.toLowerCase();
156
+ return onchain === offchain;
157
+ }
158
+ function scalarKind(path, onchain) {
159
+ if (path.endsWith("valueUsd")) return "usd";
160
+ return typeof onchain === "number" || typeof onchain === "bigint" ? "numeric" : "other";
161
+ }
162
+ function summarize(onchain, offchain, onlyOnchain, onlyOffchain, matched) {
163
+ const byChain = union(onchain.map((row) => String(row.chainId)), offchain.map((row) => String(row.chainId))).map((chainId) => ({
164
+ chainId: Number(chainId),
165
+ ...count(onchain.filter((row) => String(row.chainId) === chainId), offchain.filter((row) => String(row.chainId) === chainId), onlyOnchain.filter((ref) => String(ref.chainId) === chainId), onlyOffchain.filter((ref) => String(ref.chainId) === chainId), matched.filter((match) => String(match.chainId) === chainId))
166
+ })).sort((a, b) => a.chainId - b.chainId);
167
+ return {
168
+ ...count(onchain, offchain, onlyOnchain, onlyOffchain, matched),
169
+ byChain,
170
+ diffsByPath: countPaths(matched)
171
+ };
172
+ }
173
+ function count(onchain, offchain, onlyOnchain, onlyOffchain, matched) {
174
+ const identical = matched.filter((match) => match.identical).length;
175
+ return {
176
+ onchainRows: onchain.length,
177
+ offchainRows: offchain.length,
178
+ matched: matched.length,
179
+ identical,
180
+ differing: matched.length - identical,
181
+ onlyOnchain: onlyOnchain.length,
182
+ onlyOffchain: onlyOffchain.length
183
+ };
184
+ }
185
+ /**
186
+ * How often each field differed, with array keys collapsed so that the same
187
+ * field of a hundred collateral tokens counts as one path.
188
+ **/
189
+ function countPaths(matched) {
190
+ const counts = /* @__PURE__ */ new Map();
191
+ for (const match of matched) for (const diff of match.diffs) {
192
+ const path = diff.path.replace(/\[[^\]]*\]/g, "[]");
193
+ const entry = counts.get(path) ?? {
194
+ path,
195
+ kinds: [],
196
+ count: 0
197
+ };
198
+ entry.count += 1;
199
+ if (!entry.kinds.includes(diff.kind)) entry.kinds.push(diff.kind);
200
+ counts.set(path, entry);
201
+ }
202
+ return [...counts.values()].sort((a, b) => b.count - a.count || a.path.localeCompare(b.path));
203
+ }
204
+ function isAbsent(value) {
205
+ return value === void 0 || value === null;
206
+ }
207
+ function isRecord(value) {
208
+ return typeof value === "object" && value !== null && !Array.isArray(value);
209
+ }
210
+ function union(left, right) {
211
+ return [.../* @__PURE__ */ new Set([...left, ...right])];
212
+ }
213
+ function join(path, key) {
214
+ return path ? `${path}.${key}` : key;
215
+ }
216
+ //#endregion
217
+ exports.compareOpportunities = compareOpportunities;
218
+ exports.diffOpportunity = diffOpportunity;
@@ -249,7 +249,7 @@ var CreditSuite = class extends require_sdk_base_SDKConstruct.SDKConstruct {
249
249
  curator: market.curator,
250
250
  underlyingToken: market.underlyingToken,
251
251
  totalBorrow: oracle.toAmount(pool.underlying, borrowed),
252
- collateralTokens: market.collateralTokens,
252
+ collateralTokens: this.strategyCollaterals.map((t) => this.tokensMeta.mustGetToken(t)),
253
253
  paused: this.isPaused,
254
254
  rwa: market.rwa,
255
255
  sunset: market.sunset || require_sdk_chain_chains.isSunsetStrategy(cm.address, collateral, this.sdk.networkType),
@@ -0,0 +1,216 @@
1
+ import { opportunityId } from "../model/opportunities.js";
2
+ import "../model/index.js";
3
+ //#region src/dev/compareOpportunities.ts
4
+ /**
5
+ * Matches two opportunity listings by {@link opportunityId} and reports every
6
+ * field the two sources disagree on.
7
+ *
8
+ * Nothing is filtered out: a diff that is expected — a field only the backend
9
+ * can fill, a formula the two sides define differently, a USD value smoothed on
10
+ * one side — is reported like any other, tagged by {@link DiffKind} so that a
11
+ * reader can bucket it afterwards.
12
+ **/
13
+ function compareOpportunities(input) {
14
+ const onchainRows = indexById(input.onchain.data);
15
+ const offchainRows = indexById(input.offchain.data);
16
+ const onlyOnchain = [];
17
+ const onlyOffchain = [];
18
+ const matched = [];
19
+ for (const [id, row] of onchainRows) {
20
+ const counterpart = offchainRows.get(id);
21
+ if (!counterpart) {
22
+ onlyOnchain.push(toRef(row));
23
+ continue;
24
+ }
25
+ const diffs = diffOpportunity(row, counterpart);
26
+ matched.push({
27
+ id,
28
+ kind: row.kind,
29
+ chainId: row.chainId,
30
+ onchainName: row.name,
31
+ offchainName: counterpart.name,
32
+ identical: diffs.length === 0,
33
+ diffs
34
+ });
35
+ }
36
+ for (const [id, row] of offchainRows) if (!onchainRows.has(id)) onlyOffchain.push(toRef(row));
37
+ byId(onlyOnchain);
38
+ byId(onlyOffchain);
39
+ matched.sort((a, b) => a.id.localeCompare(b.id));
40
+ return {
41
+ generatedAt: input.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
42
+ backendUrl: input.backendUrl,
43
+ networks: [...input.networks],
44
+ onchainChains: input.onchain.meta.chains,
45
+ offchainChains: input.offchain.meta.chains,
46
+ summary: summarize(input.onchain.data, input.offchain.data, onlyOnchain, onlyOffchain, matched),
47
+ onlyOnchain,
48
+ onlyOffchain,
49
+ matched
50
+ };
51
+ }
52
+ function indexById(rows) {
53
+ return new Map(rows.map((row) => [opportunityId(row), row]));
54
+ }
55
+ function byId(refs) {
56
+ refs.sort((a, b) => a.id.localeCompare(b.id));
57
+ }
58
+ function toRef(row) {
59
+ const base = {
60
+ id: opportunityId(row),
61
+ kind: row.kind,
62
+ chainId: row.chainId,
63
+ name: row.name
64
+ };
65
+ return row.kind === "pool" ? {
66
+ ...base,
67
+ pool: row.pool
68
+ } : {
69
+ ...base,
70
+ creditManager: row.creditManager,
71
+ targetCollateral: row.targetCollateral.address
72
+ };
73
+ }
74
+ /**
75
+ * Every field two versions of one opportunity disagree on.
76
+ **/
77
+ function diffOpportunity(onchain, offchain) {
78
+ const diffs = [];
79
+ diffValue("", onchain, offchain, diffs);
80
+ return diffs;
81
+ }
82
+ function diffValue(path, onchain, offchain, out) {
83
+ if (isAbsent(onchain) && isAbsent(offchain)) return;
84
+ if (isAbsent(onchain) || isAbsent(offchain)) {
85
+ out.push({
86
+ path,
87
+ onchain,
88
+ offchain,
89
+ kind: "presence"
90
+ });
91
+ return;
92
+ }
93
+ if (Array.isArray(onchain) && Array.isArray(offchain)) {
94
+ diffArray(path, onchain, offchain, out);
95
+ return;
96
+ }
97
+ if (isRecord(onchain) && isRecord(offchain)) {
98
+ for (const key of union(Object.keys(onchain), Object.keys(offchain))) diffValue(join(path, key), onchain[key], offchain[key], out);
99
+ return;
100
+ }
101
+ if (!sameScalar(onchain, offchain)) out.push({
102
+ path,
103
+ onchain,
104
+ offchain,
105
+ kind: scalarKind(path, onchain)
106
+ });
107
+ }
108
+ /**
109
+ * Arrays whose elements identify themselves — collateral tokens, points
110
+ * programs — are matched by that identity, so a token present on one side only
111
+ * is reported as such rather than shifting every later element into a diff.
112
+ **/
113
+ function diffArray(path, onchain, offchain, out) {
114
+ const onchainKeyed = keyElements(onchain);
115
+ const offchainKeyed = keyElements(offchain);
116
+ if (!onchainKeyed || !offchainKeyed) {
117
+ if (onchain.length !== offchain.length) {
118
+ out.push({
119
+ path,
120
+ onchain,
121
+ offchain,
122
+ kind: "other"
123
+ });
124
+ return;
125
+ }
126
+ onchain.forEach((element, index) => {
127
+ diffValue(`${path}[${index}]`, element, offchain[index], out);
128
+ });
129
+ return;
130
+ }
131
+ for (const key of union([...onchainKeyed.keys()], [...offchainKeyed.keys()])) diffValue(`${path}[${key}]`, onchainKeyed.get(key), offchainKeyed.get(key), out);
132
+ }
133
+ /**
134
+ * The array indexed by each element's own identity, or `undefined` when its
135
+ * elements have none and order is all there is to go by.
136
+ **/
137
+ function keyElements(values) {
138
+ const keyed = /* @__PURE__ */ new Map();
139
+ for (const value of values) {
140
+ if (!isRecord(value)) return;
141
+ const identity = value.address ?? value.id ?? value.token;
142
+ if (typeof identity !== "string") return;
143
+ keyed.set(identity.toLowerCase(), value);
144
+ }
145
+ return keyed.size === values.length ? keyed : void 0;
146
+ }
147
+ const ADDRESS = /^0x[0-9a-f]{40}$/i;
148
+ /**
149
+ * Only addresses are compared case-insensitively: the backend lowercases them
150
+ * while the chain hands out checksummed ones, which is not a disagreement. A
151
+ * symbol or a name spelled differently is.
152
+ **/
153
+ function sameScalar(onchain, offchain) {
154
+ if (typeof onchain === "string" && typeof offchain === "string" && ADDRESS.test(onchain) && ADDRESS.test(offchain)) return onchain.toLowerCase() === offchain.toLowerCase();
155
+ return onchain === offchain;
156
+ }
157
+ function scalarKind(path, onchain) {
158
+ if (path.endsWith("valueUsd")) return "usd";
159
+ return typeof onchain === "number" || typeof onchain === "bigint" ? "numeric" : "other";
160
+ }
161
+ function summarize(onchain, offchain, onlyOnchain, onlyOffchain, matched) {
162
+ const byChain = union(onchain.map((row) => String(row.chainId)), offchain.map((row) => String(row.chainId))).map((chainId) => ({
163
+ chainId: Number(chainId),
164
+ ...count(onchain.filter((row) => String(row.chainId) === chainId), offchain.filter((row) => String(row.chainId) === chainId), onlyOnchain.filter((ref) => String(ref.chainId) === chainId), onlyOffchain.filter((ref) => String(ref.chainId) === chainId), matched.filter((match) => String(match.chainId) === chainId))
165
+ })).sort((a, b) => a.chainId - b.chainId);
166
+ return {
167
+ ...count(onchain, offchain, onlyOnchain, onlyOffchain, matched),
168
+ byChain,
169
+ diffsByPath: countPaths(matched)
170
+ };
171
+ }
172
+ function count(onchain, offchain, onlyOnchain, onlyOffchain, matched) {
173
+ const identical = matched.filter((match) => match.identical).length;
174
+ return {
175
+ onchainRows: onchain.length,
176
+ offchainRows: offchain.length,
177
+ matched: matched.length,
178
+ identical,
179
+ differing: matched.length - identical,
180
+ onlyOnchain: onlyOnchain.length,
181
+ onlyOffchain: onlyOffchain.length
182
+ };
183
+ }
184
+ /**
185
+ * How often each field differed, with array keys collapsed so that the same
186
+ * field of a hundred collateral tokens counts as one path.
187
+ **/
188
+ function countPaths(matched) {
189
+ const counts = /* @__PURE__ */ new Map();
190
+ for (const match of matched) for (const diff of match.diffs) {
191
+ const path = diff.path.replace(/\[[^\]]*\]/g, "[]");
192
+ const entry = counts.get(path) ?? {
193
+ path,
194
+ kinds: [],
195
+ count: 0
196
+ };
197
+ entry.count += 1;
198
+ if (!entry.kinds.includes(diff.kind)) entry.kinds.push(diff.kind);
199
+ counts.set(path, entry);
200
+ }
201
+ return [...counts.values()].sort((a, b) => b.count - a.count || a.path.localeCompare(b.path));
202
+ }
203
+ function isAbsent(value) {
204
+ return value === void 0 || value === null;
205
+ }
206
+ function isRecord(value) {
207
+ return typeof value === "object" && value !== null && !Array.isArray(value);
208
+ }
209
+ function union(left, right) {
210
+ return [.../* @__PURE__ */ new Set([...left, ...right])];
211
+ }
212
+ function join(path, key) {
213
+ return path ? `${path}.${key}` : key;
214
+ }
215
+ //#endregion
216
+ export { compareOpportunities, diffOpportunity };
@@ -248,7 +248,7 @@ var CreditSuite = class extends SDKConstruct {
248
248
  curator: market.curator,
249
249
  underlyingToken: market.underlyingToken,
250
250
  totalBorrow: oracle.toAmount(pool.underlying, borrowed),
251
- collateralTokens: market.collateralTokens,
251
+ collateralTokens: this.strategyCollaterals.map((t) => this.tokensMeta.mustGetToken(t)),
252
252
  paused: this.isPaused,
253
253
  rwa: market.rwa,
254
254
  sunset: market.sunset || isSunsetStrategy(cm.address, collateral, this.sdk.networkType),
@@ -0,0 +1,153 @@
1
+ import { ChainId } from "../model/primitives.js";
2
+ import { Opportunity, OpportunityId, OpportunityKind } from "../model/opportunities.js";
3
+ import { ChainMetadata, DataResponse } from "../model/response.js";
4
+ import "../model/index.js";
5
+ import { Address } from "viem";
6
+ //#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
+ /**
37
+ * Enough of an opportunity to identify it in a report without carrying the
38
+ * whole row.
39
+ **/
40
+ interface OpportunityRef {
41
+ id: OpportunityId;
42
+ kind: OpportunityKind;
43
+ chainId: ChainId;
44
+ name: string;
45
+ /**
46
+ * Set on a pool opportunity.
47
+ **/
48
+ pool?: Address;
49
+ /**
50
+ * Set on a strategy opportunity, together with {@link targetCollateral}.
51
+ **/
52
+ creditManager?: Address;
53
+ targetCollateral?: Address;
54
+ }
55
+ /**
56
+ * One opportunity both sources listed, and everything they disagree on.
57
+ **/
58
+ interface OpportunityMatch {
59
+ id: OpportunityId;
60
+ kind: OpportunityKind;
61
+ chainId: ChainId;
62
+ /**
63
+ * Name each source gave the row, which is itself a frequent diff.
64
+ **/
65
+ onchainName: string;
66
+ offchainName: string;
67
+ identical: boolean;
68
+ diffs: FieldDiff[];
69
+ }
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
+ /**
98
+ * Totals of the comparison plus the fields that differed most often.
99
+ **/
100
+ interface CompareSummary extends CompareCounts {
101
+ byChain: ChainCompareCounts[];
102
+ diffsByPath: DiffPathCount[];
103
+ }
104
+ /**
105
+ * Everything one comparison run produced, ready to be written out as JSON.
106
+ **/
107
+ interface OpportunityCompareReport {
108
+ generatedAt: string;
109
+ backendUrl: string;
110
+ networks: string[];
111
+ /**
112
+ * Per-chain metadata of the on-chain read, which says which block each chain
113
+ * answered from.
114
+ **/
115
+ onchainChains: ChainMetadata[];
116
+ /**
117
+ * Per-chain metadata of the backend read, see {@link onchainChains}.
118
+ **/
119
+ offchainChains: ChainMetadata[];
120
+ summary: CompareSummary;
121
+ onlyOnchain: OpportunityRef[];
122
+ onlyOffchain: OpportunityRef[];
123
+ matched: OpportunityMatch[];
124
+ }
125
+ /**
126
+ * The two listings to compare, plus what the run was pointed at.
127
+ **/
128
+ interface CompareOpportunitiesInput {
129
+ onchain: DataResponse<Opportunity[]>;
130
+ offchain: DataResponse<Opportunity[]>;
131
+ backendUrl: string;
132
+ networks: string[];
133
+ /**
134
+ * ISO timestamp stamped onto the report, defaulting to now. Pinned by tests.
135
+ **/
136
+ generatedAt?: string;
137
+ }
138
+ /**
139
+ * Matches two opportunity listings by {@link opportunityId} and reports every
140
+ * field the two sources disagree on.
141
+ *
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.
146
+ **/
147
+ declare function compareOpportunities(input: CompareOpportunitiesInput): OpportunityCompareReport;
148
+ /**
149
+ * Every field two versions of one opportunity disagree on.
150
+ **/
151
+ declare function diffOpportunity(onchain: Opportunity, offchain: Opportunity): FieldDiff[];
152
+ //#endregion
153
+ export { ChainCompareCounts, CompareCounts, CompareOpportunitiesInput, CompareSummary, DiffKind, DiffPathCount, FieldDiff, OpportunityCompareReport, OpportunityMatch, OpportunityRef, compareOpportunities, diffOpportunity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "15.1.0-next.4",
3
+ "version": "15.1.0-next.5",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {