@morpho-org/midnight-sdk 1.7.0 → 2.0.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/MIGRATION-v1-to-v2.md +6 -0
- package/README.md +63 -61
- package/lib/cjs/abis.d.ts +1962 -759
- package/lib/cjs/abis.js +2021 -995
- package/lib/cjs/api/helpers.d.ts +1 -17
- package/lib/cjs/api/helpers.js +0 -4
- package/lib/cjs/api/types.d.ts +5 -4
- package/lib/cjs/api/version.generated.d.ts +1 -1
- package/lib/cjs/api/version.generated.js +2 -2
- package/lib/cjs/bundlesV2.d.ts +15 -0
- package/lib/cjs/bundlesV2.js +2 -0
- package/lib/cjs/constants.d.ts +34 -0
- package/lib/cjs/constants.js +35 -1
- package/lib/cjs/errors.d.ts +107 -0
- package/lib/cjs/errors.js +139 -1
- package/lib/cjs/fetch/Ratifier.d.ts +4 -3
- package/lib/cjs/fetch/Ratifier.js +6 -4
- package/lib/cjs/index.d.ts +8 -0
- package/lib/cjs/index.js +16 -1
- package/lib/cjs/offers/Offer.d.ts +10 -0
- package/lib/cjs/offers/Offer.js +15 -1
- package/lib/cjs/offers/OfferUtils.d.ts +3 -0
- package/lib/cjs/offers/OfferUtils.js +3 -0
- package/lib/cjs/signatures/{EcrecoverRatifierUtils.d.ts → EcrecoverRatifier.d.ts} +118 -2
- package/lib/cjs/signatures/{EcrecoverRatifierUtils.js → EcrecoverRatifier.js} +146 -9
- package/lib/cjs/signatures/GroupUtils.d.ts +55 -2
- package/lib/cjs/signatures/GroupUtils.js +64 -5
- package/lib/cjs/signatures/Payload.d.ts +3 -3
- package/lib/cjs/signatures/PriceRatifierV1.d.ts +472 -0
- package/lib/cjs/signatures/PriceRatifierV1.js +521 -0
- package/lib/cjs/signatures/RateRatifierV1.d.ts +581 -0
- package/lib/cjs/signatures/RateRatifierV1.js +696 -0
- package/lib/{esm/signatures/RatifierUtils.d.ts → cjs/signatures/Ratifier.d.ts} +14 -12
- package/lib/cjs/signatures/{RatifierUtils.js → Ratifier.js} +29 -29
- package/lib/cjs/signatures/{SetterRatifierUtils.d.ts → SetterRatifier.d.ts} +50 -3
- package/lib/cjs/signatures/{SetterRatifierUtils.js → SetterRatifier.js} +65 -7
- package/lib/cjs/signatures/Tree.d.ts +94 -17
- package/lib/cjs/signatures/Tree.js +146 -111
- package/lib/cjs/signatures/TreeUtils.d.ts +191 -21
- package/lib/cjs/signatures/TreeUtils.js +320 -134
- package/lib/cjs/signatures/index.d.ts +7 -3
- package/lib/cjs/signatures/index.js +5 -3
- package/lib/cjs/signatures/ratifierRequests.d.ts +55 -0
- package/lib/cjs/signatures/ratifierRequests.js +2 -0
- package/lib/cjs/signatures/ratifierV1Internal.d.ts +57 -0
- package/lib/cjs/signatures/ratifierV1Internal.js +183 -0
- package/lib/cjs/signatures/standardRatifierInternal.d.ts +4 -0
- package/lib/cjs/signatures/standardRatifierInternal.js +12 -0
- package/lib/cjs/signatures/treeMathInternal.d.ts +4 -0
- package/lib/cjs/signatures/treeMathInternal.js +12 -0
- package/lib/cjs/signatures/treeTypes.d.ts +109 -0
- package/lib/cjs/signatures/treeTypes.js +2 -0
- package/lib/esm/abis.d.ts +1962 -759
- package/lib/esm/abis.js +2020 -994
- package/lib/esm/api/helpers.d.ts +1 -17
- package/lib/esm/api/helpers.js +4 -4
- package/lib/esm/api/types.d.ts +5 -4
- package/lib/esm/api/version.generated.d.ts +1 -1
- package/lib/esm/api/version.generated.js +2 -2
- package/lib/esm/bundlesV2.d.ts +15 -0
- package/lib/esm/bundlesV2.js +1 -0
- package/lib/esm/constants.d.ts +34 -0
- package/lib/esm/constants.js +34 -0
- package/lib/esm/errors.d.ts +107 -0
- package/lib/esm/errors.js +132 -0
- package/lib/esm/fetch/Ratifier.d.ts +4 -3
- package/lib/esm/fetch/Ratifier.js +6 -4
- package/lib/esm/index.d.ts +8 -0
- package/lib/esm/index.js +5 -0
- package/lib/esm/offers/Offer.d.ts +10 -0
- package/lib/esm/offers/Offer.js +15 -1
- package/lib/esm/offers/OfferUtils.d.ts +3 -0
- package/lib/esm/offers/OfferUtils.js +3 -0
- package/lib/esm/signatures/{EcrecoverRatifierUtils.d.ts → EcrecoverRatifier.d.ts} +118 -2
- package/lib/esm/signatures/{EcrecoverRatifierUtils.js → EcrecoverRatifier.js} +146 -9
- package/lib/esm/signatures/GroupUtils.d.ts +55 -2
- package/lib/esm/signatures/GroupUtils.js +64 -5
- package/lib/esm/signatures/Payload.d.ts +3 -3
- package/lib/esm/signatures/PriceRatifierV1.d.ts +472 -0
- package/lib/esm/signatures/PriceRatifierV1.js +520 -0
- package/lib/esm/signatures/RateRatifierV1.d.ts +581 -0
- package/lib/esm/signatures/RateRatifierV1.js +695 -0
- package/lib/{cjs/signatures/RatifierUtils.d.ts → esm/signatures/Ratifier.d.ts} +14 -12
- package/lib/esm/signatures/{RatifierUtils.js → Ratifier.js} +31 -29
- package/lib/esm/signatures/{SetterRatifierUtils.d.ts → SetterRatifier.d.ts} +50 -3
- package/lib/esm/signatures/{SetterRatifierUtils.js → SetterRatifier.js} +65 -7
- package/lib/esm/signatures/Tree.d.ts +94 -17
- package/lib/esm/signatures/Tree.js +147 -112
- package/lib/esm/signatures/TreeUtils.d.ts +191 -21
- package/lib/esm/signatures/TreeUtils.js +318 -132
- package/lib/esm/signatures/index.d.ts +7 -3
- package/lib/esm/signatures/index.js +5 -3
- package/lib/esm/signatures/ratifierRequests.d.ts +55 -0
- package/lib/esm/signatures/ratifierRequests.js +1 -0
- package/lib/esm/signatures/ratifierV1Internal.d.ts +57 -0
- package/lib/esm/signatures/ratifierV1Internal.js +176 -0
- package/lib/esm/signatures/standardRatifierInternal.d.ts +4 -0
- package/lib/esm/signatures/standardRatifierInternal.js +9 -0
- package/lib/esm/signatures/treeMathInternal.d.ts +4 -0
- package/lib/esm/signatures/treeMathInternal.js +8 -0
- package/lib/esm/signatures/treeTypes.d.ts +109 -0
- package/lib/esm/signatures/treeTypes.js +1 -0
- package/package.json +9 -8
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Tree = void 0;
|
|
4
|
+
const morpho_ts_1 = require("@morpho-org/morpho-ts");
|
|
5
|
+
const errors_js_1 = require("../errors.js");
|
|
4
6
|
const index_js_1 = require("../offers/index.js");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
+
const PriceRatifierV1_js_1 = require("./PriceRatifierV1.js");
|
|
8
|
+
const RateRatifierV1_js_1 = require("./RateRatifierV1.js");
|
|
9
|
+
const Ratifier_js_1 = require("./Ratifier.js");
|
|
7
10
|
const TreeUtils_js_1 = require("./TreeUtils.js");
|
|
8
11
|
/**
|
|
9
12
|
* Maker-side Merkle tree used by Midnight ratifiers.
|
|
10
13
|
*
|
|
11
14
|
* Build a tree after offers have been created and related offers have been
|
|
12
15
|
* grouped. The tree root is what Ecrecover makers sign, Setter makers approve,
|
|
13
|
-
* and payload items later prove with per-leaf ratifier data.
|
|
16
|
+
* and payload items later prove with per-leaf ratifier data. Price/Rate V1
|
|
17
|
+
* trees carry their additional leaf commitments and use onchain root approval.
|
|
14
18
|
*
|
|
15
19
|
* @example
|
|
16
20
|
* ```ts
|
|
@@ -42,135 +46,144 @@ const TreeUtils_js_1 = require("./TreeUtils.js");
|
|
|
42
46
|
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
43
47
|
* maxUnits: 100n,
|
|
44
48
|
* });
|
|
45
|
-
* const tree = Tree.create([offer]);
|
|
49
|
+
* const tree = Tree.create({ type: "ecrecover", entries: [offer] });
|
|
46
50
|
* console.log(tree.root);
|
|
47
51
|
* ```
|
|
48
52
|
*/
|
|
49
53
|
class Tree {
|
|
54
|
+
/** Explicit route, or undefined for a legacy standard tree. */
|
|
55
|
+
type;
|
|
56
|
+
/** Complete padded leaf commitments for this route. */
|
|
57
|
+
entries;
|
|
50
58
|
/** Non-padding offers in leaf order. */
|
|
51
59
|
offers;
|
|
52
60
|
/** ABI-compatible offers in leaf order, including protocol-zero padding. */
|
|
53
61
|
paddedOffers;
|
|
54
|
-
/** Leaf hashes for `
|
|
62
|
+
/** Leaf hashes for the complete padded `entries`. */
|
|
55
63
|
leaves;
|
|
56
64
|
/** Merkle root. */
|
|
57
65
|
root;
|
|
58
66
|
/** Tree height. */
|
|
59
67
|
height;
|
|
60
|
-
constructor(
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}),
|
|
68
|
-
]);
|
|
69
|
-
const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(params);
|
|
70
|
-
this.paddedOffers = descriptor.offers;
|
|
71
|
-
this.leaves = descriptor.leaves;
|
|
68
|
+
constructor(type, descriptor) {
|
|
69
|
+
this.type = type;
|
|
70
|
+
this.offers = Object.freeze(descriptor.offers.map((offer) => index_js_1.Offer.from(offer)));
|
|
71
|
+
this.entries = (0, morpho_ts_1.deepFreeze)(structuredClone(descriptor.entries));
|
|
72
|
+
const entries = this.entries;
|
|
73
|
+
this.paddedOffers = Object.freeze(entries.map((entry) => ("offer" in entry ? entry.offer : entry)));
|
|
74
|
+
this.leaves = Object.freeze([...descriptor.leaves]);
|
|
72
75
|
this.root = descriptor.root;
|
|
73
76
|
this.height = descriptor.height;
|
|
74
77
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Returns a tree instance from class or plain input.
|
|
77
|
-
*
|
|
78
|
-
* Use at boundaries that accept either a prebuilt tree or raw group/offer
|
|
79
|
-
* inputs, such as API validation helpers. Existing `Tree` instances are
|
|
80
|
-
* returned as-is.
|
|
81
|
-
*
|
|
82
|
-
* @param tree - Tree class or creation input.
|
|
83
|
-
* @returns Tree instance.
|
|
84
|
-
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated.
|
|
85
|
-
* @throws {InvalidTreeHeightError} when the resulting height is unsupported.
|
|
86
|
-
* @example
|
|
87
|
-
* ```ts
|
|
88
|
-
* import { Offer, Tree } from "@morpho-org/midnight-sdk";
|
|
89
|
-
* import { zeroAddress } from "viem";
|
|
90
|
-
*
|
|
91
|
-
* const offer = Offer.create({
|
|
92
|
-
* market: {
|
|
93
|
-
* chainId: 8453,
|
|
94
|
-
* midnight: "0x0000000000000000000000000000000000001000",
|
|
95
|
-
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
96
|
-
* collateralParams: [
|
|
97
|
-
* {
|
|
98
|
-
* token: "0x0000000000000000000000000000000000007000",
|
|
99
|
-
* lltv: 770000000000000000n,
|
|
100
|
-
* liquidationCursor: 250000000000000000n,
|
|
101
|
-
* oracle: "0x0000000000000000000000000000000000008000",
|
|
102
|
-
* },
|
|
103
|
-
* ],
|
|
104
|
-
* maturity: 54_000n,
|
|
105
|
-
* rcfThreshold: 0n,
|
|
106
|
-
* enterGate: zeroAddress,
|
|
107
|
-
* liquidatorGate: zeroAddress,
|
|
108
|
-
* },
|
|
109
|
-
* buy: true,
|
|
110
|
-
* maker: "0x0000000000000000000000000000000000009000",
|
|
111
|
-
* tick: 5_000n,
|
|
112
|
-
* expiry: 3_600n,
|
|
113
|
-
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
114
|
-
* maxUnits: 100n,
|
|
115
|
-
* });
|
|
116
|
-
* const tree = Tree.from([offer]);
|
|
117
|
-
* console.log(tree.root);
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
78
|
static from(tree) {
|
|
121
79
|
if (tree instanceof Tree)
|
|
122
80
|
return tree;
|
|
81
|
+
// Portable snapshots resume through descriptor validation instead of rebuilding.
|
|
82
|
+
if (!Array.isArray(tree) &&
|
|
83
|
+
"entries" in tree &&
|
|
84
|
+
"leaves" in tree &&
|
|
85
|
+
"root" in tree) {
|
|
86
|
+
return "type" in tree && tree.type != null
|
|
87
|
+
? Tree.fromDescriptor(tree)
|
|
88
|
+
: Tree.fromDescriptor(tree);
|
|
89
|
+
}
|
|
90
|
+
if ("type" in tree && tree.type != null)
|
|
91
|
+
return Tree.create(tree);
|
|
123
92
|
return Tree.create(Array.isArray(tree) ? tree : [tree]);
|
|
124
93
|
}
|
|
94
|
+
static create(params) {
|
|
95
|
+
if ("type" in params) {
|
|
96
|
+
const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(params);
|
|
97
|
+
switch (descriptor.type) {
|
|
98
|
+
case "ecrecover":
|
|
99
|
+
return new Tree("ecrecover", descriptor);
|
|
100
|
+
case "setter":
|
|
101
|
+
return new Tree("setter", descriptor);
|
|
102
|
+
case "priceV1":
|
|
103
|
+
return new Tree("priceV1", descriptor);
|
|
104
|
+
case "rateV1":
|
|
105
|
+
return new Tree("rateV1", descriptor);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const offers = TreeUtils_js_1.TreeUtils.normalizeEntries(params);
|
|
109
|
+
const descriptor = TreeUtils_js_1.TreeUtils.buildDescriptor(params);
|
|
110
|
+
return new Tree(undefined, {
|
|
111
|
+
...descriptor,
|
|
112
|
+
offers,
|
|
113
|
+
entries: descriptor.offers,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
125
116
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* Use after `Offer.create` and optional `Group.create`, before
|
|
129
|
-
* `Tree.mempoolValidate`, `EcrecoverRatifierUtils.ratify`, or
|
|
130
|
-
* `SetterRatifierUtils.ratify`. Groups are flattened, and every standalone
|
|
131
|
-
* offer is normalized as a singleton group using the router-compatible group
|
|
132
|
-
* id algorithm.
|
|
133
|
-
*
|
|
134
|
-
* @param params - Groups or standalone offers in leaf order.
|
|
135
|
-
* @returns Tree instance.
|
|
136
|
-
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated.
|
|
137
|
-
* @throws {InvalidTreeHeightError} when the resulting height is unsupported.
|
|
117
|
+
* Exports plain normalized data for transport; does not claim root authorization.
|
|
118
|
+
* @returns Descriptor with the same route and padded commitments.
|
|
138
119
|
* @example
|
|
139
120
|
* ```ts
|
|
140
|
-
* import {
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* market: {
|
|
145
|
-
* chainId: 8453,
|
|
146
|
-
* midnight: "0x0000000000000000000000000000000000001000",
|
|
147
|
-
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
148
|
-
* collateralParams: [
|
|
149
|
-
* {
|
|
150
|
-
* token: "0x0000000000000000000000000000000000007000",
|
|
151
|
-
* lltv: 770000000000000000n,
|
|
152
|
-
* liquidationCursor: 250000000000000000n,
|
|
153
|
-
* oracle: "0x0000000000000000000000000000000000008000",
|
|
154
|
-
* },
|
|
155
|
-
* ],
|
|
156
|
-
* maturity: 54_000n,
|
|
157
|
-
* rcfThreshold: 0n,
|
|
158
|
-
* enterGate: zeroAddress,
|
|
159
|
-
* liquidatorGate: zeroAddress,
|
|
160
|
-
* },
|
|
161
|
-
* buy: true,
|
|
162
|
-
* maker: "0x0000000000000000000000000000000000009000",
|
|
163
|
-
* tick: 5_000n,
|
|
164
|
-
* expiry: 3_600n,
|
|
165
|
-
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
166
|
-
* maxUnits: 100n,
|
|
167
|
-
* });
|
|
168
|
-
* const tree = Tree.create([offer]);
|
|
169
|
-
* console.log(tree.height);
|
|
121
|
+
* import { Tree, type IOffer } from "@morpho-org/midnight-sdk";
|
|
122
|
+
* function prepare(offers: readonly IOffer[]) {
|
|
123
|
+
* return Tree.create({ type: "setter", entries: offers }).toDescriptor();
|
|
124
|
+
* }
|
|
170
125
|
* ```
|
|
171
126
|
*/
|
|
172
|
-
|
|
173
|
-
return
|
|
127
|
+
toDescriptor() {
|
|
128
|
+
return (0, morpho_ts_1.deepFreeze)({
|
|
129
|
+
type: this.type,
|
|
130
|
+
entries: [...this.entries],
|
|
131
|
+
offers: this.paddedOffers.slice(0, this.offers.length),
|
|
132
|
+
leaves: [...this.leaves],
|
|
133
|
+
root: this.root,
|
|
134
|
+
height: this.height,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
static fromDescriptor(descriptor) {
|
|
138
|
+
switch (descriptor.type) {
|
|
139
|
+
case "priceV1":
|
|
140
|
+
// Validate caller-controlled hashes, offers and padding before constructing an instance.
|
|
141
|
+
PriceRatifierV1_js_1.PriceRatifierV1.buildProof({ tree: descriptor, leafIndex: 0n });
|
|
142
|
+
return new Tree("priceV1", {
|
|
143
|
+
...descriptor,
|
|
144
|
+
entries: descriptor.entries.map((entry, index) => ({
|
|
145
|
+
allowedTaker: entry.allowedTaker,
|
|
146
|
+
offer: index < descriptor.offers.length
|
|
147
|
+
? index_js_1.OfferUtils.toStruct({ offer: entry.offer })
|
|
148
|
+
: entry.offer,
|
|
149
|
+
})),
|
|
150
|
+
});
|
|
151
|
+
case "rateV1":
|
|
152
|
+
// Validate caller-controlled hashes, offers and padding before constructing an instance.
|
|
153
|
+
RateRatifierV1_js_1.RateRatifierV1.buildProof({ tree: descriptor, leafIndex: 0n });
|
|
154
|
+
return new Tree("rateV1", {
|
|
155
|
+
...descriptor,
|
|
156
|
+
entries: descriptor.entries.map((entry, index) => ({
|
|
157
|
+
rate: entry.rate,
|
|
158
|
+
allowedTaker: entry.allowedTaker,
|
|
159
|
+
offer: index < descriptor.offers.length
|
|
160
|
+
? index_js_1.OfferUtils.toStruct({ offer: entry.offer })
|
|
161
|
+
: entry.offer,
|
|
162
|
+
})),
|
|
163
|
+
});
|
|
164
|
+
case "ecrecover":
|
|
165
|
+
case "setter":
|
|
166
|
+
case undefined: {
|
|
167
|
+
// Validate the complete standard offer commitment without reassigning groups.
|
|
168
|
+
Ratifier_js_1.Ratifier.normalizeRatifierTree({
|
|
169
|
+
tree: { ...descriptor, paddedOffers: descriptor.entries },
|
|
170
|
+
label: descriptor.type === "setter" ? "Setter" : "Ecrecover",
|
|
171
|
+
});
|
|
172
|
+
const normalized = {
|
|
173
|
+
...descriptor,
|
|
174
|
+
entries: descriptor.entries.map((offer, index) => index < descriptor.offers.length
|
|
175
|
+
? index_js_1.OfferUtils.toStruct({ offer })
|
|
176
|
+
: offer),
|
|
177
|
+
};
|
|
178
|
+
if (descriptor.type === "ecrecover")
|
|
179
|
+
return new Tree("ecrecover", normalized);
|
|
180
|
+
if (descriptor.type === "setter")
|
|
181
|
+
return new Tree("setter", normalized);
|
|
182
|
+
return new Tree(undefined, normalized);
|
|
183
|
+
}
|
|
184
|
+
default:
|
|
185
|
+
throw new errors_js_1.InvalidTreeError("Unsupported tree ratifier route.");
|
|
186
|
+
}
|
|
174
187
|
}
|
|
175
188
|
/**
|
|
176
189
|
* Validates this tree against Midnight mempool API policy.
|
|
@@ -179,15 +192,18 @@ class Tree {
|
|
|
179
192
|
* with empty `ratifierData`, then sends the temporary payload to the Midnight
|
|
180
193
|
* API `POST /mempool/validate` endpoint. Pass `ratification` after signing or
|
|
181
194
|
* Setter root preparation to validate final payload bytes with real
|
|
182
|
-
* `ratifierData`.
|
|
195
|
+
* `ratifierData`. Price/Rate V1 routes always post their real ratifier data
|
|
196
|
+
* because the router decodes it to identify each offer; their
|
|
197
|
+
* `ratification` only asserts the route.
|
|
183
198
|
*
|
|
184
199
|
* @param params.chainId - Chain id whose API policy should validate this tree.
|
|
185
200
|
* @param params.apiUrl - Optional Midnight API URL override used for the validation HTTP request.
|
|
186
201
|
* @param params.timestamp - Optional ISO-8601 timestamp or `Date` selecting the API policy snapshot.
|
|
187
202
|
* @param params.fetch - Optional fetch implementation override used for the API call.
|
|
188
203
|
* @param params.request - Optional fetch options forwarded to the API request.
|
|
189
|
-
* @param params.ratification - Optional
|
|
204
|
+
* @param params.ratification - Optional route-matching authorization inputs; Price/Rate routes require their root to have been approved onchain.
|
|
190
205
|
* @returns Successful API validation result with `valid: true`.
|
|
206
|
+
* @throws {InvalidTreeError} when the ratification route differs from the tree route.
|
|
191
207
|
* @throws {PayloadDecodeError} when validation payload encoding fails.
|
|
192
208
|
* @throws {MidnightApiError} when the API returns a non-2xx response.
|
|
193
209
|
* @throws {InvalidMidnightApiResponseError} when the API returns malformed success JSON.
|
|
@@ -222,15 +238,34 @@ class Tree {
|
|
|
222
238
|
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
223
239
|
* maxUnits: 100n,
|
|
224
240
|
* });
|
|
225
|
-
* await Tree.create([offer]).mempoolValidate({
|
|
241
|
+
* await Tree.create({ type: "ecrecover", entries: [offer] }).mempoolValidate({
|
|
226
242
|
* chainId: 8453,
|
|
227
243
|
* });
|
|
228
244
|
* ```
|
|
229
245
|
*/
|
|
230
|
-
mempoolValidate(params) {
|
|
246
|
+
async mempoolValidate(params) {
|
|
247
|
+
const descriptor = this.toDescriptor();
|
|
248
|
+
if (params.ratification != null &&
|
|
249
|
+
(this.type == null
|
|
250
|
+
? params.ratification.type !== "ecrecover" &&
|
|
251
|
+
params.ratification.type !== "setter"
|
|
252
|
+
: params.ratification.type !== this.type)) {
|
|
253
|
+
throw new errors_js_1.InvalidTreeError("Ratification route does not match the tree route.");
|
|
254
|
+
}
|
|
255
|
+
if (this.type === "priceV1" || this.type === "rateV1") {
|
|
256
|
+
return TreeUtils_js_1.TreeUtils.mempoolValidate({
|
|
257
|
+
...params,
|
|
258
|
+
tree: descriptor,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
231
261
|
return TreeUtils_js_1.TreeUtils.mempoolValidate({
|
|
232
262
|
...params,
|
|
233
|
-
|
|
263
|
+
ratification: params.ratification,
|
|
264
|
+
tree: Tree.fromDescriptor({
|
|
265
|
+
...descriptor,
|
|
266
|
+
type: undefined,
|
|
267
|
+
entries: this.paddedOffers,
|
|
268
|
+
}),
|
|
234
269
|
});
|
|
235
270
|
}
|
|
236
271
|
/**
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type BigIntish } from "@morpho-org/morpho-ts";
|
|
2
2
|
import { type Account, type Address, type Chain, type Client, type Hash, type Transport } from "viem";
|
|
3
3
|
import type { MempoolPayloadValidationSuccess, MidnightApiFetch, MidnightApiRequestOptions } from "../api/types.js";
|
|
4
|
-
import { type IOffer, type OfferStruct } from "../offers/index.js";
|
|
5
|
-
import { type EcrecoverSignatureInput } from "./
|
|
4
|
+
import { type IOffer, Offer, type OfferStruct } from "../offers/index.js";
|
|
5
|
+
import { type EcrecoverSignatureInput } from "./EcrecoverRatifier.js";
|
|
6
6
|
import { type GroupInput } from "./GroupUtils.js";
|
|
7
|
-
import
|
|
7
|
+
import { Tree } from "./Tree.js";
|
|
8
|
+
import type { AnyTreeSnapshot, EcrecoverTreeCreateRequest, TreeCreateRequest, TreeSnapshot } from "./treeTypes.js";
|
|
8
9
|
/**
|
|
9
10
|
* Fully materialized tree descriptor.
|
|
10
11
|
*
|
|
@@ -105,7 +106,9 @@ export interface TreeProof {
|
|
|
105
106
|
readonly proof: readonly Hash[];
|
|
106
107
|
}
|
|
107
108
|
/**
|
|
108
|
-
*
|
|
109
|
+
* Legacy untagged entries accepted by {@link Tree.create}.
|
|
110
|
+
*
|
|
111
|
+
* @deprecated Use EcrecoverTreeCreateRequest or SetterTreeCreateRequest with an explicit type and entries.
|
|
109
112
|
*
|
|
110
113
|
* Entries are either explicit groups or standalone offers. Explicit groups are
|
|
111
114
|
* flattened, and standalone offers are hashed with their own group ids.
|
|
@@ -146,7 +149,7 @@ export interface TreeProof {
|
|
|
146
149
|
* console.log(tree.root);
|
|
147
150
|
* ```
|
|
148
151
|
*/
|
|
149
|
-
export type TreeCreateParams =
|
|
152
|
+
export type TreeCreateParams = EcrecoverTreeCreateRequest["entries"];
|
|
150
153
|
/**
|
|
151
154
|
* Plain creation input or class tree accepted by {@link Tree.from}.
|
|
152
155
|
*
|
|
@@ -291,7 +294,9 @@ export type RatifierTreeInput = TreeLike | TreeInput;
|
|
|
291
294
|
* Omit this when validating offer policy before the maker signs or approves a
|
|
292
295
|
* tree. Provide it when validating the final payload shape, including real
|
|
293
296
|
* `ratifierData`, after the Ecrecover signature and signer address exist or the
|
|
294
|
-
* Setter root is ready for publication.
|
|
297
|
+
* Setter root is ready for publication. Price/Rate V1 routes always post real
|
|
298
|
+
* ratifier data because the router identifies each offer from its decoded
|
|
299
|
+
* leaf fields; their `ratification` is only a route assertion.
|
|
295
300
|
*
|
|
296
301
|
* @example
|
|
297
302
|
* ```ts
|
|
@@ -327,14 +332,23 @@ export type TreeMempoolValidateRatification = {
|
|
|
327
332
|
} | {
|
|
328
333
|
/** Setter ratifier route. */
|
|
329
334
|
readonly type: "setter";
|
|
335
|
+
} | {
|
|
336
|
+
/** PriceRatifierV1 route assertion; validation always encodes its ratifier data. */
|
|
337
|
+
readonly type: "priceV1";
|
|
338
|
+
} | {
|
|
339
|
+
/** RateRatifierV1 route assertion; validation always encodes its ratifier data. */
|
|
340
|
+
readonly type: "rateV1";
|
|
330
341
|
};
|
|
331
342
|
/**
|
|
332
343
|
* Parameters for {@link Tree.mempoolValidate}.
|
|
333
344
|
*
|
|
334
345
|
* Use this when an already-created tree should be validated by the Midnight
|
|
335
|
-
* API.
|
|
336
|
-
* `ratifierData
|
|
337
|
-
* real ratifier data.
|
|
346
|
+
* API. Standard routes validate the pre-ratification tree with empty
|
|
347
|
+
* `ratifierData` by default; pass `ratification` to validate the final
|
|
348
|
+
* payload shape with real ratifier data. Price/Rate V1 routes always encode
|
|
349
|
+
* real ratifier data (root, leaf index, proof, allowed taker, and the rate for
|
|
350
|
+
* RateRatifierV1) because the router identifies each offer by decoding it; their
|
|
351
|
+
* `ratification` only asserts the route.
|
|
338
352
|
*
|
|
339
353
|
* @example
|
|
340
354
|
* ```ts
|
|
@@ -401,6 +415,27 @@ export interface TreeMempoolValidateParams {
|
|
|
401
415
|
* ```
|
|
402
416
|
*/
|
|
403
417
|
export declare namespace TreeUtils {
|
|
418
|
+
/**
|
|
419
|
+
* Normalizes legacy standard tree entries into grouped offers.
|
|
420
|
+
*
|
|
421
|
+
* Explicit groups are flattened into their member offers, and every
|
|
422
|
+
* standalone offer is normalized as a singleton group using the
|
|
423
|
+
* router-compatible `GroupUtils.hash` group id. Use this when you need the
|
|
424
|
+
* exact offer list a standard Ecrecover/Setter tree commits to.
|
|
425
|
+
*
|
|
426
|
+
* @param entries - Groups or standalone offers in leaf order.
|
|
427
|
+
* @returns Offers in leaf order with their committed group ids.
|
|
428
|
+
* @throws {InvalidOfferGroupError} when an explicit group entry violates group mechanics.
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* import { TreeUtils, type TreeCreateParams } from "@morpho-org/midnight-sdk";
|
|
432
|
+
*
|
|
433
|
+
* function normalize(entries: TreeCreateParams) {
|
|
434
|
+
* return TreeUtils.normalizeEntries(entries);
|
|
435
|
+
* }
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
function normalizeEntries(entries: TreeCreateParams): readonly Offer[];
|
|
404
439
|
/**
|
|
405
440
|
* Validates a tree against Midnight mempool API policy.
|
|
406
441
|
*
|
|
@@ -408,17 +443,20 @@ export declare namespace TreeUtils {
|
|
|
408
443
|
* with empty `ratifierData`, then sends the temporary payload to the Midnight
|
|
409
444
|
* API `POST /mempool/validate` endpoint. Pass `ratification` after signing or
|
|
410
445
|
* Setter root preparation to validate final payload bytes with real
|
|
411
|
-
* `ratifierData`.
|
|
446
|
+
* `ratifierData`. Price/Rate V1 tree snapshots are supported directly and
|
|
447
|
+
* always post the corresponding V1 `ratify` output — there is no empty
|
|
448
|
+
* ratifier-data shape because the router decodes the leaf fields to identify
|
|
449
|
+
* each offer. A V1 `ratification` only asserts the matching route.
|
|
412
450
|
*
|
|
413
451
|
* @param params.chainId - Chain id whose API policy should validate the tree.
|
|
414
|
-
* @param params.tree - Offer tree to validate.
|
|
452
|
+
* @param params.tree - Offer tree or route-typed tree snapshot to validate. Serialized standard snapshots resume without rewriting committed groups.
|
|
415
453
|
* @param params.apiUrl - Optional Midnight API URL override used for the validation HTTP request.
|
|
416
454
|
* @param params.timestamp - Optional ISO-8601 timestamp or `Date` selecting the API policy snapshot.
|
|
417
455
|
* @param params.fetch - Optional fetch implementation override used for the API call.
|
|
418
456
|
* @param params.request - Optional fetch options forwarded to the API request.
|
|
419
|
-
* @param params.ratification - Optional ratification inputs used to validate final payload bytes with real ratifier data.
|
|
457
|
+
* @param params.ratification - Optional route-matching ratification inputs used to validate final payload bytes with real ratifier data.
|
|
420
458
|
* @returns Successful API validation result with `valid: true`.
|
|
421
|
-
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated.
|
|
459
|
+
* @throws {InvalidTreeError} when the tree is empty, all padding, or duplicated, or when `ratification` does not match the tree route.
|
|
422
460
|
* @throws {InvalidTreeHeightError} when the resulting height is unsupported.
|
|
423
461
|
* @throws {PayloadDecodeError} when validation payload encoding fails.
|
|
424
462
|
* @throws {MidnightApiError} when the API returns a non-2xx response.
|
|
@@ -461,7 +499,7 @@ export declare namespace TreeUtils {
|
|
|
461
499
|
* ```
|
|
462
500
|
*/
|
|
463
501
|
function mempoolValidate(params: Pick<TreeMempoolValidateParams, "chainId" | "apiUrl" | "timestamp" | "fetch" | "request"> & {
|
|
464
|
-
readonly tree: TreeInput
|
|
502
|
+
readonly tree: TreeInput | TreeSnapshot<"ecrecover"> | TreeSnapshot<"setter"> | TreeSnapshot<"priceV1"> | TreeSnapshot<"rateV1">;
|
|
465
503
|
readonly ratification?: TreeMempoolValidateRatification;
|
|
466
504
|
}): Promise<MempoolPayloadValidationSuccess>;
|
|
467
505
|
/**
|
|
@@ -493,10 +531,12 @@ export declare namespace TreeUtils {
|
|
|
493
531
|
* `Tree.create` calls this internally and is the simpler API for most
|
|
494
532
|
* make-side code.
|
|
495
533
|
*
|
|
496
|
-
* @param entries -
|
|
534
|
+
* @param entries - Tagged route and leaf inputs in leaf order.
|
|
497
535
|
* @returns Tree descriptor.
|
|
498
536
|
* @throws {InvalidTreeError} when the offer count is empty, all padding, or duplicated.
|
|
499
537
|
* @throws {InvalidTreeHeightError} when the padded tree exceeds supported ratifier typehashes.
|
|
538
|
+
* @throws {InvalidRateRatifierV1RateError} when a Rate leaf has a negative rate.
|
|
539
|
+
* @throws {InvalidRateRatifierV1TickError} when a Rate leaf offer tick is below `RateRatifierV1.MIN_TICK`.
|
|
500
540
|
* @example
|
|
501
541
|
* ```ts
|
|
502
542
|
* import { Offer, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
@@ -527,10 +567,28 @@ export declare namespace TreeUtils {
|
|
|
527
567
|
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
528
568
|
* maxUnits: 100n,
|
|
529
569
|
* });
|
|
530
|
-
* const tree = TreeUtils.buildDescriptor([offer]);
|
|
570
|
+
* const tree = TreeUtils.buildDescriptor({ type: "ecrecover", entries: [offer] });
|
|
531
571
|
* console.log(tree.root);
|
|
532
572
|
* ```
|
|
533
573
|
*/
|
|
574
|
+
function buildDescriptor<R extends TreeCreateRequest>(entries: R): Extract<AnyTreeSnapshot, {
|
|
575
|
+
readonly type: R["type"];
|
|
576
|
+
}>;
|
|
577
|
+
/**
|
|
578
|
+
* Builds a descriptor using the legacy standard-offer input.
|
|
579
|
+
* @deprecated Pass a TreeCreateRequest with an explicit ratifier type instead.
|
|
580
|
+
* @param entries - Untagged offers or groups in leaf order.
|
|
581
|
+
* @returns Legacy padded standard-offer descriptor.
|
|
582
|
+
* @throws {InvalidTreeError} When entries are empty, all padding, or duplicated.
|
|
583
|
+
* @throws {InvalidTreeHeightError} When the tree height is unsupported.
|
|
584
|
+
* @example
|
|
585
|
+
* ```ts
|
|
586
|
+
* import { TreeUtils, type TreeCreateParams } from "@morpho-org/midnight-sdk";
|
|
587
|
+
* function legacyDescriptor(entries: TreeCreateParams) {
|
|
588
|
+
* return TreeUtils.buildDescriptor(entries);
|
|
589
|
+
* }
|
|
590
|
+
* ```
|
|
591
|
+
*/
|
|
534
592
|
function buildDescriptor(entries: TreeCreateParams): TreeDescriptor;
|
|
535
593
|
/**
|
|
536
594
|
* Builds only the tree root.
|
|
@@ -577,18 +635,43 @@ export declare namespace TreeUtils {
|
|
|
577
635
|
* console.log(root);
|
|
578
636
|
* ```
|
|
579
637
|
*/
|
|
580
|
-
function buildRoot(entries: TreeCreateParams):
|
|
638
|
+
function buildRoot(entries: TreeCreateParams): Hash;
|
|
639
|
+
/**
|
|
640
|
+
* Builds a Merkle root from already-hashed leaves.
|
|
641
|
+
*
|
|
642
|
+
* Use this leaf-hash-agnostic form when a ratifier's leaves are not plain
|
|
643
|
+
* offer hashes, for example `RateRatifierV1.hashLeaf` outputs. The leaf
|
|
644
|
+
* count must be a power of two; pad non-power-of-two lists beforehand.
|
|
645
|
+
*
|
|
646
|
+
* @param leaves - Leaf hashes in leaf order; length must be a power of two.
|
|
647
|
+
* @returns Merkle root and tree height.
|
|
648
|
+
* @throws {InvalidTreeError} when the leaf count is not a power of two.
|
|
649
|
+
* @throws {InvalidTreeHeightError} when the tree exceeds supported ratifier typehashes.
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* import { TreeUtils } from "@morpho-org/midnight-sdk";
|
|
653
|
+
* import { zeroHash } from "viem";
|
|
654
|
+
*
|
|
655
|
+
* const { root, height } = TreeUtils.buildRootFromLeaves([zeroHash]);
|
|
656
|
+
* console.log(height);
|
|
657
|
+
* ```
|
|
658
|
+
*/
|
|
659
|
+
function buildRootFromLeaves(leaves: readonly Hash[]): {
|
|
660
|
+
readonly root: Hash;
|
|
661
|
+
readonly height: number;
|
|
662
|
+
};
|
|
581
663
|
/**
|
|
582
664
|
* Builds a Merkle proof for one offer.
|
|
583
665
|
*
|
|
584
|
-
* Use after tree construction when a custom ratifier needs one proof
|
|
585
|
-
* built-in
|
|
586
|
-
* `ratifierData
|
|
666
|
+
* Use after tree construction when a custom ratifier needs one proof; the
|
|
667
|
+
* built-in ratify helpers use {@link TreeUtils.buildProofs} to generate
|
|
668
|
+
* `ratifierData` in bulk.
|
|
587
669
|
*
|
|
588
670
|
* @param params.tree - Tree-like data with the root and leaves that contain the leaf.
|
|
589
671
|
* @param params.leafIndex - Leaf index to prove.
|
|
590
672
|
* @returns Proof descriptor.
|
|
591
|
-
* @throws {InvalidTreeError} when leaf index is out of range.
|
|
673
|
+
* @throws {InvalidTreeError} when leaf index is out of range or when the leaf count is not a power of two.
|
|
674
|
+
* @throws {InvalidTreeHeightError} when the tree height (log2 of the leaf count) exceeds 20.
|
|
592
675
|
* @example
|
|
593
676
|
* ```ts
|
|
594
677
|
* import { Offer, Tree, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
@@ -630,6 +713,60 @@ export declare namespace TreeUtils {
|
|
|
630
713
|
readonly tree: Pick<TreeLike, "leaves" | "root">;
|
|
631
714
|
readonly leafIndex: BigIntish;
|
|
632
715
|
}): TreeProof;
|
|
716
|
+
/**
|
|
717
|
+
* Builds Merkle proofs for a range of leaves from one tree-layer pass.
|
|
718
|
+
*
|
|
719
|
+
* Use instead of calling {@link TreeUtils.buildProof} per leaf when many
|
|
720
|
+
* proofs are needed at once, for example inside `ratify` helpers: the
|
|
721
|
+
* parent layers are computed once instead of once per leaf. Each returned
|
|
722
|
+
* proof is byte-identical to `buildProof` on the same tree and leaf index.
|
|
723
|
+
*
|
|
724
|
+
* @param params.tree - Tree leaves and root to prove against.
|
|
725
|
+
* @param params.count - Number of leading leaf indices to prove; defaults to `tree.leaves.length`.
|
|
726
|
+
* @returns Frozen proofs for leaf indices `0` through `count - 1`.
|
|
727
|
+
* @throws {InvalidTreeError} when `count` is negative, non-integer, or exceeds the leaf count, or when the leaf count is not a power of two.
|
|
728
|
+
* @throws {InvalidTreeHeightError} when the tree height (log2 of the leaf count) exceeds 20.
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* import { Offer, Tree, TreeUtils } from "@morpho-org/midnight-sdk";
|
|
732
|
+
* import { zeroAddress } from "viem";
|
|
733
|
+
*
|
|
734
|
+
* const offer = Offer.create({
|
|
735
|
+
* market: {
|
|
736
|
+
* chainId: 8453,
|
|
737
|
+
* midnight: "0x0000000000000000000000000000000000001000",
|
|
738
|
+
* loanToken: "0x0000000000000000000000000000000000006000",
|
|
739
|
+
* collateralParams: [
|
|
740
|
+
* {
|
|
741
|
+
* token: "0x0000000000000000000000000000000000007000",
|
|
742
|
+
* lltv: 770000000000000000n,
|
|
743
|
+
* liquidationCursor: 250000000000000000n,
|
|
744
|
+
* oracle: "0x0000000000000000000000000000000000008000",
|
|
745
|
+
* },
|
|
746
|
+
* ],
|
|
747
|
+
* maturity: 54_000n,
|
|
748
|
+
* rcfThreshold: 0n,
|
|
749
|
+
* enterGate: zeroAddress,
|
|
750
|
+
* liquidatorGate: zeroAddress,
|
|
751
|
+
* },
|
|
752
|
+
* buy: true,
|
|
753
|
+
* maker: "0x0000000000000000000000000000000000009000",
|
|
754
|
+
* tick: 5_000n,
|
|
755
|
+
* expiry: 3_600n,
|
|
756
|
+
* ratifier: "0x0000000000000000000000000000000000004000",
|
|
757
|
+
* maxUnits: 100n,
|
|
758
|
+
* });
|
|
759
|
+
* const proofs = TreeUtils.buildProofs({
|
|
760
|
+
* tree: Tree.create([offer]),
|
|
761
|
+
* count: 1,
|
|
762
|
+
* });
|
|
763
|
+
* console.log(proofs[0]!.proof.length);
|
|
764
|
+
* ```
|
|
765
|
+
*/
|
|
766
|
+
function buildProofs(params: {
|
|
767
|
+
readonly tree: Pick<TreeLike, "leaves" | "root">;
|
|
768
|
+
readonly count?: number;
|
|
769
|
+
}): readonly TreeProof[];
|
|
633
770
|
/**
|
|
634
771
|
* Verifies a local Merkle proof against a root.
|
|
635
772
|
*
|
|
@@ -689,4 +826,37 @@ export declare namespace TreeUtils {
|
|
|
689
826
|
readonly leafIndex: BigIntish;
|
|
690
827
|
readonly proof: readonly Hash[];
|
|
691
828
|
}): boolean;
|
|
829
|
+
/**
|
|
830
|
+
* Verifies a local Merkle proof for an already-hashed leaf against a root.
|
|
831
|
+
*
|
|
832
|
+
* Use this leaf-hash-agnostic form when a ratifier's leaves are not plain
|
|
833
|
+
* offer hashes, for example `RateRatifierV1.hashLeaf` outputs. The leaf
|
|
834
|
+
* index determines each sibling's left/right position, matching
|
|
835
|
+
* `HashLib.isLeaf` onchain.
|
|
836
|
+
*
|
|
837
|
+
* @param params.leaf - Leaf hash that starts proof reconstruction.
|
|
838
|
+
* @param params.root - Expected Merkle root.
|
|
839
|
+
* @param params.leafIndex - Leaf index proven by `params.proof`.
|
|
840
|
+
* @param params.proof - Merkle proof siblings for the leaf.
|
|
841
|
+
* @returns Whether the proof reconstructs the supplied root.
|
|
842
|
+
* @example
|
|
843
|
+
* ```ts
|
|
844
|
+
* import { TreeUtils } from "@morpho-org/midnight-sdk";
|
|
845
|
+
* import { zeroHash } from "viem";
|
|
846
|
+
*
|
|
847
|
+
* const valid = TreeUtils.verifyLeafProof({
|
|
848
|
+
* leaf: zeroHash,
|
|
849
|
+
* root: zeroHash,
|
|
850
|
+
* leafIndex: 0n,
|
|
851
|
+
* proof: [],
|
|
852
|
+
* });
|
|
853
|
+
* console.log(valid);
|
|
854
|
+
* ```
|
|
855
|
+
*/
|
|
856
|
+
function verifyLeafProof(params: {
|
|
857
|
+
readonly leaf: Hash;
|
|
858
|
+
readonly root: Hash;
|
|
859
|
+
readonly leafIndex: BigIntish;
|
|
860
|
+
readonly proof: readonly Hash[];
|
|
861
|
+
}): boolean;
|
|
692
862
|
}
|