@morpho-dev/router 0.5.0 → 0.6.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/dist/cli.js +2147 -989
- package/dist/drizzle/migrations/0023_remove-block-number-for-collaterals.sql +1 -0
- package/dist/drizzle/migrations/meta/0023_snapshot.json +1436 -0
- package/dist/drizzle/migrations/meta/_journal.json +7 -0
- package/dist/index.browser.d.mts +497 -162
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +497 -162
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +881 -426
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +888 -427
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +579 -174
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +578 -173
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +6671 -5605
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +6659 -5599
- package/dist/index.node.mjs.map +1 -1
- package/docs/integrator.md +7 -1
- package/package.json +2 -2
package/dist/index.browser.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-Bo1DHCg-.mjs";
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
|
-
import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress,
|
|
3
|
+
import { bytesToHex, decodeAbiParameters, encodeAbiParameters, getAddress, hashTypedData, hexToBytes, isAddress, isHex, keccak256, maxUint256, numberToHex, pad, parseAbi, publicActions, recoverAddress, zeroAddress } from "viem";
|
|
4
4
|
import { getBlock, getLogs, multicall } from "viem/actions";
|
|
5
5
|
import { anvil, base, mainnet } from "viem/chains";
|
|
6
6
|
import * as z$1 from "zod";
|
|
@@ -1372,6 +1372,7 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
|
|
|
1372
1372
|
InvalidObligationError: () => InvalidObligationError,
|
|
1373
1373
|
ObligationSchema: () => ObligationSchema,
|
|
1374
1374
|
from: () => from$10,
|
|
1375
|
+
fromOffer: () => fromOffer$1,
|
|
1375
1376
|
fromSnakeCase: () => fromSnakeCase$2,
|
|
1376
1377
|
id: () => id,
|
|
1377
1378
|
random: () => random$2
|
|
@@ -1500,6 +1501,21 @@ function random$2() {
|
|
|
1500
1501
|
maturity: from$11("end_of_next_quarter")
|
|
1501
1502
|
});
|
|
1502
1503
|
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Creates an obligation from an offer.
|
|
1506
|
+
* @constructor
|
|
1507
|
+
*
|
|
1508
|
+
* @param offer - The offer to create the obligation from.
|
|
1509
|
+
* @returns The created obligation. {@link fromOffer.ReturnType}
|
|
1510
|
+
*/
|
|
1511
|
+
function fromOffer$1(offer) {
|
|
1512
|
+
return from$10({
|
|
1513
|
+
chainId: offer.chainId,
|
|
1514
|
+
loanToken: offer.loanToken,
|
|
1515
|
+
collaterals: offer.collaterals,
|
|
1516
|
+
maturity: offer.maturity
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1503
1519
|
var InvalidObligationError = class extends BaseError {
|
|
1504
1520
|
constructor(error) {
|
|
1505
1521
|
super("Invalid obligation.", { cause: error });
|
|
@@ -1513,273 +1529,22 @@ var CollateralsAreNotSortedError = class extends BaseError {
|
|
|
1513
1529
|
}
|
|
1514
1530
|
};
|
|
1515
1531
|
|
|
1516
|
-
//#endregion
|
|
1517
|
-
//#region src/core/Tree.ts
|
|
1518
|
-
var Tree_exports = /* @__PURE__ */ __exportAll({
|
|
1519
|
-
DecodeError: () => DecodeError,
|
|
1520
|
-
EncodeError: () => EncodeError,
|
|
1521
|
-
TreeError: () => TreeError,
|
|
1522
|
-
VERSION: () => VERSION,
|
|
1523
|
-
decode: () => decode$1,
|
|
1524
|
-
encode: () => encode$1,
|
|
1525
|
-
encodeUnsigned: () => encodeUnsigned,
|
|
1526
|
-
from: () => from$9,
|
|
1527
|
-
proofs: () => proofs
|
|
1528
|
-
});
|
|
1529
|
-
const VERSION = 1;
|
|
1530
|
-
const normalizeHash = (hash) => hash.toLowerCase();
|
|
1531
|
-
/**
|
|
1532
|
-
* Builds a Merkle tree from a list of offers.
|
|
1533
|
-
*
|
|
1534
|
-
* Leaves are the offer `hash` values as `bytes32` and are deterministically
|
|
1535
|
-
* ordered following the StandardMerkleTree leaf ordering so that the resulting
|
|
1536
|
-
* root is stable regardless of the input order.
|
|
1537
|
-
*
|
|
1538
|
-
* @param offers - Offers to include in the tree.
|
|
1539
|
-
* @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
|
|
1540
|
-
* @throws {TreeError} If tree building fails due to offer inconsistencies.
|
|
1541
|
-
*/
|
|
1542
|
-
const from$9 = (offers) => {
|
|
1543
|
-
const leaves = offers.map((offer) => [hash(offer)]);
|
|
1544
|
-
const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
|
|
1545
|
-
const orderedOffers = orderOffers(tree, offers);
|
|
1546
|
-
return Object.assign(tree, { offers: orderedOffers });
|
|
1547
|
-
};
|
|
1548
|
-
const orderOffers = (tree, offers) => {
|
|
1549
|
-
const offerByHash = /* @__PURE__ */ new Map();
|
|
1550
|
-
for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
|
|
1551
|
-
const entries = tree.dump().values.map((value) => {
|
|
1552
|
-
const hash = normalizeHash(value.value[0]);
|
|
1553
|
-
const offer = offerByHash.get(hash);
|
|
1554
|
-
if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
|
|
1555
|
-
return {
|
|
1556
|
-
offer,
|
|
1557
|
-
treeIndex: value.treeIndex
|
|
1558
|
-
};
|
|
1559
|
-
});
|
|
1560
|
-
entries.sort((a, b) => b.treeIndex - a.treeIndex);
|
|
1561
|
-
return entries.map((item) => item.offer);
|
|
1562
|
-
};
|
|
1563
|
-
/**
|
|
1564
|
-
* Generates merkle proofs for all offers in a tree.
|
|
1565
|
-
*
|
|
1566
|
-
* Each proof allows independent verification that an offer is included in the tree
|
|
1567
|
-
* without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
|
|
1568
|
-
*
|
|
1569
|
-
* @param tree - The {@link Tree} to generate proofs for.
|
|
1570
|
-
* @returns Array of proofs - {@link Proof}
|
|
1571
|
-
*/
|
|
1572
|
-
const proofs = (tree) => {
|
|
1573
|
-
return tree.offers.map((offer) => {
|
|
1574
|
-
return {
|
|
1575
|
-
offer,
|
|
1576
|
-
path: tree.getProof([hash(offer)])
|
|
1577
|
-
};
|
|
1578
|
-
});
|
|
1579
|
-
};
|
|
1580
|
-
const assertHex = (value, expectedBytes, name) => {
|
|
1581
|
-
if (typeof value !== "string" || !isHex(value)) throw new DecodeError(`${name} is not a valid hex string`);
|
|
1582
|
-
if (hexToBytes(value).length !== expectedBytes) throw new DecodeError(`${name}: expected ${expectedBytes} bytes`);
|
|
1583
|
-
};
|
|
1584
|
-
const verifySignatureAndRecoverAddress = async (params) => {
|
|
1585
|
-
const { root, signature } = params;
|
|
1586
|
-
assertHex(signature, 65, "signature");
|
|
1587
|
-
const hash = hashMessage({ raw: root });
|
|
1588
|
-
try {
|
|
1589
|
-
return await recoverAddress({
|
|
1590
|
-
hash,
|
|
1591
|
-
signature
|
|
1592
|
-
});
|
|
1593
|
-
} catch {
|
|
1594
|
-
throw new DecodeError("signature recovery failed");
|
|
1595
|
-
}
|
|
1596
|
-
};
|
|
1597
|
-
/**
|
|
1598
|
-
* Encodes a merkle tree with signature into hex calldata for onchain broadcast.
|
|
1599
|
-
*
|
|
1600
|
-
* Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
|
|
1601
|
-
* - `{vv}`: 1-byte version (currently 0x01)
|
|
1602
|
-
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
1603
|
-
* - `{root}`: 32-byte merkle root
|
|
1604
|
-
* - `{signature}`: 65-byte EIP-191 signature over raw root bytes
|
|
1605
|
-
*
|
|
1606
|
-
* Validates signature authenticity and root integrity before encoding.
|
|
1607
|
-
*
|
|
1608
|
-
* @example
|
|
1609
|
-
* ```typescript
|
|
1610
|
-
* const tree = Tree.from(offers);
|
|
1611
|
-
* const signature = await wallet.signMessage({ message: { raw: tree.root } });
|
|
1612
|
-
* const calldata = await Tree.encode(tree, signature);
|
|
1613
|
-
* await broadcast(calldata);
|
|
1614
|
-
* ```
|
|
1615
|
-
*
|
|
1616
|
-
* @example
|
|
1617
|
-
* Manual construction (for advanced users):
|
|
1618
|
-
* ```typescript
|
|
1619
|
-
* const tree = Tree.from(offers);
|
|
1620
|
-
* const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
|
|
1621
|
-
* const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
|
|
1622
|
-
* const signature = await wallet.signMessage({ message: { raw: tree.root } });
|
|
1623
|
-
* const calldata = `${partial}${signature.slice(2)}`;
|
|
1624
|
-
* ```
|
|
1625
|
-
*
|
|
1626
|
-
* @param tree - Merkle tree of offers
|
|
1627
|
-
* @param signature - EIP-191 signature over raw root bytes
|
|
1628
|
-
* @returns Hex-encoded calldata ready for onchain broadcast
|
|
1629
|
-
* @throws {EncodeError} If signature verification fails or root mismatch
|
|
1630
|
-
*/
|
|
1631
|
-
const encode$1 = async (tree, signature) => {
|
|
1632
|
-
validateTreeForEncoding(tree);
|
|
1633
|
-
await verifySignatureAndRecoverAddress({
|
|
1634
|
-
root: tree.root,
|
|
1635
|
-
signature
|
|
1636
|
-
});
|
|
1637
|
-
const unsigned = encodeUnsignedBytes(tree);
|
|
1638
|
-
const sigBytes = hexToBytes(signature);
|
|
1639
|
-
const encoded = new Uint8Array(unsigned.length + sigBytes.length);
|
|
1640
|
-
encoded.set(unsigned, 0);
|
|
1641
|
-
encoded.set(sigBytes, unsigned.length);
|
|
1642
|
-
return bytesToHex(encoded);
|
|
1643
|
-
};
|
|
1644
|
-
/**
|
|
1645
|
-
* Encodes a merkle tree without a signature into hex payload for client-side signing.
|
|
1646
|
-
*
|
|
1647
|
-
* Layout: `0x{vv}{gzip([...offers])}{root}` where:
|
|
1648
|
-
* - `{vv}`: 1-byte version (currently 0x01)
|
|
1649
|
-
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
1650
|
-
* - `{root}`: 32-byte merkle root
|
|
1651
|
-
*
|
|
1652
|
-
* Validates root integrity before encoding.
|
|
1653
|
-
*
|
|
1654
|
-
* @param tree - Merkle tree of offers
|
|
1655
|
-
* @returns Hex-encoded unsigned payload
|
|
1656
|
-
* @throws {EncodeError} If root mismatch
|
|
1657
|
-
*/
|
|
1658
|
-
const encodeUnsigned = (tree) => {
|
|
1659
|
-
validateTreeForEncoding(tree);
|
|
1660
|
-
return bytesToHex(encodeUnsignedBytes(tree));
|
|
1661
|
-
};
|
|
1662
|
-
const validateTreeForEncoding = (tree) => {
|
|
1663
|
-
if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
|
|
1664
|
-
const computed = from$9(tree.offers);
|
|
1665
|
-
if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
|
|
1666
|
-
};
|
|
1667
|
-
const encodeUnsignedBytes = (tree) => {
|
|
1668
|
-
const offersPayload = tree.offers.map(serialize);
|
|
1669
|
-
const compressed = gzip(JSON.stringify(offersPayload));
|
|
1670
|
-
const rootBytes = hexToBytes(tree.root);
|
|
1671
|
-
const encoded = new Uint8Array(1 + compressed.length + 32);
|
|
1672
|
-
encoded[0] = VERSION;
|
|
1673
|
-
encoded.set(compressed, 1);
|
|
1674
|
-
encoded.set(rootBytes, 1 + compressed.length);
|
|
1675
|
-
return encoded;
|
|
1676
|
-
};
|
|
1677
|
-
/**
|
|
1678
|
-
* Decodes hex calldata into a validated merkle tree.
|
|
1679
|
-
*
|
|
1680
|
-
* Validates signature before decompression for fail-fast rejection of invalid payloads.
|
|
1681
|
-
* Returns the tree with separately validated signature and recovered signer address.
|
|
1682
|
-
*
|
|
1683
|
-
* Validation order:
|
|
1684
|
-
* 1. Version check
|
|
1685
|
-
* 2. Signature verification (fail-fast, before decompression)
|
|
1686
|
-
* 3. Decompression (only if signature valid)
|
|
1687
|
-
* 4. Root verification (computed from offers vs embedded root)
|
|
1688
|
-
*
|
|
1689
|
-
* @example
|
|
1690
|
-
* ```typescript
|
|
1691
|
-
* const { tree, signature, signer } = await Tree.decode(calldata);
|
|
1692
|
-
* console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
|
|
1693
|
-
* ```
|
|
1694
|
-
*
|
|
1695
|
-
* @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
|
|
1696
|
-
* @returns Validated tree, signature, and recovered signer address
|
|
1697
|
-
* @throws {DecodeError} If version invalid, signature invalid, or root mismatch
|
|
1698
|
-
*/
|
|
1699
|
-
const decode$1 = async (encoded) => {
|
|
1700
|
-
const bytes = hexToBytes(encoded);
|
|
1701
|
-
if (bytes.length < 98) throw new DecodeError("payload too short");
|
|
1702
|
-
const version = bytes[0];
|
|
1703
|
-
if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
|
|
1704
|
-
const signature = bytesToHex(bytes.slice(-65));
|
|
1705
|
-
const root = bytesToHex(bytes.slice(-97, -65));
|
|
1706
|
-
assertHex(root, 32, "root");
|
|
1707
|
-
assertHex(signature, 65, "signature");
|
|
1708
|
-
const signer = await verifySignatureAndRecoverAddress({
|
|
1709
|
-
root,
|
|
1710
|
-
signature
|
|
1711
|
-
});
|
|
1712
|
-
const compressed = bytes.slice(1, -97);
|
|
1713
|
-
let decoded;
|
|
1714
|
-
try {
|
|
1715
|
-
decoded = ungzip(compressed, { to: "string" });
|
|
1716
|
-
} catch {
|
|
1717
|
-
throw new DecodeError("decompression failed");
|
|
1718
|
-
}
|
|
1719
|
-
let rawOffers;
|
|
1720
|
-
try {
|
|
1721
|
-
rawOffers = JSON.parse(decoded);
|
|
1722
|
-
} catch {
|
|
1723
|
-
throw new DecodeError("JSON parse failed");
|
|
1724
|
-
}
|
|
1725
|
-
const tree = from$9(rawOffers.map((o) => OfferSchema().parse(o)));
|
|
1726
|
-
if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
|
|
1727
|
-
return {
|
|
1728
|
-
tree,
|
|
1729
|
-
signature,
|
|
1730
|
-
signer
|
|
1731
|
-
};
|
|
1732
|
-
};
|
|
1733
|
-
/**
|
|
1734
|
-
* Error thrown during tree building operations.
|
|
1735
|
-
* Indicates structural issues with the tree (missing offers, inconsistent state).
|
|
1736
|
-
*/
|
|
1737
|
-
var TreeError = class extends BaseError {
|
|
1738
|
-
constructor(reason) {
|
|
1739
|
-
super(`Tree error: ${reason}`);
|
|
1740
|
-
_defineProperty(this, "name", "Tree.TreeError");
|
|
1741
|
-
}
|
|
1742
|
-
};
|
|
1743
|
-
/**
|
|
1744
|
-
* Error thrown during tree encoding.
|
|
1745
|
-
* Indicates validation failures (signature, root mismatch, mixed makers).
|
|
1746
|
-
*/
|
|
1747
|
-
var EncodeError = class extends BaseError {
|
|
1748
|
-
constructor(reason) {
|
|
1749
|
-
super(`Failed to encode tree: ${reason}`);
|
|
1750
|
-
_defineProperty(this, "name", "Tree.EncodeError");
|
|
1751
|
-
}
|
|
1752
|
-
};
|
|
1753
|
-
/**
|
|
1754
|
-
* Error thrown during tree decoding.
|
|
1755
|
-
* Indicates payload corruption, version mismatch, or validation failures.
|
|
1756
|
-
*/
|
|
1757
|
-
var DecodeError = class extends BaseError {
|
|
1758
|
-
constructor(reason) {
|
|
1759
|
-
super(`Failed to decode tree: ${reason}`);
|
|
1760
|
-
_defineProperty(this, "name", "Tree.DecodeError");
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
1532
|
//#endregion
|
|
1765
1533
|
//#region src/core/Offer.ts
|
|
1766
1534
|
var Offer_exports = /* @__PURE__ */ __exportAll({
|
|
1767
|
-
AccountNotSetError: () => AccountNotSetError,
|
|
1768
1535
|
InvalidOfferError: () => InvalidOfferError,
|
|
1769
1536
|
OfferSchema: () => OfferSchema,
|
|
1770
1537
|
Status: () => Status,
|
|
1771
1538
|
consumedEvent: () => consumedEvent,
|
|
1772
|
-
decode: () => decode,
|
|
1539
|
+
decode: () => decode$1,
|
|
1773
1540
|
domain: () => domain,
|
|
1774
|
-
encode: () => encode,
|
|
1775
|
-
from: () => from$
|
|
1541
|
+
encode: () => encode$1,
|
|
1542
|
+
from: () => from$9,
|
|
1776
1543
|
fromSnakeCase: () => fromSnakeCase$1,
|
|
1777
1544
|
hash: () => hash,
|
|
1778
1545
|
obligationId: () => obligationId,
|
|
1779
1546
|
random: () => random$1,
|
|
1780
1547
|
serialize: () => serialize,
|
|
1781
|
-
sign: () => sign,
|
|
1782
|
-
signatureMsg: () => signatureMsg,
|
|
1783
1548
|
toSnakeCase: () => toSnakeCase,
|
|
1784
1549
|
types: () => types
|
|
1785
1550
|
});
|
|
@@ -1832,7 +1597,7 @@ const OfferSchema = () => {
|
|
|
1832
1597
|
* @param input - The offer to create.
|
|
1833
1598
|
* @returns The created offer.
|
|
1834
1599
|
*/
|
|
1835
|
-
function from$
|
|
1600
|
+
function from$9(input) {
|
|
1836
1601
|
try {
|
|
1837
1602
|
return OfferSchema().parse(input);
|
|
1838
1603
|
} catch (error) {
|
|
@@ -1846,7 +1611,7 @@ function from$8(input) {
|
|
|
1846
1611
|
* @returns The created offer.
|
|
1847
1612
|
*/
|
|
1848
1613
|
function fromSnakeCase$1(input) {
|
|
1849
|
-
return from$
|
|
1614
|
+
return from$9(fromSnakeCase$3(input));
|
|
1850
1615
|
}
|
|
1851
1616
|
/**
|
|
1852
1617
|
* Converts an offer to a snake case object.
|
|
@@ -1940,7 +1705,7 @@ function random$1(config) {
|
|
|
1940
1705
|
})
|
|
1941
1706
|
};
|
|
1942
1707
|
})();
|
|
1943
|
-
return from$
|
|
1708
|
+
return from$9({
|
|
1944
1709
|
maker: config?.maker ?? address(),
|
|
1945
1710
|
assets: assetsScaled,
|
|
1946
1711
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
@@ -2068,23 +1833,6 @@ const types = {
|
|
|
2068
1833
|
type: "bytes"
|
|
2069
1834
|
}]
|
|
2070
1835
|
};
|
|
2071
|
-
/**
|
|
2072
|
-
* Signs an array of offers.
|
|
2073
|
-
* @throws {Error} If the wallet account is not set.
|
|
2074
|
-
* @param offers - The offers to sign.
|
|
2075
|
-
* @param wallet - The wallet to sign the offers with.
|
|
2076
|
-
* @returns The signed offers.
|
|
2077
|
-
*/
|
|
2078
|
-
async function sign(offers, wallet) {
|
|
2079
|
-
if (!wallet.account) throw new AccountNotSetError();
|
|
2080
|
-
return wallet.signMessage({
|
|
2081
|
-
account: wallet.account,
|
|
2082
|
-
message: { raw: signatureMsg(offers) }
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
function signatureMsg(offers) {
|
|
2086
|
-
return from$9(offers).root;
|
|
2087
|
-
}
|
|
2088
1836
|
function hash(offer) {
|
|
2089
1837
|
const cached = offer[HASH_CACHE];
|
|
2090
1838
|
if (cached) return cached;
|
|
@@ -2211,7 +1959,7 @@ const OfferAbi = [
|
|
|
2211
1959
|
}]
|
|
2212
1960
|
}
|
|
2213
1961
|
];
|
|
2214
|
-
function encode(offer) {
|
|
1962
|
+
function encode$1(offer) {
|
|
2215
1963
|
return encodeAbiParameters(OfferAbi, [
|
|
2216
1964
|
offer.maker,
|
|
2217
1965
|
offer.assets,
|
|
@@ -2230,14 +1978,14 @@ function encode(offer) {
|
|
|
2230
1978
|
offer.callback
|
|
2231
1979
|
]);
|
|
2232
1980
|
}
|
|
2233
|
-
function decode(data) {
|
|
1981
|
+
function decode$1(data) {
|
|
2234
1982
|
let decoded;
|
|
2235
1983
|
try {
|
|
2236
1984
|
decoded = decodeAbiParameters(OfferAbi, data);
|
|
2237
1985
|
} catch (error) {
|
|
2238
1986
|
throw new InvalidOfferError(error);
|
|
2239
1987
|
}
|
|
2240
|
-
return from$
|
|
1988
|
+
return from$9({
|
|
2241
1989
|
maker: decoded[0],
|
|
2242
1990
|
assets: decoded[1],
|
|
2243
1991
|
obligationUnits: decoded[2],
|
|
@@ -2316,25 +2064,22 @@ var InvalidOfferError = class InvalidOfferError extends BaseError {
|
|
|
2316
2064
|
return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
|
|
2317
2065
|
}
|
|
2318
2066
|
};
|
|
2319
|
-
var AccountNotSetError = class extends BaseError {
|
|
2320
|
-
constructor() {
|
|
2321
|
-
super("Account not set.");
|
|
2322
|
-
_defineProperty(this, "name", "Offer.AccountNotSetError");
|
|
2323
|
-
}
|
|
2324
|
-
};
|
|
2325
2067
|
|
|
2326
2068
|
//#endregion
|
|
2327
2069
|
//#region src/core/Oracle.ts
|
|
2328
2070
|
var Oracle_exports = /* @__PURE__ */ __exportAll({
|
|
2329
2071
|
Conversion: () => Conversion,
|
|
2330
|
-
from: () => from$
|
|
2072
|
+
from: () => from$8,
|
|
2073
|
+
fromCollateral: () => fromCollateral,
|
|
2074
|
+
fromOffer: () => fromOffer,
|
|
2075
|
+
fromOffers: () => fromOffers
|
|
2331
2076
|
});
|
|
2332
2077
|
/**
|
|
2333
2078
|
* Create an Oracle from a plain object.
|
|
2334
2079
|
* @param data - The data to create the oracle from.
|
|
2335
2080
|
* @returns The created oracle.
|
|
2336
2081
|
*/
|
|
2337
|
-
function from$
|
|
2082
|
+
function from$8(data) {
|
|
2338
2083
|
return {
|
|
2339
2084
|
chainId: data.chainId,
|
|
2340
2085
|
address: data.address.toLowerCase(),
|
|
@@ -2342,8 +2087,61 @@ function from$7(data) {
|
|
|
2342
2087
|
blockNumber: data.blockNumber
|
|
2343
2088
|
};
|
|
2344
2089
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2090
|
+
/**
|
|
2091
|
+
* Creates an oracle from a collateral.
|
|
2092
|
+
* @constructor
|
|
2093
|
+
*
|
|
2094
|
+
* @param parameters - {@link fromCollateral.Parameters}
|
|
2095
|
+
* @returns The created oracle. {@link fromCollateral.ReturnType}
|
|
2096
|
+
*/
|
|
2097
|
+
function fromCollateral(parameters) {
|
|
2098
|
+
const { chainId, collateral, blockNumber, price = null } = parameters;
|
|
2099
|
+
return {
|
|
2100
|
+
chainId,
|
|
2101
|
+
address: collateral.oracle.toLowerCase(),
|
|
2102
|
+
price,
|
|
2103
|
+
blockNumber
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Creates oracles from a single offer.
|
|
2108
|
+
* @constructor
|
|
2109
|
+
*
|
|
2110
|
+
* @param parameters - {@link fromOffer.Parameters}
|
|
2111
|
+
* @returns The created oracles. {@link fromOffer.ReturnType}
|
|
2112
|
+
*/
|
|
2113
|
+
function fromOffer(parameters) {
|
|
2114
|
+
const { offer, blockNumber, price = null } = parameters;
|
|
2115
|
+
return fromOffers({
|
|
2116
|
+
offers: [offer],
|
|
2117
|
+
blockNumber,
|
|
2118
|
+
price
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Creates oracles from a list of offers.
|
|
2123
|
+
* @constructor
|
|
2124
|
+
*
|
|
2125
|
+
* @param parameters - {@link fromOffers.Parameters}
|
|
2126
|
+
* @returns The created oracles. {@link fromOffers.ReturnType}
|
|
2127
|
+
*/
|
|
2128
|
+
function fromOffers(parameters) {
|
|
2129
|
+
const { offers, blockNumber, price = null } = parameters;
|
|
2130
|
+
const rowsByKey = /* @__PURE__ */ new Map();
|
|
2131
|
+
for (const offer of offers) for (const collateral of offer.collaterals) {
|
|
2132
|
+
const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();
|
|
2133
|
+
if (rowsByKey.has(key)) continue;
|
|
2134
|
+
rowsByKey.set(key, fromCollateral({
|
|
2135
|
+
chainId: offer.chainId,
|
|
2136
|
+
collateral,
|
|
2137
|
+
blockNumber,
|
|
2138
|
+
price
|
|
2139
|
+
}));
|
|
2140
|
+
}
|
|
2141
|
+
return Array.from(rowsByKey.values());
|
|
2142
|
+
}
|
|
2143
|
+
let Conversion;
|
|
2144
|
+
(function(_Conversion) {
|
|
2347
2145
|
function collateralToLoan(amount, params) {
|
|
2348
2146
|
return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
|
|
2349
2147
|
}
|
|
@@ -2359,7 +2157,7 @@ let Conversion;
|
|
|
2359
2157
|
//#region src/core/Position.ts
|
|
2360
2158
|
var Position_exports = /* @__PURE__ */ __exportAll({
|
|
2361
2159
|
Type: () => Type,
|
|
2362
|
-
from: () => from$
|
|
2160
|
+
from: () => from$7
|
|
2363
2161
|
});
|
|
2364
2162
|
let Type = /* @__PURE__ */ function(Type) {
|
|
2365
2163
|
Type["ERC20"] = "erc20";
|
|
@@ -2372,7 +2170,7 @@ let Type = /* @__PURE__ */ function(Type) {
|
|
|
2372
2170
|
* @param parameters - {@link from.Parameters}
|
|
2373
2171
|
* @returns The created Position. {@link from.ReturnType}
|
|
2374
2172
|
*/
|
|
2375
|
-
function from$
|
|
2173
|
+
function from$7(parameters) {
|
|
2376
2174
|
return {
|
|
2377
2175
|
chainId: parameters.chainId,
|
|
2378
2176
|
contract: parameters.contract.toLowerCase(),
|
|
@@ -2389,7 +2187,7 @@ function from$6(parameters) {
|
|
|
2389
2187
|
var Quote_exports = /* @__PURE__ */ __exportAll({
|
|
2390
2188
|
InvalidQuoteError: () => InvalidQuoteError,
|
|
2391
2189
|
QuoteSchema: () => QuoteSchema,
|
|
2392
|
-
from: () => from$
|
|
2190
|
+
from: () => from$6,
|
|
2393
2191
|
fromSnakeCase: () => fromSnakeCase,
|
|
2394
2192
|
random: () => random
|
|
2395
2193
|
});
|
|
@@ -2410,7 +2208,7 @@ const QuoteSchema = z$1.object({
|
|
|
2410
2208
|
* const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
|
|
2411
2209
|
* ```
|
|
2412
2210
|
*/
|
|
2413
|
-
function from$
|
|
2211
|
+
function from$6(parameters) {
|
|
2414
2212
|
try {
|
|
2415
2213
|
const parsedQuote = QuoteSchema.parse(parameters);
|
|
2416
2214
|
return {
|
|
@@ -2429,7 +2227,7 @@ function from$5(parameters) {
|
|
|
2429
2227
|
* @returns The created quote. {@link fromSnakeCase.ReturnType}
|
|
2430
2228
|
*/
|
|
2431
2229
|
function fromSnakeCase(snake) {
|
|
2432
|
-
return from$
|
|
2230
|
+
return from$6(fromSnakeCase$3(snake));
|
|
2433
2231
|
}
|
|
2434
2232
|
/**
|
|
2435
2233
|
* Generates a random quote.
|
|
@@ -2441,7 +2239,7 @@ function fromSnakeCase(snake) {
|
|
|
2441
2239
|
* ```
|
|
2442
2240
|
*/
|
|
2443
2241
|
function random() {
|
|
2444
|
-
return from$
|
|
2242
|
+
return from$6({
|
|
2445
2243
|
obligationId: id(random$2()),
|
|
2446
2244
|
ask: { price: BigInt(int(1e6)) },
|
|
2447
2245
|
bid: { price: BigInt(int(1e6)) }
|
|
@@ -2464,7 +2262,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
|
2464
2262
|
activate: () => activate,
|
|
2465
2263
|
compute: () => compute,
|
|
2466
2264
|
deactivate: () => deactivate,
|
|
2467
|
-
from: () => from$
|
|
2265
|
+
from: () => from$5,
|
|
2468
2266
|
getFees: () => getFees,
|
|
2469
2267
|
isActivated: () => isActivated
|
|
2470
2268
|
});
|
|
@@ -2490,7 +2288,7 @@ const WAD = 10n ** 18n;
|
|
|
2490
2288
|
* @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
|
|
2491
2289
|
* @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
|
|
2492
2290
|
*/
|
|
2493
|
-
function from$
|
|
2291
|
+
function from$5(activated, fees) {
|
|
2494
2292
|
if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
|
|
2495
2293
|
for (let i = 0; i < 6; i++) {
|
|
2496
2294
|
const fee = fees[i];
|
|
@@ -2595,40 +2393,371 @@ var InvalidFeeError = class extends BaseError {
|
|
|
2595
2393
|
_defineProperty(this, "name", "TradingFee.InvalidFeeError");
|
|
2596
2394
|
}
|
|
2597
2395
|
};
|
|
2598
|
-
/** Error thrown when fees array doesn't have exactly 6 elements. */
|
|
2599
|
-
var InvalidFeesLengthError = class extends BaseError {
|
|
2600
|
-
constructor(length) {
|
|
2601
|
-
super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
|
|
2602
|
-
_defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
|
|
2396
|
+
/** Error thrown when fees array doesn't have exactly 6 elements. */
|
|
2397
|
+
var InvalidFeesLengthError = class extends BaseError {
|
|
2398
|
+
constructor(length) {
|
|
2399
|
+
super(`Invalid fees length: ${length}. Expected exactly 6 fee values.`);
|
|
2400
|
+
_defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
|
|
2401
|
+
}
|
|
2402
|
+
};
|
|
2403
|
+
|
|
2404
|
+
//#endregion
|
|
2405
|
+
//#region src/core/Transfer.ts
|
|
2406
|
+
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$4 });
|
|
2407
|
+
/**
|
|
2408
|
+
* @constructor
|
|
2409
|
+
*
|
|
2410
|
+
* Creates a {@link Transfer}.
|
|
2411
|
+
* @param parameters - {@link from.Parameters}
|
|
2412
|
+
* @returns The created Transfer. {@link from.ReturnType}
|
|
2413
|
+
*
|
|
2414
|
+
* @example
|
|
2415
|
+
* ```ts
|
|
2416
|
+
* const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
|
|
2417
|
+
* ```
|
|
2418
|
+
*/
|
|
2419
|
+
function from$4(parameters) {
|
|
2420
|
+
return {
|
|
2421
|
+
id: parameters.id,
|
|
2422
|
+
chainId: parameters.chainId,
|
|
2423
|
+
contract: parameters.contract.toLowerCase(),
|
|
2424
|
+
from: parameters.from.toLowerCase(),
|
|
2425
|
+
to: parameters.to.toLowerCase(),
|
|
2426
|
+
value: parameters.value,
|
|
2427
|
+
blockNumber: parameters.blockNumber
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
//#endregion
|
|
2432
|
+
//#region src/core/Tree.ts
|
|
2433
|
+
var Tree_exports = /* @__PURE__ */ __exportAll({
|
|
2434
|
+
DecodeError: () => DecodeError,
|
|
2435
|
+
EncodeError: () => EncodeError,
|
|
2436
|
+
SignatureDomainError: () => SignatureDomainError,
|
|
2437
|
+
TreeError: () => TreeError,
|
|
2438
|
+
VERSION: () => VERSION,
|
|
2439
|
+
decode: () => decode,
|
|
2440
|
+
encode: () => encode,
|
|
2441
|
+
encodeUnsigned: () => encodeUnsigned,
|
|
2442
|
+
from: () => from$3,
|
|
2443
|
+
proofs: () => proofs,
|
|
2444
|
+
signatureDomain: () => signatureDomain,
|
|
2445
|
+
signatureTypes: () => signatureTypes
|
|
2446
|
+
});
|
|
2447
|
+
const VERSION = 1;
|
|
2448
|
+
/**
|
|
2449
|
+
* EIP-712 types for signing the tree root (Root(bytes32 root)).
|
|
2450
|
+
*/
|
|
2451
|
+
const signatureTypes = {
|
|
2452
|
+
EIP712Domain: [{
|
|
2453
|
+
name: "chainId",
|
|
2454
|
+
type: "uint256"
|
|
2455
|
+
}, {
|
|
2456
|
+
name: "verifyingContract",
|
|
2457
|
+
type: "address"
|
|
2458
|
+
}],
|
|
2459
|
+
Root: [{
|
|
2460
|
+
name: "root",
|
|
2461
|
+
type: "bytes32"
|
|
2462
|
+
}]
|
|
2463
|
+
};
|
|
2464
|
+
const normalizeHash = (hash) => hash.toLowerCase();
|
|
2465
|
+
/**
|
|
2466
|
+
* Builds a Merkle tree from a list of offers.
|
|
2467
|
+
*
|
|
2468
|
+
* Leaves are the offer `hash` values as `bytes32` and are deterministically
|
|
2469
|
+
* ordered following the StandardMerkleTree leaf ordering so that the resulting
|
|
2470
|
+
* root is stable regardless of the input order.
|
|
2471
|
+
*
|
|
2472
|
+
* @param offers - Offers to include in the tree.
|
|
2473
|
+
* @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
|
|
2474
|
+
* @throws {TreeError} If tree building fails due to offer inconsistencies.
|
|
2475
|
+
*/
|
|
2476
|
+
const from$3 = (offers) => {
|
|
2477
|
+
const leaves = offers.map((offer) => [hash(offer)]);
|
|
2478
|
+
const tree = StandardMerkleTree.of(leaves, ["bytes32"]);
|
|
2479
|
+
const orderedOffers = orderOffers(tree, offers);
|
|
2480
|
+
return Object.assign(tree, { offers: orderedOffers });
|
|
2481
|
+
};
|
|
2482
|
+
const orderOffers = (tree, offers) => {
|
|
2483
|
+
const offerByHash = /* @__PURE__ */ new Map();
|
|
2484
|
+
for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
|
|
2485
|
+
const entries = tree.dump().values.map((value) => {
|
|
2486
|
+
const hash = normalizeHash(value.value[0]);
|
|
2487
|
+
const offer = offerByHash.get(hash);
|
|
2488
|
+
if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
|
|
2489
|
+
return {
|
|
2490
|
+
offer,
|
|
2491
|
+
treeIndex: value.treeIndex
|
|
2492
|
+
};
|
|
2493
|
+
});
|
|
2494
|
+
entries.sort((a, b) => b.treeIndex - a.treeIndex);
|
|
2495
|
+
return entries.map((item) => item.offer);
|
|
2496
|
+
};
|
|
2497
|
+
/**
|
|
2498
|
+
* Generates merkle proofs for all offers in a tree.
|
|
2499
|
+
*
|
|
2500
|
+
* Each proof allows independent verification that an offer is included in the tree
|
|
2501
|
+
* without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
|
|
2502
|
+
*
|
|
2503
|
+
* @param tree - The {@link Tree} to generate proofs for.
|
|
2504
|
+
* @returns Array of proofs - {@link Proof}
|
|
2505
|
+
*/
|
|
2506
|
+
const proofs = (tree) => {
|
|
2507
|
+
return tree.offers.map((offer) => {
|
|
2508
|
+
return {
|
|
2509
|
+
offer,
|
|
2510
|
+
path: tree.getProof([hash(offer)])
|
|
2511
|
+
};
|
|
2512
|
+
});
|
|
2513
|
+
};
|
|
2514
|
+
/**
|
|
2515
|
+
* Normalizes a Root signature domain (BigInt chain id, lowercase address).
|
|
2516
|
+
* @throws {SignatureDomainError} When the domain is invalid.
|
|
2517
|
+
*/
|
|
2518
|
+
const signatureDomain = (domain) => {
|
|
2519
|
+
return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));
|
|
2520
|
+
};
|
|
2521
|
+
const normalizeSignatureDomain = (domain, errorFactory) => {
|
|
2522
|
+
let chainId;
|
|
2523
|
+
try {
|
|
2524
|
+
chainId = typeof domain.chainId === "bigint" ? domain.chainId : BigInt(domain.chainId);
|
|
2525
|
+
} catch {
|
|
2526
|
+
throw errorFactory("invalid chainId");
|
|
2527
|
+
}
|
|
2528
|
+
if (chainId < 0n) throw errorFactory("invalid chainId");
|
|
2529
|
+
if (!isAddress(domain.verifyingContract)) throw errorFactory("invalid verifyingContract");
|
|
2530
|
+
return {
|
|
2531
|
+
chainId,
|
|
2532
|
+
verifyingContract: domain.verifyingContract.toLowerCase()
|
|
2533
|
+
};
|
|
2534
|
+
};
|
|
2535
|
+
const assertHex = (value, expectedBytes, name, errorFactory = (reason) => new DecodeError(reason)) => {
|
|
2536
|
+
if (typeof value !== "string" || !isHex(value)) throw errorFactory(`${name} is not a valid hex string`);
|
|
2537
|
+
if (hexToBytes(value).length !== expectedBytes) throw errorFactory(`${name}: expected ${expectedBytes} bytes`);
|
|
2538
|
+
};
|
|
2539
|
+
const verifySignatureAndRecoverAddress = async (params) => {
|
|
2540
|
+
const { root, signature, domain, errorFactory } = params;
|
|
2541
|
+
assertHex(root, 32, "root", errorFactory);
|
|
2542
|
+
assertHex(signature, 65, "signature", errorFactory);
|
|
2543
|
+
const hash = hashTypedData({
|
|
2544
|
+
domain,
|
|
2545
|
+
types: signatureTypes,
|
|
2546
|
+
primaryType: "Root",
|
|
2547
|
+
message: { root }
|
|
2548
|
+
});
|
|
2549
|
+
try {
|
|
2550
|
+
return await recoverAddress({
|
|
2551
|
+
hash,
|
|
2552
|
+
signature
|
|
2553
|
+
});
|
|
2554
|
+
} catch {
|
|
2555
|
+
throw errorFactory("signature recovery failed");
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
/**
|
|
2559
|
+
* Encodes a merkle tree with signature into hex calldata for onchain broadcast.
|
|
2560
|
+
*
|
|
2561
|
+
* Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
|
|
2562
|
+
* - `{vv}`: 1-byte version (currently 0x01)
|
|
2563
|
+
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
2564
|
+
* - `{root}`: 32-byte merkle root
|
|
2565
|
+
* - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)
|
|
2566
|
+
*
|
|
2567
|
+
* Validates signature authenticity and root integrity before encoding.
|
|
2568
|
+
*
|
|
2569
|
+
* @example
|
|
2570
|
+
* ```typescript
|
|
2571
|
+
* const tree = Tree.from(offers);
|
|
2572
|
+
* const signature = await wallet.signTypedData({
|
|
2573
|
+
* account: wallet.account,
|
|
2574
|
+
* domain: Tree.signatureDomain({ chainId, verifyingContract }),
|
|
2575
|
+
* types: Tree.signatureTypes,
|
|
2576
|
+
* primaryType: "Root",
|
|
2577
|
+
* message: { root: tree.root },
|
|
2578
|
+
* });
|
|
2579
|
+
* const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });
|
|
2580
|
+
* await broadcast(calldata);
|
|
2581
|
+
* ```
|
|
2582
|
+
*
|
|
2583
|
+
* @example
|
|
2584
|
+
* Manual construction (for advanced users):
|
|
2585
|
+
* ```typescript
|
|
2586
|
+
* const tree = Tree.from(offers);
|
|
2587
|
+
* const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
|
|
2588
|
+
* const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
|
|
2589
|
+
* const signature = await wallet.signTypedData({
|
|
2590
|
+
* account: wallet.account,
|
|
2591
|
+
* domain: Tree.signatureDomain({ chainId, verifyingContract }),
|
|
2592
|
+
* types: Tree.signatureTypes,
|
|
2593
|
+
* primaryType: "Root",
|
|
2594
|
+
* message: { root: tree.root },
|
|
2595
|
+
* });
|
|
2596
|
+
* const calldata = `${partial}${signature.slice(2)}`;
|
|
2597
|
+
* ```
|
|
2598
|
+
*
|
|
2599
|
+
* @param tree - Merkle tree of offers
|
|
2600
|
+
* @param signature - EIP-712 signature over Root(bytes32 root)
|
|
2601
|
+
* @param domain - EIP-712 domain with chain id and verifying contract
|
|
2602
|
+
* @returns Hex-encoded calldata ready for onchain broadcast
|
|
2603
|
+
* @throws {EncodeError} If signature verification fails or root mismatch
|
|
2604
|
+
*/
|
|
2605
|
+
const encode = async (tree, signature, domain) => {
|
|
2606
|
+
const errorFactory = (reason) => new EncodeError(reason);
|
|
2607
|
+
const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
|
|
2608
|
+
validateTreeForEncoding(tree, normalizedDomain);
|
|
2609
|
+
await verifySignatureAndRecoverAddress({
|
|
2610
|
+
root: tree.root,
|
|
2611
|
+
signature,
|
|
2612
|
+
domain: normalizedDomain,
|
|
2613
|
+
errorFactory
|
|
2614
|
+
});
|
|
2615
|
+
const unsigned = encodeUnsignedBytes(tree);
|
|
2616
|
+
const sigBytes = hexToBytes(signature);
|
|
2617
|
+
const encoded = new Uint8Array(unsigned.length + sigBytes.length);
|
|
2618
|
+
encoded.set(unsigned, 0);
|
|
2619
|
+
encoded.set(sigBytes, unsigned.length);
|
|
2620
|
+
return bytesToHex(encoded);
|
|
2621
|
+
};
|
|
2622
|
+
/**
|
|
2623
|
+
* Encodes a merkle tree without a signature into hex payload for client-side signing.
|
|
2624
|
+
*
|
|
2625
|
+
* Layout: `0x{vv}{gzip([...offers])}{root}` where:
|
|
2626
|
+
* - `{vv}`: 1-byte version (currently 0x01)
|
|
2627
|
+
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
2628
|
+
* - `{root}`: 32-byte merkle root
|
|
2629
|
+
*
|
|
2630
|
+
* Validates root integrity before encoding.
|
|
2631
|
+
*
|
|
2632
|
+
* @param tree - Merkle tree of offers
|
|
2633
|
+
* @returns Hex-encoded unsigned payload
|
|
2634
|
+
* @throws {EncodeError} If root mismatch
|
|
2635
|
+
*/
|
|
2636
|
+
const encodeUnsigned = (tree) => {
|
|
2637
|
+
validateTreeForEncoding(tree);
|
|
2638
|
+
return bytesToHex(encodeUnsignedBytes(tree));
|
|
2639
|
+
};
|
|
2640
|
+
const validateTreeForEncoding = (tree, domain) => {
|
|
2641
|
+
if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
|
|
2642
|
+
const computed = from$3(tree.offers);
|
|
2643
|
+
if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
|
|
2644
|
+
if (domain) {
|
|
2645
|
+
const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);
|
|
2646
|
+
if (mismatched) throw new EncodeError(`chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`);
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
const encodeUnsignedBytes = (tree) => {
|
|
2650
|
+
const offersPayload = tree.offers.map(serialize);
|
|
2651
|
+
const compressed = gzip(JSON.stringify(offersPayload));
|
|
2652
|
+
const rootBytes = hexToBytes(tree.root);
|
|
2653
|
+
const encoded = new Uint8Array(1 + compressed.length + 32);
|
|
2654
|
+
encoded[0] = VERSION;
|
|
2655
|
+
encoded.set(compressed, 1);
|
|
2656
|
+
encoded.set(rootBytes, 1 + compressed.length);
|
|
2657
|
+
return encoded;
|
|
2658
|
+
};
|
|
2659
|
+
/**
|
|
2660
|
+
* Decodes hex calldata into a validated merkle tree.
|
|
2661
|
+
*
|
|
2662
|
+
* Validates signature before decompression for fail-fast rejection of invalid payloads.
|
|
2663
|
+
* Returns the tree with separately validated signature and recovered signer address.
|
|
2664
|
+
*
|
|
2665
|
+
* Validation order:
|
|
2666
|
+
* 1. Version check
|
|
2667
|
+
* 2. Signature verification (fail-fast, before decompression)
|
|
2668
|
+
* 3. Decompression (only if signature valid)
|
|
2669
|
+
* 4. Root verification (computed from offers vs embedded root)
|
|
2670
|
+
*
|
|
2671
|
+
* @example
|
|
2672
|
+
* ```typescript
|
|
2673
|
+
* const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });
|
|
2674
|
+
* console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
|
|
2675
|
+
* ```
|
|
2676
|
+
*
|
|
2677
|
+
* @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
|
|
2678
|
+
* @param domain - EIP-712 domain with chain id and verifying contract
|
|
2679
|
+
* @returns Validated tree, signature, and recovered signer address
|
|
2680
|
+
* @throws {DecodeError} If version invalid, signature invalid, or root mismatch
|
|
2681
|
+
*/
|
|
2682
|
+
const decode = async (encoded, domain) => {
|
|
2683
|
+
const errorFactory = (reason) => new DecodeError(reason);
|
|
2684
|
+
const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
|
|
2685
|
+
const bytes = hexToBytes(encoded);
|
|
2686
|
+
if (bytes.length < 98) throw new DecodeError("payload too short");
|
|
2687
|
+
const version = bytes[0];
|
|
2688
|
+
if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
|
|
2689
|
+
const signature = bytesToHex(bytes.slice(-65));
|
|
2690
|
+
const root = bytesToHex(bytes.slice(-97, -65));
|
|
2691
|
+
assertHex(root, 32, "root");
|
|
2692
|
+
assertHex(signature, 65, "signature");
|
|
2693
|
+
const signer = await verifySignatureAndRecoverAddress({
|
|
2694
|
+
root,
|
|
2695
|
+
signature,
|
|
2696
|
+
domain: normalizedDomain,
|
|
2697
|
+
errorFactory
|
|
2698
|
+
});
|
|
2699
|
+
const compressed = bytes.slice(1, -97);
|
|
2700
|
+
let decoded;
|
|
2701
|
+
try {
|
|
2702
|
+
decoded = ungzip(compressed, { to: "string" });
|
|
2703
|
+
} catch {
|
|
2704
|
+
throw new DecodeError("decompression failed");
|
|
2705
|
+
}
|
|
2706
|
+
let rawOffers;
|
|
2707
|
+
try {
|
|
2708
|
+
rawOffers = JSON.parse(decoded);
|
|
2709
|
+
} catch {
|
|
2710
|
+
throw new DecodeError("JSON parse failed");
|
|
2711
|
+
}
|
|
2712
|
+
const tree = from$3(rawOffers.map((o) => OfferSchema().parse(o)));
|
|
2713
|
+
if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
|
|
2714
|
+
const chainIdMismatch = tree.offers.find((offer) => BigInt(offer.chainId) !== normalizedDomain.chainId);
|
|
2715
|
+
if (chainIdMismatch) throw new DecodeError(`chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`);
|
|
2716
|
+
return {
|
|
2717
|
+
tree,
|
|
2718
|
+
signature,
|
|
2719
|
+
signer
|
|
2720
|
+
};
|
|
2721
|
+
};
|
|
2722
|
+
/**
|
|
2723
|
+
* Error thrown during tree building operations.
|
|
2724
|
+
* Indicates structural issues with the tree (missing offers, inconsistent state).
|
|
2725
|
+
*/
|
|
2726
|
+
var TreeError = class extends BaseError {
|
|
2727
|
+
constructor(reason) {
|
|
2728
|
+
super(`Tree error: ${reason}`);
|
|
2729
|
+
_defineProperty(this, "name", "Tree.TreeError");
|
|
2730
|
+
}
|
|
2731
|
+
};
|
|
2732
|
+
/**
|
|
2733
|
+
* Error thrown during tree encoding.
|
|
2734
|
+
* Indicates validation failures (signature, root mismatch, mixed makers).
|
|
2735
|
+
*/
|
|
2736
|
+
var EncodeError = class extends BaseError {
|
|
2737
|
+
constructor(reason) {
|
|
2738
|
+
super(`Failed to encode tree: ${reason}`);
|
|
2739
|
+
_defineProperty(this, "name", "Tree.EncodeError");
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
/**
|
|
2743
|
+
* Error thrown during tree decoding.
|
|
2744
|
+
* Indicates payload corruption, version mismatch, or validation failures.
|
|
2745
|
+
*/
|
|
2746
|
+
var DecodeError = class extends BaseError {
|
|
2747
|
+
constructor(reason) {
|
|
2748
|
+
super(`Failed to decode tree: ${reason}`);
|
|
2749
|
+
_defineProperty(this, "name", "Tree.DecodeError");
|
|
2603
2750
|
}
|
|
2604
2751
|
};
|
|
2605
|
-
|
|
2606
|
-
//#endregion
|
|
2607
|
-
//#region src/core/Transfer.ts
|
|
2608
|
-
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
2609
2752
|
/**
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2612
|
-
* Creates a {@link Transfer}.
|
|
2613
|
-
* @param parameters - {@link from.Parameters}
|
|
2614
|
-
* @returns The created Transfer. {@link from.ReturnType}
|
|
2615
|
-
*
|
|
2616
|
-
* @example
|
|
2617
|
-
* ```ts
|
|
2618
|
-
* const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
|
|
2619
|
-
* ```
|
|
2753
|
+
* Error thrown when an invalid signature domain is supplied.
|
|
2620
2754
|
*/
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
to: parameters.to.toLowerCase(),
|
|
2628
|
-
value: parameters.value,
|
|
2629
|
-
blockNumber: parameters.blockNumber
|
|
2630
|
-
};
|
|
2631
|
-
}
|
|
2755
|
+
var SignatureDomainError = class extends BaseError {
|
|
2756
|
+
constructor(reason) {
|
|
2757
|
+
super(`Invalid signature domain: ${reason}`);
|
|
2758
|
+
_defineProperty(this, "name", "Tree.SignatureDomainError");
|
|
2759
|
+
}
|
|
2760
|
+
};
|
|
2632
2761
|
|
|
2633
2762
|
//#endregion
|
|
2634
2763
|
//#region src/core/types.ts
|
|
@@ -2795,6 +2924,21 @@ const validateOfferExample = {
|
|
|
2795
2924
|
data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
|
|
2796
2925
|
}
|
|
2797
2926
|
};
|
|
2927
|
+
const callbackTypesRequestExample = { callbacks: [{
|
|
2928
|
+
chain_id: 1,
|
|
2929
|
+
addresses: [
|
|
2930
|
+
"0x1111111111111111111111111111111111111111",
|
|
2931
|
+
"0x3333333333333333333333333333333333333333",
|
|
2932
|
+
"0x9999999999999999999999999999999999999999"
|
|
2933
|
+
]
|
|
2934
|
+
}] };
|
|
2935
|
+
const callbackTypesResponseExample = [{
|
|
2936
|
+
chain_id: 1,
|
|
2937
|
+
sell_erc20_callback: ["0x1111111111111111111111111111111111111111"],
|
|
2938
|
+
buy_erc20: ["0x5555555555555555555555555555555555555555"],
|
|
2939
|
+
buy_vault_v1_callback: ["0x3333333333333333333333333333333333333333"],
|
|
2940
|
+
not_supported: ["0x9999999999999999999999999999999999999999"]
|
|
2941
|
+
}];
|
|
2798
2942
|
const routerStatusExample = {
|
|
2799
2943
|
status: "live",
|
|
2800
2944
|
initialized: true,
|
|
@@ -2863,6 +3007,55 @@ __decorate([ApiProperty({
|
|
|
2863
3007
|
type: "string",
|
|
2864
3008
|
example: validateOfferExample.callback.data
|
|
2865
3009
|
})], ValidateCallbackRequest.prototype, "data", void 0);
|
|
3010
|
+
var CallbackTypesChainRequest = class {};
|
|
3011
|
+
__decorate([ApiProperty({
|
|
3012
|
+
type: "number",
|
|
3013
|
+
example: callbackTypesRequestExample.callbacks[0].chain_id
|
|
3014
|
+
})], CallbackTypesChainRequest.prototype, "chain_id", void 0);
|
|
3015
|
+
__decorate([ApiProperty({
|
|
3016
|
+
type: () => [String],
|
|
3017
|
+
example: callbackTypesRequestExample.callbacks[0].addresses
|
|
3018
|
+
})], CallbackTypesChainRequest.prototype, "addresses", void 0);
|
|
3019
|
+
var CallbackTypesRequest = class {};
|
|
3020
|
+
__decorate([ApiProperty({
|
|
3021
|
+
type: () => [CallbackTypesChainRequest],
|
|
3022
|
+
example: callbackTypesRequestExample.callbacks
|
|
3023
|
+
})], CallbackTypesRequest.prototype, "callbacks", void 0);
|
|
3024
|
+
var CallbackTypesChainResponse = class {};
|
|
3025
|
+
__decorate([ApiProperty({
|
|
3026
|
+
type: "number",
|
|
3027
|
+
example: callbackTypesResponseExample[0].chain_id
|
|
3028
|
+
})], CallbackTypesChainResponse.prototype, "chain_id", void 0);
|
|
3029
|
+
__decorate([ApiProperty({
|
|
3030
|
+
type: () => [String],
|
|
3031
|
+
required: false,
|
|
3032
|
+
example: callbackTypesResponseExample[0].buy_vault_v1_callback
|
|
3033
|
+
})], CallbackTypesChainResponse.prototype, "buy_vault_v1_callback", void 0);
|
|
3034
|
+
__decorate([ApiProperty({
|
|
3035
|
+
type: () => [String],
|
|
3036
|
+
required: false,
|
|
3037
|
+
example: callbackTypesResponseExample[0].sell_erc20_callback
|
|
3038
|
+
})], CallbackTypesChainResponse.prototype, "sell_erc20_callback", void 0);
|
|
3039
|
+
__decorate([ApiProperty({
|
|
3040
|
+
type: () => [String],
|
|
3041
|
+
required: false,
|
|
3042
|
+
example: callbackTypesResponseExample[0].buy_erc20
|
|
3043
|
+
})], CallbackTypesChainResponse.prototype, "buy_erc20", void 0);
|
|
3044
|
+
__decorate([ApiProperty({
|
|
3045
|
+
type: () => [String],
|
|
3046
|
+
example: callbackTypesResponseExample[0].not_supported
|
|
3047
|
+
})], CallbackTypesChainResponse.prototype, "not_supported", void 0);
|
|
3048
|
+
var CallbackTypesSuccessResponse = class extends SuccessResponse {};
|
|
3049
|
+
__decorate([ApiProperty({
|
|
3050
|
+
type: "string",
|
|
3051
|
+
nullable: true,
|
|
3052
|
+
example: "maturity:1:1730415600:end_of_next_month"
|
|
3053
|
+
})], CallbackTypesSuccessResponse.prototype, "cursor", void 0);
|
|
3054
|
+
__decorate([ApiProperty({
|
|
3055
|
+
type: () => [CallbackTypesChainResponse],
|
|
3056
|
+
description: "Callback types grouped by chain.",
|
|
3057
|
+
example: callbackTypesResponseExample
|
|
3058
|
+
})], CallbackTypesSuccessResponse.prototype, "data", void 0);
|
|
2866
3059
|
var AskResponse = class {};
|
|
2867
3060
|
__decorate([ApiProperty({
|
|
2868
3061
|
type: "string",
|
|
@@ -3398,6 +3591,28 @@ ValidateController = __decorate([ApiTags("Make"), ApiResponse({
|
|
|
3398
3591
|
description: "Bad Request",
|
|
3399
3592
|
type: BadRequestResponse
|
|
3400
3593
|
})], ValidateController);
|
|
3594
|
+
let CallbacksController = class CallbacksController {
|
|
3595
|
+
async resolveCallbackTypes() {}
|
|
3596
|
+
};
|
|
3597
|
+
__decorate([
|
|
3598
|
+
ApiOperation({
|
|
3599
|
+
methods: ["post"],
|
|
3600
|
+
path: "/v1/callbacks",
|
|
3601
|
+
summary: "Resolve callback types",
|
|
3602
|
+
description: "Returns callback types for callback addresses grouped by chain."
|
|
3603
|
+
}),
|
|
3604
|
+
ApiBody({ type: CallbackTypesRequest }),
|
|
3605
|
+
ApiResponse({
|
|
3606
|
+
status: 200,
|
|
3607
|
+
description: "Success",
|
|
3608
|
+
type: CallbackTypesSuccessResponse
|
|
3609
|
+
})
|
|
3610
|
+
], CallbacksController.prototype, "resolveCallbackTypes", null);
|
|
3611
|
+
CallbacksController = __decorate([ApiTags("Make"), ApiResponse({
|
|
3612
|
+
status: 400,
|
|
3613
|
+
description: "Bad Request",
|
|
3614
|
+
type: BadRequestResponse
|
|
3615
|
+
})], CallbacksController);
|
|
3401
3616
|
let OffersController = class OffersController {
|
|
3402
3617
|
async getOffers() {}
|
|
3403
3618
|
};
|
|
@@ -3519,54 +3734,221 @@ __decorate([
|
|
|
3519
3734
|
})
|
|
3520
3735
|
], HealthController.prototype, "getChainsHealth", null);
|
|
3521
3736
|
HealthController = __decorate([ApiTags("System")], HealthController);
|
|
3522
|
-
const
|
|
3523
|
-
const chainConfigExample = {
|
|
3737
|
+
const configContractsExample = {
|
|
3524
3738
|
chain_id: 505050505,
|
|
3525
|
-
|
|
3526
|
-
|
|
3739
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3740
|
+
name: "mempool"
|
|
3741
|
+
};
|
|
3742
|
+
const configContractsPayloadExample = [
|
|
3743
|
+
{
|
|
3744
|
+
chain_id: 505050505,
|
|
3745
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3746
|
+
name: "mempool"
|
|
3747
|
+
},
|
|
3748
|
+
{
|
|
3749
|
+
chain_id: 505050505,
|
|
3750
|
+
address: "0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d",
|
|
3751
|
+
name: "multicall"
|
|
3752
|
+
},
|
|
3753
|
+
{
|
|
3754
|
+
chain_id: 505050505,
|
|
3755
|
+
address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
3756
|
+
name: "v2"
|
|
3757
|
+
}
|
|
3758
|
+
];
|
|
3759
|
+
const configRulesMaturityExample = {
|
|
3760
|
+
type: "maturity",
|
|
3761
|
+
chain_id: 1,
|
|
3762
|
+
name: "end_of_next_month",
|
|
3763
|
+
timestamp: 1730415600
|
|
3764
|
+
};
|
|
3765
|
+
const configRulesCallbackExample = {
|
|
3766
|
+
type: "callback",
|
|
3767
|
+
chain_id: 1,
|
|
3768
|
+
address: "0x1111111111111111111111111111111111111111",
|
|
3769
|
+
callback_type: "sell_erc20_callback"
|
|
3527
3770
|
};
|
|
3528
|
-
|
|
3771
|
+
const configRulesLoanTokenExample = {
|
|
3772
|
+
type: "loan_token",
|
|
3773
|
+
chain_id: 1,
|
|
3774
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
3775
|
+
};
|
|
3776
|
+
const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
3777
|
+
const configRulesPayloadExample = [
|
|
3778
|
+
configRulesMaturityExample,
|
|
3779
|
+
configRulesCallbackExample,
|
|
3780
|
+
configRulesLoanTokenExample
|
|
3781
|
+
];
|
|
3782
|
+
const configContractNames = [
|
|
3783
|
+
"mempool",
|
|
3784
|
+
"multicall",
|
|
3785
|
+
"v2"
|
|
3786
|
+
];
|
|
3787
|
+
const configContractsCursorExample = "505050505:0xd946246695a9259f3b33a78629026f61b3ab40af";
|
|
3788
|
+
var ConfigContractResponse = class {};
|
|
3789
|
+
__decorate([ApiProperty({
|
|
3790
|
+
type: "number",
|
|
3791
|
+
example: configContractsExample.chain_id
|
|
3792
|
+
})], ConfigContractResponse.prototype, "chain_id", void 0);
|
|
3793
|
+
__decorate([ApiProperty({
|
|
3794
|
+
type: "string",
|
|
3795
|
+
example: configContractsExample.address
|
|
3796
|
+
})], ConfigContractResponse.prototype, "address", void 0);
|
|
3529
3797
|
__decorate([ApiProperty({
|
|
3530
3798
|
type: "string",
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3799
|
+
enum: configContractNames,
|
|
3800
|
+
example: configContractsExample.name
|
|
3801
|
+
})], ConfigContractResponse.prototype, "name", void 0);
|
|
3802
|
+
var ConfigContractsSuccessResponse = class extends SuccessResponse {};
|
|
3803
|
+
__decorate([ApiProperty({
|
|
3804
|
+
type: "string",
|
|
3805
|
+
nullable: true,
|
|
3806
|
+
example: null
|
|
3807
|
+
})], ConfigContractsSuccessResponse.prototype, "cursor", void 0);
|
|
3808
|
+
__decorate([ApiProperty({
|
|
3809
|
+
type: () => [ConfigContractResponse],
|
|
3810
|
+
description: "Indexer contract configuration for all indexed chains.",
|
|
3811
|
+
example: configContractsPayloadExample
|
|
3812
|
+
})], ConfigContractsSuccessResponse.prototype, "data", void 0);
|
|
3813
|
+
var ConfigRulesMeta = class {};
|
|
3814
|
+
__decorate([ApiProperty({
|
|
3815
|
+
type: "string",
|
|
3816
|
+
example: timestampExample
|
|
3817
|
+
})], ConfigRulesMeta.prototype, "timestamp", void 0);
|
|
3818
|
+
__decorate([ApiProperty({
|
|
3819
|
+
type: "string",
|
|
3820
|
+
example: configRulesChecksumExample
|
|
3821
|
+
})], ConfigRulesMeta.prototype, "checksum", void 0);
|
|
3822
|
+
var ConfigRulesRuleResponse = class {};
|
|
3823
|
+
__decorate([ApiProperty({
|
|
3824
|
+
type: "string",
|
|
3825
|
+
example: configRulesMaturityExample.type
|
|
3826
|
+
})], ConfigRulesRuleResponse.prototype, "type", void 0);
|
|
3534
3827
|
__decorate([ApiProperty({
|
|
3535
3828
|
type: "number",
|
|
3536
|
-
example:
|
|
3537
|
-
})],
|
|
3538
|
-
__decorate([ApiProperty({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
|
|
3829
|
+
example: configRulesMaturityExample.chain_id
|
|
3830
|
+
})], ConfigRulesRuleResponse.prototype, "chain_id", void 0);
|
|
3539
3831
|
__decorate([ApiProperty({
|
|
3540
|
-
type:
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3832
|
+
type: "string",
|
|
3833
|
+
example: configRulesMaturityExample.name,
|
|
3834
|
+
required: false
|
|
3835
|
+
})], ConfigRulesRuleResponse.prototype, "name", void 0);
|
|
3836
|
+
__decorate([ApiProperty({
|
|
3837
|
+
type: "number",
|
|
3838
|
+
example: configRulesMaturityExample.timestamp,
|
|
3839
|
+
required: false
|
|
3840
|
+
})], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
|
|
3841
|
+
__decorate([ApiProperty({
|
|
3842
|
+
type: "string",
|
|
3843
|
+
example: configRulesCallbackExample.address,
|
|
3844
|
+
required: false
|
|
3845
|
+
})], ConfigRulesRuleResponse.prototype, "address", void 0);
|
|
3846
|
+
__decorate([ApiProperty({
|
|
3847
|
+
type: "string",
|
|
3848
|
+
example: configRulesCallbackExample.callback_type,
|
|
3849
|
+
required: false
|
|
3850
|
+
})], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
|
|
3851
|
+
var ConfigRulesSuccessResponse = class {};
|
|
3852
|
+
__decorate([ApiProperty({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
|
|
3546
3853
|
__decorate([ApiProperty({
|
|
3547
3854
|
type: "string",
|
|
3548
3855
|
nullable: true,
|
|
3549
3856
|
example: null
|
|
3550
|
-
})],
|
|
3551
|
-
__decorate([ApiProperty({
|
|
3552
|
-
type: () => [
|
|
3553
|
-
description: "
|
|
3554
|
-
example:
|
|
3555
|
-
})],
|
|
3556
|
-
let
|
|
3557
|
-
async
|
|
3857
|
+
})], ConfigRulesSuccessResponse.prototype, "cursor", void 0);
|
|
3858
|
+
__decorate([ApiProperty({
|
|
3859
|
+
type: () => [ConfigRulesRuleResponse],
|
|
3860
|
+
description: "Configured rules returned by the router API.",
|
|
3861
|
+
example: configRulesPayloadExample
|
|
3862
|
+
})], ConfigRulesSuccessResponse.prototype, "data", void 0);
|
|
3863
|
+
let ConfigContractsController = class ConfigContractsController {
|
|
3864
|
+
async getConfigContracts() {}
|
|
3865
|
+
};
|
|
3866
|
+
__decorate([
|
|
3867
|
+
ApiOperation({
|
|
3868
|
+
methods: ["get"],
|
|
3869
|
+
path: "/v1/config/contracts",
|
|
3870
|
+
summary: "Get indexer contract configuration",
|
|
3871
|
+
description: "Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains."
|
|
3872
|
+
}),
|
|
3873
|
+
ApiQuery({
|
|
3874
|
+
name: "cursor",
|
|
3875
|
+
type: "string",
|
|
3876
|
+
required: false,
|
|
3877
|
+
example: configContractsCursorExample,
|
|
3878
|
+
description: "Pagination cursor in chain_id:address format (lowercase address)."
|
|
3879
|
+
}),
|
|
3880
|
+
ApiQuery({
|
|
3881
|
+
name: "limit",
|
|
3882
|
+
type: "number",
|
|
3883
|
+
required: false,
|
|
3884
|
+
example: 1e3,
|
|
3885
|
+
description: "Maximum number of contracts to return (max 1000)."
|
|
3886
|
+
}),
|
|
3887
|
+
ApiQuery({
|
|
3888
|
+
name: "chains",
|
|
3889
|
+
type: ["number"],
|
|
3890
|
+
required: false,
|
|
3891
|
+
example: "1,8453",
|
|
3892
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3893
|
+
style: "form",
|
|
3894
|
+
explode: false
|
|
3895
|
+
}),
|
|
3896
|
+
ApiResponse({
|
|
3897
|
+
status: 200,
|
|
3898
|
+
description: "Success",
|
|
3899
|
+
type: ConfigContractsSuccessResponse
|
|
3900
|
+
})
|
|
3901
|
+
], ConfigContractsController.prototype, "getConfigContracts", null);
|
|
3902
|
+
ConfigContractsController = __decorate([ApiTags("System")], ConfigContractsController);
|
|
3903
|
+
let ConfigRulesController = class ConfigRulesController {
|
|
3904
|
+
async getConfigRules() {}
|
|
3558
3905
|
};
|
|
3559
|
-
__decorate([
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3906
|
+
__decorate([
|
|
3907
|
+
ApiOperation({
|
|
3908
|
+
methods: ["get"],
|
|
3909
|
+
path: "/v1/config/rules",
|
|
3910
|
+
summary: "Get config rules",
|
|
3911
|
+
description: "Returns configured rules for supported chains."
|
|
3912
|
+
}),
|
|
3913
|
+
ApiQuery({
|
|
3914
|
+
name: "cursor",
|
|
3915
|
+
type: "string",
|
|
3916
|
+
required: false,
|
|
3917
|
+
example: "maturity:1:1730415600:end_of_next_month",
|
|
3918
|
+
description: "Pagination cursor in type:chain_id:<value> format."
|
|
3919
|
+
}),
|
|
3920
|
+
ApiQuery({
|
|
3921
|
+
name: "limit",
|
|
3922
|
+
type: "number",
|
|
3923
|
+
required: false,
|
|
3924
|
+
example: 100,
|
|
3925
|
+
description: "Maximum number of rules to return (max 1000)."
|
|
3926
|
+
}),
|
|
3927
|
+
ApiQuery({
|
|
3928
|
+
name: "types",
|
|
3929
|
+
type: ["string"],
|
|
3930
|
+
required: false,
|
|
3931
|
+
example: "maturity,loan_token",
|
|
3932
|
+
description: "Filter by rule types (comma-separated).",
|
|
3933
|
+
style: "form",
|
|
3934
|
+
explode: false
|
|
3935
|
+
}),
|
|
3936
|
+
ApiQuery({
|
|
3937
|
+
name: "chains",
|
|
3938
|
+
type: ["number"],
|
|
3939
|
+
required: false,
|
|
3940
|
+
example: "1,8453",
|
|
3941
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3942
|
+
style: "form",
|
|
3943
|
+
explode: false
|
|
3944
|
+
}),
|
|
3945
|
+
ApiResponse({
|
|
3946
|
+
status: 200,
|
|
3947
|
+
description: "Success",
|
|
3948
|
+
type: ConfigRulesSuccessResponse
|
|
3949
|
+
})
|
|
3950
|
+
], ConfigRulesController.prototype, "getConfigRules", null);
|
|
3951
|
+
ConfigRulesController = __decorate([ApiTags("System")], ConfigRulesController);
|
|
3570
3952
|
let ObligationsController = class ObligationsController {
|
|
3571
3953
|
async getObligations() {}
|
|
3572
3954
|
async getObligation() {}
|
|
@@ -3695,16 +4077,18 @@ UsersController = __decorate([ApiTags("Make"), ApiResponse({
|
|
|
3695
4077
|
description: "Bad Request",
|
|
3696
4078
|
type: BadRequestResponse
|
|
3697
4079
|
})], UsersController);
|
|
3698
|
-
const OpenApi = async (
|
|
3699
|
-
|
|
4080
|
+
const OpenApi = async () => {
|
|
4081
|
+
return await generateDocument({
|
|
3700
4082
|
controllers: [
|
|
3701
4083
|
BooksController,
|
|
3702
|
-
|
|
4084
|
+
ConfigContractsController,
|
|
4085
|
+
ConfigRulesController,
|
|
3703
4086
|
OffersController,
|
|
3704
4087
|
ObligationsController,
|
|
3705
4088
|
HealthController,
|
|
3706
4089
|
UsersController,
|
|
3707
|
-
ValidateController
|
|
4090
|
+
ValidateController,
|
|
4091
|
+
CallbacksController
|
|
3708
4092
|
],
|
|
3709
4093
|
document: {
|
|
3710
4094
|
openapi: "3.1.0",
|
|
@@ -3736,12 +4120,6 @@ const OpenApi = async (options = {}) => {
|
|
|
3736
4120
|
]
|
|
3737
4121
|
}
|
|
3738
4122
|
});
|
|
3739
|
-
if (options.rules && options.rules.length > 0) {
|
|
3740
|
-
const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
|
|
3741
|
-
const validatePath = document.paths?.["/v1/validate"];
|
|
3742
|
-
if (validatePath && "post" in validatePath && validatePath.post) validatePath.post.description = `Validates offers against router validation rules. Returns unsigned payload + root on success, or issues only on validation failure.\n\n**Available validation rules:**\n${rulesDescription}`;
|
|
3743
|
-
}
|
|
3744
|
-
return document;
|
|
3745
4123
|
};
|
|
3746
4124
|
|
|
3747
4125
|
//#endregion
|
|
@@ -3766,6 +4144,10 @@ function from$1(position) {
|
|
|
3766
4144
|
//#region src/api/Schema/requests.ts
|
|
3767
4145
|
const MAX_LIMIT = 100;
|
|
3768
4146
|
const DEFAULT_LIMIT = 20;
|
|
4147
|
+
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
4148
|
+
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
4149
|
+
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
4150
|
+
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
3769
4151
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
3770
4152
|
* Domain layer handles semantic validation of cursor fields. */
|
|
3771
4153
|
function isValidBase64urlJson(val) {
|
|
@@ -3799,6 +4181,43 @@ const PaginationQueryParams = z$1.object({
|
|
|
3799
4181
|
example: 10
|
|
3800
4182
|
})
|
|
3801
4183
|
});
|
|
4184
|
+
const ConfigRuleTypes = z$1.enum([
|
|
4185
|
+
"maturity",
|
|
4186
|
+
"callback",
|
|
4187
|
+
"loan_token"
|
|
4188
|
+
]);
|
|
4189
|
+
const GetConfigRulesQueryParams = z$1.object({
|
|
4190
|
+
cursor: z$1.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
4191
|
+
description: "Pagination cursor in type:chain_id:<value> format",
|
|
4192
|
+
example: "maturity:1:1730415600:end_of_next_month"
|
|
4193
|
+
}),
|
|
4194
|
+
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(CONFIG_RULES_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}` })).optional().default(CONFIG_RULES_DEFAULT_LIMIT).meta({
|
|
4195
|
+
description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,
|
|
4196
|
+
example: 100
|
|
4197
|
+
}),
|
|
4198
|
+
types: csvArray(ConfigRuleTypes).meta({
|
|
4199
|
+
description: "Filter by rule types (comma-separated).",
|
|
4200
|
+
example: "maturity,loan_token"
|
|
4201
|
+
}),
|
|
4202
|
+
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4203
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4204
|
+
example: "1,8453"
|
|
4205
|
+
})
|
|
4206
|
+
});
|
|
4207
|
+
const GetConfigContractsQueryParams = z$1.object({
|
|
4208
|
+
cursor: z$1.string().regex(/^[1-9]\d*:0x[a-fA-F0-9]{40}$/, { message: "Cursor must be in the format chain_id:0x..." }).optional().meta({
|
|
4209
|
+
description: "Pagination cursor in chain_id:address format (lowercase address).",
|
|
4210
|
+
example: "1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4211
|
+
}),
|
|
4212
|
+
limit: z$1.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(z$1.number().max(CONFIG_CONTRACTS_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}` })).optional().default(CONFIG_CONTRACTS_DEFAULT_LIMIT).meta({
|
|
4213
|
+
description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,
|
|
4214
|
+
example: 1e3
|
|
4215
|
+
}),
|
|
4216
|
+
chains: csvArray(z$1.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4217
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4218
|
+
example: "1,8453"
|
|
4219
|
+
})
|
|
4220
|
+
});
|
|
3802
4221
|
const GetOffersQueryParams = z$1.object({
|
|
3803
4222
|
...PaginationQueryParams.shape,
|
|
3804
4223
|
side: z$1.enum(["buy", "sell"]).optional().meta({
|
|
@@ -3901,6 +4320,16 @@ const GetBookParams = z$1.object({
|
|
|
3901
4320
|
})
|
|
3902
4321
|
});
|
|
3903
4322
|
const ValidateOffersBody = z$1.object({ offers: z$1.array(z$1.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
|
|
4323
|
+
const CallbackTypesBody = z$1.object({ callbacks: z$1.array(z$1.object({
|
|
4324
|
+
chain_id: z$1.number().int().positive().meta({
|
|
4325
|
+
description: "Chain id.",
|
|
4326
|
+
example: 1
|
|
4327
|
+
}),
|
|
4328
|
+
addresses: z$1.array(z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Callback address must be a valid 20-byte address" }).transform((val) => val.toLowerCase())).meta({
|
|
4329
|
+
description: "Callback contract addresses.",
|
|
4330
|
+
example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
|
|
4331
|
+
})
|
|
4332
|
+
}).strict()) }).strict();
|
|
3904
4333
|
const GetUserPositionsParams = z$1.object({
|
|
3905
4334
|
...PaginationQueryParams.shape,
|
|
3906
4335
|
user_address: z$1.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
|
|
@@ -3912,11 +4341,14 @@ const schemas = {
|
|
|
3912
4341
|
get_health: HealthQueryParams,
|
|
3913
4342
|
get_health_collectors: HealthQueryParams,
|
|
3914
4343
|
get_health_chains: HealthQueryParams,
|
|
4344
|
+
get_config_contracts: GetConfigContractsQueryParams,
|
|
4345
|
+
get_config_rules: GetConfigRulesQueryParams,
|
|
3915
4346
|
get_offers: GetOffersQueryParams,
|
|
3916
4347
|
get_obligations: GetObligationsQueryParams,
|
|
3917
4348
|
get_obligation: GetObligationParams,
|
|
3918
4349
|
get_book: GetBookParams,
|
|
3919
4350
|
validate_offers: ValidateOffersBody,
|
|
4351
|
+
callback_types: CallbackTypesBody,
|
|
3920
4352
|
get_user_positions: GetUserPositionsParams
|
|
3921
4353
|
};
|
|
3922
4354
|
function parse(action, query) {
|
|
@@ -3931,11 +4363,13 @@ function safeParse(action, query, error) {
|
|
|
3931
4363
|
var Schema_exports = /* @__PURE__ */ __exportAll({
|
|
3932
4364
|
BookResponse: () => BookResponse_exports,
|
|
3933
4365
|
BooksController: () => BooksController,
|
|
4366
|
+
CallbacksController: () => CallbacksController,
|
|
3934
4367
|
ChainHealth: () => ChainHealth,
|
|
3935
4368
|
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
3936
4369
|
CollectorHealth: () => CollectorHealth,
|
|
3937
4370
|
CollectorsHealthResponse: () => CollectorsHealthResponse,
|
|
3938
|
-
|
|
4371
|
+
ConfigContractsController: () => ConfigContractsController,
|
|
4372
|
+
ConfigRulesController: () => ConfigRulesController,
|
|
3939
4373
|
HealthController: () => HealthController,
|
|
3940
4374
|
ObligationResponse: () => ObligationResponse_exports,
|
|
3941
4375
|
ObligationsController: () => ObligationsController,
|
|
@@ -4141,12 +4575,14 @@ function createHttpClient(config) {
|
|
|
4141
4575
|
const fetchFn = config.fetchFn ?? fetch;
|
|
4142
4576
|
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
4143
4577
|
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
4578
|
+
const baseHeaders = config.originSecret ? { "x-origin-verify": config.originSecret } : void 0;
|
|
4144
4579
|
const request = async (path, init) => {
|
|
4145
4580
|
const controller = new AbortController();
|
|
4146
4581
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4147
4582
|
try {
|
|
4148
4583
|
return await fetchFn(`${baseUrl}${path}`, {
|
|
4149
4584
|
...init,
|
|
4585
|
+
headers: mergeHeaders(baseHeaders, init.headers),
|
|
4150
4586
|
signal: controller.signal
|
|
4151
4587
|
});
|
|
4152
4588
|
} finally {
|
|
@@ -4165,12 +4601,20 @@ function createHttpClient(config) {
|
|
|
4165
4601
|
body: json
|
|
4166
4602
|
};
|
|
4167
4603
|
};
|
|
4168
|
-
const
|
|
4169
|
-
const
|
|
4604
|
+
const getConfigRules = async (query) => {
|
|
4605
|
+
const params = new URLSearchParams();
|
|
4606
|
+
if (query?.cursor) params.set("cursor", query.cursor);
|
|
4607
|
+
if (query?.limit !== void 0) params.set("limit", query.limit.toString());
|
|
4608
|
+
if (query?.types !== void 0) {
|
|
4609
|
+
const typesValue = Array.isArray(query.types) ? query.types.join(",") : query.types;
|
|
4610
|
+
if (typesValue.length > 0) params.set("types", typesValue);
|
|
4611
|
+
}
|
|
4612
|
+
const response = await request(params.size > 0 ? `/v1/config/rules?${params.toString()}` : "/v1/config/rules", { method: "GET" });
|
|
4170
4613
|
const json = await response.json();
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4614
|
+
return {
|
|
4615
|
+
statusCode: response.status,
|
|
4616
|
+
body: json
|
|
4617
|
+
};
|
|
4174
4618
|
};
|
|
4175
4619
|
const isAllowed = async (offers) => {
|
|
4176
4620
|
const { statusCode, body } = await validate({ offers: offers.map((offer) => toSnakeCase(offer)) });
|
|
@@ -4198,13 +4642,31 @@ function createHttpClient(config) {
|
|
|
4198
4642
|
issues: []
|
|
4199
4643
|
};
|
|
4200
4644
|
};
|
|
4645
|
+
const getCallbackTypes = async (requestPayload) => {
|
|
4646
|
+
const response = await request("/v1/callbacks", {
|
|
4647
|
+
method: "POST",
|
|
4648
|
+
headers: { "content-type": "application/json" },
|
|
4649
|
+
body: JSON.stringify(requestPayload)
|
|
4650
|
+
});
|
|
4651
|
+
const json = await response.json();
|
|
4652
|
+
if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
|
|
4653
|
+
if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
|
|
4654
|
+
return json.data;
|
|
4655
|
+
};
|
|
4201
4656
|
return {
|
|
4202
4657
|
baseUrl,
|
|
4203
4658
|
validate,
|
|
4659
|
+
getConfigRules,
|
|
4204
4660
|
isAllowed,
|
|
4205
|
-
|
|
4661
|
+
getCallbackTypes
|
|
4206
4662
|
};
|
|
4207
4663
|
}
|
|
4664
|
+
function mergeHeaders(base, extra) {
|
|
4665
|
+
if (!base && !extra) return void 0;
|
|
4666
|
+
const merged = new Headers(base ?? void 0);
|
|
4667
|
+
if (extra) for (const [key, value] of new Headers(extra).entries()) merged.set(key, value);
|
|
4668
|
+
return merged;
|
|
4669
|
+
}
|
|
4208
4670
|
function normalizeBaseUrl(url) {
|
|
4209
4671
|
return url.trim().replace(/\/+$/, "");
|
|
4210
4672
|
}
|
|
@@ -4300,16 +4762,26 @@ async function run(parameters) {
|
|
|
4300
4762
|
};
|
|
4301
4763
|
}
|
|
4302
4764
|
|
|
4765
|
+
//#endregion
|
|
4766
|
+
//#region src/gatekeeper/Gatekeeper.ts
|
|
4767
|
+
var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
4768
|
+
/**
|
|
4769
|
+
* Create a gatekeeper instance with the provided rules.
|
|
4770
|
+
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
4771
|
+
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
4772
|
+
*/
|
|
4773
|
+
function create(parameters) {
|
|
4774
|
+
const { rules } = parameters;
|
|
4775
|
+
return { isAllowed: async (offers) => {
|
|
4776
|
+
return await run({
|
|
4777
|
+
items: offers,
|
|
4778
|
+
rules
|
|
4779
|
+
});
|
|
4780
|
+
} };
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4303
4783
|
//#endregion
|
|
4304
4784
|
//#region src/gatekeeper/GateConfig.ts
|
|
4305
|
-
var GateConfig_exports = /* @__PURE__ */ __exportAll({
|
|
4306
|
-
assets: () => assets,
|
|
4307
|
-
configs: () => configs,
|
|
4308
|
-
getCallback: () => getCallback,
|
|
4309
|
-
getCallbackAddresses: () => getCallbackAddresses,
|
|
4310
|
-
getCallbackType: () => getCallbackType,
|
|
4311
|
-
getCallbackTypeAddresses: () => getCallbackTypeAddresses
|
|
4312
|
-
});
|
|
4313
4785
|
/**
|
|
4314
4786
|
* Returns the callback configuration for a given chain and callback type, if it exists.
|
|
4315
4787
|
*
|
|
@@ -4332,17 +4804,6 @@ function getCallbackType(chain, address) {
|
|
|
4332
4804
|
return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
|
|
4333
4805
|
}
|
|
4334
4806
|
/**
|
|
4335
|
-
* Returns the callback addresses for a given chain and callback type, if it exists.
|
|
4336
|
-
* @param chain - Chain name for which to read the validation configuration
|
|
4337
|
-
* @param type - Callback type to retrieve
|
|
4338
|
-
* @returns The matching callback addresses or an empty array if not configured
|
|
4339
|
-
*/
|
|
4340
|
-
function getCallbackTypeAddresses(chain, type) {
|
|
4341
|
-
if (type === Type$1.BuyWithEmptyCallback) return [];
|
|
4342
|
-
const match = configs[chain].callbacks?.find((c) => c.type === type);
|
|
4343
|
-
return match && "addresses" in match ? match.addresses : [];
|
|
4344
|
-
}
|
|
4345
|
-
/**
|
|
4346
4807
|
* Returns the list of allowed non-empty callback addresses for a chain.
|
|
4347
4808
|
*
|
|
4348
4809
|
* @param chain - Chain name
|
|
@@ -4441,30 +4902,6 @@ const configs = {
|
|
|
4441
4902
|
}
|
|
4442
4903
|
};
|
|
4443
4904
|
|
|
4444
|
-
//#endregion
|
|
4445
|
-
//#region src/gatekeeper/Gatekeeper.ts
|
|
4446
|
-
var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
4447
|
-
/**
|
|
4448
|
-
* Create a gatekeeper instance with the provided rules.
|
|
4449
|
-
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
4450
|
-
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
4451
|
-
*/
|
|
4452
|
-
function create(parameters) {
|
|
4453
|
-
const { rules } = parameters;
|
|
4454
|
-
return {
|
|
4455
|
-
isAllowed: async (offers) => {
|
|
4456
|
-
return await run({
|
|
4457
|
-
items: offers,
|
|
4458
|
-
rules
|
|
4459
|
-
});
|
|
4460
|
-
},
|
|
4461
|
-
getRules: async () => rules.map((rule) => ({
|
|
4462
|
-
name: rule.name,
|
|
4463
|
-
description: rule.description
|
|
4464
|
-
}))
|
|
4465
|
-
};
|
|
4466
|
-
}
|
|
4467
|
-
|
|
4468
4905
|
//#endregion
|
|
4469
4906
|
//#region src/gatekeeper/Rules.ts
|
|
4470
4907
|
var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -4665,6 +5102,7 @@ function from(parameters) {
|
|
|
4665
5102
|
const config = {
|
|
4666
5103
|
client: parameters.client,
|
|
4667
5104
|
mempoolAddress: parameters.mempoolAddress,
|
|
5105
|
+
morphoAddress: parameters.morphoAddress,
|
|
4668
5106
|
blockWindow: parameters.blockWindow
|
|
4669
5107
|
};
|
|
4670
5108
|
return {
|
|
@@ -4682,11 +5120,18 @@ function from(parameters) {
|
|
|
4682
5120
|
*/
|
|
4683
5121
|
async function add(config, offers) {
|
|
4684
5122
|
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
4685
|
-
const tree = from$
|
|
5123
|
+
const tree = from$3(offers.map((o) => from$9(o)));
|
|
4686
5124
|
const chainId = await getChainId(config.client);
|
|
4687
5125
|
for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
|
|
4688
|
-
const
|
|
4689
|
-
const
|
|
5126
|
+
const signatureDomain$1 = resolveSignatureDomain(config, chainId);
|
|
5127
|
+
const signature = await config.client.signTypedData({
|
|
5128
|
+
account: config.client.account,
|
|
5129
|
+
domain: signatureDomain(signatureDomain$1),
|
|
5130
|
+
types: signatureTypes,
|
|
5131
|
+
primaryType: "Root",
|
|
5132
|
+
message: { root: tree.root }
|
|
5133
|
+
});
|
|
5134
|
+
const encoded = await encode(tree, signature, signatureDomain$1);
|
|
4690
5135
|
try {
|
|
4691
5136
|
return await config.client.sendTransaction({
|
|
4692
5137
|
chain: config.client.chain,
|
|
@@ -4725,6 +5170,7 @@ const getChainId = async (client) => {
|
|
|
4725
5170
|
};
|
|
4726
5171
|
async function* streamOffers(config, parameters) {
|
|
4727
5172
|
const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
|
|
5173
|
+
const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));
|
|
4728
5174
|
const stream = streamLogs({
|
|
4729
5175
|
client: config.client.extend(publicActions),
|
|
4730
5176
|
contractAddress: config.mempoolAddress,
|
|
@@ -4756,7 +5202,7 @@ async function* streamOffers(config, parameters) {
|
|
|
4756
5202
|
if (!log) continue;
|
|
4757
5203
|
const [payload] = decodeAbiParameters([{ type: "bytes" }], log.data);
|
|
4758
5204
|
try {
|
|
4759
|
-
const { tree } = await decode
|
|
5205
|
+
const { tree } = await decode(payload, signatureDomain);
|
|
4760
5206
|
for (const offer of tree.offers) {
|
|
4761
5207
|
if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
|
|
4762
5208
|
offers.push(offer);
|
|
@@ -4791,6 +5237,21 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
4791
5237
|
_defineProperty(this, "name", "Mempool.ChainIdMismatchError");
|
|
4792
5238
|
}
|
|
4793
5239
|
};
|
|
5240
|
+
const resolveSignatureDomain = (config, chainId) => {
|
|
5241
|
+
const chain = config.client.chain;
|
|
5242
|
+
const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
|
|
5243
|
+
if (!verifyingContract || verifyingContract.toLowerCase() === zeroAddress) throw new MissingMorphoAddressError();
|
|
5244
|
+
return {
|
|
5245
|
+
chainId,
|
|
5246
|
+
verifyingContract
|
|
5247
|
+
};
|
|
5248
|
+
};
|
|
5249
|
+
var MissingMorphoAddressError = class extends BaseError {
|
|
5250
|
+
constructor() {
|
|
5251
|
+
super("Morpho address is required to verify root signatures (zero address is invalid).");
|
|
5252
|
+
_defineProperty(this, "name", "Mempool.MissingMorphoAddressError");
|
|
5253
|
+
}
|
|
5254
|
+
};
|
|
4794
5255
|
|
|
4795
5256
|
//#endregion
|
|
4796
5257
|
//#region src/mempool/MempoolClient.ts
|
|
@@ -4955,5 +5416,5 @@ var utils_exports = /* @__PURE__ */ __exportAll({
|
|
|
4955
5416
|
});
|
|
4956
5417
|
|
|
4957
5418
|
//#endregion
|
|
4958
|
-
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainRegistry_exports as ChainRegistry, Collateral_exports as Collateral, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format,
|
|
5419
|
+
export { Abi_exports as Abi, BrandTypeId, Callback_exports as Callback, Chain_exports as Chain, ChainRegistry_exports as ChainRegistry, Collateral_exports as Collateral, ERC4626_exports as ERC4626, Errors_exports as Errors, Format_exports as Format, Gatekeeper_exports as Gatekeeper, Client_exports as GatekeeperClient, LLTV_exports as LLTV, Liquidity_exports as Liquidity, Maturity_exports as Maturity, MempoolClient_exports as Mempool, Obligation_exports as Obligation, Offer_exports as Offer, Oracle_exports as Oracle, Position_exports as Position, Quote_exports as Quote, Schema_exports as RouterApi, Client_exports$1 as RouterClient, Rules_exports as Rules, time_exports as Time, TradingFee_exports as TradingFee, Transfer_exports as Transfer, Tree_exports as Tree, utils_exports as Utils, Gate_exports as Validation, morphoRules };
|
|
4959
5420
|
//# sourceMappingURL=index.browser.mjs.map
|