@quip.network/quip-swap-sdk 0.1.0-beta.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/LICENSE +235 -0
- package/README.md +124 -0
- package/dist/index.d.ts +3136 -0
- package/dist/index.js +2596 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2596 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var AssetType = /* @__PURE__ */ ((AssetType2) => {
|
|
3
|
+
AssetType2[AssetType2["Native"] = 0] = "Native";
|
|
4
|
+
AssetType2[AssetType2["ERC20"] = 1] = "ERC20";
|
|
5
|
+
AssetType2[AssetType2["ERC721"] = 2] = "ERC721";
|
|
6
|
+
AssetType2[AssetType2["ERC1155"] = 3] = "ERC1155";
|
|
7
|
+
return AssetType2;
|
|
8
|
+
})(AssetType || {});
|
|
9
|
+
var LockState = /* @__PURE__ */ ((LockState2) => {
|
|
10
|
+
LockState2[LockState2["Unused"] = 0] = "Unused";
|
|
11
|
+
LockState2[LockState2["Free"] = 1] = "Free";
|
|
12
|
+
LockState2[LockState2["Committed"] = 2] = "Committed";
|
|
13
|
+
LockState2[LockState2["Spent"] = 3] = "Spent";
|
|
14
|
+
return LockState2;
|
|
15
|
+
})(LockState || {});
|
|
16
|
+
|
|
17
|
+
// src/errors.ts
|
|
18
|
+
import { BaseError, ContractFunctionRevertedError } from "viem";
|
|
19
|
+
var QuipSwapError = class extends Error {
|
|
20
|
+
name = "QuipSwapError";
|
|
21
|
+
code;
|
|
22
|
+
contractErrorName;
|
|
23
|
+
cause;
|
|
24
|
+
details;
|
|
25
|
+
constructor(args) {
|
|
26
|
+
super(args.message);
|
|
27
|
+
this.code = args.code;
|
|
28
|
+
if (args.contractErrorName !== void 0) this.contractErrorName = args.contractErrorName;
|
|
29
|
+
if (args.cause !== void 0) this.cause = args.cause;
|
|
30
|
+
if (args.details !== void 0) this.details = args.details;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function extractContractErrorName(error) {
|
|
34
|
+
if (error instanceof BaseError) {
|
|
35
|
+
const revert = error.walk((e) => e instanceof ContractFunctionRevertedError);
|
|
36
|
+
if (revert instanceof ContractFunctionRevertedError) {
|
|
37
|
+
return revert.data?.errorName ?? revert.signature;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
function wrapContractError(error, context) {
|
|
43
|
+
const contractErrorName = extractContractErrorName(error);
|
|
44
|
+
const suffix = contractErrorName !== void 0 ? ` (contract error: ${contractErrorName})` : "";
|
|
45
|
+
return new QuipSwapError({
|
|
46
|
+
code: "CONTRACT_REVERT",
|
|
47
|
+
message: `${context} reverted${suffix}`,
|
|
48
|
+
...contractErrorName !== void 0 ? { contractErrorName } : {},
|
|
49
|
+
cause: error
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/assets.ts
|
|
54
|
+
import { isAddress, zeroAddress } from "viem";
|
|
55
|
+
function nativeAsset(amount) {
|
|
56
|
+
if (amount <= 0n) {
|
|
57
|
+
throw new QuipSwapError({
|
|
58
|
+
code: "ZERO_AMOUNT",
|
|
59
|
+
message: "Native asset amount must be greater than zero (contract: ZeroAmount)",
|
|
60
|
+
details: { amount }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return Object.freeze({ assetType: 0 /* Native */, target: zeroAddress, id: 0n, amount });
|
|
64
|
+
}
|
|
65
|
+
function erc20Asset(target, amount) {
|
|
66
|
+
assertTokenTarget(target, "INVALID_ERC20_ASSET", "ERC-20");
|
|
67
|
+
if (amount <= 0n) {
|
|
68
|
+
throw new QuipSwapError({
|
|
69
|
+
code: "ZERO_AMOUNT",
|
|
70
|
+
message: "ERC-20 asset amount must be greater than zero (contract: ZeroAmount)",
|
|
71
|
+
details: { target, amount }
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze({ assetType: 1 /* ERC20 */, target, id: 0n, amount });
|
|
75
|
+
}
|
|
76
|
+
function erc721Asset(target, tokenId) {
|
|
77
|
+
assertTokenTarget(target, "INVALID_ERC721_ASSET", "ERC-721");
|
|
78
|
+
if (tokenId < 0n) {
|
|
79
|
+
throw new QuipSwapError({
|
|
80
|
+
code: "INVALID_ERC721_ASSET",
|
|
81
|
+
message: "ERC-721 token id must be non-negative",
|
|
82
|
+
details: { target, tokenId }
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({ assetType: 2 /* ERC721 */, target, id: tokenId, amount: 1n });
|
|
86
|
+
}
|
|
87
|
+
function erc1155Asset(target, tokenId, amount) {
|
|
88
|
+
assertTokenTarget(target, "INVALID_ERC1155_ASSET", "ERC-1155");
|
|
89
|
+
if (tokenId < 0n) {
|
|
90
|
+
throw new QuipSwapError({
|
|
91
|
+
code: "INVALID_ERC1155_ASSET",
|
|
92
|
+
message: "ERC-1155 token id must be non-negative",
|
|
93
|
+
details: { target, tokenId }
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (amount <= 0n) {
|
|
97
|
+
throw new QuipSwapError({
|
|
98
|
+
code: "ZERO_AMOUNT",
|
|
99
|
+
message: "ERC-1155 asset amount must be greater than zero (contract: ZeroAmount)",
|
|
100
|
+
details: { target, tokenId, amount }
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return Object.freeze({ assetType: 3 /* ERC1155 */, target, id: tokenId, amount });
|
|
104
|
+
}
|
|
105
|
+
function validateAsset(asset) {
|
|
106
|
+
if (asset.assetType !== 0 /* Native */ && asset.assetType !== 1 /* ERC20 */ && asset.assetType !== 2 /* ERC721 */ && asset.assetType !== 3 /* ERC1155 */) {
|
|
107
|
+
throw new QuipSwapError({
|
|
108
|
+
code: "INVALID_ASSET_TYPE",
|
|
109
|
+
message: `Unknown asset type ${String(asset.assetType)}; expected 0 (Native), 1 (ERC20), 2 (ERC721), or 3 (ERC1155)`,
|
|
110
|
+
details: { asset }
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (asset.amount <= 0n) {
|
|
114
|
+
throw new QuipSwapError({
|
|
115
|
+
code: "ZERO_AMOUNT",
|
|
116
|
+
message: "Asset amount must be greater than zero for every asset type (contract: ZeroAmount)",
|
|
117
|
+
details: { asset }
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (!isAddress(asset.target, { strict: false })) {
|
|
121
|
+
throw new QuipSwapError({
|
|
122
|
+
code: assetTypeErrorCode(asset.assetType),
|
|
123
|
+
message: `Asset target ${String(asset.target)} is not a valid address`,
|
|
124
|
+
details: { asset }
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const isZeroTarget = asset.target.toLowerCase() === zeroAddress;
|
|
128
|
+
const isZeroId = asset.id === 0n;
|
|
129
|
+
if (asset.assetType === 0 /* Native */ && (!isZeroTarget || !isZeroId)) {
|
|
130
|
+
throw new QuipSwapError({
|
|
131
|
+
code: "INVALID_NATIVE_ASSET",
|
|
132
|
+
message: "Native asset must have zero target and zero id (contract: InvalidNativeAsset)",
|
|
133
|
+
details: { asset }
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (asset.assetType === 1 /* ERC20 */ && (isZeroTarget || !isZeroId)) {
|
|
137
|
+
throw new QuipSwapError({
|
|
138
|
+
code: "INVALID_ERC20_ASSET",
|
|
139
|
+
message: "ERC-20 asset must have a non-zero target and id 0 (contract: InvalidERC20Asset)",
|
|
140
|
+
details: { asset }
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (asset.assetType === 2 /* ERC721 */ && isZeroTarget) {
|
|
144
|
+
throw new QuipSwapError({
|
|
145
|
+
code: "INVALID_ERC721_ASSET",
|
|
146
|
+
message: "ERC-721 asset must have a non-zero target (contract: InvalidERC721Asset)",
|
|
147
|
+
details: { asset }
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (asset.assetType === 3 /* ERC1155 */ && isZeroTarget) {
|
|
151
|
+
throw new QuipSwapError({
|
|
152
|
+
code: "INVALID_ERC1155_ASSET",
|
|
153
|
+
message: "ERC-1155 asset must have a non-zero target (contract: InvalidERC1155Asset)",
|
|
154
|
+
details: { asset }
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function assetTypeErrorCode(assetType) {
|
|
159
|
+
switch (assetType) {
|
|
160
|
+
case 0 /* Native */:
|
|
161
|
+
return "INVALID_NATIVE_ASSET";
|
|
162
|
+
case 1 /* ERC20 */:
|
|
163
|
+
return "INVALID_ERC20_ASSET";
|
|
164
|
+
case 2 /* ERC721 */:
|
|
165
|
+
return "INVALID_ERC721_ASSET";
|
|
166
|
+
case 3 /* ERC1155 */:
|
|
167
|
+
return "INVALID_ERC1155_ASSET";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function assertTokenTarget(target, code, label) {
|
|
171
|
+
if (!isAddress(target, { strict: false }) || target.toLowerCase() === zeroAddress) {
|
|
172
|
+
throw new QuipSwapError({
|
|
173
|
+
code,
|
|
174
|
+
message: `${label} asset target must be a non-zero contract address`,
|
|
175
|
+
details: { target }
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function totalNative(terms) {
|
|
180
|
+
let total = 0n;
|
|
181
|
+
for (const asset of terms.assets) {
|
|
182
|
+
if (asset.assetType === 0 /* Native */) total += asset.amount;
|
|
183
|
+
}
|
|
184
|
+
return total;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/terms.ts
|
|
188
|
+
import { isAddress as isAddress2, zeroAddress as zeroAddress2 } from "viem";
|
|
189
|
+
function createTerms(args) {
|
|
190
|
+
const terms = Object.freeze({
|
|
191
|
+
chainId: args.chainId,
|
|
192
|
+
reclaimRecipient: args.reclaimRecipient,
|
|
193
|
+
recipient: args.recipient,
|
|
194
|
+
commitmentDeadline: args.commitmentDeadline,
|
|
195
|
+
claimDeadline: args.claimDeadline,
|
|
196
|
+
reclaimRelease: args.reclaimRelease,
|
|
197
|
+
assets: Object.freeze([...args.assets])
|
|
198
|
+
});
|
|
199
|
+
validateTerms(terms);
|
|
200
|
+
return terms;
|
|
201
|
+
}
|
|
202
|
+
function validateTerms(terms) {
|
|
203
|
+
if (terms.assets.length === 0) {
|
|
204
|
+
throw new QuipSwapError({
|
|
205
|
+
code: "EMPTY_ASSETS",
|
|
206
|
+
message: "Terms must contain at least one asset (contract: EmptyAssets)"
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (!isRecipientAddress(terms.reclaimRecipient) || !isRecipientAddress(terms.recipient)) {
|
|
210
|
+
throw new QuipSwapError({
|
|
211
|
+
code: "ZERO_ADDRESS_RECIPIENT",
|
|
212
|
+
message: "Both recipient and reclaimRecipient must be valid non-zero addresses (contract: ZeroAddressRecipient)",
|
|
213
|
+
details: { recipient: terms.recipient, reclaimRecipient: terms.reclaimRecipient }
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if (terms.commitmentDeadline === 0n) {
|
|
217
|
+
throw new QuipSwapError({
|
|
218
|
+
code: "ZERO_DEADLINE",
|
|
219
|
+
message: "commitmentDeadline must be non-zero (contract: ZeroDeadline)"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (!(terms.commitmentDeadline < terms.claimDeadline && terms.claimDeadline < terms.reclaimRelease)) {
|
|
223
|
+
throw new QuipSwapError({
|
|
224
|
+
code: "DISORDERED_DEADLINES",
|
|
225
|
+
message: "Lifecycle timestamps must satisfy commitmentDeadline < claimDeadline < reclaimRelease, strictly (contract: DisordedDeadlines)",
|
|
226
|
+
details: {
|
|
227
|
+
commitmentDeadline: terms.commitmentDeadline,
|
|
228
|
+
claimDeadline: terms.claimDeadline,
|
|
229
|
+
reclaimRelease: terms.reclaimRelease
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
if (terms.chainId <= 0n) {
|
|
234
|
+
throw new QuipSwapError({
|
|
235
|
+
code: "ZERO_CHAIN_ID",
|
|
236
|
+
message: "chainId must be greater than zero (contract: ZeroChainId)",
|
|
237
|
+
details: { chainId: terms.chainId }
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
for (const asset of terms.assets) validateAsset(asset);
|
|
241
|
+
}
|
|
242
|
+
function isRecipientAddress(value) {
|
|
243
|
+
return isAddress2(value, { strict: false }) && value.toLowerCase() !== zeroAddress2;
|
|
244
|
+
}
|
|
245
|
+
function validateTermPairing(a, b) {
|
|
246
|
+
const aProposes = a.commitmentDeadline < b.commitmentDeadline && b.commitmentDeadline < a.claimDeadline && a.claimDeadline < b.claimDeadline && b.claimDeadline < a.reclaimRelease && a.reclaimRelease < b.reclaimRelease;
|
|
247
|
+
const bProposes = b.commitmentDeadline < a.commitmentDeadline && a.commitmentDeadline < b.claimDeadline && b.claimDeadline < a.claimDeadline && a.claimDeadline < b.reclaimRelease && b.reclaimRelease < a.reclaimRelease;
|
|
248
|
+
if (!(aProposes || bProposes)) {
|
|
249
|
+
throw new QuipSwapError({
|
|
250
|
+
code: "DISORDERED_DEADLINES",
|
|
251
|
+
message: "The two sides' lifecycle timestamps must strictly interleave (proposer.commit < taker.commit < proposer.claim < taker.claim < proposer.reclaim < taker.reclaim; contract: DisordedDeadlines)",
|
|
252
|
+
details: { a: lifecycleOf(a), b: lifecycleOf(b) }
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function lifecycleOf(terms) {
|
|
257
|
+
return {
|
|
258
|
+
commitmentDeadline: terms.commitmentDeadline,
|
|
259
|
+
claimDeadline: terms.claimDeadline,
|
|
260
|
+
reclaimRelease: terms.reclaimRelease
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function proposedBy(party, counterparty) {
|
|
264
|
+
return party.commitmentDeadline < counterparty.commitmentDeadline ? "party" : "counterparty";
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/windows.ts
|
|
268
|
+
var MAX_UINT256 = (1n << 256n) - 1n;
|
|
269
|
+
function enforceWithin(lower, upper, timestamp) {
|
|
270
|
+
if (lower >= upper) {
|
|
271
|
+
throw new QuipSwapError({
|
|
272
|
+
code: "INVALID_RANGE",
|
|
273
|
+
message: `Degenerate window: lower (${lower}) must be strictly less than upper (${upper}) (contract: InvalidRange)`,
|
|
274
|
+
details: { lower, upper, timestamp }
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (lower > timestamp || upper <= timestamp) {
|
|
278
|
+
throw new QuipSwapError({
|
|
279
|
+
code: "WINDOW_VIOLATED",
|
|
280
|
+
message: `Timestamp ${timestamp} is outside the half-open window [${lower}, ${upper}) (contract: WindowViolated; the upper bound is exclusive)`,
|
|
281
|
+
details: { lower, upper, timestamp }
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function isWithinWindow(window, timestamp) {
|
|
286
|
+
return window.lower < window.upper && window.lower <= timestamp && timestamp < window.upper;
|
|
287
|
+
}
|
|
288
|
+
function proposerCommitWindow(proposer) {
|
|
289
|
+
return { lower: 0n, upper: proposer.commitmentDeadline };
|
|
290
|
+
}
|
|
291
|
+
function takerCommitWindow(taker, proposer) {
|
|
292
|
+
return { lower: proposer.commitmentDeadline, upper: taker.commitmentDeadline };
|
|
293
|
+
}
|
|
294
|
+
function proposerClaimWindow(proposer, taker) {
|
|
295
|
+
return { lower: taker.commitmentDeadline, upper: proposer.claimDeadline };
|
|
296
|
+
}
|
|
297
|
+
function takerClaimWindow(proposer) {
|
|
298
|
+
return { lower: proposer.claimDeadline, upper: proposer.reclaimRelease };
|
|
299
|
+
}
|
|
300
|
+
function reclaimWindow(leg) {
|
|
301
|
+
return { lower: leg.reclaimRelease, upper: MAX_UINT256 };
|
|
302
|
+
}
|
|
303
|
+
function validateCommitWindow(party, counterparty, currentTimestamp) {
|
|
304
|
+
if (proposedBy(party, counterparty) === "party") {
|
|
305
|
+
enforceWithin(0n, party.commitmentDeadline, currentTimestamp);
|
|
306
|
+
} else {
|
|
307
|
+
enforceWithin(counterparty.commitmentDeadline, party.commitmentDeadline, currentTimestamp);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function validateClaimWindow(party, counterparty, currentTimestamp) {
|
|
311
|
+
if (proposedBy(party, counterparty) === "party") {
|
|
312
|
+
enforceWithin(counterparty.commitmentDeadline, party.claimDeadline, currentTimestamp);
|
|
313
|
+
} else {
|
|
314
|
+
enforceWithin(counterparty.claimDeadline, counterparty.reclaimRelease, currentTimestamp);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function validateReclaimWindow(party, currentTimestamp) {
|
|
318
|
+
enforceWithin(party.reclaimRelease, MAX_UINT256, currentTimestamp);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/hashing.ts
|
|
322
|
+
import { concat, encodeAbiParameters, isHex, keccak256 } from "viem";
|
|
323
|
+
var assetArrayAbiParameter = {
|
|
324
|
+
name: "assets",
|
|
325
|
+
type: "tuple[]",
|
|
326
|
+
components: [
|
|
327
|
+
{ name: "assetType", type: "uint8" },
|
|
328
|
+
{ name: "target", type: "address" },
|
|
329
|
+
{ name: "id", type: "uint256" },
|
|
330
|
+
{ name: "amount", type: "uint256" }
|
|
331
|
+
]
|
|
332
|
+
};
|
|
333
|
+
var termsAbiParameter = {
|
|
334
|
+
name: "terms",
|
|
335
|
+
type: "tuple",
|
|
336
|
+
components: [
|
|
337
|
+
{ name: "chainId", type: "uint256" },
|
|
338
|
+
{ name: "reclaimRecipient", type: "address" },
|
|
339
|
+
{ name: "recipient", type: "address" },
|
|
340
|
+
{ name: "commitmentDeadline", type: "uint256" },
|
|
341
|
+
{ name: "claimDeadline", type: "uint256" },
|
|
342
|
+
{ name: "reclaimRelease", type: "uint256" },
|
|
343
|
+
assetArrayAbiParameter
|
|
344
|
+
]
|
|
345
|
+
};
|
|
346
|
+
var termsDigestAbiParameters = [
|
|
347
|
+
{ name: "chainId", type: "uint256" },
|
|
348
|
+
{ name: "reclaimRecipient", type: "address" },
|
|
349
|
+
{ name: "recipient", type: "address" },
|
|
350
|
+
{ name: "commitmentDeadline", type: "uint256" },
|
|
351
|
+
{ name: "claimDeadline", type: "uint256" },
|
|
352
|
+
{ name: "reclaimRelease", type: "uint256" },
|
|
353
|
+
assetArrayAbiParameter
|
|
354
|
+
];
|
|
355
|
+
function digestTerms(terms) {
|
|
356
|
+
return keccak256(
|
|
357
|
+
encodeAbiParameters(termsDigestAbiParameters, [
|
|
358
|
+
terms.chainId,
|
|
359
|
+
terms.reclaimRecipient,
|
|
360
|
+
terms.recipient,
|
|
361
|
+
terms.commitmentDeadline,
|
|
362
|
+
terms.claimDeadline,
|
|
363
|
+
terms.reclaimRelease,
|
|
364
|
+
// readonly Asset[] is structurally compatible with the tuple components
|
|
365
|
+
terms.assets.map((a) => ({ assetType: a.assetType, target: a.target, id: a.id, amount: a.amount }))
|
|
366
|
+
])
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
function digestTermsCanonically(party, counterparty) {
|
|
370
|
+
const partyDigest = digestTerms(party);
|
|
371
|
+
const counterpartyDigest = digestTerms(counterparty);
|
|
372
|
+
return BigInt(partyDigest) < BigInt(counterpartyDigest) ? keccak256(concat([partyDigest, counterpartyDigest])) : keccak256(concat([counterpartyDigest, partyDigest]));
|
|
373
|
+
}
|
|
374
|
+
function generateLock(secret) {
|
|
375
|
+
assertHex32(secret, "secret");
|
|
376
|
+
return keccak256(secret);
|
|
377
|
+
}
|
|
378
|
+
function assertHex32(value, label) {
|
|
379
|
+
if (!isHex(value, { strict: true }) || value.length !== 66) {
|
|
380
|
+
throw new QuipSwapError({
|
|
381
|
+
code: "INVALID_HEX32",
|
|
382
|
+
message: `${label} must be a 0x-prefixed 32-byte hex string (66 chars total); received ${typeof value === "string" ? `${value.length} chars` : typeof value}`
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/secrets.ts
|
|
388
|
+
import { bytesToHex } from "viem";
|
|
389
|
+
function generateSecret() {
|
|
390
|
+
const bytes = new Uint8Array(32);
|
|
391
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
392
|
+
const secret = bytesToHex(bytes);
|
|
393
|
+
return Object.freeze({ secret, lock: generateLock(secret) });
|
|
394
|
+
}
|
|
395
|
+
function secretToPair(secret) {
|
|
396
|
+
assertHex32(secret, "secret");
|
|
397
|
+
return Object.freeze({ secret, lock: generateLock(secret) });
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/deployments.ts
|
|
401
|
+
import { isAddress as isAddress3, zeroAddress as zeroAddress3 } from "viem";
|
|
402
|
+
|
|
403
|
+
// src/address.json
|
|
404
|
+
var address_default = {
|
|
405
|
+
_comment: "Verified Omnibus deployments. 'omnibusAddress' is the canonical CREATE3 address derived from (Deployer contract, salt); 'chains' lists chain ids where it is VERIFIED-deployed (verify with `make verify-omnibus`). Empty/placeholder until a real deployment is confirmed; while empty, the SDK resolves no built-in address and requires an override.",
|
|
406
|
+
omnibusAddress: "0x07b74fb3805f75E669488F64E9a27E74E08fC9e0",
|
|
407
|
+
chains: [84532]
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// src/deployments.ts
|
|
411
|
+
var OMNIBUS_CREATE3_ADDRESS = address_default.omnibusAddress;
|
|
412
|
+
var VERIFIED_DEPLOYMENT_CHAINS = new Set(
|
|
413
|
+
address_default.chains.map((chainId) => BigInt(chainId))
|
|
414
|
+
);
|
|
415
|
+
var knownDeployments = new Map(
|
|
416
|
+
[...VERIFIED_DEPLOYMENT_CHAINS].map((chainId) => [chainId, { chainId, omnibusAddress: OMNIBUS_CREATE3_ADDRESS }])
|
|
417
|
+
);
|
|
418
|
+
function resolveDeployment(chainId, override) {
|
|
419
|
+
if (override !== void 0) {
|
|
420
|
+
if (!isAddress3(override.omnibusAddress, { strict: false }) || override.omnibusAddress.toLowerCase() === zeroAddress3) {
|
|
421
|
+
throw new QuipSwapError({
|
|
422
|
+
code: "UNKNOWN_DEPLOYMENT",
|
|
423
|
+
message: `Deployment override for chain ${chainId} has an invalid omnibusAddress`,
|
|
424
|
+
details: { override }
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
if (override.chainId !== chainId) {
|
|
428
|
+
throw new QuipSwapError({
|
|
429
|
+
code: "UNKNOWN_DEPLOYMENT",
|
|
430
|
+
message: `Deployment override names chain ${override.chainId} but chain ${chainId} was requested`,
|
|
431
|
+
details: { override, chainId }
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
return override;
|
|
435
|
+
}
|
|
436
|
+
const known = knownDeployments.get(chainId);
|
|
437
|
+
if (known === void 0) {
|
|
438
|
+
throw new QuipSwapError({
|
|
439
|
+
code: "UNKNOWN_DEPLOYMENT",
|
|
440
|
+
message: `No verified Omnibus deployment is known for chain ${chainId} and no override was provided. Supply {chainId, omnibusAddress} explicitly. Addresses are never guessed: a CREATE3 address ignores init code, so a deployment must be verified on-chain before it is trusted (run \`make verify-omnibus\`).`,
|
|
441
|
+
details: { chainId }
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return known;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// src/gas.ts
|
|
448
|
+
import { BaseError as BaseError2, ContractFunctionRevertedError as ContractFunctionRevertedError2 } from "viem";
|
|
449
|
+
var DEFAULT_GAS_MULTIPLIER = 1.2;
|
|
450
|
+
var MIN_GAS_MULTIPLIER = 1;
|
|
451
|
+
var MAX_GAS_MULTIPLIER = 2;
|
|
452
|
+
function resolveGasMultiplier(opts = {}) {
|
|
453
|
+
const requested = opts.gasMultiplier ?? DEFAULT_GAS_MULTIPLIER;
|
|
454
|
+
if (!Number.isFinite(requested)) return MIN_GAS_MULTIPLIER;
|
|
455
|
+
return Math.min(MAX_GAS_MULTIPLIER, Math.max(MIN_GAS_MULTIPLIER, requested));
|
|
456
|
+
}
|
|
457
|
+
function applyGasMultiplier(estimate, opts = {}) {
|
|
458
|
+
const scaled = Math.round(resolveGasMultiplier(opts) * 1e3);
|
|
459
|
+
return estimate * BigInt(scaled) / 1000n;
|
|
460
|
+
}
|
|
461
|
+
function buildFeeOverrides(opts = {}) {
|
|
462
|
+
return {
|
|
463
|
+
...opts.maxFeePerGas !== void 0 ? { maxFeePerGas: opts.maxFeePerGas } : {},
|
|
464
|
+
...opts.maxPriorityFeePerGas !== void 0 ? { maxPriorityFeePerGas: opts.maxPriorityFeePerGas } : {},
|
|
465
|
+
...opts.gasPrice !== void 0 ? { gasPrice: opts.gasPrice } : {}
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function isContractRevert(error) {
|
|
469
|
+
return error instanceof BaseError2 && error.walk((e) => e instanceof ContractFunctionRevertedError2) !== null;
|
|
470
|
+
}
|
|
471
|
+
async function preflightBalanceCheck(publicClient, account, required) {
|
|
472
|
+
if (required <= 0n) return;
|
|
473
|
+
const balance = await publicClient.getBalance({ address: account });
|
|
474
|
+
if (balance < required) {
|
|
475
|
+
throw new QuipSwapError({
|
|
476
|
+
code: "BALANCE_TOO_LOW",
|
|
477
|
+
message: `Sender ${account} holds ${balance} wei but the call requires ${required} wei of value`,
|
|
478
|
+
details: { required, balance }
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
async function prepareTx(args) {
|
|
483
|
+
const { publicClient, contractParams, totalValue, opts = {} } = args;
|
|
484
|
+
if (opts.skipPreflightChecks !== true) {
|
|
485
|
+
await preflightBalanceCheck(publicClient, contractParams.account, totalValue);
|
|
486
|
+
}
|
|
487
|
+
let gas;
|
|
488
|
+
if (opts.gas !== void 0) {
|
|
489
|
+
gas = opts.gas;
|
|
490
|
+
} else {
|
|
491
|
+
let estimate;
|
|
492
|
+
try {
|
|
493
|
+
estimate = await publicClient.estimateContractGas({
|
|
494
|
+
address: contractParams.address,
|
|
495
|
+
abi: contractParams.abi,
|
|
496
|
+
functionName: contractParams.functionName,
|
|
497
|
+
args: contractParams.args ?? [],
|
|
498
|
+
account: contractParams.account,
|
|
499
|
+
...contractParams.value !== void 0 ? { value: contractParams.value } : {}
|
|
500
|
+
// dynamic functionName + optional payable value cannot satisfy viem's
|
|
501
|
+
// conditional parameter types statically; the runtime shape is
|
|
502
|
+
// exercised by the mocked-client and Anvil integration suites
|
|
503
|
+
});
|
|
504
|
+
} catch (error) {
|
|
505
|
+
if (isContractRevert(error)) {
|
|
506
|
+
throw wrapContractError(error, `Estimating gas for ${contractParams.functionName}`);
|
|
507
|
+
}
|
|
508
|
+
throw new QuipSwapError({
|
|
509
|
+
code: "GAS_ESTIMATION_FAILED",
|
|
510
|
+
message: `Gas estimation for ${contractParams.functionName} failed for a non-revert reason (network error or invalid request); see cause`,
|
|
511
|
+
cause: error
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
gas = applyGasMultiplier(estimate, opts);
|
|
515
|
+
}
|
|
516
|
+
return { gas, fees: buildFeeOverrides(opts), ...opts.nonce !== void 0 ? { nonce: opts.nonce } : {} };
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/client.ts
|
|
520
|
+
import { BaseError as BaseError3, InsufficientFundsError } from "viem";
|
|
521
|
+
|
|
522
|
+
// src/generated/omnibusAbi.ts
|
|
523
|
+
var omnibusAbi = [
|
|
524
|
+
{
|
|
525
|
+
"type": "constructor",
|
|
526
|
+
"inputs": [
|
|
527
|
+
{
|
|
528
|
+
"name": "initialOwner",
|
|
529
|
+
"type": "address",
|
|
530
|
+
"internalType": "address"
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"name": "quipFactory",
|
|
534
|
+
"type": "address",
|
|
535
|
+
"internalType": "address"
|
|
536
|
+
}
|
|
537
|
+
],
|
|
538
|
+
"stateMutability": "nonpayable"
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
"type": "receive",
|
|
542
|
+
"stateMutability": "payable"
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"type": "function",
|
|
546
|
+
"name": "MAX_FEE",
|
|
547
|
+
"inputs": [],
|
|
548
|
+
"outputs": [
|
|
549
|
+
{
|
|
550
|
+
"name": "",
|
|
551
|
+
"type": "uint256",
|
|
552
|
+
"internalType": "uint256"
|
|
553
|
+
}
|
|
554
|
+
],
|
|
555
|
+
"stateMutability": "view"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
"type": "function",
|
|
559
|
+
"name": "QUIP_FACTORY",
|
|
560
|
+
"inputs": [],
|
|
561
|
+
"outputs": [
|
|
562
|
+
{
|
|
563
|
+
"name": "",
|
|
564
|
+
"type": "address",
|
|
565
|
+
"internalType": "contract IQuipFactory"
|
|
566
|
+
}
|
|
567
|
+
],
|
|
568
|
+
"stateMutability": "view"
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
"type": "function",
|
|
572
|
+
"name": "VERSION",
|
|
573
|
+
"inputs": [],
|
|
574
|
+
"outputs": [
|
|
575
|
+
{
|
|
576
|
+
"name": "",
|
|
577
|
+
"type": "uint256",
|
|
578
|
+
"internalType": "uint256"
|
|
579
|
+
}
|
|
580
|
+
],
|
|
581
|
+
"stateMutability": "view"
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"type": "function",
|
|
585
|
+
"name": "acceptOwnership",
|
|
586
|
+
"inputs": [],
|
|
587
|
+
"outputs": [],
|
|
588
|
+
"stateMutability": "nonpayable"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"type": "function",
|
|
592
|
+
"name": "accruedFees",
|
|
593
|
+
"inputs": [],
|
|
594
|
+
"outputs": [
|
|
595
|
+
{
|
|
596
|
+
"name": "",
|
|
597
|
+
"type": "uint256",
|
|
598
|
+
"internalType": "uint256"
|
|
599
|
+
}
|
|
600
|
+
],
|
|
601
|
+
"stateMutability": "view"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
"type": "function",
|
|
605
|
+
"name": "claim",
|
|
606
|
+
"inputs": [
|
|
607
|
+
{
|
|
608
|
+
"name": "secret",
|
|
609
|
+
"type": "bytes32",
|
|
610
|
+
"internalType": "bytes32"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"name": "party",
|
|
614
|
+
"type": "tuple",
|
|
615
|
+
"internalType": "struct Terms",
|
|
616
|
+
"components": [
|
|
617
|
+
{
|
|
618
|
+
"name": "chainId",
|
|
619
|
+
"type": "uint256",
|
|
620
|
+
"internalType": "uint256"
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"name": "reclaimRecipient",
|
|
624
|
+
"type": "address",
|
|
625
|
+
"internalType": "address"
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
"name": "recipient",
|
|
629
|
+
"type": "address",
|
|
630
|
+
"internalType": "address"
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"name": "commitmentDeadline",
|
|
634
|
+
"type": "uint256",
|
|
635
|
+
"internalType": "uint256"
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"name": "claimDeadline",
|
|
639
|
+
"type": "uint256",
|
|
640
|
+
"internalType": "uint256"
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
"name": "reclaimRelease",
|
|
644
|
+
"type": "uint256",
|
|
645
|
+
"internalType": "uint256"
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
"name": "assets",
|
|
649
|
+
"type": "tuple[]",
|
|
650
|
+
"internalType": "struct Asset[]",
|
|
651
|
+
"components": [
|
|
652
|
+
{
|
|
653
|
+
"name": "assetType",
|
|
654
|
+
"type": "uint8",
|
|
655
|
+
"internalType": "enum AssetType"
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
"name": "target",
|
|
659
|
+
"type": "address",
|
|
660
|
+
"internalType": "address"
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"name": "id",
|
|
664
|
+
"type": "uint256",
|
|
665
|
+
"internalType": "uint256"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"name": "amount",
|
|
669
|
+
"type": "uint256",
|
|
670
|
+
"internalType": "uint256"
|
|
671
|
+
}
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
]
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
"name": "counterparty",
|
|
678
|
+
"type": "tuple",
|
|
679
|
+
"internalType": "struct Terms",
|
|
680
|
+
"components": [
|
|
681
|
+
{
|
|
682
|
+
"name": "chainId",
|
|
683
|
+
"type": "uint256",
|
|
684
|
+
"internalType": "uint256"
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
"name": "reclaimRecipient",
|
|
688
|
+
"type": "address",
|
|
689
|
+
"internalType": "address"
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"name": "recipient",
|
|
693
|
+
"type": "address",
|
|
694
|
+
"internalType": "address"
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
"name": "commitmentDeadline",
|
|
698
|
+
"type": "uint256",
|
|
699
|
+
"internalType": "uint256"
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
"name": "claimDeadline",
|
|
703
|
+
"type": "uint256",
|
|
704
|
+
"internalType": "uint256"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"name": "reclaimRelease",
|
|
708
|
+
"type": "uint256",
|
|
709
|
+
"internalType": "uint256"
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
"name": "assets",
|
|
713
|
+
"type": "tuple[]",
|
|
714
|
+
"internalType": "struct Asset[]",
|
|
715
|
+
"components": [
|
|
716
|
+
{
|
|
717
|
+
"name": "assetType",
|
|
718
|
+
"type": "uint8",
|
|
719
|
+
"internalType": "enum AssetType"
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
"name": "target",
|
|
723
|
+
"type": "address",
|
|
724
|
+
"internalType": "address"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
"name": "id",
|
|
728
|
+
"type": "uint256",
|
|
729
|
+
"internalType": "uint256"
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
"name": "amount",
|
|
733
|
+
"type": "uint256",
|
|
734
|
+
"internalType": "uint256"
|
|
735
|
+
}
|
|
736
|
+
]
|
|
737
|
+
}
|
|
738
|
+
]
|
|
739
|
+
}
|
|
740
|
+
],
|
|
741
|
+
"outputs": [],
|
|
742
|
+
"stateMutability": "nonpayable"
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
"type": "function",
|
|
746
|
+
"name": "commit",
|
|
747
|
+
"inputs": [
|
|
748
|
+
{
|
|
749
|
+
"name": "lock",
|
|
750
|
+
"type": "bytes32",
|
|
751
|
+
"internalType": "bytes32"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
"name": "party",
|
|
755
|
+
"type": "tuple",
|
|
756
|
+
"internalType": "struct Terms",
|
|
757
|
+
"components": [
|
|
758
|
+
{
|
|
759
|
+
"name": "chainId",
|
|
760
|
+
"type": "uint256",
|
|
761
|
+
"internalType": "uint256"
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
"name": "reclaimRecipient",
|
|
765
|
+
"type": "address",
|
|
766
|
+
"internalType": "address"
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
"name": "recipient",
|
|
770
|
+
"type": "address",
|
|
771
|
+
"internalType": "address"
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
"name": "commitmentDeadline",
|
|
775
|
+
"type": "uint256",
|
|
776
|
+
"internalType": "uint256"
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
"name": "claimDeadline",
|
|
780
|
+
"type": "uint256",
|
|
781
|
+
"internalType": "uint256"
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
"name": "reclaimRelease",
|
|
785
|
+
"type": "uint256",
|
|
786
|
+
"internalType": "uint256"
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
"name": "assets",
|
|
790
|
+
"type": "tuple[]",
|
|
791
|
+
"internalType": "struct Asset[]",
|
|
792
|
+
"components": [
|
|
793
|
+
{
|
|
794
|
+
"name": "assetType",
|
|
795
|
+
"type": "uint8",
|
|
796
|
+
"internalType": "enum AssetType"
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
"name": "target",
|
|
800
|
+
"type": "address",
|
|
801
|
+
"internalType": "address"
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
"name": "id",
|
|
805
|
+
"type": "uint256",
|
|
806
|
+
"internalType": "uint256"
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
"name": "amount",
|
|
810
|
+
"type": "uint256",
|
|
811
|
+
"internalType": "uint256"
|
|
812
|
+
}
|
|
813
|
+
]
|
|
814
|
+
}
|
|
815
|
+
]
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
"name": "counterparty",
|
|
819
|
+
"type": "tuple",
|
|
820
|
+
"internalType": "struct Terms",
|
|
821
|
+
"components": [
|
|
822
|
+
{
|
|
823
|
+
"name": "chainId",
|
|
824
|
+
"type": "uint256",
|
|
825
|
+
"internalType": "uint256"
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
"name": "reclaimRecipient",
|
|
829
|
+
"type": "address",
|
|
830
|
+
"internalType": "address"
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
"name": "recipient",
|
|
834
|
+
"type": "address",
|
|
835
|
+
"internalType": "address"
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
"name": "commitmentDeadline",
|
|
839
|
+
"type": "uint256",
|
|
840
|
+
"internalType": "uint256"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
"name": "claimDeadline",
|
|
844
|
+
"type": "uint256",
|
|
845
|
+
"internalType": "uint256"
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
"name": "reclaimRelease",
|
|
849
|
+
"type": "uint256",
|
|
850
|
+
"internalType": "uint256"
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
"name": "assets",
|
|
854
|
+
"type": "tuple[]",
|
|
855
|
+
"internalType": "struct Asset[]",
|
|
856
|
+
"components": [
|
|
857
|
+
{
|
|
858
|
+
"name": "assetType",
|
|
859
|
+
"type": "uint8",
|
|
860
|
+
"internalType": "enum AssetType"
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
"name": "target",
|
|
864
|
+
"type": "address",
|
|
865
|
+
"internalType": "address"
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
"name": "id",
|
|
869
|
+
"type": "uint256",
|
|
870
|
+
"internalType": "uint256"
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"name": "amount",
|
|
874
|
+
"type": "uint256",
|
|
875
|
+
"internalType": "uint256"
|
|
876
|
+
}
|
|
877
|
+
]
|
|
878
|
+
}
|
|
879
|
+
]
|
|
880
|
+
}
|
|
881
|
+
],
|
|
882
|
+
"outputs": [],
|
|
883
|
+
"stateMutability": "payable"
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
"type": "function",
|
|
887
|
+
"name": "commitmentFee",
|
|
888
|
+
"inputs": [],
|
|
889
|
+
"outputs": [
|
|
890
|
+
{
|
|
891
|
+
"name": "",
|
|
892
|
+
"type": "uint256",
|
|
893
|
+
"internalType": "uint256"
|
|
894
|
+
}
|
|
895
|
+
],
|
|
896
|
+
"stateMutability": "view"
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
"type": "function",
|
|
900
|
+
"name": "lockState",
|
|
901
|
+
"inputs": [
|
|
902
|
+
{
|
|
903
|
+
"name": "lock",
|
|
904
|
+
"type": "bytes32",
|
|
905
|
+
"internalType": "bytes32"
|
|
906
|
+
}
|
|
907
|
+
],
|
|
908
|
+
"outputs": [
|
|
909
|
+
{
|
|
910
|
+
"name": "state",
|
|
911
|
+
"type": "uint8",
|
|
912
|
+
"internalType": "enum LockState"
|
|
913
|
+
}
|
|
914
|
+
],
|
|
915
|
+
"stateMutability": "view"
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
"type": "function",
|
|
919
|
+
"name": "onERC1155BatchReceived",
|
|
920
|
+
"inputs": [
|
|
921
|
+
{
|
|
922
|
+
"name": "",
|
|
923
|
+
"type": "address",
|
|
924
|
+
"internalType": "address"
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
"name": "",
|
|
928
|
+
"type": "address",
|
|
929
|
+
"internalType": "address"
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
"name": "",
|
|
933
|
+
"type": "uint256[]",
|
|
934
|
+
"internalType": "uint256[]"
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
"name": "",
|
|
938
|
+
"type": "uint256[]",
|
|
939
|
+
"internalType": "uint256[]"
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
"name": "",
|
|
943
|
+
"type": "bytes",
|
|
944
|
+
"internalType": "bytes"
|
|
945
|
+
}
|
|
946
|
+
],
|
|
947
|
+
"outputs": [
|
|
948
|
+
{
|
|
949
|
+
"name": "",
|
|
950
|
+
"type": "bytes4",
|
|
951
|
+
"internalType": "bytes4"
|
|
952
|
+
}
|
|
953
|
+
],
|
|
954
|
+
"stateMutability": "pure"
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
"type": "function",
|
|
958
|
+
"name": "onERC1155Received",
|
|
959
|
+
"inputs": [
|
|
960
|
+
{
|
|
961
|
+
"name": "",
|
|
962
|
+
"type": "address",
|
|
963
|
+
"internalType": "address"
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
"name": "",
|
|
967
|
+
"type": "address",
|
|
968
|
+
"internalType": "address"
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
"name": "",
|
|
972
|
+
"type": "uint256",
|
|
973
|
+
"internalType": "uint256"
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"name": "",
|
|
977
|
+
"type": "uint256",
|
|
978
|
+
"internalType": "uint256"
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
"name": "",
|
|
982
|
+
"type": "bytes",
|
|
983
|
+
"internalType": "bytes"
|
|
984
|
+
}
|
|
985
|
+
],
|
|
986
|
+
"outputs": [
|
|
987
|
+
{
|
|
988
|
+
"name": "",
|
|
989
|
+
"type": "bytes4",
|
|
990
|
+
"internalType": "bytes4"
|
|
991
|
+
}
|
|
992
|
+
],
|
|
993
|
+
"stateMutability": "pure"
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
"type": "function",
|
|
997
|
+
"name": "onERC721Received",
|
|
998
|
+
"inputs": [
|
|
999
|
+
{
|
|
1000
|
+
"name": "",
|
|
1001
|
+
"type": "address",
|
|
1002
|
+
"internalType": "address"
|
|
1003
|
+
},
|
|
1004
|
+
{
|
|
1005
|
+
"name": "",
|
|
1006
|
+
"type": "address",
|
|
1007
|
+
"internalType": "address"
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
"name": "",
|
|
1011
|
+
"type": "uint256",
|
|
1012
|
+
"internalType": "uint256"
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
"name": "",
|
|
1016
|
+
"type": "bytes",
|
|
1017
|
+
"internalType": "bytes"
|
|
1018
|
+
}
|
|
1019
|
+
],
|
|
1020
|
+
"outputs": [
|
|
1021
|
+
{
|
|
1022
|
+
"name": "",
|
|
1023
|
+
"type": "bytes4",
|
|
1024
|
+
"internalType": "bytes4"
|
|
1025
|
+
}
|
|
1026
|
+
],
|
|
1027
|
+
"stateMutability": "pure"
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
"type": "function",
|
|
1031
|
+
"name": "owner",
|
|
1032
|
+
"inputs": [],
|
|
1033
|
+
"outputs": [
|
|
1034
|
+
{
|
|
1035
|
+
"name": "",
|
|
1036
|
+
"type": "address",
|
|
1037
|
+
"internalType": "address"
|
|
1038
|
+
}
|
|
1039
|
+
],
|
|
1040
|
+
"stateMutability": "view"
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
"type": "function",
|
|
1044
|
+
"name": "pendingOwner",
|
|
1045
|
+
"inputs": [],
|
|
1046
|
+
"outputs": [
|
|
1047
|
+
{
|
|
1048
|
+
"name": "",
|
|
1049
|
+
"type": "address",
|
|
1050
|
+
"internalType": "address"
|
|
1051
|
+
}
|
|
1052
|
+
],
|
|
1053
|
+
"stateMutability": "view"
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
"type": "function",
|
|
1057
|
+
"name": "posted",
|
|
1058
|
+
"inputs": [
|
|
1059
|
+
{
|
|
1060
|
+
"name": "lock",
|
|
1061
|
+
"type": "bytes32",
|
|
1062
|
+
"internalType": "bytes32"
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
"name": "termsDigest",
|
|
1066
|
+
"type": "bytes32",
|
|
1067
|
+
"internalType": "bytes32"
|
|
1068
|
+
}
|
|
1069
|
+
],
|
|
1070
|
+
"outputs": [
|
|
1071
|
+
{
|
|
1072
|
+
"name": "isPosted",
|
|
1073
|
+
"type": "bool",
|
|
1074
|
+
"internalType": "bool"
|
|
1075
|
+
}
|
|
1076
|
+
],
|
|
1077
|
+
"stateMutability": "view"
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
"type": "function",
|
|
1081
|
+
"name": "reclaim",
|
|
1082
|
+
"inputs": [
|
|
1083
|
+
{
|
|
1084
|
+
"name": "lock",
|
|
1085
|
+
"type": "bytes32",
|
|
1086
|
+
"internalType": "bytes32"
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
"name": "party",
|
|
1090
|
+
"type": "tuple",
|
|
1091
|
+
"internalType": "struct Terms",
|
|
1092
|
+
"components": [
|
|
1093
|
+
{
|
|
1094
|
+
"name": "chainId",
|
|
1095
|
+
"type": "uint256",
|
|
1096
|
+
"internalType": "uint256"
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
"name": "reclaimRecipient",
|
|
1100
|
+
"type": "address",
|
|
1101
|
+
"internalType": "address"
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
"name": "recipient",
|
|
1105
|
+
"type": "address",
|
|
1106
|
+
"internalType": "address"
|
|
1107
|
+
},
|
|
1108
|
+
{
|
|
1109
|
+
"name": "commitmentDeadline",
|
|
1110
|
+
"type": "uint256",
|
|
1111
|
+
"internalType": "uint256"
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
"name": "claimDeadline",
|
|
1115
|
+
"type": "uint256",
|
|
1116
|
+
"internalType": "uint256"
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
"name": "reclaimRelease",
|
|
1120
|
+
"type": "uint256",
|
|
1121
|
+
"internalType": "uint256"
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
"name": "assets",
|
|
1125
|
+
"type": "tuple[]",
|
|
1126
|
+
"internalType": "struct Asset[]",
|
|
1127
|
+
"components": [
|
|
1128
|
+
{
|
|
1129
|
+
"name": "assetType",
|
|
1130
|
+
"type": "uint8",
|
|
1131
|
+
"internalType": "enum AssetType"
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"name": "target",
|
|
1135
|
+
"type": "address",
|
|
1136
|
+
"internalType": "address"
|
|
1137
|
+
},
|
|
1138
|
+
{
|
|
1139
|
+
"name": "id",
|
|
1140
|
+
"type": "uint256",
|
|
1141
|
+
"internalType": "uint256"
|
|
1142
|
+
},
|
|
1143
|
+
{
|
|
1144
|
+
"name": "amount",
|
|
1145
|
+
"type": "uint256",
|
|
1146
|
+
"internalType": "uint256"
|
|
1147
|
+
}
|
|
1148
|
+
]
|
|
1149
|
+
}
|
|
1150
|
+
]
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
"name": "counterparty",
|
|
1154
|
+
"type": "tuple",
|
|
1155
|
+
"internalType": "struct Terms",
|
|
1156
|
+
"components": [
|
|
1157
|
+
{
|
|
1158
|
+
"name": "chainId",
|
|
1159
|
+
"type": "uint256",
|
|
1160
|
+
"internalType": "uint256"
|
|
1161
|
+
},
|
|
1162
|
+
{
|
|
1163
|
+
"name": "reclaimRecipient",
|
|
1164
|
+
"type": "address",
|
|
1165
|
+
"internalType": "address"
|
|
1166
|
+
},
|
|
1167
|
+
{
|
|
1168
|
+
"name": "recipient",
|
|
1169
|
+
"type": "address",
|
|
1170
|
+
"internalType": "address"
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
"name": "commitmentDeadline",
|
|
1174
|
+
"type": "uint256",
|
|
1175
|
+
"internalType": "uint256"
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
"name": "claimDeadline",
|
|
1179
|
+
"type": "uint256",
|
|
1180
|
+
"internalType": "uint256"
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
"name": "reclaimRelease",
|
|
1184
|
+
"type": "uint256",
|
|
1185
|
+
"internalType": "uint256"
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
"name": "assets",
|
|
1189
|
+
"type": "tuple[]",
|
|
1190
|
+
"internalType": "struct Asset[]",
|
|
1191
|
+
"components": [
|
|
1192
|
+
{
|
|
1193
|
+
"name": "assetType",
|
|
1194
|
+
"type": "uint8",
|
|
1195
|
+
"internalType": "enum AssetType"
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
"name": "target",
|
|
1199
|
+
"type": "address",
|
|
1200
|
+
"internalType": "address"
|
|
1201
|
+
},
|
|
1202
|
+
{
|
|
1203
|
+
"name": "id",
|
|
1204
|
+
"type": "uint256",
|
|
1205
|
+
"internalType": "uint256"
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
"name": "amount",
|
|
1209
|
+
"type": "uint256",
|
|
1210
|
+
"internalType": "uint256"
|
|
1211
|
+
}
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
]
|
|
1215
|
+
}
|
|
1216
|
+
],
|
|
1217
|
+
"outputs": [],
|
|
1218
|
+
"stateMutability": "nonpayable"
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
"type": "function",
|
|
1222
|
+
"name": "renounceOwnership",
|
|
1223
|
+
"inputs": [],
|
|
1224
|
+
"outputs": [],
|
|
1225
|
+
"stateMutability": "nonpayable"
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
"type": "function",
|
|
1229
|
+
"name": "setCommitmentFee",
|
|
1230
|
+
"inputs": [
|
|
1231
|
+
{
|
|
1232
|
+
"name": "newFee",
|
|
1233
|
+
"type": "uint256",
|
|
1234
|
+
"internalType": "uint256"
|
|
1235
|
+
}
|
|
1236
|
+
],
|
|
1237
|
+
"outputs": [],
|
|
1238
|
+
"stateMutability": "nonpayable"
|
|
1239
|
+
},
|
|
1240
|
+
{
|
|
1241
|
+
"type": "function",
|
|
1242
|
+
"name": "supportsInterface",
|
|
1243
|
+
"inputs": [
|
|
1244
|
+
{
|
|
1245
|
+
"name": "interfaceId",
|
|
1246
|
+
"type": "bytes4",
|
|
1247
|
+
"internalType": "bytes4"
|
|
1248
|
+
}
|
|
1249
|
+
],
|
|
1250
|
+
"outputs": [
|
|
1251
|
+
{
|
|
1252
|
+
"name": "",
|
|
1253
|
+
"type": "bool",
|
|
1254
|
+
"internalType": "bool"
|
|
1255
|
+
}
|
|
1256
|
+
],
|
|
1257
|
+
"stateMutability": "pure"
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
"type": "function",
|
|
1261
|
+
"name": "termsHash",
|
|
1262
|
+
"inputs": [
|
|
1263
|
+
{
|
|
1264
|
+
"name": "lock",
|
|
1265
|
+
"type": "bytes32",
|
|
1266
|
+
"internalType": "bytes32"
|
|
1267
|
+
}
|
|
1268
|
+
],
|
|
1269
|
+
"outputs": [
|
|
1270
|
+
{
|
|
1271
|
+
"name": "canonicalDigest",
|
|
1272
|
+
"type": "bytes32",
|
|
1273
|
+
"internalType": "bytes32"
|
|
1274
|
+
}
|
|
1275
|
+
],
|
|
1276
|
+
"stateMutability": "view"
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
"type": "function",
|
|
1280
|
+
"name": "transferOwnership",
|
|
1281
|
+
"inputs": [
|
|
1282
|
+
{
|
|
1283
|
+
"name": "newOwner",
|
|
1284
|
+
"type": "address",
|
|
1285
|
+
"internalType": "address"
|
|
1286
|
+
}
|
|
1287
|
+
],
|
|
1288
|
+
"outputs": [],
|
|
1289
|
+
"stateMutability": "nonpayable"
|
|
1290
|
+
},
|
|
1291
|
+
{
|
|
1292
|
+
"type": "function",
|
|
1293
|
+
"name": "withdrawFees",
|
|
1294
|
+
"inputs": [
|
|
1295
|
+
{
|
|
1296
|
+
"name": "to",
|
|
1297
|
+
"type": "address",
|
|
1298
|
+
"internalType": "address"
|
|
1299
|
+
}
|
|
1300
|
+
],
|
|
1301
|
+
"outputs": [],
|
|
1302
|
+
"stateMutability": "nonpayable"
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
"type": "event",
|
|
1306
|
+
"name": "Claim",
|
|
1307
|
+
"inputs": [
|
|
1308
|
+
{
|
|
1309
|
+
"name": "recipient",
|
|
1310
|
+
"type": "address",
|
|
1311
|
+
"indexed": false,
|
|
1312
|
+
"internalType": "address"
|
|
1313
|
+
},
|
|
1314
|
+
{
|
|
1315
|
+
"name": "lock",
|
|
1316
|
+
"type": "bytes32",
|
|
1317
|
+
"indexed": true,
|
|
1318
|
+
"internalType": "bytes32"
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
"name": "secret",
|
|
1322
|
+
"type": "bytes32",
|
|
1323
|
+
"indexed": false,
|
|
1324
|
+
"internalType": "bytes32"
|
|
1325
|
+
}
|
|
1326
|
+
],
|
|
1327
|
+
"anonymous": false
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
"type": "event",
|
|
1331
|
+
"name": "Commitment",
|
|
1332
|
+
"inputs": [
|
|
1333
|
+
{
|
|
1334
|
+
"name": "lock",
|
|
1335
|
+
"type": "bytes32",
|
|
1336
|
+
"indexed": true,
|
|
1337
|
+
"internalType": "bytes32"
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
"name": "party",
|
|
1341
|
+
"type": "tuple",
|
|
1342
|
+
"indexed": false,
|
|
1343
|
+
"internalType": "struct Terms",
|
|
1344
|
+
"components": [
|
|
1345
|
+
{
|
|
1346
|
+
"name": "chainId",
|
|
1347
|
+
"type": "uint256",
|
|
1348
|
+
"internalType": "uint256"
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
"name": "reclaimRecipient",
|
|
1352
|
+
"type": "address",
|
|
1353
|
+
"internalType": "address"
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
"name": "recipient",
|
|
1357
|
+
"type": "address",
|
|
1358
|
+
"internalType": "address"
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
"name": "commitmentDeadline",
|
|
1362
|
+
"type": "uint256",
|
|
1363
|
+
"internalType": "uint256"
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
"name": "claimDeadline",
|
|
1367
|
+
"type": "uint256",
|
|
1368
|
+
"internalType": "uint256"
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
"name": "reclaimRelease",
|
|
1372
|
+
"type": "uint256",
|
|
1373
|
+
"internalType": "uint256"
|
|
1374
|
+
},
|
|
1375
|
+
{
|
|
1376
|
+
"name": "assets",
|
|
1377
|
+
"type": "tuple[]",
|
|
1378
|
+
"internalType": "struct Asset[]",
|
|
1379
|
+
"components": [
|
|
1380
|
+
{
|
|
1381
|
+
"name": "assetType",
|
|
1382
|
+
"type": "uint8",
|
|
1383
|
+
"internalType": "enum AssetType"
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
"name": "target",
|
|
1387
|
+
"type": "address",
|
|
1388
|
+
"internalType": "address"
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
"name": "id",
|
|
1392
|
+
"type": "uint256",
|
|
1393
|
+
"internalType": "uint256"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
"name": "amount",
|
|
1397
|
+
"type": "uint256",
|
|
1398
|
+
"internalType": "uint256"
|
|
1399
|
+
}
|
|
1400
|
+
]
|
|
1401
|
+
}
|
|
1402
|
+
]
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
"name": "committer",
|
|
1406
|
+
"type": "address",
|
|
1407
|
+
"indexed": true,
|
|
1408
|
+
"internalType": "address"
|
|
1409
|
+
}
|
|
1410
|
+
],
|
|
1411
|
+
"anonymous": false
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
"type": "event",
|
|
1415
|
+
"name": "FeeUpdated",
|
|
1416
|
+
"inputs": [
|
|
1417
|
+
{
|
|
1418
|
+
"name": "oldFee",
|
|
1419
|
+
"type": "uint256",
|
|
1420
|
+
"indexed": false,
|
|
1421
|
+
"internalType": "uint256"
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
"name": "newFee",
|
|
1425
|
+
"type": "uint256",
|
|
1426
|
+
"indexed": false,
|
|
1427
|
+
"internalType": "uint256"
|
|
1428
|
+
}
|
|
1429
|
+
],
|
|
1430
|
+
"anonymous": false
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
"type": "event",
|
|
1434
|
+
"name": "FeesWithdrawn",
|
|
1435
|
+
"inputs": [
|
|
1436
|
+
{
|
|
1437
|
+
"name": "to",
|
|
1438
|
+
"type": "address",
|
|
1439
|
+
"indexed": true,
|
|
1440
|
+
"internalType": "address"
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
"name": "amount",
|
|
1444
|
+
"type": "uint256",
|
|
1445
|
+
"indexed": false,
|
|
1446
|
+
"internalType": "uint256"
|
|
1447
|
+
}
|
|
1448
|
+
],
|
|
1449
|
+
"anonymous": false
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
"type": "event",
|
|
1453
|
+
"name": "OwnershipTransferStarted",
|
|
1454
|
+
"inputs": [
|
|
1455
|
+
{
|
|
1456
|
+
"name": "previousOwner",
|
|
1457
|
+
"type": "address",
|
|
1458
|
+
"indexed": true,
|
|
1459
|
+
"internalType": "address"
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
"name": "newOwner",
|
|
1463
|
+
"type": "address",
|
|
1464
|
+
"indexed": true,
|
|
1465
|
+
"internalType": "address"
|
|
1466
|
+
}
|
|
1467
|
+
],
|
|
1468
|
+
"anonymous": false
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
"type": "event",
|
|
1472
|
+
"name": "OwnershipTransferred",
|
|
1473
|
+
"inputs": [
|
|
1474
|
+
{
|
|
1475
|
+
"name": "previousOwner",
|
|
1476
|
+
"type": "address",
|
|
1477
|
+
"indexed": true,
|
|
1478
|
+
"internalType": "address"
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
"name": "newOwner",
|
|
1482
|
+
"type": "address",
|
|
1483
|
+
"indexed": true,
|
|
1484
|
+
"internalType": "address"
|
|
1485
|
+
}
|
|
1486
|
+
],
|
|
1487
|
+
"anonymous": false
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
"type": "event",
|
|
1491
|
+
"name": "Reclaimed",
|
|
1492
|
+
"inputs": [
|
|
1493
|
+
{
|
|
1494
|
+
"name": "caller",
|
|
1495
|
+
"type": "address",
|
|
1496
|
+
"indexed": false,
|
|
1497
|
+
"internalType": "address"
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
"name": "lock",
|
|
1501
|
+
"type": "bytes32",
|
|
1502
|
+
"indexed": true,
|
|
1503
|
+
"internalType": "bytes32"
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
"name": "recipient",
|
|
1507
|
+
"type": "address",
|
|
1508
|
+
"indexed": true,
|
|
1509
|
+
"internalType": "address"
|
|
1510
|
+
}
|
|
1511
|
+
],
|
|
1512
|
+
"anonymous": false
|
|
1513
|
+
},
|
|
1514
|
+
{
|
|
1515
|
+
"type": "error",
|
|
1516
|
+
"name": "CallerNotQuipWallet",
|
|
1517
|
+
"inputs": []
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
"type": "error",
|
|
1521
|
+
"name": "ChainIdMismatch",
|
|
1522
|
+
"inputs": []
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
"type": "error",
|
|
1526
|
+
"name": "DisordedDeadlines",
|
|
1527
|
+
"inputs": []
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
"type": "error",
|
|
1531
|
+
"name": "EmptyAssets",
|
|
1532
|
+
"inputs": []
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
"type": "error",
|
|
1536
|
+
"name": "FeeExceedsMax",
|
|
1537
|
+
"inputs": []
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
"type": "error",
|
|
1541
|
+
"name": "IncorrectNativeAmountReceived",
|
|
1542
|
+
"inputs": []
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
"type": "error",
|
|
1546
|
+
"name": "InvalidERC1155Asset",
|
|
1547
|
+
"inputs": []
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
"type": "error",
|
|
1551
|
+
"name": "InvalidERC20Asset",
|
|
1552
|
+
"inputs": []
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
"type": "error",
|
|
1556
|
+
"name": "InvalidERC721Asset",
|
|
1557
|
+
"inputs": []
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
"type": "error",
|
|
1561
|
+
"name": "InvalidLockAdvancement",
|
|
1562
|
+
"inputs": []
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
"type": "error",
|
|
1566
|
+
"name": "InvalidLockState",
|
|
1567
|
+
"inputs": []
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
"type": "error",
|
|
1571
|
+
"name": "InvalidNativeAsset",
|
|
1572
|
+
"inputs": []
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
"type": "error",
|
|
1576
|
+
"name": "InvalidRange",
|
|
1577
|
+
"inputs": []
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
"type": "error",
|
|
1581
|
+
"name": "OwnableInvalidOwner",
|
|
1582
|
+
"inputs": [
|
|
1583
|
+
{
|
|
1584
|
+
"name": "owner",
|
|
1585
|
+
"type": "address",
|
|
1586
|
+
"internalType": "address"
|
|
1587
|
+
}
|
|
1588
|
+
]
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
"type": "error",
|
|
1592
|
+
"name": "OwnableUnauthorizedAccount",
|
|
1593
|
+
"inputs": [
|
|
1594
|
+
{
|
|
1595
|
+
"name": "account",
|
|
1596
|
+
"type": "address",
|
|
1597
|
+
"internalType": "address"
|
|
1598
|
+
}
|
|
1599
|
+
]
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
"type": "error",
|
|
1603
|
+
"name": "TermsAlreadyPosted",
|
|
1604
|
+
"inputs": []
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
"type": "error",
|
|
1608
|
+
"name": "TermsMismatch",
|
|
1609
|
+
"inputs": []
|
|
1610
|
+
},
|
|
1611
|
+
{
|
|
1612
|
+
"type": "error",
|
|
1613
|
+
"name": "TermsNotPosted",
|
|
1614
|
+
"inputs": []
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
"type": "error",
|
|
1618
|
+
"name": "UnexpectedAmountReceived",
|
|
1619
|
+
"inputs": []
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
"type": "error",
|
|
1623
|
+
"name": "WindowViolated",
|
|
1624
|
+
"inputs": []
|
|
1625
|
+
},
|
|
1626
|
+
{
|
|
1627
|
+
"type": "error",
|
|
1628
|
+
"name": "ZeroAddressRecipient",
|
|
1629
|
+
"inputs": []
|
|
1630
|
+
},
|
|
1631
|
+
{
|
|
1632
|
+
"type": "error",
|
|
1633
|
+
"name": "ZeroAmount",
|
|
1634
|
+
"inputs": []
|
|
1635
|
+
},
|
|
1636
|
+
{
|
|
1637
|
+
"type": "error",
|
|
1638
|
+
"name": "ZeroChainId",
|
|
1639
|
+
"inputs": []
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
"type": "error",
|
|
1643
|
+
"name": "ZeroDeadline",
|
|
1644
|
+
"inputs": []
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
"type": "error",
|
|
1648
|
+
"name": "ZeroQuipFactory",
|
|
1649
|
+
"inputs": []
|
|
1650
|
+
}
|
|
1651
|
+
];
|
|
1652
|
+
|
|
1653
|
+
// src/events.ts
|
|
1654
|
+
import { parseEventLogs } from "viem";
|
|
1655
|
+
function toAssetType(value) {
|
|
1656
|
+
if (value === 0 || value === 1 || value === 2 || value === 3) return value;
|
|
1657
|
+
throw new QuipSwapError({
|
|
1658
|
+
code: "INVALID_ASSET_TYPE",
|
|
1659
|
+
message: `Decoded asset type ${value} is out of range`
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
function toTerms(decoded) {
|
|
1663
|
+
return Object.freeze({
|
|
1664
|
+
chainId: decoded.chainId,
|
|
1665
|
+
reclaimRecipient: decoded.reclaimRecipient,
|
|
1666
|
+
recipient: decoded.recipient,
|
|
1667
|
+
commitmentDeadline: decoded.commitmentDeadline,
|
|
1668
|
+
claimDeadline: decoded.claimDeadline,
|
|
1669
|
+
reclaimRelease: decoded.reclaimRelease,
|
|
1670
|
+
assets: Object.freeze(
|
|
1671
|
+
decoded.assets.map(
|
|
1672
|
+
(a) => Object.freeze({ assetType: toAssetType(a.assetType), target: a.target, id: a.id, amount: a.amount })
|
|
1673
|
+
)
|
|
1674
|
+
)
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
function decodeCommitmentEvents(logs) {
|
|
1678
|
+
const parsed = parseEventLogs({ abi: omnibusAbi, eventName: "Commitment", logs, strict: true });
|
|
1679
|
+
return parsed.map((log) => ({
|
|
1680
|
+
lock: log.args.lock,
|
|
1681
|
+
party: toTerms(log.args.party),
|
|
1682
|
+
committer: log.args.committer,
|
|
1683
|
+
blockNumber: log.blockNumber,
|
|
1684
|
+
transactionHash: log.transactionHash,
|
|
1685
|
+
logIndex: log.logIndex
|
|
1686
|
+
}));
|
|
1687
|
+
}
|
|
1688
|
+
function decodeClaimEvents(logs) {
|
|
1689
|
+
const parsed = parseEventLogs({ abi: omnibusAbi, eventName: "Claim", logs, strict: true });
|
|
1690
|
+
return parsed.map((log) => ({
|
|
1691
|
+
recipient: log.args.recipient,
|
|
1692
|
+
lock: log.args.lock,
|
|
1693
|
+
secret: log.args.secret,
|
|
1694
|
+
blockNumber: log.blockNumber,
|
|
1695
|
+
transactionHash: log.transactionHash,
|
|
1696
|
+
logIndex: log.logIndex
|
|
1697
|
+
}));
|
|
1698
|
+
}
|
|
1699
|
+
function extractRevealedSecret(logs, lock) {
|
|
1700
|
+
return extractSecretFromClaims(decodeClaimEvents(logs), lock);
|
|
1701
|
+
}
|
|
1702
|
+
function extractSecretFromClaims(claims, lock) {
|
|
1703
|
+
const lockLower = lock.toLowerCase();
|
|
1704
|
+
for (const event of claims) {
|
|
1705
|
+
if (event.lock.toLowerCase() !== lockLower) continue;
|
|
1706
|
+
if (generateLock(event.secret).toLowerCase() !== lockLower) continue;
|
|
1707
|
+
return event.secret;
|
|
1708
|
+
}
|
|
1709
|
+
return void 0;
|
|
1710
|
+
}
|
|
1711
|
+
function decodeReclaimedEvents(logs) {
|
|
1712
|
+
const parsed = parseEventLogs({ abi: omnibusAbi, eventName: "Reclaimed", logs, strict: true });
|
|
1713
|
+
return parsed.map((log) => ({
|
|
1714
|
+
caller: log.args.caller,
|
|
1715
|
+
lock: log.args.lock,
|
|
1716
|
+
recipient: log.args.recipient,
|
|
1717
|
+
blockNumber: log.blockNumber,
|
|
1718
|
+
transactionHash: log.transactionHash,
|
|
1719
|
+
logIndex: log.logIndex
|
|
1720
|
+
}));
|
|
1721
|
+
}
|
|
1722
|
+
async function getCommitmentEvents(args) {
|
|
1723
|
+
const logs = await getOmnibusLogs(args, "Commitment");
|
|
1724
|
+
return decodeCommitmentEvents(logs);
|
|
1725
|
+
}
|
|
1726
|
+
async function getClaimEvents(args) {
|
|
1727
|
+
const logs = await getOmnibusLogs(args, "Claim");
|
|
1728
|
+
return decodeClaimEvents(logs);
|
|
1729
|
+
}
|
|
1730
|
+
async function getReclaimedEvents(args) {
|
|
1731
|
+
const logs = await getOmnibusLogs(args, "Reclaimed");
|
|
1732
|
+
return decodeReclaimedEvents(logs);
|
|
1733
|
+
}
|
|
1734
|
+
async function getOmnibusLogs(args, eventName) {
|
|
1735
|
+
const event = omnibusAbi.find(
|
|
1736
|
+
(entry) => entry.type === "event" && entry.name === eventName
|
|
1737
|
+
);
|
|
1738
|
+
if (event === void 0) {
|
|
1739
|
+
throw new QuipSwapError({ code: "EVENT_NOT_FOUND", message: `Event ${eventName} missing from generated ABI` });
|
|
1740
|
+
}
|
|
1741
|
+
return await args.publicClient.getLogs({
|
|
1742
|
+
address: args.address,
|
|
1743
|
+
event,
|
|
1744
|
+
...args.lock !== void 0 ? { args: { lock: args.lock } } : {},
|
|
1745
|
+
...args.fromBlock !== void 0 ? { fromBlock: args.fromBlock } : {},
|
|
1746
|
+
...args.toBlock !== void 0 ? { toBlock: args.toBlock } : {}
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
function watchClaimEvents(args) {
|
|
1750
|
+
return args.publicClient.watchContractEvent({
|
|
1751
|
+
address: args.address,
|
|
1752
|
+
abi: omnibusAbi,
|
|
1753
|
+
eventName: "Claim",
|
|
1754
|
+
...args.lock !== void 0 ? { args: { lock: args.lock } } : {},
|
|
1755
|
+
onLogs: (logs) => {
|
|
1756
|
+
for (const event of decodeClaimEvents(logs)) args.onClaim(event);
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
// src/receipts.ts
|
|
1762
|
+
function filterLogsByAddress(logs, address) {
|
|
1763
|
+
if (address === void 0) return logs;
|
|
1764
|
+
const expected = address.toLowerCase();
|
|
1765
|
+
return logs.filter((log) => log.address.toLowerCase() === expected);
|
|
1766
|
+
}
|
|
1767
|
+
async function waitForOmnibusReceipt(publicClient, hash, options = {}) {
|
|
1768
|
+
let receipt;
|
|
1769
|
+
try {
|
|
1770
|
+
receipt = await publicClient.waitForTransactionReceipt({
|
|
1771
|
+
hash,
|
|
1772
|
+
...options.confirmations !== void 0 ? { confirmations: options.confirmations } : {},
|
|
1773
|
+
...options.timeout !== void 0 ? { timeout: options.timeout } : {}
|
|
1774
|
+
});
|
|
1775
|
+
} catch (error) {
|
|
1776
|
+
throw wrapContractError(error, `Waiting for receipt of ${hash}`);
|
|
1777
|
+
}
|
|
1778
|
+
if (receipt.status !== "success") {
|
|
1779
|
+
throw new QuipSwapError({
|
|
1780
|
+
code: "TRANSACTION_REVERTED",
|
|
1781
|
+
message: `Transaction ${hash} was mined but reverted`,
|
|
1782
|
+
details: { receipt }
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
const logs = filterLogsByAddress(receipt.logs, options.address);
|
|
1786
|
+
return {
|
|
1787
|
+
transactionHash: hash,
|
|
1788
|
+
receipt,
|
|
1789
|
+
commitments: decodeCommitmentEvents(logs),
|
|
1790
|
+
claims: decodeClaimEvents(logs),
|
|
1791
|
+
reclaims: decodeReclaimedEvents(logs)
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
// src/client.ts
|
|
1796
|
+
var quipFactoryAbi = [
|
|
1797
|
+
{
|
|
1798
|
+
type: "function",
|
|
1799
|
+
name: "vaultIdOf",
|
|
1800
|
+
stateMutability: "view",
|
|
1801
|
+
inputs: [{ name: "wallet", type: "address" }],
|
|
1802
|
+
outputs: [{ name: "vaultId", type: "bytes32" }]
|
|
1803
|
+
}
|
|
1804
|
+
];
|
|
1805
|
+
function toAbiTerms(terms) {
|
|
1806
|
+
return {
|
|
1807
|
+
chainId: terms.chainId,
|
|
1808
|
+
reclaimRecipient: terms.reclaimRecipient,
|
|
1809
|
+
recipient: terms.recipient,
|
|
1810
|
+
commitmentDeadline: terms.commitmentDeadline,
|
|
1811
|
+
claimDeadline: terms.claimDeadline,
|
|
1812
|
+
reclaimRelease: terms.reclaimRelease,
|
|
1813
|
+
assets: terms.assets.map((a) => ({ assetType: a.assetType, target: a.target, id: a.id, amount: a.amount }))
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
function lockStateName(state) {
|
|
1817
|
+
return LockState[state] ?? `unknown(${state})`;
|
|
1818
|
+
}
|
|
1819
|
+
function createOmnibusClient(args) {
|
|
1820
|
+
const { address, publicClient, walletClient } = args;
|
|
1821
|
+
const contract = { address, abi: omnibusAbi };
|
|
1822
|
+
let quipFactoryAddress;
|
|
1823
|
+
async function getQuipFactory() {
|
|
1824
|
+
if (quipFactoryAddress === void 0) {
|
|
1825
|
+
const factory = await read("QUIP_FACTORY");
|
|
1826
|
+
quipFactoryAddress = factory;
|
|
1827
|
+
return factory;
|
|
1828
|
+
}
|
|
1829
|
+
return quipFactoryAddress;
|
|
1830
|
+
}
|
|
1831
|
+
async function read(functionName, fnArgs = []) {
|
|
1832
|
+
try {
|
|
1833
|
+
return await publicClient.readContract({
|
|
1834
|
+
...contract,
|
|
1835
|
+
functionName,
|
|
1836
|
+
args: fnArgs
|
|
1837
|
+
});
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
throw wrapContractError(error, `Reading ${functionName}`);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
function requireWallet() {
|
|
1843
|
+
if (walletClient === void 0) {
|
|
1844
|
+
throw new QuipSwapError({
|
|
1845
|
+
code: "MISSING_WALLET_CLIENT",
|
|
1846
|
+
message: "This operation submits a transaction; create the client with a walletClient to use it"
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
const account = walletClient.account;
|
|
1850
|
+
if (account === void 0) {
|
|
1851
|
+
throw new QuipSwapError({
|
|
1852
|
+
code: "MISSING_ACCOUNT",
|
|
1853
|
+
message: "The wallet client has no account; hoist an account onto the wallet client"
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
return { wallet: walletClient, sender: account.address };
|
|
1857
|
+
}
|
|
1858
|
+
async function chainTimestamp() {
|
|
1859
|
+
const block = await publicClient.getBlock();
|
|
1860
|
+
return block.timestamp;
|
|
1861
|
+
}
|
|
1862
|
+
async function isQuipWallet(account) {
|
|
1863
|
+
const factory = await getQuipFactory();
|
|
1864
|
+
try {
|
|
1865
|
+
const vaultId = await publicClient.readContract({
|
|
1866
|
+
address: factory,
|
|
1867
|
+
abi: quipFactoryAbi,
|
|
1868
|
+
functionName: "vaultIdOf",
|
|
1869
|
+
args: [account]
|
|
1870
|
+
});
|
|
1871
|
+
return BigInt(vaultId) !== 0n;
|
|
1872
|
+
} catch (error) {
|
|
1873
|
+
throw wrapContractError(error, "Reading vaultIdOf from QUIP_FACTORY");
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
async function readLockBatch(lock, postedDigest) {
|
|
1877
|
+
const [state, onChainTermsHash, isPosted] = await Promise.all([
|
|
1878
|
+
read("lockState", [lock]),
|
|
1879
|
+
read("termsHash", [lock]),
|
|
1880
|
+
read("posted", [lock, postedDigest])
|
|
1881
|
+
]);
|
|
1882
|
+
return { state, onChainTermsHash, isPosted };
|
|
1883
|
+
}
|
|
1884
|
+
function checkTermsHash(lock, onChainTermsHash, party, counterparty) {
|
|
1885
|
+
const expected = digestTermsCanonically(party, counterparty);
|
|
1886
|
+
if (onChainTermsHash.toLowerCase() !== expected.toLowerCase()) {
|
|
1887
|
+
throw new QuipSwapError({
|
|
1888
|
+
code: "TERMS_NOT_ON_CHAIN",
|
|
1889
|
+
message: "The on-chain termsHash for this lock does not match the canonical digest of the supplied terms (contract would revert TermsMismatch)",
|
|
1890
|
+
details: { lock, onChainTermsHash, expected }
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
function checkPosted(lock, isPosted) {
|
|
1895
|
+
if (!isPosted) {
|
|
1896
|
+
throw new QuipSwapError({
|
|
1897
|
+
code: "TERMS_NOT_ON_CHAIN",
|
|
1898
|
+
message: "The required side's terms have not been posted for this lock (contract would revert TermsNotPosted)",
|
|
1899
|
+
details: { lock }
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
async function verifyClaimState(lock, party, counterparty) {
|
|
1904
|
+
const { state, onChainTermsHash, isPosted } = await readLockBatch(lock, digestTerms(counterparty));
|
|
1905
|
+
if (state !== 2 /* Committed */) {
|
|
1906
|
+
const cause = state === 0 /* Unused */ ? "nothing has been committed under this lock on this chain \u2014 either the swap was never committed here, or the supplied secret is not the preimage for this swap (a wrong secret derives a different lock)" : state === 1 /* Free */ ? "the counterparty has not committed yet (same-chain swap is half-committed)" : "the lock was already claimed or reclaimed";
|
|
1907
|
+
throw new QuipSwapError({
|
|
1908
|
+
code: "INVALID_LOCK_STATE",
|
|
1909
|
+
message: `Cannot claim: lock state is ${lockStateName(state)} but claim requires Committed \u2014 ${cause} (contract would revert InvalidLockState)`,
|
|
1910
|
+
details: { lock, lockState: state, required: "Committed" }
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
checkTermsHash(lock, onChainTermsHash, party, counterparty);
|
|
1914
|
+
checkPosted(lock, isPosted);
|
|
1915
|
+
}
|
|
1916
|
+
async function verifyReclaimState(lock, party, counterparty) {
|
|
1917
|
+
const { state, onChainTermsHash, isPosted } = await readLockBatch(lock, digestTerms(party));
|
|
1918
|
+
if (state !== 1 /* Free */ && state !== 2 /* Committed */) {
|
|
1919
|
+
const cause = state === 0 /* Unused */ ? "nothing has been committed under this lock on this chain" : "the lock was already claimed or reclaimed";
|
|
1920
|
+
throw new QuipSwapError({
|
|
1921
|
+
code: "INVALID_LOCK_STATE",
|
|
1922
|
+
message: `Cannot reclaim: lock state is ${lockStateName(state)} but reclaim requires Free or Committed \u2014 ${cause} (contract would revert InvalidLockAdvancement)`,
|
|
1923
|
+
details: { lock, lockState: state, required: "Free or Committed" }
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
checkTermsHash(lock, onChainTermsHash, party, counterparty);
|
|
1927
|
+
checkPosted(lock, isPosted);
|
|
1928
|
+
}
|
|
1929
|
+
async function verifyCommitState(lock, party, counterparty) {
|
|
1930
|
+
const { state, onChainTermsHash, isPosted } = await readLockBatch(lock, digestTerms(party));
|
|
1931
|
+
if (state === 3 /* Spent */ || state === 2 /* Committed */) {
|
|
1932
|
+
throw new QuipSwapError({
|
|
1933
|
+
code: "INVALID_LOCK_STATE",
|
|
1934
|
+
message: `Cannot commit: lock state is ${lockStateName(state)} and no commit can advance from it (contract would revert InvalidLockAdvancement)`,
|
|
1935
|
+
details: { lock, lockState: state, required: "Unused or Free" }
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
if (state === 1 /* Free */) {
|
|
1939
|
+
checkTermsHash(lock, onChainTermsHash, party, counterparty);
|
|
1940
|
+
if (isPosted) {
|
|
1941
|
+
throw new QuipSwapError({
|
|
1942
|
+
code: "TERMS_ALREADY_POSTED",
|
|
1943
|
+
message: "This side's terms are already posted for the lock; the second same-chain commit must post the OTHER side (contract would revert TermsAlreadyPosted)",
|
|
1944
|
+
details: { lock, partyDigest: digestTerms(party) }
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
async function submitWrite(params) {
|
|
1950
|
+
const prepared = await prepareTx({
|
|
1951
|
+
publicClient,
|
|
1952
|
+
contractParams: {
|
|
1953
|
+
address,
|
|
1954
|
+
abi: omnibusAbi,
|
|
1955
|
+
functionName: params.functionName,
|
|
1956
|
+
args: params.args,
|
|
1957
|
+
...params.value !== void 0 ? { value: params.value } : {},
|
|
1958
|
+
account: params.sender
|
|
1959
|
+
},
|
|
1960
|
+
totalValue: params.value ?? 0n,
|
|
1961
|
+
...params.opts !== void 0 ? { opts: params.opts } : {}
|
|
1962
|
+
});
|
|
1963
|
+
try {
|
|
1964
|
+
return await params.wallet.writeContract({
|
|
1965
|
+
...contract,
|
|
1966
|
+
functionName: params.functionName,
|
|
1967
|
+
args: params.args,
|
|
1968
|
+
account: params.wallet.account ?? params.sender,
|
|
1969
|
+
chain: params.wallet.chain ?? publicClient.chain ?? null,
|
|
1970
|
+
...params.value !== void 0 ? { value: params.value } : {},
|
|
1971
|
+
gas: prepared.gas,
|
|
1972
|
+
...prepared.fees,
|
|
1973
|
+
...prepared.nonce !== void 0 ? { nonce: prepared.nonce } : {}
|
|
1974
|
+
// dynamic functionName + optional payable value cannot satisfy viem's
|
|
1975
|
+
// conditional parameter types statically; the runtime shape is
|
|
1976
|
+
// exercised by the mocked-client and Anvil integration suites
|
|
1977
|
+
});
|
|
1978
|
+
} catch (error) {
|
|
1979
|
+
if (error instanceof BaseError3 && error.walk((e) => e instanceof InsufficientFundsError) !== null) {
|
|
1980
|
+
throw new QuipSwapError({
|
|
1981
|
+
code: "BALANCE_TOO_LOW",
|
|
1982
|
+
message: `Sender cannot cover gas for ${params.functionName}; fund the account and retry`,
|
|
1983
|
+
cause: error
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
throw wrapContractError(error, params.context);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
const admin = {
|
|
1990
|
+
async setCommitmentFee(newFee, opts) {
|
|
1991
|
+
const { wallet, sender } = requireWallet();
|
|
1992
|
+
return submitWrite({ wallet, sender, functionName: "setCommitmentFee", args: [newFee], opts, context: "setCommitmentFee" });
|
|
1993
|
+
},
|
|
1994
|
+
async withdrawFees(to, opts) {
|
|
1995
|
+
const { wallet, sender } = requireWallet();
|
|
1996
|
+
return submitWrite({ wallet, sender, functionName: "withdrawFees", args: [to], opts, context: "withdrawFees" });
|
|
1997
|
+
},
|
|
1998
|
+
async transferOwnership(newOwner, opts) {
|
|
1999
|
+
const { wallet, sender } = requireWallet();
|
|
2000
|
+
return submitWrite({
|
|
2001
|
+
wallet,
|
|
2002
|
+
sender,
|
|
2003
|
+
functionName: "transferOwnership",
|
|
2004
|
+
args: [newOwner],
|
|
2005
|
+
opts,
|
|
2006
|
+
context: "transferOwnership"
|
|
2007
|
+
});
|
|
2008
|
+
},
|
|
2009
|
+
async acceptOwnership(opts) {
|
|
2010
|
+
const { wallet, sender } = requireWallet();
|
|
2011
|
+
return submitWrite({ wallet, sender, functionName: "acceptOwnership", args: [], opts, context: "acceptOwnership" });
|
|
2012
|
+
}
|
|
2013
|
+
};
|
|
2014
|
+
return {
|
|
2015
|
+
address,
|
|
2016
|
+
publicClient,
|
|
2017
|
+
getVersion: () => read("VERSION"),
|
|
2018
|
+
getMaxFee: () => read("MAX_FEE"),
|
|
2019
|
+
getQuipFactory,
|
|
2020
|
+
getCommitmentFee: () => read("commitmentFee"),
|
|
2021
|
+
getAccruedFees: () => read("accruedFees"),
|
|
2022
|
+
getLockState: async (lock) => {
|
|
2023
|
+
assertHex32(lock, "lock");
|
|
2024
|
+
const state = await read("lockState", [lock]);
|
|
2025
|
+
return state;
|
|
2026
|
+
},
|
|
2027
|
+
getTermsHash: (lock) => {
|
|
2028
|
+
assertHex32(lock, "lock");
|
|
2029
|
+
return read("termsHash", [lock]);
|
|
2030
|
+
},
|
|
2031
|
+
getPosted: (lock, termsDigest) => {
|
|
2032
|
+
assertHex32(lock, "lock");
|
|
2033
|
+
assertHex32(termsDigest, "termsDigest");
|
|
2034
|
+
return read("posted", [lock, termsDigest]);
|
|
2035
|
+
},
|
|
2036
|
+
getOwner: () => read("owner"),
|
|
2037
|
+
getPendingOwner: () => read("pendingOwner"),
|
|
2038
|
+
isQuipWallet,
|
|
2039
|
+
// confirm a write and decode events, always scoped to this client's
|
|
2040
|
+
// Omnibus address (the client knows the right address for its chain)
|
|
2041
|
+
waitForReceipt: (hash, options = {}) => waitForOmnibusReceipt(publicClient, hash, { ...options, address }),
|
|
2042
|
+
// @audit-ok
|
|
2043
|
+
async commit({ lock, party, counterparty, verifyOnChainState = true }, opts) {
|
|
2044
|
+
assertHex32(lock, "lock");
|
|
2045
|
+
const { wallet, sender } = requireWallet();
|
|
2046
|
+
validateTerms(party);
|
|
2047
|
+
validateTerms(counterparty);
|
|
2048
|
+
validateTermPairing(party, counterparty);
|
|
2049
|
+
const connectedChainId = BigInt(await publicClient.getChainId());
|
|
2050
|
+
if (party.chainId !== connectedChainId) {
|
|
2051
|
+
throw new QuipSwapError({
|
|
2052
|
+
code: "CHAIN_ID_MISMATCH",
|
|
2053
|
+
message: `party.chainId (${party.chainId}) does not match the connected chain (${connectedChainId}); commit must be sent on the chain holding the party's assets (contract: ChainIdMismatch)`,
|
|
2054
|
+
details: { partyChainId: party.chainId, connectedChainId }
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
if (!await isQuipWallet(sender)) {
|
|
2058
|
+
throw new QuipSwapError({
|
|
2059
|
+
code: "NOT_QUIP_WALLET",
|
|
2060
|
+
message: `Sender ${sender} is not a factory-deployed QuipWallet (QUIP_FACTORY.vaultIdOf is zero); only QuipWallet contracts can commit (contract: CallerNotQuipWallet). The committer must be the QuipWallet CONTRACT address \u2014 never substitute the wallet owner's EOA`,
|
|
2061
|
+
details: { sender }
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
const timestamp = await chainTimestamp();
|
|
2065
|
+
try {
|
|
2066
|
+
validateCommitWindow(party, counterparty, timestamp);
|
|
2067
|
+
} catch (error) {
|
|
2068
|
+
if (error instanceof QuipSwapError && error.code === "WINDOW_VIOLATED" && proposedBy(party, counterparty) === "counterparty" && timestamp < counterparty.commitmentDeadline) {
|
|
2069
|
+
throw new QuipSwapError({
|
|
2070
|
+
code: "WINDOW_VIOLATED",
|
|
2071
|
+
message: `Taker commit window has not opened yet: it opens at the proposer's commitmentDeadline (${counterparty.commitmentDeadline}) and the chain time is ${timestamp}. Wait for the proposer's deadline to elapse before committing`,
|
|
2072
|
+
details: { opensAt: counterparty.commitmentDeadline, timestamp },
|
|
2073
|
+
cause: error
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
throw error;
|
|
2077
|
+
}
|
|
2078
|
+
if (verifyOnChainState) {
|
|
2079
|
+
await verifyCommitState(lock, party, counterparty);
|
|
2080
|
+
}
|
|
2081
|
+
const fee = await read("commitmentFee");
|
|
2082
|
+
const value = totalNative(party) + fee;
|
|
2083
|
+
return submitWrite({
|
|
2084
|
+
wallet,
|
|
2085
|
+
sender,
|
|
2086
|
+
functionName: "commit",
|
|
2087
|
+
args: [lock, toAbiTerms(party), toAbiTerms(counterparty)],
|
|
2088
|
+
value,
|
|
2089
|
+
opts,
|
|
2090
|
+
context: "commit"
|
|
2091
|
+
});
|
|
2092
|
+
},
|
|
2093
|
+
async claim({ secret, party, counterparty, verifyOnChainState = true }, opts) {
|
|
2094
|
+
assertHex32(secret, "secret");
|
|
2095
|
+
const lock = generateLock(secret);
|
|
2096
|
+
const { wallet, sender } = requireWallet();
|
|
2097
|
+
validateTerms(party);
|
|
2098
|
+
validateTerms(counterparty);
|
|
2099
|
+
validateTermPairing(party, counterparty);
|
|
2100
|
+
const connectedChainId = BigInt(await publicClient.getChainId());
|
|
2101
|
+
if (counterparty.chainId !== connectedChainId) {
|
|
2102
|
+
throw new QuipSwapError({
|
|
2103
|
+
code: "CHAIN_ID_MISMATCH",
|
|
2104
|
+
message: `counterparty.chainId (${counterparty.chainId}) does not match the connected chain (${connectedChainId}); claim must be sent on the chain holding the counterparty's assets (contract: ChainIdMismatch)`,
|
|
2105
|
+
details: { counterpartyChainId: counterparty.chainId, connectedChainId }
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
const timestamp = await chainTimestamp();
|
|
2109
|
+
validateClaimWindow(party, counterparty, timestamp);
|
|
2110
|
+
if (verifyOnChainState) {
|
|
2111
|
+
await verifyClaimState(lock, party, counterparty);
|
|
2112
|
+
}
|
|
2113
|
+
return submitWrite({
|
|
2114
|
+
wallet,
|
|
2115
|
+
sender,
|
|
2116
|
+
functionName: "claim",
|
|
2117
|
+
args: [secret, toAbiTerms(party), toAbiTerms(counterparty)],
|
|
2118
|
+
opts,
|
|
2119
|
+
context: "claim"
|
|
2120
|
+
});
|
|
2121
|
+
},
|
|
2122
|
+
async reclaim({ lock, party, counterparty, verifyOnChainState = true }, opts) {
|
|
2123
|
+
assertHex32(lock, "lock");
|
|
2124
|
+
const { wallet, sender } = requireWallet();
|
|
2125
|
+
validateTerms(party);
|
|
2126
|
+
validateTerms(counterparty);
|
|
2127
|
+
validateTermPairing(party, counterparty);
|
|
2128
|
+
const connectedChainId = BigInt(await publicClient.getChainId());
|
|
2129
|
+
if (party.chainId !== connectedChainId) {
|
|
2130
|
+
throw new QuipSwapError({
|
|
2131
|
+
code: "CHAIN_ID_MISMATCH",
|
|
2132
|
+
message: `party.chainId (${party.chainId}) does not match the connected chain (${connectedChainId}); reclaim must be sent on the chain holding the party's assets (contract: ChainIdMismatch)`,
|
|
2133
|
+
details: { partyChainId: party.chainId, connectedChainId }
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
const timestamp = await chainTimestamp();
|
|
2137
|
+
validateReclaimWindow(party, timestamp);
|
|
2138
|
+
if (verifyOnChainState) {
|
|
2139
|
+
await verifyReclaimState(lock, party, counterparty);
|
|
2140
|
+
}
|
|
2141
|
+
return submitWrite({
|
|
2142
|
+
wallet,
|
|
2143
|
+
sender,
|
|
2144
|
+
functionName: "reclaim",
|
|
2145
|
+
args: [lock, toAbiTerms(party), toAbiTerms(counterparty)],
|
|
2146
|
+
opts,
|
|
2147
|
+
context: "reclaim"
|
|
2148
|
+
});
|
|
2149
|
+
},
|
|
2150
|
+
admin
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
// src/approvals.ts
|
|
2155
|
+
var erc20Abi = [
|
|
2156
|
+
{
|
|
2157
|
+
type: "function",
|
|
2158
|
+
name: "allowance",
|
|
2159
|
+
stateMutability: "view",
|
|
2160
|
+
inputs: [
|
|
2161
|
+
{ name: "owner", type: "address" },
|
|
2162
|
+
{ name: "spender", type: "address" }
|
|
2163
|
+
],
|
|
2164
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2165
|
+
},
|
|
2166
|
+
{
|
|
2167
|
+
type: "function",
|
|
2168
|
+
name: "approve",
|
|
2169
|
+
stateMutability: "nonpayable",
|
|
2170
|
+
inputs: [
|
|
2171
|
+
{ name: "spender", type: "address" },
|
|
2172
|
+
{ name: "amount", type: "uint256" }
|
|
2173
|
+
],
|
|
2174
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2175
|
+
}
|
|
2176
|
+
];
|
|
2177
|
+
var erc721Abi = [
|
|
2178
|
+
{
|
|
2179
|
+
type: "function",
|
|
2180
|
+
name: "getApproved",
|
|
2181
|
+
stateMutability: "view",
|
|
2182
|
+
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
2183
|
+
outputs: [{ name: "", type: "address" }]
|
|
2184
|
+
},
|
|
2185
|
+
{
|
|
2186
|
+
type: "function",
|
|
2187
|
+
name: "isApprovedForAll",
|
|
2188
|
+
stateMutability: "view",
|
|
2189
|
+
inputs: [
|
|
2190
|
+
{ name: "owner", type: "address" },
|
|
2191
|
+
{ name: "operator", type: "address" }
|
|
2192
|
+
],
|
|
2193
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2194
|
+
},
|
|
2195
|
+
{
|
|
2196
|
+
type: "function",
|
|
2197
|
+
name: "approve",
|
|
2198
|
+
stateMutability: "nonpayable",
|
|
2199
|
+
inputs: [
|
|
2200
|
+
{ name: "to", type: "address" },
|
|
2201
|
+
{ name: "tokenId", type: "uint256" }
|
|
2202
|
+
],
|
|
2203
|
+
outputs: []
|
|
2204
|
+
},
|
|
2205
|
+
{
|
|
2206
|
+
type: "function",
|
|
2207
|
+
name: "setApprovalForAll",
|
|
2208
|
+
stateMutability: "nonpayable",
|
|
2209
|
+
inputs: [
|
|
2210
|
+
{ name: "operator", type: "address" },
|
|
2211
|
+
{ name: "approved", type: "bool" }
|
|
2212
|
+
],
|
|
2213
|
+
outputs: []
|
|
2214
|
+
}
|
|
2215
|
+
];
|
|
2216
|
+
var erc1155Abi = [
|
|
2217
|
+
{
|
|
2218
|
+
type: "function",
|
|
2219
|
+
name: "isApprovedForAll",
|
|
2220
|
+
stateMutability: "view",
|
|
2221
|
+
inputs: [
|
|
2222
|
+
{ name: "account", type: "address" },
|
|
2223
|
+
{ name: "operator", type: "address" }
|
|
2224
|
+
],
|
|
2225
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
type: "function",
|
|
2229
|
+
name: "setApprovalForAll",
|
|
2230
|
+
stateMutability: "nonpayable",
|
|
2231
|
+
inputs: [
|
|
2232
|
+
{ name: "operator", type: "address" },
|
|
2233
|
+
{ name: "approved", type: "bool" }
|
|
2234
|
+
],
|
|
2235
|
+
outputs: []
|
|
2236
|
+
}
|
|
2237
|
+
];
|
|
2238
|
+
async function planApprovals(args) {
|
|
2239
|
+
const { publicClient, omnibusAddress, committer, terms } = args;
|
|
2240
|
+
const erc20Required = /* @__PURE__ */ new Map();
|
|
2241
|
+
const erc721Items = [];
|
|
2242
|
+
const erc1155Tokens = /* @__PURE__ */ new Map();
|
|
2243
|
+
for (const asset of terms.assets) {
|
|
2244
|
+
if (asset.assetType === 0 /* Native */) continue;
|
|
2245
|
+
if (asset.assetType === 1 /* ERC20 */) {
|
|
2246
|
+
const key = asset.target.toLowerCase();
|
|
2247
|
+
const existing = erc20Required.get(key);
|
|
2248
|
+
erc20Required.set(key, { token: asset.target, amount: (existing?.amount ?? 0n) + asset.amount });
|
|
2249
|
+
} else if (asset.assetType === 2 /* ERC721 */) {
|
|
2250
|
+
erc721Items.push({ token: asset.target, tokenId: asset.id });
|
|
2251
|
+
} else {
|
|
2252
|
+
erc1155Tokens.set(asset.target.toLowerCase(), asset.target);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
const items = [];
|
|
2256
|
+
try {
|
|
2257
|
+
for (const { token, amount } of erc20Required.values()) {
|
|
2258
|
+
const currentAllowance = await publicClient.readContract({
|
|
2259
|
+
address: token,
|
|
2260
|
+
abi: erc20Abi,
|
|
2261
|
+
functionName: "allowance",
|
|
2262
|
+
args: [committer, omnibusAddress]
|
|
2263
|
+
});
|
|
2264
|
+
items.push({
|
|
2265
|
+
kind: "erc20",
|
|
2266
|
+
token,
|
|
2267
|
+
requiredAllowance: amount,
|
|
2268
|
+
currentAllowance,
|
|
2269
|
+
satisfied: currentAllowance >= amount
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
for (const { token, tokenId } of erc721Items) {
|
|
2273
|
+
const [approvedAddress, operatorApproved] = await Promise.all([
|
|
2274
|
+
publicClient.readContract({ address: token, abi: erc721Abi, functionName: "getApproved", args: [tokenId] }),
|
|
2275
|
+
publicClient.readContract({
|
|
2276
|
+
address: token,
|
|
2277
|
+
abi: erc721Abi,
|
|
2278
|
+
functionName: "isApprovedForAll",
|
|
2279
|
+
args: [committer, omnibusAddress]
|
|
2280
|
+
})
|
|
2281
|
+
]);
|
|
2282
|
+
const tokenApproved = approvedAddress.toLowerCase() === omnibusAddress.toLowerCase();
|
|
2283
|
+
items.push({
|
|
2284
|
+
kind: "erc721",
|
|
2285
|
+
token,
|
|
2286
|
+
tokenId,
|
|
2287
|
+
tokenApproved,
|
|
2288
|
+
operatorApproved,
|
|
2289
|
+
satisfied: tokenApproved || operatorApproved
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
for (const token of erc1155Tokens.values()) {
|
|
2293
|
+
const operatorApproved = await publicClient.readContract({
|
|
2294
|
+
address: token,
|
|
2295
|
+
abi: erc1155Abi,
|
|
2296
|
+
functionName: "isApprovedForAll",
|
|
2297
|
+
args: [committer, omnibusAddress]
|
|
2298
|
+
});
|
|
2299
|
+
items.push({ kind: "erc1155", token, operatorApproved, satisfied: operatorApproved });
|
|
2300
|
+
}
|
|
2301
|
+
} catch (error) {
|
|
2302
|
+
throw wrapContractError(error, "Reading token approvals");
|
|
2303
|
+
}
|
|
2304
|
+
return { committer, omnibusAddress, items, satisfied: items.every((item) => item.satisfied) };
|
|
2305
|
+
}
|
|
2306
|
+
var MAX_UINT2562 = (1n << 256n) - 1n;
|
|
2307
|
+
async function submitApproval(args) {
|
|
2308
|
+
const { publicClient, walletClient, omnibusAddress, item } = args;
|
|
2309
|
+
const account = walletClient.account;
|
|
2310
|
+
if (account === void 0) {
|
|
2311
|
+
throw new QuipSwapError({
|
|
2312
|
+
code: "MISSING_ACCOUNT",
|
|
2313
|
+
message: "The wallet client must have an account to submit an approval"
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
try {
|
|
2317
|
+
if (item.kind === "erc20") {
|
|
2318
|
+
if (args.erc20Mode === void 0) {
|
|
2319
|
+
throw new QuipSwapError({
|
|
2320
|
+
code: "INVALID_RANGE",
|
|
2321
|
+
message: "ERC-20 approvals require an explicit erc20Mode ('exact' or 'unlimited'); the SDK never defaults to unlimited"
|
|
2322
|
+
});
|
|
2323
|
+
}
|
|
2324
|
+
const amount = args.erc20Mode === "exact" ? item.requiredAllowance : MAX_UINT2562;
|
|
2325
|
+
const { request: request2 } = await publicClient.simulateContract({
|
|
2326
|
+
address: item.token,
|
|
2327
|
+
abi: erc20Abi,
|
|
2328
|
+
functionName: "approve",
|
|
2329
|
+
args: [omnibusAddress, amount],
|
|
2330
|
+
account
|
|
2331
|
+
});
|
|
2332
|
+
return await walletClient.writeContract(request2);
|
|
2333
|
+
}
|
|
2334
|
+
if (item.kind === "erc721") {
|
|
2335
|
+
if ((args.erc721Mode ?? "token") === "token") {
|
|
2336
|
+
const { request: request3 } = await publicClient.simulateContract({
|
|
2337
|
+
address: item.token,
|
|
2338
|
+
abi: erc721Abi,
|
|
2339
|
+
functionName: "approve",
|
|
2340
|
+
args: [omnibusAddress, item.tokenId],
|
|
2341
|
+
account
|
|
2342
|
+
});
|
|
2343
|
+
return await walletClient.writeContract(request3);
|
|
2344
|
+
}
|
|
2345
|
+
const { request: request2 } = await publicClient.simulateContract({
|
|
2346
|
+
address: item.token,
|
|
2347
|
+
abi: erc721Abi,
|
|
2348
|
+
functionName: "setApprovalForAll",
|
|
2349
|
+
args: [omnibusAddress, true],
|
|
2350
|
+
account
|
|
2351
|
+
});
|
|
2352
|
+
return await walletClient.writeContract(request2);
|
|
2353
|
+
}
|
|
2354
|
+
const { request } = await publicClient.simulateContract({
|
|
2355
|
+
address: item.token,
|
|
2356
|
+
abi: erc1155Abi,
|
|
2357
|
+
functionName: "setApprovalForAll",
|
|
2358
|
+
args: [omnibusAddress, true],
|
|
2359
|
+
account
|
|
2360
|
+
});
|
|
2361
|
+
return await walletClient.writeContract(request);
|
|
2362
|
+
} catch (error) {
|
|
2363
|
+
if (error instanceof QuipSwapError) throw error;
|
|
2364
|
+
throw wrapContractError(error, `Approving ${item.kind} ${item.token}`);
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
// src/buffers.ts
|
|
2369
|
+
var DEFAULT_BUFFERS = {
|
|
2370
|
+
/** ~5 min — fast-finality L2s. */
|
|
2371
|
+
fastL2: 300n,
|
|
2372
|
+
/** ~30 min — general default. */
|
|
2373
|
+
standard: 1800n,
|
|
2374
|
+
/** ~1 hr — congested / deep-reorg-risk L1s. */
|
|
2375
|
+
conservativeL1: 3600n
|
|
2376
|
+
};
|
|
2377
|
+
var DEFAULT_CROSS_CHAIN_BUFFER_SECONDS = DEFAULT_BUFFERS.standard;
|
|
2378
|
+
var DEFAULT_SAME_CHAIN_BUFFER_SECONDS = DEFAULT_BUFFERS.standard;
|
|
2379
|
+
function checkScheduleBuffers(proposerTerms, takerTerms, minimumBufferSeconds) {
|
|
2380
|
+
const sequence = [
|
|
2381
|
+
["proposer.commitmentDeadline", proposerTerms.commitmentDeadline],
|
|
2382
|
+
["taker.commitmentDeadline", takerTerms.commitmentDeadline],
|
|
2383
|
+
["proposer.claimDeadline", proposerTerms.claimDeadline],
|
|
2384
|
+
["taker.claimDeadline", takerTerms.claimDeadline],
|
|
2385
|
+
["proposer.reclaimRelease", proposerTerms.reclaimRelease],
|
|
2386
|
+
["taker.reclaimRelease", takerTerms.reclaimRelease]
|
|
2387
|
+
];
|
|
2388
|
+
let minimumGapSeconds;
|
|
2389
|
+
for (let i = 1; i < sequence.length; i++) {
|
|
2390
|
+
const [prevName, prev] = sequence[i - 1];
|
|
2391
|
+
const [nextName, next] = sequence[i];
|
|
2392
|
+
const gap = next - prev;
|
|
2393
|
+
if (gap < minimumBufferSeconds) {
|
|
2394
|
+
throw new QuipSwapError({
|
|
2395
|
+
code: "INSUFFICIENT_BUFFER",
|
|
2396
|
+
message: `Gap between ${prevName} (${prev}) and ${nextName} (${next}) is ${gap}s, below the required minimum of ${minimumBufferSeconds}s. Every adjacent gap \u2014 especially the taker's post-reveal reaction buffer (proposer.reclaimRelease - proposer.claimDeadline) \u2014 must cover finality, reorg risk, RPC outages, congestion, and relayer latency`,
|
|
2397
|
+
details: { prevName, prev, nextName, next, gap, minimumBufferSeconds }
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
if (minimumGapSeconds === void 0 || gap < minimumGapSeconds) minimumGapSeconds = gap;
|
|
2401
|
+
}
|
|
2402
|
+
return { minimumGapSeconds: minimumGapSeconds ?? 0n };
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
// src/workflows/sameChain.ts
|
|
2406
|
+
function planSameChainSwap(a, b, opts) {
|
|
2407
|
+
validateTerms(a);
|
|
2408
|
+
validateTerms(b);
|
|
2409
|
+
validateTermPairing(a, b);
|
|
2410
|
+
if (a.chainId !== b.chainId) {
|
|
2411
|
+
throw new QuipSwapError({
|
|
2412
|
+
code: "CHAIN_ID_MISMATCH",
|
|
2413
|
+
message: `Same-chain plan requires both sides on one chain; got ${a.chainId} and ${b.chainId}`,
|
|
2414
|
+
details: { aChainId: a.chainId, bChainId: b.chainId }
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
const [proposerTerms, takerTerms] = proposedBy(a, b) === "party" ? [a, b] : [b, a];
|
|
2418
|
+
checkScheduleBuffers(proposerTerms, takerTerms, opts?.minimumBufferSeconds ?? DEFAULT_SAME_CHAIN_BUFFER_SECONDS);
|
|
2419
|
+
return {
|
|
2420
|
+
proposerTerms,
|
|
2421
|
+
takerTerms,
|
|
2422
|
+
canonicalDigest: digestTermsCanonically(proposerTerms, takerTerms),
|
|
2423
|
+
proposerDigest: digestTerms(proposerTerms),
|
|
2424
|
+
takerDigest: digestTerms(takerTerms),
|
|
2425
|
+
proposerCommitWindow: proposerCommitWindow(proposerTerms),
|
|
2426
|
+
takerCommitWindow: takerCommitWindow(takerTerms, proposerTerms),
|
|
2427
|
+
claimWindow: proposerClaimWindow(proposerTerms, takerTerms),
|
|
2428
|
+
proposerReclaimWindow: reclaimWindow(proposerTerms),
|
|
2429
|
+
takerReclaimWindow: reclaimWindow(takerTerms)
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
async function getSameChainSwapStatus(client, lock, plan) {
|
|
2433
|
+
const [state, proposerPosted, takerPosted, block] = await Promise.all([
|
|
2434
|
+
client.getLockState(lock),
|
|
2435
|
+
client.getPosted(lock, plan.proposerDigest),
|
|
2436
|
+
client.getPosted(lock, plan.takerDigest),
|
|
2437
|
+
client.publicClient.getBlock()
|
|
2438
|
+
]);
|
|
2439
|
+
const timestamp = block.timestamp;
|
|
2440
|
+
let status;
|
|
2441
|
+
switch (state) {
|
|
2442
|
+
case 0 /* Unused */:
|
|
2443
|
+
status = isWithinWindow(plan.proposerCommitWindow, timestamp) ? "awaiting-proposer-commit" : "proposer-commit-expired";
|
|
2444
|
+
break;
|
|
2445
|
+
case 1 /* Free */:
|
|
2446
|
+
if (isWithinWindow(plan.proposerReclaimWindow, timestamp)) {
|
|
2447
|
+
status = "reclaimable-from-free";
|
|
2448
|
+
} else if (timestamp < plan.takerCommitWindow.lower) {
|
|
2449
|
+
status = "awaiting-taker-window";
|
|
2450
|
+
} else if (isWithinWindow(plan.takerCommitWindow, timestamp)) {
|
|
2451
|
+
status = "awaiting-taker-commit";
|
|
2452
|
+
} else {
|
|
2453
|
+
status = "half-committed-expired";
|
|
2454
|
+
}
|
|
2455
|
+
break;
|
|
2456
|
+
case 2 /* Committed */:
|
|
2457
|
+
if (isWithinWindow(plan.claimWindow, timestamp)) {
|
|
2458
|
+
status = "claimable";
|
|
2459
|
+
} else if (isWithinWindow(plan.proposerReclaimWindow, timestamp)) {
|
|
2460
|
+
status = "reclaimable";
|
|
2461
|
+
} else if (timestamp >= plan.proposerTerms.claimDeadline) {
|
|
2462
|
+
status = "late-claimable";
|
|
2463
|
+
} else {
|
|
2464
|
+
status = "awaiting-claim-window";
|
|
2465
|
+
}
|
|
2466
|
+
break;
|
|
2467
|
+
case 3 /* Spent */:
|
|
2468
|
+
status = "settled";
|
|
2469
|
+
break;
|
|
2470
|
+
}
|
|
2471
|
+
return { status, lockState: state, proposerPosted, takerPosted, timestamp };
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
// src/workflows/crossChain.ts
|
|
2475
|
+
function validateCrossChainSchedule(args) {
|
|
2476
|
+
const { proposerTerms, takerTerms } = args;
|
|
2477
|
+
const minimumBufferSeconds = args.minimumBufferSeconds ?? DEFAULT_CROSS_CHAIN_BUFFER_SECONDS;
|
|
2478
|
+
validateTerms(proposerTerms);
|
|
2479
|
+
validateTerms(takerTerms);
|
|
2480
|
+
validateTermPairing(proposerTerms, takerTerms);
|
|
2481
|
+
if (proposedBy(proposerTerms, takerTerms) !== "party") {
|
|
2482
|
+
throw new QuipSwapError({
|
|
2483
|
+
code: "SECRET_HOLDER_NOT_PROPOSER",
|
|
2484
|
+
message: "The secret holder's leg must be the proposer (smaller commitmentDeadline). A secret-holding taker could claim the counterparty leg while letting its own leg expire \u2014 the cross-chain free option. Swap the role assignment or rebuild the schedule",
|
|
2485
|
+
details: {
|
|
2486
|
+
proposerCommitmentDeadline: proposerTerms.commitmentDeadline,
|
|
2487
|
+
takerCommitmentDeadline: takerTerms.commitmentDeadline
|
|
2488
|
+
}
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
if (proposerTerms.chainId === takerTerms.chainId) {
|
|
2492
|
+
throw new QuipSwapError({
|
|
2493
|
+
code: "CHAIN_ID_MISMATCH",
|
|
2494
|
+
message: `Cross-chain schedule requires the two legs on different chains; both are on ${proposerTerms.chainId}`,
|
|
2495
|
+
details: { chainId: proposerTerms.chainId }
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
const { minimumGapSeconds } = checkScheduleBuffers(proposerTerms, takerTerms, minimumBufferSeconds);
|
|
2499
|
+
return {
|
|
2500
|
+
proposerTerms,
|
|
2501
|
+
takerTerms,
|
|
2502
|
+
// reactionBuffer = proposer.reclaimRelease - proposer.claimDeadline
|
|
2503
|
+
reactionBufferSeconds: proposerTerms.reclaimRelease - proposerTerms.claimDeadline,
|
|
2504
|
+
minimumGapSeconds
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
async function verifyRemoteCommitment(remoteClient, lock, proposerTerms, takerTerms) {
|
|
2508
|
+
const [state, proposerPosted, onChainTermsHash] = await Promise.all([
|
|
2509
|
+
remoteClient.getLockState(lock),
|
|
2510
|
+
remoteClient.getPosted(lock, digestTerms(proposerTerms)),
|
|
2511
|
+
remoteClient.getTermsHash(lock)
|
|
2512
|
+
]);
|
|
2513
|
+
const termsHashMatches = onChainTermsHash.toLowerCase() === digestTermsCanonically(proposerTerms, takerTerms).toLowerCase();
|
|
2514
|
+
return {
|
|
2515
|
+
// cross-chain local commits move Unused -> Committed directly
|
|
2516
|
+
committed: state === 2 /* Committed */ && proposerPosted && termsHashMatches,
|
|
2517
|
+
lockState: state,
|
|
2518
|
+
proposerPosted,
|
|
2519
|
+
termsHashMatches
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
function deriveSharedLock(secret) {
|
|
2523
|
+
return generateLock(secret);
|
|
2524
|
+
}
|
|
2525
|
+
export {
|
|
2526
|
+
AssetType,
|
|
2527
|
+
DEFAULT_BUFFERS,
|
|
2528
|
+
DEFAULT_CROSS_CHAIN_BUFFER_SECONDS,
|
|
2529
|
+
DEFAULT_GAS_MULTIPLIER,
|
|
2530
|
+
DEFAULT_SAME_CHAIN_BUFFER_SECONDS,
|
|
2531
|
+
LockState,
|
|
2532
|
+
MAX_GAS_MULTIPLIER,
|
|
2533
|
+
MAX_UINT256,
|
|
2534
|
+
MIN_GAS_MULTIPLIER,
|
|
2535
|
+
OMNIBUS_CREATE3_ADDRESS,
|
|
2536
|
+
QuipSwapError,
|
|
2537
|
+
applyGasMultiplier,
|
|
2538
|
+
assertHex32,
|
|
2539
|
+
assetArrayAbiParameter,
|
|
2540
|
+
buildFeeOverrides,
|
|
2541
|
+
checkScheduleBuffers,
|
|
2542
|
+
createOmnibusClient,
|
|
2543
|
+
createTerms,
|
|
2544
|
+
decodeClaimEvents,
|
|
2545
|
+
decodeCommitmentEvents,
|
|
2546
|
+
decodeReclaimedEvents,
|
|
2547
|
+
deriveSharedLock,
|
|
2548
|
+
digestTerms,
|
|
2549
|
+
digestTermsCanonically,
|
|
2550
|
+
enforceWithin,
|
|
2551
|
+
erc1155Asset,
|
|
2552
|
+
erc20Asset,
|
|
2553
|
+
erc721Asset,
|
|
2554
|
+
extractContractErrorName,
|
|
2555
|
+
extractRevealedSecret,
|
|
2556
|
+
extractSecretFromClaims,
|
|
2557
|
+
generateLock,
|
|
2558
|
+
generateSecret,
|
|
2559
|
+
getClaimEvents,
|
|
2560
|
+
getCommitmentEvents,
|
|
2561
|
+
getReclaimedEvents,
|
|
2562
|
+
getSameChainSwapStatus,
|
|
2563
|
+
isWithinWindow,
|
|
2564
|
+
knownDeployments,
|
|
2565
|
+
nativeAsset,
|
|
2566
|
+
omnibusAbi,
|
|
2567
|
+
planApprovals,
|
|
2568
|
+
planSameChainSwap,
|
|
2569
|
+
preflightBalanceCheck,
|
|
2570
|
+
prepareTx,
|
|
2571
|
+
proposedBy,
|
|
2572
|
+
proposerClaimWindow,
|
|
2573
|
+
proposerCommitWindow,
|
|
2574
|
+
quipFactoryAbi,
|
|
2575
|
+
reclaimWindow,
|
|
2576
|
+
resolveDeployment,
|
|
2577
|
+
resolveGasMultiplier,
|
|
2578
|
+
secretToPair,
|
|
2579
|
+
submitApproval,
|
|
2580
|
+
takerClaimWindow,
|
|
2581
|
+
takerCommitWindow,
|
|
2582
|
+
termsAbiParameter,
|
|
2583
|
+
totalNative,
|
|
2584
|
+
validateAsset,
|
|
2585
|
+
validateClaimWindow,
|
|
2586
|
+
validateCommitWindow,
|
|
2587
|
+
validateCrossChainSchedule,
|
|
2588
|
+
validateReclaimWindow,
|
|
2589
|
+
validateTermPairing,
|
|
2590
|
+
validateTerms,
|
|
2591
|
+
verifyRemoteCommitment,
|
|
2592
|
+
waitForOmnibusReceipt,
|
|
2593
|
+
watchClaimEvents,
|
|
2594
|
+
wrapContractError
|
|
2595
|
+
};
|
|
2596
|
+
//# sourceMappingURL=index.js.map
|