@morpho-org/midnight-sdk 0.1.0
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/README.md +252 -0
- package/lib/cjs/abis.d.ts +3170 -0
- package/lib/cjs/abis.js +4073 -0
- package/lib/cjs/api/MidnightApi.d.ts +532 -0
- package/lib/cjs/api/MidnightApi.js +713 -0
- package/lib/cjs/api/helpers.d.ts +20 -0
- package/lib/cjs/api/helpers.js +189 -0
- package/lib/cjs/api/index.d.ts +2 -0
- package/lib/cjs/api/index.js +21 -0
- package/lib/cjs/api/types.d.ts +453 -0
- package/lib/cjs/api/types.js +2 -0
- package/lib/cjs/constants.d.ts +168 -0
- package/lib/cjs/constants.js +187 -0
- package/lib/cjs/errors.d.ts +253 -0
- package/lib/cjs/errors.js +309 -0
- package/lib/cjs/fetch/Market.d.ts +65 -0
- package/lib/cjs/fetch/Market.js +117 -0
- package/lib/cjs/fetch/Offer.d.ts +74 -0
- package/lib/cjs/fetch/Offer.js +119 -0
- package/lib/cjs/fetch/Position.d.ts +85 -0
- package/lib/cjs/fetch/Position.js +148 -0
- package/lib/cjs/fetch/Ratifier.d.ts +38 -0
- package/lib/cjs/fetch/Ratifier.js +57 -0
- package/lib/cjs/fetch/index.d.ts +5 -0
- package/lib/cjs/fetch/index.js +21 -0
- package/lib/cjs/fetch/types.d.ts +57 -0
- package/lib/cjs/fetch/types.js +2 -0
- package/lib/cjs/fetch/utils.d.ts +8 -0
- package/lib/cjs/fetch/utils.js +18 -0
- package/lib/cjs/index.d.ts +18 -0
- package/lib/cjs/index.js +57 -0
- package/lib/cjs/market/Market.d.ts +613 -0
- package/lib/cjs/market/Market.js +503 -0
- package/lib/cjs/market/MarketUtils.d.ts +189 -0
- package/lib/cjs/market/MarketUtils.js +303 -0
- package/lib/cjs/market/Position.d.ts +424 -0
- package/lib/cjs/market/Position.js +425 -0
- package/lib/cjs/market/PositionUtils.d.ts +115 -0
- package/lib/cjs/market/PositionUtils.js +194 -0
- package/lib/cjs/market/index.d.ts +4 -0
- package/lib/cjs/market/index.js +20 -0
- package/lib/cjs/math/ConsumableUnitsLib.d.ts +57 -0
- package/lib/cjs/math/ConsumableUnitsLib.js +77 -0
- package/lib/cjs/math/TakeAmountsLib.d.ts +175 -0
- package/lib/cjs/math/TakeAmountsLib.js +199 -0
- package/lib/cjs/math/TickLib.d.ts +200 -0
- package/lib/cjs/math/TickLib.js +272 -0
- package/lib/cjs/math/index.d.ts +3 -0
- package/lib/cjs/math/index.js +19 -0
- package/lib/cjs/offers/Offer.d.ts +534 -0
- package/lib/cjs/offers/Offer.js +343 -0
- package/lib/cjs/offers/OfferUtils.d.ts +565 -0
- package/lib/cjs/offers/OfferUtils.js +659 -0
- package/lib/cjs/offers/index.d.ts +2 -0
- package/lib/cjs/offers/index.js +18 -0
- package/lib/cjs/package.json +1 -0
- package/lib/cjs/queries/GetPosition.d.ts +55 -0
- package/lib/cjs/queries/GetPosition.js +74 -0
- package/lib/cjs/queries/index.d.ts +1 -0
- package/lib/cjs/queries/index.js +37 -0
- package/lib/cjs/signatures/EcrecoverRatifierUtils.d.ts +733 -0
- package/lib/cjs/signatures/EcrecoverRatifierUtils.js +618 -0
- package/lib/cjs/signatures/Group.d.ts +178 -0
- package/lib/cjs/signatures/Group.js +193 -0
- package/lib/cjs/signatures/GroupUtils.d.ts +191 -0
- package/lib/cjs/signatures/GroupUtils.js +127 -0
- package/lib/cjs/signatures/Payload.d.ts +283 -0
- package/lib/cjs/signatures/Payload.js +570 -0
- package/lib/cjs/signatures/RatifierUtils.d.ts +109 -0
- package/lib/cjs/signatures/RatifierUtils.js +76 -0
- package/lib/cjs/signatures/SetterRatifierUtils.d.ts +243 -0
- package/lib/cjs/signatures/SetterRatifierUtils.js +217 -0
- package/lib/cjs/signatures/Tree.d.ts +241 -0
- package/lib/cjs/signatures/Tree.js +263 -0
- package/lib/cjs/signatures/TreeUtils.d.ts +573 -0
- package/lib/cjs/signatures/TreeUtils.js +461 -0
- package/lib/cjs/signatures/index.d.ts +7 -0
- package/lib/cjs/signatures/index.js +23 -0
- package/lib/esm/abis.d.ts +3170 -0
- package/lib/esm/abis.js +4070 -0
- package/lib/esm/api/MidnightApi.d.ts +532 -0
- package/lib/esm/api/MidnightApi.js +709 -0
- package/lib/esm/api/helpers.d.ts +20 -0
- package/lib/esm/api/helpers.js +180 -0
- package/lib/esm/api/index.d.ts +2 -0
- package/lib/esm/api/index.js +2 -0
- package/lib/esm/api/types.d.ts +453 -0
- package/lib/esm/api/types.js +1 -0
- package/lib/esm/constants.d.ts +168 -0
- package/lib/esm/constants.js +184 -0
- package/lib/esm/errors.d.ts +253 -0
- package/lib/esm/errors.js +291 -0
- package/lib/esm/fetch/Market.d.ts +65 -0
- package/lib/esm/fetch/Market.js +113 -0
- package/lib/esm/fetch/Offer.d.ts +74 -0
- package/lib/esm/fetch/Offer.js +116 -0
- package/lib/esm/fetch/Position.d.ts +85 -0
- package/lib/esm/fetch/Position.js +144 -0
- package/lib/esm/fetch/Ratifier.d.ts +38 -0
- package/lib/esm/fetch/Ratifier.js +54 -0
- package/lib/esm/fetch/index.d.ts +5 -0
- package/lib/esm/fetch/index.js +5 -0
- package/lib/esm/fetch/types.d.ts +57 -0
- package/lib/esm/fetch/types.js +1 -0
- package/lib/esm/fetch/utils.d.ts +8 -0
- package/lib/esm/fetch/utils.js +12 -0
- package/lib/esm/index.d.ts +18 -0
- package/lib/esm/index.js +18 -0
- package/lib/esm/market/Market.d.ts +613 -0
- package/lib/esm/market/Market.js +498 -0
- package/lib/esm/market/MarketUtils.d.ts +189 -0
- package/lib/esm/market/MarketUtils.js +300 -0
- package/lib/esm/market/Position.d.ts +424 -0
- package/lib/esm/market/Position.js +420 -0
- package/lib/esm/market/PositionUtils.d.ts +115 -0
- package/lib/esm/market/PositionUtils.js +191 -0
- package/lib/esm/market/index.d.ts +4 -0
- package/lib/esm/market/index.js +4 -0
- package/lib/esm/math/ConsumableUnitsLib.d.ts +57 -0
- package/lib/esm/math/ConsumableUnitsLib.js +74 -0
- package/lib/esm/math/TakeAmountsLib.d.ts +175 -0
- package/lib/esm/math/TakeAmountsLib.js +196 -0
- package/lib/esm/math/TickLib.d.ts +200 -0
- package/lib/esm/math/TickLib.js +269 -0
- package/lib/esm/math/index.d.ts +3 -0
- package/lib/esm/math/index.js +3 -0
- package/lib/esm/offers/Offer.d.ts +534 -0
- package/lib/esm/offers/Offer.js +339 -0
- package/lib/esm/offers/OfferUtils.d.ts +565 -0
- package/lib/esm/offers/OfferUtils.js +656 -0
- package/lib/esm/offers/index.d.ts +2 -0
- package/lib/esm/offers/index.js +2 -0
- package/lib/esm/package.json +1 -0
- package/lib/esm/queries/GetPosition.d.ts +55 -0
- package/lib/esm/queries/GetPosition.js +71 -0
- package/lib/esm/queries/index.d.ts +1 -0
- package/lib/esm/queries/index.js +1 -0
- package/lib/esm/signatures/EcrecoverRatifierUtils.d.ts +733 -0
- package/lib/esm/signatures/EcrecoverRatifierUtils.js +615 -0
- package/lib/esm/signatures/Group.d.ts +178 -0
- package/lib/esm/signatures/Group.js +189 -0
- package/lib/esm/signatures/GroupUtils.d.ts +191 -0
- package/lib/esm/signatures/GroupUtils.js +124 -0
- package/lib/esm/signatures/Payload.d.ts +283 -0
- package/lib/esm/signatures/Payload.js +564 -0
- package/lib/esm/signatures/RatifierUtils.d.ts +109 -0
- package/lib/esm/signatures/RatifierUtils.js +73 -0
- package/lib/esm/signatures/SetterRatifierUtils.d.ts +243 -0
- package/lib/esm/signatures/SetterRatifierUtils.js +214 -0
- package/lib/esm/signatures/Tree.d.ts +241 -0
- package/lib/esm/signatures/Tree.js +259 -0
- package/lib/esm/signatures/TreeUtils.d.ts +573 -0
- package/lib/esm/signatures/TreeUtils.js +458 -0
- package/lib/esm/signatures/index.d.ts +7 -0
- package/lib/esm/signatures/index.js +7 -0
- package/package.json +69 -0
- package/src/index.ts +19 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TreeUtils = void 0;
|
|
4
|
+
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
5
|
+
const viem_1 = require("viem");
|
|
6
|
+
const MidnightApi_js_1 = require("../api/MidnightApi.js");
|
|
7
|
+
const errors_js_1 = require("../errors.js");
|
|
8
|
+
const index_js_1 = require("../offers/index.js");
|
|
9
|
+
const Group_js_1 = require("./Group.js");
|
|
10
|
+
const GroupUtils_js_1 = require("./GroupUtils.js");
|
|
11
|
+
const Payload_js_1 = require("./Payload.js");
|
|
12
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
13
|
+
const ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
14
|
+
const EMPTY_OFFER_STRUCT = {
|
|
15
|
+
market: {
|
|
16
|
+
loanToken: ZERO_ADDRESS,
|
|
17
|
+
collateralParams: [],
|
|
18
|
+
maturity: 0n,
|
|
19
|
+
rcfThreshold: 0n,
|
|
20
|
+
enterGate: ZERO_ADDRESS,
|
|
21
|
+
liquidatorGate: ZERO_ADDRESS,
|
|
22
|
+
},
|
|
23
|
+
buy: false,
|
|
24
|
+
maker: ZERO_ADDRESS,
|
|
25
|
+
start: 0n,
|
|
26
|
+
expiry: 0n,
|
|
27
|
+
tick: 0n,
|
|
28
|
+
group: ZERO_BYTES32,
|
|
29
|
+
callback: ZERO_ADDRESS,
|
|
30
|
+
callbackData: "0x",
|
|
31
|
+
receiverIfMakerIsSeller: ZERO_ADDRESS,
|
|
32
|
+
ratifier: ZERO_ADDRESS,
|
|
33
|
+
reduceOnly: false,
|
|
34
|
+
maxUnits: 0n,
|
|
35
|
+
maxAssets: 0n,
|
|
36
|
+
continuousFeeCap: 0n,
|
|
37
|
+
};
|
|
38
|
+
const EMPTY_OFFER_DEFAULT_GROUP = index_js_1.OfferUtils.hashStruct(EMPTY_OFFER_STRUCT);
|
|
39
|
+
function isEmptyOfferStruct(offer) {
|
|
40
|
+
return (offer.market.loanToken === ZERO_ADDRESS &&
|
|
41
|
+
offer.market.collateralParams.length === 0 &&
|
|
42
|
+
offer.market.maturity === 0n &&
|
|
43
|
+
offer.market.rcfThreshold === 0n &&
|
|
44
|
+
offer.market.enterGate === ZERO_ADDRESS &&
|
|
45
|
+
offer.market.liquidatorGate === ZERO_ADDRESS &&
|
|
46
|
+
offer.buy === false &&
|
|
47
|
+
offer.maker === ZERO_ADDRESS &&
|
|
48
|
+
offer.start === 0n &&
|
|
49
|
+
offer.expiry === 0n &&
|
|
50
|
+
offer.tick === 0n &&
|
|
51
|
+
(offer.group === ZERO_BYTES32 ||
|
|
52
|
+
offer.group === EMPTY_OFFER_DEFAULT_GROUP) &&
|
|
53
|
+
offer.callback === ZERO_ADDRESS &&
|
|
54
|
+
offer.callbackData === "0x" &&
|
|
55
|
+
offer.receiverIfMakerIsSeller === ZERO_ADDRESS &&
|
|
56
|
+
offer.ratifier === ZERO_ADDRESS &&
|
|
57
|
+
offer.reduceOnly === false &&
|
|
58
|
+
offer.maxUnits === 0n &&
|
|
59
|
+
offer.maxAssets === 0n &&
|
|
60
|
+
offer.continuousFeeCap === 0n);
|
|
61
|
+
}
|
|
62
|
+
function isPowerOfTwo(value) {
|
|
63
|
+
return value > 0 && (value & (value - 1)) === 0;
|
|
64
|
+
}
|
|
65
|
+
function nextPowerOfTwo(value) {
|
|
66
|
+
return 2 ** Math.ceil(Math.log2(value));
|
|
67
|
+
}
|
|
68
|
+
function padOfferStructs(offers) {
|
|
69
|
+
if (isPowerOfTwo(offers.length))
|
|
70
|
+
return [...offers];
|
|
71
|
+
const paddedLength = nextPowerOfTwo(offers.length);
|
|
72
|
+
return [
|
|
73
|
+
...offers,
|
|
74
|
+
...Array.from({ length: paddedLength - offers.length }, () => EMPTY_OFFER_STRUCT),
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
function assertLeafOffers(offers, leafHashes) {
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
for (const [index, offer] of offers.entries()) {
|
|
80
|
+
if (isEmptyOfferStruct(offer))
|
|
81
|
+
continue;
|
|
82
|
+
const leafHash = leafHashes[index];
|
|
83
|
+
if (seen.has(leafHash)) {
|
|
84
|
+
throw new errors_js_1.InvalidTreeError(`Duplicate offer hash "${leafHash}" in tree.`);
|
|
85
|
+
}
|
|
86
|
+
seen.add(leafHash);
|
|
87
|
+
}
|
|
88
|
+
if (seen.size === 0) {
|
|
89
|
+
throw new errors_js_1.InvalidTreeError("Tree must not be empty.");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Object-compatible tree hashing, root, proof, and verification helpers.
|
|
94
|
+
*
|
|
95
|
+
* Use these when you need pure tree hashing, descriptor construction, or proof
|
|
96
|
+
* verification. In the normal make-side flow, `Tree.create` wraps descriptor
|
|
97
|
+
* construction; proof helpers accept the built `Tree` so cached leaves/root are
|
|
98
|
+
* reused.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* import { TreeUtils } from "@morpho-org/midnight-sdk";
|
|
103
|
+
*
|
|
104
|
+
* console.log(typeof TreeUtils.buildRoot);
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
var TreeUtils;
|
|
108
|
+
(function (TreeUtils) {
|
|
109
|
+
/**
|
|
110
|
+
* Validates a tree against Midnight mempool API policy.
|
|
111
|
+
*
|
|
112
|
+
* This is an API-backed convenience: it encodes each tree leaf with empty
|
|
113
|
+
* `ratifierData`, then sends the temporary payload to the Midnight API
|
|
114
|
+
* `POST /mempool/validate` endpoint. API policy only inspects offer contents,
|
|
115
|
+
* so use this after `Tree.create` and before wallet signature or Setter root
|
|
116
|
+
* approval.
|
|
117
|
+
*
|
|
118
|
+
* @param params.chainId - Chain id whose API policy should validate the tree.
|
|
119
|
+
* @param params.tree - Offer tree to validate before ratifier data or payload publication exists.
|
|
120
|
+
* @param params.apiUrl - Optional Midnight API URL override used for the validation HTTP request.
|
|
121
|
+
* @param params.timestamp - Optional ISO-8601 timestamp or `Date` selecting the API policy snapshot.
|
|
122
|
+
* @param params.fetch - Optional fetch implementation override used for the API call.
|
|
123
|
+
* @param params.request - Optional fetch options forwarded to the API request.
|
|
124
|
+
* @returns API issues and `valid` summary.
|
|
125
|
+
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated.
|
|
126
|
+
* @throws {InvalidTreeHeightError} when the resulting height is unsupported.
|
|
127
|
+
* @throws {Payload.DecodeError} when validation payload encoding fails.
|
|
128
|
+
* @throws {MidnightApiError} when the API returns a non-2xx response.
|
|
129
|
+
* @throws {InvalidMidnightApiResponseError} when the API returns malformed success JSON.
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* import { Offer, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
133
|
+
* import { zeroAddress } from "viem";
|
|
134
|
+
*
|
|
135
|
+
* const offer = Offer.create({
|
|
136
|
+
* market: {
|
|
137
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
138
|
+
* collateralParams: [
|
|
139
|
+
* {
|
|
140
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
141
|
+
* lltv: 770000000000000000n,
|
|
142
|
+
* maxLif: 1061007957559681697n,
|
|
143
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
144
|
+
* },
|
|
145
|
+
* ],
|
|
146
|
+
* maturity: 54_000n,
|
|
147
|
+
* rcfThreshold: 0n,
|
|
148
|
+
* enterGate: zeroAddress,
|
|
149
|
+
* liquidatorGate: zeroAddress,
|
|
150
|
+
* },
|
|
151
|
+
* buy: true,
|
|
152
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
153
|
+
* tick: 5_000n,
|
|
154
|
+
* expiry: 3_600n,
|
|
155
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
156
|
+
* maxUnits: 100n,
|
|
157
|
+
* });
|
|
158
|
+
* const validation = await TreeUtils.mempoolValidate({
|
|
159
|
+
* chainId: 8453,
|
|
160
|
+
* tree: [offer],
|
|
161
|
+
* });
|
|
162
|
+
* console.log(validation.valid);
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
async function mempoolValidate(params) {
|
|
166
|
+
const offers = "offers" in params.tree
|
|
167
|
+
? params.tree.offers
|
|
168
|
+
: params.tree.flatMap((entry) => "offers" in entry ? Group_js_1.Group.from(entry).offers : [index_js_1.Offer.from(entry)]);
|
|
169
|
+
buildDescriptor(offers);
|
|
170
|
+
const payload = await (0, Payload_js_1.encode)(offers.map((offer) => ({ offer, ratifierData: "0x" })));
|
|
171
|
+
return MidnightApi_js_1.MidnightApi.validateMempoolPayload({
|
|
172
|
+
baseUrl: params.apiUrl,
|
|
173
|
+
fetch: params.fetch,
|
|
174
|
+
request: params.request,
|
|
175
|
+
chainId: params.chainId,
|
|
176
|
+
timestamp: params.timestamp,
|
|
177
|
+
payload,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
TreeUtils.mempoolValidate = mempoolValidate;
|
|
181
|
+
/**
|
|
182
|
+
* Computes HashLib node hash from left and right child hashes.
|
|
183
|
+
*
|
|
184
|
+
* @param left - Left child hash.
|
|
185
|
+
* @param right - Right child hash.
|
|
186
|
+
* @returns Node hash.
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* import { TreeUtils } from "@morpho-org/midnight-sdk";
|
|
190
|
+
*
|
|
191
|
+
* const root = TreeUtils.hashNode(
|
|
192
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
193
|
+
* "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
194
|
+
* );
|
|
195
|
+
* console.log(root);
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
function hashNode(left, right) {
|
|
199
|
+
return (0, viem_1.keccak256)((0, viem_1.concat)([left, right]));
|
|
200
|
+
}
|
|
201
|
+
TreeUtils.hashNode = hashNode;
|
|
202
|
+
/**
|
|
203
|
+
* Builds a tree descriptor and Merkle root. Non-power-of-two batches are
|
|
204
|
+
* padded with protocol-zero offers at the highest leaf indices.
|
|
205
|
+
*
|
|
206
|
+
* Use after `Group.create` or standalone `Offer.create` when you need the
|
|
207
|
+
* padded leaves for custom signing, root approval, or proof construction.
|
|
208
|
+
* Groups are encoded with their derived shared group id, and standalone
|
|
209
|
+
* offers are encoded with their own group id.
|
|
210
|
+
* `Tree.create` calls this internally and is the simpler API for most
|
|
211
|
+
* make-side code.
|
|
212
|
+
*
|
|
213
|
+
* @param entries - Groups or standalone offers in leaf order.
|
|
214
|
+
* @returns Tree descriptor.
|
|
215
|
+
* @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
|
|
216
|
+
* @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { Offer, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
220
|
+
* import { zeroAddress } from "viem";
|
|
221
|
+
*
|
|
222
|
+
* const offer = Offer.create({
|
|
223
|
+
* market: {
|
|
224
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
225
|
+
* collateralParams: [
|
|
226
|
+
* {
|
|
227
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
228
|
+
* lltv: 770000000000000000n,
|
|
229
|
+
* maxLif: 1061007957559681697n,
|
|
230
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
231
|
+
* },
|
|
232
|
+
* ],
|
|
233
|
+
* maturity: 54_000n,
|
|
234
|
+
* rcfThreshold: 0n,
|
|
235
|
+
* enterGate: zeroAddress,
|
|
236
|
+
* liquidatorGate: zeroAddress,
|
|
237
|
+
* },
|
|
238
|
+
* buy: true,
|
|
239
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
240
|
+
* tick: 5_000n,
|
|
241
|
+
* expiry: 3_600n,
|
|
242
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
243
|
+
* maxUnits: 100n,
|
|
244
|
+
* });
|
|
245
|
+
* const tree = TreeUtils.buildDescriptor([offer]);
|
|
246
|
+
* console.log(tree.root);
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
function buildDescriptor(entries) {
|
|
250
|
+
const structs = entries.flatMap((entry) => "offers" in entry
|
|
251
|
+
? GroupUtils_js_1.GroupUtils.toStructs(entry)
|
|
252
|
+
: [index_js_1.OfferUtils.toStruct({ offer: entry })]);
|
|
253
|
+
if (structs.length === 0) {
|
|
254
|
+
throw new errors_js_1.InvalidTreeError("Tree must not be empty.");
|
|
255
|
+
}
|
|
256
|
+
const offerStructs = padOfferStructs(structs);
|
|
257
|
+
const leaves = offerStructs.map(index_js_1.OfferUtils.hashStruct);
|
|
258
|
+
assertLeafOffers(offerStructs, leaves);
|
|
259
|
+
const height = Math.log2(offerStructs.length);
|
|
260
|
+
if (height > 20)
|
|
261
|
+
throw new errors_js_1.InvalidTreeHeightError(height);
|
|
262
|
+
let level = [...leaves];
|
|
263
|
+
while (level.length > 1) {
|
|
264
|
+
const next = [];
|
|
265
|
+
for (let i = 0; i < level.length; i += 2) {
|
|
266
|
+
next.push(hashNode(level[i], level[i + 1]));
|
|
267
|
+
}
|
|
268
|
+
level = next;
|
|
269
|
+
}
|
|
270
|
+
return (0, morpho_ts_1.deepFreeze)({
|
|
271
|
+
offers: offerStructs,
|
|
272
|
+
leaves,
|
|
273
|
+
root: level[0],
|
|
274
|
+
height,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
TreeUtils.buildDescriptor = buildDescriptor;
|
|
278
|
+
/**
|
|
279
|
+
* Builds only the tree root.
|
|
280
|
+
*
|
|
281
|
+
* Use when only the root is needed, for example to compare a locally built
|
|
282
|
+
* tree with an approved root. Use `Tree.create` or `buildDescriptor` if later
|
|
283
|
+
* proof generation is required.
|
|
284
|
+
*
|
|
285
|
+
* @param entries - Groups or standalone offers in leaf order.
|
|
286
|
+
* @returns Merkle root.
|
|
287
|
+
* @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
|
|
288
|
+
* @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* import { Offer, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
292
|
+
* import { zeroAddress } from "viem";
|
|
293
|
+
*
|
|
294
|
+
* const offer = Offer.create({
|
|
295
|
+
* market: {
|
|
296
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
297
|
+
* collateralParams: [
|
|
298
|
+
* {
|
|
299
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
300
|
+
* lltv: 770000000000000000n,
|
|
301
|
+
* maxLif: 1061007957559681697n,
|
|
302
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
303
|
+
* },
|
|
304
|
+
* ],
|
|
305
|
+
* maturity: 54_000n,
|
|
306
|
+
* rcfThreshold: 0n,
|
|
307
|
+
* enterGate: zeroAddress,
|
|
308
|
+
* liquidatorGate: zeroAddress,
|
|
309
|
+
* },
|
|
310
|
+
* buy: true,
|
|
311
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
312
|
+
* tick: 5_000n,
|
|
313
|
+
* expiry: 3_600n,
|
|
314
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
315
|
+
* maxUnits: 100n,
|
|
316
|
+
* });
|
|
317
|
+
* const root = TreeUtils.buildRoot([offer]);
|
|
318
|
+
* console.log(root);
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
function buildRoot(entries) {
|
|
322
|
+
return buildDescriptor(entries).root;
|
|
323
|
+
}
|
|
324
|
+
TreeUtils.buildRoot = buildRoot;
|
|
325
|
+
/**
|
|
326
|
+
* Builds a Merkle proof for one offer.
|
|
327
|
+
*
|
|
328
|
+
* Use after tree construction when a custom ratifier needs one proof. The
|
|
329
|
+
* built-in Ecrecover and Setter helpers call this while generating
|
|
330
|
+
* `ratifierData`.
|
|
331
|
+
*
|
|
332
|
+
* @param params.tree - Tree that contains the leaf.
|
|
333
|
+
* @param params.leafIndex - Leaf index to prove.
|
|
334
|
+
* @returns Proof descriptor.
|
|
335
|
+
* @throws {InvalidTreeError} when leaf index is out of range.
|
|
336
|
+
* @example
|
|
337
|
+
* ```ts
|
|
338
|
+
* import { Offer, Tree, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
339
|
+
* import { zeroAddress } from "viem";
|
|
340
|
+
*
|
|
341
|
+
* const offer = Offer.create({
|
|
342
|
+
* market: {
|
|
343
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
344
|
+
* collateralParams: [
|
|
345
|
+
* {
|
|
346
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
347
|
+
* lltv: 770000000000000000n,
|
|
348
|
+
* maxLif: 1061007957559681697n,
|
|
349
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
350
|
+
* },
|
|
351
|
+
* ],
|
|
352
|
+
* maturity: 54_000n,
|
|
353
|
+
* rcfThreshold: 0n,
|
|
354
|
+
* enterGate: zeroAddress,
|
|
355
|
+
* liquidatorGate: zeroAddress,
|
|
356
|
+
* },
|
|
357
|
+
* buy: true,
|
|
358
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
359
|
+
* tick: 5_000n,
|
|
360
|
+
* expiry: 3_600n,
|
|
361
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
362
|
+
* maxUnits: 100n,
|
|
363
|
+
* });
|
|
364
|
+
* const proof = TreeUtils.buildProof({
|
|
365
|
+
* tree: Tree.create([offer]),
|
|
366
|
+
* leafIndex: 0n,
|
|
367
|
+
* });
|
|
368
|
+
* console.log(proof.proof.length);
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
function buildProof(params) {
|
|
372
|
+
const leafIndex = BigInt(params.leafIndex);
|
|
373
|
+
if (leafIndex < 0n ||
|
|
374
|
+
leafIndex >= BigInt(params.tree.paddedOffers.length)) {
|
|
375
|
+
throw new errors_js_1.InvalidTreeError(`Leaf index "${leafIndex}" is outside the tree.`);
|
|
376
|
+
}
|
|
377
|
+
let index = Number(leafIndex);
|
|
378
|
+
let level = [...params.tree.leaves];
|
|
379
|
+
const proof = [];
|
|
380
|
+
while (level.length > 1) {
|
|
381
|
+
proof.push(level[index ^ 1]);
|
|
382
|
+
const next = [];
|
|
383
|
+
for (let i = 0; i < level.length; i += 2) {
|
|
384
|
+
next.push(hashNode(level[i], level[i + 1]));
|
|
385
|
+
}
|
|
386
|
+
index = Math.floor(index / 2);
|
|
387
|
+
level = next;
|
|
388
|
+
}
|
|
389
|
+
return (0, morpho_ts_1.deepFreeze)({ root: params.tree.root, leafIndex, proof });
|
|
390
|
+
}
|
|
391
|
+
TreeUtils.buildProof = buildProof;
|
|
392
|
+
/**
|
|
393
|
+
* Verifies a local Merkle proof against a root.
|
|
394
|
+
*
|
|
395
|
+
* Use on the take-side or in tests to inspect decoded payload or ratifier
|
|
396
|
+
* data before forwarding it to a transaction builder. Onchain ratifiers still
|
|
397
|
+
* perform the authoritative verification.
|
|
398
|
+
*
|
|
399
|
+
* @param params.offer - Offer whose hash starts proof reconstruction.
|
|
400
|
+
* @param params.root - Expected Merkle root.
|
|
401
|
+
* @param params.leafIndex - Leaf index proven by `params.proof`.
|
|
402
|
+
* @param params.proof - Merkle proof siblings for the leaf.
|
|
403
|
+
* @returns Whether the proof reconstructs the supplied root.
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* import { Offer, Tree, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
407
|
+
* import { zeroAddress } from "viem";
|
|
408
|
+
*
|
|
409
|
+
* const offer = Offer.create({
|
|
410
|
+
* market: {
|
|
411
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
412
|
+
* collateralParams: [
|
|
413
|
+
* {
|
|
414
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
415
|
+
* lltv: 770000000000000000n,
|
|
416
|
+
* maxLif: 1061007957559681697n,
|
|
417
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
418
|
+
* },
|
|
419
|
+
* ],
|
|
420
|
+
* maturity: 54_000n,
|
|
421
|
+
* rcfThreshold: 0n,
|
|
422
|
+
* enterGate: zeroAddress,
|
|
423
|
+
* liquidatorGate: zeroAddress,
|
|
424
|
+
* },
|
|
425
|
+
* buy: true,
|
|
426
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
427
|
+
* tick: 5_000n,
|
|
428
|
+
* expiry: 3_600n,
|
|
429
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
430
|
+
* maxUnits: 100n,
|
|
431
|
+
* });
|
|
432
|
+
* const tree = Tree.create([offer]);
|
|
433
|
+
* const proof = tree.proof(0n);
|
|
434
|
+
* const valid = TreeUtils.verifyProof({
|
|
435
|
+
* offer: tree.offers[0]!,
|
|
436
|
+
* root: proof.root,
|
|
437
|
+
* leafIndex: proof.leafIndex,
|
|
438
|
+
* proof: proof.proof,
|
|
439
|
+
* });
|
|
440
|
+
* console.log(valid);
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
function verifyProof(params) {
|
|
444
|
+
const offer = index_js_1.Offer.from(params.offer);
|
|
445
|
+
let node = index_js_1.OfferUtils.hash(offer);
|
|
446
|
+
const leafIndex = BigInt(params.leafIndex);
|
|
447
|
+
if (leafIndex < 0n || leafIndex >> BigInt(params.proof.length) !== 0n) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
let remainingLeafIndex = leafIndex;
|
|
451
|
+
for (const sibling of params.proof) {
|
|
452
|
+
node =
|
|
453
|
+
(remainingLeafIndex & 1n) === 0n
|
|
454
|
+
? hashNode(node, sibling)
|
|
455
|
+
: hashNode(sibling, node);
|
|
456
|
+
remainingLeafIndex >>= 1n;
|
|
457
|
+
}
|
|
458
|
+
return node === params.root;
|
|
459
|
+
}
|
|
460
|
+
TreeUtils.verifyProof = verifyProof;
|
|
461
|
+
})(TreeUtils || (exports.TreeUtils = TreeUtils = {}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./EcrecoverRatifierUtils.js"), exports);
|
|
18
|
+
__exportStar(require("./Group.js"), exports);
|
|
19
|
+
__exportStar(require("./GroupUtils.js"), exports);
|
|
20
|
+
__exportStar(require("./RatifierUtils.js"), exports);
|
|
21
|
+
__exportStar(require("./SetterRatifierUtils.js"), exports);
|
|
22
|
+
__exportStar(require("./Tree.js"), exports);
|
|
23
|
+
__exportStar(require("./TreeUtils.js"), exports);
|