@morpho-dev/router 0.5.0 → 0.7.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 +2353 -1043
- 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 +540 -169
- package/dist/index.browser.d.mts.map +1 -1
- package/dist/index.browser.d.ts +540 -169
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +956 -411
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +958 -407
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.node.d.mts +628 -187
- package/dist/index.node.d.mts.map +1 -1
- package/dist/index.node.d.ts +627 -186
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +6776 -5605
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +6767 -5602
- package/dist/index.node.mjs.map +1 -1
- package/docs/integrator.md +7 -1
- package/package.json +2 -2
package/dist/index.browser.js
CHANGED
|
@@ -1413,6 +1413,7 @@ var Obligation_exports = /* @__PURE__ */ __exportAll({
|
|
|
1413
1413
|
InvalidObligationError: () => InvalidObligationError,
|
|
1414
1414
|
ObligationSchema: () => ObligationSchema,
|
|
1415
1415
|
from: () => from$10,
|
|
1416
|
+
fromOffer: () => fromOffer$1,
|
|
1416
1417
|
fromSnakeCase: () => fromSnakeCase$2,
|
|
1417
1418
|
id: () => id,
|
|
1418
1419
|
random: () => random$2
|
|
@@ -1541,6 +1542,21 @@ function random$2() {
|
|
|
1541
1542
|
maturity: from$11("end_of_next_quarter")
|
|
1542
1543
|
});
|
|
1543
1544
|
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Creates an obligation from an offer.
|
|
1547
|
+
* @constructor
|
|
1548
|
+
*
|
|
1549
|
+
* @param offer - The offer to create the obligation from.
|
|
1550
|
+
* @returns The created obligation. {@link fromOffer.ReturnType}
|
|
1551
|
+
*/
|
|
1552
|
+
function fromOffer$1(offer) {
|
|
1553
|
+
return from$10({
|
|
1554
|
+
chainId: offer.chainId,
|
|
1555
|
+
loanToken: offer.loanToken,
|
|
1556
|
+
collaterals: offer.collaterals,
|
|
1557
|
+
maturity: offer.maturity
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1544
1560
|
var InvalidObligationError = class extends BaseError {
|
|
1545
1561
|
constructor(error) {
|
|
1546
1562
|
super("Invalid obligation.", { cause: error });
|
|
@@ -1554,273 +1570,22 @@ var CollateralsAreNotSortedError = class extends BaseError {
|
|
|
1554
1570
|
}
|
|
1555
1571
|
};
|
|
1556
1572
|
|
|
1557
|
-
//#endregion
|
|
1558
|
-
//#region src/core/Tree.ts
|
|
1559
|
-
var Tree_exports = /* @__PURE__ */ __exportAll({
|
|
1560
|
-
DecodeError: () => DecodeError,
|
|
1561
|
-
EncodeError: () => EncodeError,
|
|
1562
|
-
TreeError: () => TreeError,
|
|
1563
|
-
VERSION: () => VERSION,
|
|
1564
|
-
decode: () => decode$1,
|
|
1565
|
-
encode: () => encode$1,
|
|
1566
|
-
encodeUnsigned: () => encodeUnsigned,
|
|
1567
|
-
from: () => from$9,
|
|
1568
|
-
proofs: () => proofs
|
|
1569
|
-
});
|
|
1570
|
-
const VERSION = 1;
|
|
1571
|
-
const normalizeHash = (hash) => hash.toLowerCase();
|
|
1572
|
-
/**
|
|
1573
|
-
* Builds a Merkle tree from a list of offers.
|
|
1574
|
-
*
|
|
1575
|
-
* Leaves are the offer `hash` values as `bytes32` and are deterministically
|
|
1576
|
-
* ordered following the StandardMerkleTree leaf ordering so that the resulting
|
|
1577
|
-
* root is stable regardless of the input order.
|
|
1578
|
-
*
|
|
1579
|
-
* @param offers - Offers to include in the tree.
|
|
1580
|
-
* @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
|
|
1581
|
-
* @throws {TreeError} If tree building fails due to offer inconsistencies.
|
|
1582
|
-
*/
|
|
1583
|
-
const from$9 = (offers) => {
|
|
1584
|
-
const leaves = offers.map((offer) => [hash(offer)]);
|
|
1585
|
-
const tree = _openzeppelin_merkle_tree.StandardMerkleTree.of(leaves, ["bytes32"]);
|
|
1586
|
-
const orderedOffers = orderOffers(tree, offers);
|
|
1587
|
-
return Object.assign(tree, { offers: orderedOffers });
|
|
1588
|
-
};
|
|
1589
|
-
const orderOffers = (tree, offers) => {
|
|
1590
|
-
const offerByHash = /* @__PURE__ */ new Map();
|
|
1591
|
-
for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
|
|
1592
|
-
const entries = tree.dump().values.map((value) => {
|
|
1593
|
-
const hash = normalizeHash(value.value[0]);
|
|
1594
|
-
const offer = offerByHash.get(hash);
|
|
1595
|
-
if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
|
|
1596
|
-
return {
|
|
1597
|
-
offer,
|
|
1598
|
-
treeIndex: value.treeIndex
|
|
1599
|
-
};
|
|
1600
|
-
});
|
|
1601
|
-
entries.sort((a, b) => b.treeIndex - a.treeIndex);
|
|
1602
|
-
return entries.map((item) => item.offer);
|
|
1603
|
-
};
|
|
1604
|
-
/**
|
|
1605
|
-
* Generates merkle proofs for all offers in a tree.
|
|
1606
|
-
*
|
|
1607
|
-
* Each proof allows independent verification that an offer is included in the tree
|
|
1608
|
-
* without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
|
|
1609
|
-
*
|
|
1610
|
-
* @param tree - The {@link Tree} to generate proofs for.
|
|
1611
|
-
* @returns Array of proofs - {@link Proof}
|
|
1612
|
-
*/
|
|
1613
|
-
const proofs = (tree) => {
|
|
1614
|
-
return tree.offers.map((offer) => {
|
|
1615
|
-
return {
|
|
1616
|
-
offer,
|
|
1617
|
-
path: tree.getProof([hash(offer)])
|
|
1618
|
-
};
|
|
1619
|
-
});
|
|
1620
|
-
};
|
|
1621
|
-
const assertHex = (value, expectedBytes, name) => {
|
|
1622
|
-
if (typeof value !== "string" || !(0, viem.isHex)(value)) throw new DecodeError(`${name} is not a valid hex string`);
|
|
1623
|
-
if ((0, viem.hexToBytes)(value).length !== expectedBytes) throw new DecodeError(`${name}: expected ${expectedBytes} bytes`);
|
|
1624
|
-
};
|
|
1625
|
-
const verifySignatureAndRecoverAddress = async (params) => {
|
|
1626
|
-
const { root, signature } = params;
|
|
1627
|
-
assertHex(signature, 65, "signature");
|
|
1628
|
-
const hash = (0, viem.hashMessage)({ raw: root });
|
|
1629
|
-
try {
|
|
1630
|
-
return await (0, viem.recoverAddress)({
|
|
1631
|
-
hash,
|
|
1632
|
-
signature
|
|
1633
|
-
});
|
|
1634
|
-
} catch {
|
|
1635
|
-
throw new DecodeError("signature recovery failed");
|
|
1636
|
-
}
|
|
1637
|
-
};
|
|
1638
|
-
/**
|
|
1639
|
-
* Encodes a merkle tree with signature into hex calldata for onchain broadcast.
|
|
1640
|
-
*
|
|
1641
|
-
* Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
|
|
1642
|
-
* - `{vv}`: 1-byte version (currently 0x01)
|
|
1643
|
-
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
1644
|
-
* - `{root}`: 32-byte merkle root
|
|
1645
|
-
* - `{signature}`: 65-byte EIP-191 signature over raw root bytes
|
|
1646
|
-
*
|
|
1647
|
-
* Validates signature authenticity and root integrity before encoding.
|
|
1648
|
-
*
|
|
1649
|
-
* @example
|
|
1650
|
-
* ```typescript
|
|
1651
|
-
* const tree = Tree.from(offers);
|
|
1652
|
-
* const signature = await wallet.signMessage({ message: { raw: tree.root } });
|
|
1653
|
-
* const calldata = await Tree.encode(tree, signature);
|
|
1654
|
-
* await broadcast(calldata);
|
|
1655
|
-
* ```
|
|
1656
|
-
*
|
|
1657
|
-
* @example
|
|
1658
|
-
* Manual construction (for advanced users):
|
|
1659
|
-
* ```typescript
|
|
1660
|
-
* const tree = Tree.from(offers);
|
|
1661
|
-
* const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
|
|
1662
|
-
* const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
|
|
1663
|
-
* const signature = await wallet.signMessage({ message: { raw: tree.root } });
|
|
1664
|
-
* const calldata = `${partial}${signature.slice(2)}`;
|
|
1665
|
-
* ```
|
|
1666
|
-
*
|
|
1667
|
-
* @param tree - Merkle tree of offers
|
|
1668
|
-
* @param signature - EIP-191 signature over raw root bytes
|
|
1669
|
-
* @returns Hex-encoded calldata ready for onchain broadcast
|
|
1670
|
-
* @throws {EncodeError} If signature verification fails or root mismatch
|
|
1671
|
-
*/
|
|
1672
|
-
const encode$1 = async (tree, signature) => {
|
|
1673
|
-
validateTreeForEncoding(tree);
|
|
1674
|
-
await verifySignatureAndRecoverAddress({
|
|
1675
|
-
root: tree.root,
|
|
1676
|
-
signature
|
|
1677
|
-
});
|
|
1678
|
-
const unsigned = encodeUnsignedBytes(tree);
|
|
1679
|
-
const sigBytes = (0, viem.hexToBytes)(signature);
|
|
1680
|
-
const encoded = new Uint8Array(unsigned.length + sigBytes.length);
|
|
1681
|
-
encoded.set(unsigned, 0);
|
|
1682
|
-
encoded.set(sigBytes, unsigned.length);
|
|
1683
|
-
return (0, viem.bytesToHex)(encoded);
|
|
1684
|
-
};
|
|
1685
|
-
/**
|
|
1686
|
-
* Encodes a merkle tree without a signature into hex payload for client-side signing.
|
|
1687
|
-
*
|
|
1688
|
-
* Layout: `0x{vv}{gzip([...offers])}{root}` where:
|
|
1689
|
-
* - `{vv}`: 1-byte version (currently 0x01)
|
|
1690
|
-
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
1691
|
-
* - `{root}`: 32-byte merkle root
|
|
1692
|
-
*
|
|
1693
|
-
* Validates root integrity before encoding.
|
|
1694
|
-
*
|
|
1695
|
-
* @param tree - Merkle tree of offers
|
|
1696
|
-
* @returns Hex-encoded unsigned payload
|
|
1697
|
-
* @throws {EncodeError} If root mismatch
|
|
1698
|
-
*/
|
|
1699
|
-
const encodeUnsigned = (tree) => {
|
|
1700
|
-
validateTreeForEncoding(tree);
|
|
1701
|
-
return (0, viem.bytesToHex)(encodeUnsignedBytes(tree));
|
|
1702
|
-
};
|
|
1703
|
-
const validateTreeForEncoding = (tree) => {
|
|
1704
|
-
if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
|
|
1705
|
-
const computed = from$9(tree.offers);
|
|
1706
|
-
if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
|
|
1707
|
-
};
|
|
1708
|
-
const encodeUnsignedBytes = (tree) => {
|
|
1709
|
-
const offersPayload = tree.offers.map(serialize);
|
|
1710
|
-
const compressed = (0, pako.gzip)(JSON.stringify(offersPayload));
|
|
1711
|
-
const rootBytes = (0, viem.hexToBytes)(tree.root);
|
|
1712
|
-
const encoded = new Uint8Array(1 + compressed.length + 32);
|
|
1713
|
-
encoded[0] = VERSION;
|
|
1714
|
-
encoded.set(compressed, 1);
|
|
1715
|
-
encoded.set(rootBytes, 1 + compressed.length);
|
|
1716
|
-
return encoded;
|
|
1717
|
-
};
|
|
1718
|
-
/**
|
|
1719
|
-
* Decodes hex calldata into a validated merkle tree.
|
|
1720
|
-
*
|
|
1721
|
-
* Validates signature before decompression for fail-fast rejection of invalid payloads.
|
|
1722
|
-
* Returns the tree with separately validated signature and recovered signer address.
|
|
1723
|
-
*
|
|
1724
|
-
* Validation order:
|
|
1725
|
-
* 1. Version check
|
|
1726
|
-
* 2. Signature verification (fail-fast, before decompression)
|
|
1727
|
-
* 3. Decompression (only if signature valid)
|
|
1728
|
-
* 4. Root verification (computed from offers vs embedded root)
|
|
1729
|
-
*
|
|
1730
|
-
* @example
|
|
1731
|
-
* ```typescript
|
|
1732
|
-
* const { tree, signature, signer } = await Tree.decode(calldata);
|
|
1733
|
-
* console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
|
|
1734
|
-
* ```
|
|
1735
|
-
*
|
|
1736
|
-
* @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
|
|
1737
|
-
* @returns Validated tree, signature, and recovered signer address
|
|
1738
|
-
* @throws {DecodeError} If version invalid, signature invalid, or root mismatch
|
|
1739
|
-
*/
|
|
1740
|
-
const decode$1 = async (encoded) => {
|
|
1741
|
-
const bytes = (0, viem.hexToBytes)(encoded);
|
|
1742
|
-
if (bytes.length < 98) throw new DecodeError("payload too short");
|
|
1743
|
-
const version = bytes[0];
|
|
1744
|
-
if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
|
|
1745
|
-
const signature = (0, viem.bytesToHex)(bytes.slice(-65));
|
|
1746
|
-
const root = (0, viem.bytesToHex)(bytes.slice(-97, -65));
|
|
1747
|
-
assertHex(root, 32, "root");
|
|
1748
|
-
assertHex(signature, 65, "signature");
|
|
1749
|
-
const signer = await verifySignatureAndRecoverAddress({
|
|
1750
|
-
root,
|
|
1751
|
-
signature
|
|
1752
|
-
});
|
|
1753
|
-
const compressed = bytes.slice(1, -97);
|
|
1754
|
-
let decoded;
|
|
1755
|
-
try {
|
|
1756
|
-
decoded = (0, pako.ungzip)(compressed, { to: "string" });
|
|
1757
|
-
} catch {
|
|
1758
|
-
throw new DecodeError("decompression failed");
|
|
1759
|
-
}
|
|
1760
|
-
let rawOffers;
|
|
1761
|
-
try {
|
|
1762
|
-
rawOffers = JSON.parse(decoded);
|
|
1763
|
-
} catch {
|
|
1764
|
-
throw new DecodeError("JSON parse failed");
|
|
1765
|
-
}
|
|
1766
|
-
const tree = from$9(rawOffers.map((o) => OfferSchema().parse(o)));
|
|
1767
|
-
if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
|
|
1768
|
-
return {
|
|
1769
|
-
tree,
|
|
1770
|
-
signature,
|
|
1771
|
-
signer
|
|
1772
|
-
};
|
|
1773
|
-
};
|
|
1774
|
-
/**
|
|
1775
|
-
* Error thrown during tree building operations.
|
|
1776
|
-
* Indicates structural issues with the tree (missing offers, inconsistent state).
|
|
1777
|
-
*/
|
|
1778
|
-
var TreeError = class extends BaseError {
|
|
1779
|
-
constructor(reason) {
|
|
1780
|
-
super(`Tree error: ${reason}`);
|
|
1781
|
-
_defineProperty(this, "name", "Tree.TreeError");
|
|
1782
|
-
}
|
|
1783
|
-
};
|
|
1784
|
-
/**
|
|
1785
|
-
* Error thrown during tree encoding.
|
|
1786
|
-
* Indicates validation failures (signature, root mismatch, mixed makers).
|
|
1787
|
-
*/
|
|
1788
|
-
var EncodeError = class extends BaseError {
|
|
1789
|
-
constructor(reason) {
|
|
1790
|
-
super(`Failed to encode tree: ${reason}`);
|
|
1791
|
-
_defineProperty(this, "name", "Tree.EncodeError");
|
|
1792
|
-
}
|
|
1793
|
-
};
|
|
1794
|
-
/**
|
|
1795
|
-
* Error thrown during tree decoding.
|
|
1796
|
-
* Indicates payload corruption, version mismatch, or validation failures.
|
|
1797
|
-
*/
|
|
1798
|
-
var DecodeError = class extends BaseError {
|
|
1799
|
-
constructor(reason) {
|
|
1800
|
-
super(`Failed to decode tree: ${reason}`);
|
|
1801
|
-
_defineProperty(this, "name", "Tree.DecodeError");
|
|
1802
|
-
}
|
|
1803
|
-
};
|
|
1804
|
-
|
|
1805
1573
|
//#endregion
|
|
1806
1574
|
//#region src/core/Offer.ts
|
|
1807
1575
|
var Offer_exports = /* @__PURE__ */ __exportAll({
|
|
1808
|
-
AccountNotSetError: () => AccountNotSetError,
|
|
1809
1576
|
InvalidOfferError: () => InvalidOfferError,
|
|
1810
1577
|
OfferSchema: () => OfferSchema,
|
|
1811
1578
|
Status: () => Status,
|
|
1812
1579
|
consumedEvent: () => consumedEvent,
|
|
1813
|
-
decode: () => decode,
|
|
1580
|
+
decode: () => decode$1,
|
|
1814
1581
|
domain: () => domain,
|
|
1815
|
-
encode: () => encode,
|
|
1816
|
-
from: () => from$
|
|
1582
|
+
encode: () => encode$1,
|
|
1583
|
+
from: () => from$9,
|
|
1817
1584
|
fromSnakeCase: () => fromSnakeCase$1,
|
|
1818
1585
|
hash: () => hash,
|
|
1819
1586
|
obligationId: () => obligationId,
|
|
1820
1587
|
random: () => random$1,
|
|
1821
1588
|
serialize: () => serialize,
|
|
1822
|
-
sign: () => sign,
|
|
1823
|
-
signatureMsg: () => signatureMsg,
|
|
1824
1589
|
toSnakeCase: () => toSnakeCase,
|
|
1825
1590
|
types: () => types
|
|
1826
1591
|
});
|
|
@@ -1873,7 +1638,7 @@ const OfferSchema = () => {
|
|
|
1873
1638
|
* @param input - The offer to create.
|
|
1874
1639
|
* @returns The created offer.
|
|
1875
1640
|
*/
|
|
1876
|
-
function from$
|
|
1641
|
+
function from$9(input) {
|
|
1877
1642
|
try {
|
|
1878
1643
|
return OfferSchema().parse(input);
|
|
1879
1644
|
} catch (error) {
|
|
@@ -1887,7 +1652,7 @@ function from$8(input) {
|
|
|
1887
1652
|
* @returns The created offer.
|
|
1888
1653
|
*/
|
|
1889
1654
|
function fromSnakeCase$1(input) {
|
|
1890
|
-
return from$
|
|
1655
|
+
return from$9(fromSnakeCase$3(input));
|
|
1891
1656
|
}
|
|
1892
1657
|
/**
|
|
1893
1658
|
* Converts an offer to a snake case object.
|
|
@@ -1981,7 +1746,7 @@ function random$1(config) {
|
|
|
1981
1746
|
})
|
|
1982
1747
|
};
|
|
1983
1748
|
})();
|
|
1984
|
-
return from$
|
|
1749
|
+
return from$9({
|
|
1985
1750
|
maker: config?.maker ?? address(),
|
|
1986
1751
|
assets: assetsScaled,
|
|
1987
1752
|
obligationUnits: config?.obligationUnits ?? 0n,
|
|
@@ -2109,23 +1874,6 @@ const types = {
|
|
|
2109
1874
|
type: "bytes"
|
|
2110
1875
|
}]
|
|
2111
1876
|
};
|
|
2112
|
-
/**
|
|
2113
|
-
* Signs an array of offers.
|
|
2114
|
-
* @throws {Error} If the wallet account is not set.
|
|
2115
|
-
* @param offers - The offers to sign.
|
|
2116
|
-
* @param wallet - The wallet to sign the offers with.
|
|
2117
|
-
* @returns The signed offers.
|
|
2118
|
-
*/
|
|
2119
|
-
async function sign(offers, wallet) {
|
|
2120
|
-
if (!wallet.account) throw new AccountNotSetError();
|
|
2121
|
-
return wallet.signMessage({
|
|
2122
|
-
account: wallet.account,
|
|
2123
|
-
message: { raw: signatureMsg(offers) }
|
|
2124
|
-
});
|
|
2125
|
-
}
|
|
2126
|
-
function signatureMsg(offers) {
|
|
2127
|
-
return from$9(offers).root;
|
|
2128
|
-
}
|
|
2129
1877
|
function hash(offer) {
|
|
2130
1878
|
const cached = offer[HASH_CACHE];
|
|
2131
1879
|
if (cached) return cached;
|
|
@@ -2252,7 +2000,7 @@ const OfferAbi = [
|
|
|
2252
2000
|
}]
|
|
2253
2001
|
}
|
|
2254
2002
|
];
|
|
2255
|
-
function encode(offer) {
|
|
2003
|
+
function encode$1(offer) {
|
|
2256
2004
|
return (0, viem.encodeAbiParameters)(OfferAbi, [
|
|
2257
2005
|
offer.maker,
|
|
2258
2006
|
offer.assets,
|
|
@@ -2271,14 +2019,14 @@ function encode(offer) {
|
|
|
2271
2019
|
offer.callback
|
|
2272
2020
|
]);
|
|
2273
2021
|
}
|
|
2274
|
-
function decode(data) {
|
|
2022
|
+
function decode$1(data) {
|
|
2275
2023
|
let decoded;
|
|
2276
2024
|
try {
|
|
2277
2025
|
decoded = (0, viem.decodeAbiParameters)(OfferAbi, data);
|
|
2278
2026
|
} catch (error) {
|
|
2279
2027
|
throw new InvalidOfferError(error);
|
|
2280
2028
|
}
|
|
2281
|
-
return from$
|
|
2029
|
+
return from$9({
|
|
2282
2030
|
maker: decoded[0],
|
|
2283
2031
|
assets: decoded[1],
|
|
2284
2032
|
obligationUnits: decoded[2],
|
|
@@ -2357,25 +2105,22 @@ var InvalidOfferError = class InvalidOfferError extends BaseError {
|
|
|
2357
2105
|
return `Invalid offer. ${InvalidOfferError.formatDetails(this.cause)}`;
|
|
2358
2106
|
}
|
|
2359
2107
|
};
|
|
2360
|
-
var AccountNotSetError = class extends BaseError {
|
|
2361
|
-
constructor() {
|
|
2362
|
-
super("Account not set.");
|
|
2363
|
-
_defineProperty(this, "name", "Offer.AccountNotSetError");
|
|
2364
|
-
}
|
|
2365
|
-
};
|
|
2366
2108
|
|
|
2367
2109
|
//#endregion
|
|
2368
2110
|
//#region src/core/Oracle.ts
|
|
2369
2111
|
var Oracle_exports = /* @__PURE__ */ __exportAll({
|
|
2370
2112
|
Conversion: () => Conversion,
|
|
2371
|
-
from: () => from$
|
|
2113
|
+
from: () => from$8,
|
|
2114
|
+
fromCollateral: () => fromCollateral,
|
|
2115
|
+
fromOffer: () => fromOffer,
|
|
2116
|
+
fromOffers: () => fromOffers
|
|
2372
2117
|
});
|
|
2373
2118
|
/**
|
|
2374
2119
|
* Create an Oracle from a plain object.
|
|
2375
2120
|
* @param data - The data to create the oracle from.
|
|
2376
2121
|
* @returns The created oracle.
|
|
2377
2122
|
*/
|
|
2378
|
-
function from$
|
|
2123
|
+
function from$8(data) {
|
|
2379
2124
|
return {
|
|
2380
2125
|
chainId: data.chainId,
|
|
2381
2126
|
address: data.address.toLowerCase(),
|
|
@@ -2383,8 +2128,61 @@ function from$7(data) {
|
|
|
2383
2128
|
blockNumber: data.blockNumber
|
|
2384
2129
|
};
|
|
2385
2130
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2131
|
+
/**
|
|
2132
|
+
* Creates an oracle from a collateral.
|
|
2133
|
+
* @constructor
|
|
2134
|
+
*
|
|
2135
|
+
* @param parameters - {@link fromCollateral.Parameters}
|
|
2136
|
+
* @returns The created oracle. {@link fromCollateral.ReturnType}
|
|
2137
|
+
*/
|
|
2138
|
+
function fromCollateral(parameters) {
|
|
2139
|
+
const { chainId, collateral, blockNumber, price = null } = parameters;
|
|
2140
|
+
return {
|
|
2141
|
+
chainId,
|
|
2142
|
+
address: collateral.oracle.toLowerCase(),
|
|
2143
|
+
price,
|
|
2144
|
+
blockNumber
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* Creates oracles from a single offer.
|
|
2149
|
+
* @constructor
|
|
2150
|
+
*
|
|
2151
|
+
* @param parameters - {@link fromOffer.Parameters}
|
|
2152
|
+
* @returns The created oracles. {@link fromOffer.ReturnType}
|
|
2153
|
+
*/
|
|
2154
|
+
function fromOffer(parameters) {
|
|
2155
|
+
const { offer, blockNumber, price = null } = parameters;
|
|
2156
|
+
return fromOffers({
|
|
2157
|
+
offers: [offer],
|
|
2158
|
+
blockNumber,
|
|
2159
|
+
price
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Creates oracles from a list of offers.
|
|
2164
|
+
* @constructor
|
|
2165
|
+
*
|
|
2166
|
+
* @param parameters - {@link fromOffers.Parameters}
|
|
2167
|
+
* @returns The created oracles. {@link fromOffers.ReturnType}
|
|
2168
|
+
*/
|
|
2169
|
+
function fromOffers(parameters) {
|
|
2170
|
+
const { offers, blockNumber, price = null } = parameters;
|
|
2171
|
+
const rowsByKey = /* @__PURE__ */ new Map();
|
|
2172
|
+
for (const offer of offers) for (const collateral of offer.collaterals) {
|
|
2173
|
+
const key = `${offer.chainId}-${collateral.oracle}`.toLowerCase();
|
|
2174
|
+
if (rowsByKey.has(key)) continue;
|
|
2175
|
+
rowsByKey.set(key, fromCollateral({
|
|
2176
|
+
chainId: offer.chainId,
|
|
2177
|
+
collateral,
|
|
2178
|
+
blockNumber,
|
|
2179
|
+
price
|
|
2180
|
+
}));
|
|
2181
|
+
}
|
|
2182
|
+
return Array.from(rowsByKey.values());
|
|
2183
|
+
}
|
|
2184
|
+
let Conversion;
|
|
2185
|
+
(function(_Conversion) {
|
|
2388
2186
|
function collateralToLoan(amount, params) {
|
|
2389
2187
|
return amount * params.price / 10n ** 36n * params.lltv / 10n ** 18n;
|
|
2390
2188
|
}
|
|
@@ -2400,7 +2198,7 @@ let Conversion;
|
|
|
2400
2198
|
//#region src/core/Position.ts
|
|
2401
2199
|
var Position_exports = /* @__PURE__ */ __exportAll({
|
|
2402
2200
|
Type: () => Type,
|
|
2403
|
-
from: () => from$
|
|
2201
|
+
from: () => from$7
|
|
2404
2202
|
});
|
|
2405
2203
|
let Type = /* @__PURE__ */ function(Type) {
|
|
2406
2204
|
Type["ERC20"] = "erc20";
|
|
@@ -2413,7 +2211,7 @@ let Type = /* @__PURE__ */ function(Type) {
|
|
|
2413
2211
|
* @param parameters - {@link from.Parameters}
|
|
2414
2212
|
* @returns The created Position. {@link from.ReturnType}
|
|
2415
2213
|
*/
|
|
2416
|
-
function from$
|
|
2214
|
+
function from$7(parameters) {
|
|
2417
2215
|
return {
|
|
2418
2216
|
chainId: parameters.chainId,
|
|
2419
2217
|
contract: parameters.contract.toLowerCase(),
|
|
@@ -2430,7 +2228,7 @@ function from$6(parameters) {
|
|
|
2430
2228
|
var Quote_exports = /* @__PURE__ */ __exportAll({
|
|
2431
2229
|
InvalidQuoteError: () => InvalidQuoteError,
|
|
2432
2230
|
QuoteSchema: () => QuoteSchema,
|
|
2433
|
-
from: () => from$
|
|
2231
|
+
from: () => from$6,
|
|
2434
2232
|
fromSnakeCase: () => fromSnakeCase,
|
|
2435
2233
|
random: () => random
|
|
2436
2234
|
});
|
|
@@ -2451,7 +2249,7 @@ const QuoteSchema = zod.object({
|
|
|
2451
2249
|
* const quote = Quote.from({ obligationId: "0x123", ask: { price: 100n }, bid: { price: 100n } });
|
|
2452
2250
|
* ```
|
|
2453
2251
|
*/
|
|
2454
|
-
function from$
|
|
2252
|
+
function from$6(parameters) {
|
|
2455
2253
|
try {
|
|
2456
2254
|
const parsedQuote = QuoteSchema.parse(parameters);
|
|
2457
2255
|
return {
|
|
@@ -2470,7 +2268,7 @@ function from$5(parameters) {
|
|
|
2470
2268
|
* @returns The created quote. {@link fromSnakeCase.ReturnType}
|
|
2471
2269
|
*/
|
|
2472
2270
|
function fromSnakeCase(snake) {
|
|
2473
|
-
return from$
|
|
2271
|
+
return from$6(fromSnakeCase$3(snake));
|
|
2474
2272
|
}
|
|
2475
2273
|
/**
|
|
2476
2274
|
* Generates a random quote.
|
|
@@ -2482,7 +2280,7 @@ function fromSnakeCase(snake) {
|
|
|
2482
2280
|
* ```
|
|
2483
2281
|
*/
|
|
2484
2282
|
function random() {
|
|
2485
|
-
return from$
|
|
2283
|
+
return from$6({
|
|
2486
2284
|
obligationId: id(random$2()),
|
|
2487
2285
|
ask: { price: BigInt(int(1e6)) },
|
|
2488
2286
|
bid: { price: BigInt(int(1e6)) }
|
|
@@ -2505,7 +2303,7 @@ var TradingFee_exports = /* @__PURE__ */ __exportAll({
|
|
|
2505
2303
|
activate: () => activate,
|
|
2506
2304
|
compute: () => compute,
|
|
2507
2305
|
deactivate: () => deactivate,
|
|
2508
|
-
from: () => from$
|
|
2306
|
+
from: () => from$5,
|
|
2509
2307
|
getFees: () => getFees,
|
|
2510
2308
|
isActivated: () => isActivated
|
|
2511
2309
|
});
|
|
@@ -2531,7 +2329,7 @@ const WAD = 10n ** 18n;
|
|
|
2531
2329
|
* @throws {@link InvalidFeeError} if any fee exceeds WAD (100%).
|
|
2532
2330
|
* @throws {@link InvalidFeesLengthError} if fees array doesn't have exactly 6 elements.
|
|
2533
2331
|
*/
|
|
2534
|
-
function from$
|
|
2332
|
+
function from$5(activated, fees) {
|
|
2535
2333
|
if (fees.length !== 6) throw new InvalidFeesLengthError(fees.length);
|
|
2536
2334
|
for (let i = 0; i < 6; i++) {
|
|
2537
2335
|
const fee = fees[i];
|
|
@@ -2646,7 +2444,7 @@ var InvalidFeesLengthError = class extends BaseError {
|
|
|
2646
2444
|
|
|
2647
2445
|
//#endregion
|
|
2648
2446
|
//#region src/core/Transfer.ts
|
|
2649
|
-
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$
|
|
2447
|
+
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$4 });
|
|
2650
2448
|
/**
|
|
2651
2449
|
* @constructor
|
|
2652
2450
|
*
|
|
@@ -2659,7 +2457,7 @@ var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$3 });
|
|
|
2659
2457
|
* const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
|
|
2660
2458
|
* ```
|
|
2661
2459
|
*/
|
|
2662
|
-
function from$
|
|
2460
|
+
function from$4(parameters) {
|
|
2663
2461
|
return {
|
|
2664
2462
|
id: parameters.id,
|
|
2665
2463
|
chainId: parameters.chainId,
|
|
@@ -2671,6 +2469,337 @@ function from$3(parameters) {
|
|
|
2671
2469
|
};
|
|
2672
2470
|
}
|
|
2673
2471
|
|
|
2472
|
+
//#endregion
|
|
2473
|
+
//#region src/core/Tree.ts
|
|
2474
|
+
var Tree_exports = /* @__PURE__ */ __exportAll({
|
|
2475
|
+
DecodeError: () => DecodeError,
|
|
2476
|
+
EncodeError: () => EncodeError,
|
|
2477
|
+
SignatureDomainError: () => SignatureDomainError,
|
|
2478
|
+
TreeError: () => TreeError,
|
|
2479
|
+
VERSION: () => VERSION,
|
|
2480
|
+
decode: () => decode,
|
|
2481
|
+
encode: () => encode,
|
|
2482
|
+
encodeUnsigned: () => encodeUnsigned,
|
|
2483
|
+
from: () => from$3,
|
|
2484
|
+
proofs: () => proofs,
|
|
2485
|
+
signatureDomain: () => signatureDomain,
|
|
2486
|
+
signatureTypes: () => signatureTypes
|
|
2487
|
+
});
|
|
2488
|
+
const VERSION = 1;
|
|
2489
|
+
/**
|
|
2490
|
+
* EIP-712 types for signing the tree root (Root(bytes32 root)).
|
|
2491
|
+
*/
|
|
2492
|
+
const signatureTypes = {
|
|
2493
|
+
EIP712Domain: [{
|
|
2494
|
+
name: "chainId",
|
|
2495
|
+
type: "uint256"
|
|
2496
|
+
}, {
|
|
2497
|
+
name: "verifyingContract",
|
|
2498
|
+
type: "address"
|
|
2499
|
+
}],
|
|
2500
|
+
Root: [{
|
|
2501
|
+
name: "root",
|
|
2502
|
+
type: "bytes32"
|
|
2503
|
+
}]
|
|
2504
|
+
};
|
|
2505
|
+
const normalizeHash = (hash) => hash.toLowerCase();
|
|
2506
|
+
/**
|
|
2507
|
+
* Builds a Merkle tree from a list of offers.
|
|
2508
|
+
*
|
|
2509
|
+
* Leaves are the offer `hash` values as `bytes32` and are deterministically
|
|
2510
|
+
* ordered following the StandardMerkleTree leaf ordering so that the resulting
|
|
2511
|
+
* root is stable regardless of the input order.
|
|
2512
|
+
*
|
|
2513
|
+
* @param offers - Offers to include in the tree.
|
|
2514
|
+
* @returns A `StandardMerkleTree` of `bytes32` leaves representing the offers.
|
|
2515
|
+
* @throws {TreeError} If tree building fails due to offer inconsistencies.
|
|
2516
|
+
*/
|
|
2517
|
+
const from$3 = (offers) => {
|
|
2518
|
+
const leaves = offers.map((offer) => [hash(offer)]);
|
|
2519
|
+
const tree = _openzeppelin_merkle_tree.StandardMerkleTree.of(leaves, ["bytes32"]);
|
|
2520
|
+
const orderedOffers = orderOffers(tree, offers);
|
|
2521
|
+
return Object.assign(tree, { offers: orderedOffers });
|
|
2522
|
+
};
|
|
2523
|
+
const orderOffers = (tree, offers) => {
|
|
2524
|
+
const offerByHash = /* @__PURE__ */ new Map();
|
|
2525
|
+
for (const offer of offers) offerByHash.set(normalizeHash(hash(offer)), offer);
|
|
2526
|
+
const entries = tree.dump().values.map((value) => {
|
|
2527
|
+
const hash = normalizeHash(value.value[0]);
|
|
2528
|
+
const offer = offerByHash.get(hash);
|
|
2529
|
+
if (!offer) throw new TreeError(`missing offer for leaf ${hash}`);
|
|
2530
|
+
return {
|
|
2531
|
+
offer,
|
|
2532
|
+
treeIndex: value.treeIndex
|
|
2533
|
+
};
|
|
2534
|
+
});
|
|
2535
|
+
entries.sort((a, b) => b.treeIndex - a.treeIndex);
|
|
2536
|
+
return entries.map((item) => item.offer);
|
|
2537
|
+
};
|
|
2538
|
+
/**
|
|
2539
|
+
* Generates merkle proofs for all offers in a tree.
|
|
2540
|
+
*
|
|
2541
|
+
* Each proof allows independent verification that an offer is included in the tree
|
|
2542
|
+
* without requiring the full tree. Proofs are ordered by StandardMerkleTree leaf ordering.
|
|
2543
|
+
*
|
|
2544
|
+
* @param tree - The {@link Tree} to generate proofs for.
|
|
2545
|
+
* @returns Array of proofs - {@link Proof}
|
|
2546
|
+
*/
|
|
2547
|
+
const proofs = (tree) => {
|
|
2548
|
+
return tree.offers.map((offer) => {
|
|
2549
|
+
return {
|
|
2550
|
+
offer,
|
|
2551
|
+
path: tree.getProof([hash(offer)])
|
|
2552
|
+
};
|
|
2553
|
+
});
|
|
2554
|
+
};
|
|
2555
|
+
/**
|
|
2556
|
+
* Normalizes a Root signature domain (BigInt chain id, lowercase address).
|
|
2557
|
+
* @throws {SignatureDomainError} When the domain is invalid.
|
|
2558
|
+
*/
|
|
2559
|
+
const signatureDomain = (domain) => {
|
|
2560
|
+
return normalizeSignatureDomain(domain, (reason) => new SignatureDomainError(reason));
|
|
2561
|
+
};
|
|
2562
|
+
const normalizeSignatureDomain = (domain, errorFactory) => {
|
|
2563
|
+
let chainId;
|
|
2564
|
+
try {
|
|
2565
|
+
chainId = typeof domain.chainId === "bigint" ? domain.chainId : BigInt(domain.chainId);
|
|
2566
|
+
} catch {
|
|
2567
|
+
throw errorFactory("invalid chainId");
|
|
2568
|
+
}
|
|
2569
|
+
if (chainId < 0n) throw errorFactory("invalid chainId");
|
|
2570
|
+
if (!(0, viem.isAddress)(domain.verifyingContract)) throw errorFactory("invalid verifyingContract");
|
|
2571
|
+
return {
|
|
2572
|
+
chainId,
|
|
2573
|
+
verifyingContract: domain.verifyingContract.toLowerCase()
|
|
2574
|
+
};
|
|
2575
|
+
};
|
|
2576
|
+
const assertHex = (value, expectedBytes, name, errorFactory = (reason) => new DecodeError(reason)) => {
|
|
2577
|
+
if (typeof value !== "string" || !(0, viem.isHex)(value)) throw errorFactory(`${name} is not a valid hex string`);
|
|
2578
|
+
if ((0, viem.hexToBytes)(value).length !== expectedBytes) throw errorFactory(`${name}: expected ${expectedBytes} bytes`);
|
|
2579
|
+
};
|
|
2580
|
+
const verifySignatureAndRecoverAddress = async (params) => {
|
|
2581
|
+
const { root, signature, domain, errorFactory } = params;
|
|
2582
|
+
assertHex(root, 32, "root", errorFactory);
|
|
2583
|
+
assertHex(signature, 65, "signature", errorFactory);
|
|
2584
|
+
const hash = (0, viem.hashTypedData)({
|
|
2585
|
+
domain,
|
|
2586
|
+
types: signatureTypes,
|
|
2587
|
+
primaryType: "Root",
|
|
2588
|
+
message: { root }
|
|
2589
|
+
});
|
|
2590
|
+
try {
|
|
2591
|
+
return await (0, viem.recoverAddress)({
|
|
2592
|
+
hash,
|
|
2593
|
+
signature
|
|
2594
|
+
});
|
|
2595
|
+
} catch {
|
|
2596
|
+
throw errorFactory("signature recovery failed");
|
|
2597
|
+
}
|
|
2598
|
+
};
|
|
2599
|
+
/**
|
|
2600
|
+
* Encodes a merkle tree with signature into hex calldata for onchain broadcast.
|
|
2601
|
+
*
|
|
2602
|
+
* Layout: `0x{vv}{gzip([...offers])}{root}{signature}` where:
|
|
2603
|
+
* - `{vv}`: 1-byte version (currently 0x01)
|
|
2604
|
+
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
2605
|
+
* - `{root}`: 32-byte merkle root
|
|
2606
|
+
* - `{signature}`: 65-byte EIP-712 signature over Root(bytes32 root)
|
|
2607
|
+
*
|
|
2608
|
+
* Validates signature authenticity and root integrity before encoding.
|
|
2609
|
+
*
|
|
2610
|
+
* @example
|
|
2611
|
+
* ```typescript
|
|
2612
|
+
* const tree = Tree.from(offers);
|
|
2613
|
+
* const signature = await wallet.signTypedData({
|
|
2614
|
+
* account: wallet.account,
|
|
2615
|
+
* domain: Tree.signatureDomain({ chainId, verifyingContract }),
|
|
2616
|
+
* types: Tree.signatureTypes,
|
|
2617
|
+
* primaryType: "Root",
|
|
2618
|
+
* message: { root: tree.root },
|
|
2619
|
+
* });
|
|
2620
|
+
* const calldata = await Tree.encode(tree, signature, { chainId, verifyingContract });
|
|
2621
|
+
* await broadcast(calldata);
|
|
2622
|
+
* ```
|
|
2623
|
+
*
|
|
2624
|
+
* @example
|
|
2625
|
+
* Manual construction (for advanced users):
|
|
2626
|
+
* ```typescript
|
|
2627
|
+
* const tree = Tree.from(offers);
|
|
2628
|
+
* const compressed = gzip(JSON.stringify(tree.offers.map(Offer.serialize)));
|
|
2629
|
+
* const partial = `0x01${bytesToHex(compressed)}${tree.root.slice(2)}`;
|
|
2630
|
+
* const signature = await wallet.signTypedData({
|
|
2631
|
+
* account: wallet.account,
|
|
2632
|
+
* domain: Tree.signatureDomain({ chainId, verifyingContract }),
|
|
2633
|
+
* types: Tree.signatureTypes,
|
|
2634
|
+
* primaryType: "Root",
|
|
2635
|
+
* message: { root: tree.root },
|
|
2636
|
+
* });
|
|
2637
|
+
* const calldata = `${partial}${signature.slice(2)}`;
|
|
2638
|
+
* ```
|
|
2639
|
+
*
|
|
2640
|
+
* @param tree - Merkle tree of offers
|
|
2641
|
+
* @param signature - EIP-712 signature over Root(bytes32 root)
|
|
2642
|
+
* @param domain - EIP-712 domain with chain id and verifying contract
|
|
2643
|
+
* @returns Hex-encoded calldata ready for onchain broadcast
|
|
2644
|
+
* @throws {EncodeError} If signature verification fails or root mismatch
|
|
2645
|
+
*/
|
|
2646
|
+
const encode = async (tree, signature, domain) => {
|
|
2647
|
+
const errorFactory = (reason) => new EncodeError(reason);
|
|
2648
|
+
const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
|
|
2649
|
+
validateTreeForEncoding(tree, normalizedDomain);
|
|
2650
|
+
await verifySignatureAndRecoverAddress({
|
|
2651
|
+
root: tree.root,
|
|
2652
|
+
signature,
|
|
2653
|
+
domain: normalizedDomain,
|
|
2654
|
+
errorFactory
|
|
2655
|
+
});
|
|
2656
|
+
const unsigned = encodeUnsignedBytes(tree);
|
|
2657
|
+
const sigBytes = (0, viem.hexToBytes)(signature);
|
|
2658
|
+
const encoded = new Uint8Array(unsigned.length + sigBytes.length);
|
|
2659
|
+
encoded.set(unsigned, 0);
|
|
2660
|
+
encoded.set(sigBytes, unsigned.length);
|
|
2661
|
+
return (0, viem.bytesToHex)(encoded);
|
|
2662
|
+
};
|
|
2663
|
+
/**
|
|
2664
|
+
* Encodes a merkle tree without a signature into hex payload for client-side signing.
|
|
2665
|
+
*
|
|
2666
|
+
* Layout: `0x{vv}{gzip([...offers])}{root}` where:
|
|
2667
|
+
* - `{vv}`: 1-byte version (currently 0x01)
|
|
2668
|
+
* - `{gzip([...offers])}`: gzipped JSON array of serialized offers
|
|
2669
|
+
* - `{root}`: 32-byte merkle root
|
|
2670
|
+
*
|
|
2671
|
+
* Validates root integrity before encoding.
|
|
2672
|
+
*
|
|
2673
|
+
* @param tree - Merkle tree of offers
|
|
2674
|
+
* @returns Hex-encoded unsigned payload
|
|
2675
|
+
* @throws {EncodeError} If root mismatch
|
|
2676
|
+
*/
|
|
2677
|
+
const encodeUnsigned = (tree) => {
|
|
2678
|
+
validateTreeForEncoding(tree);
|
|
2679
|
+
return (0, viem.bytesToHex)(encodeUnsignedBytes(tree));
|
|
2680
|
+
};
|
|
2681
|
+
const validateTreeForEncoding = (tree, domain) => {
|
|
2682
|
+
if (VERSION > 255) throw new EncodeError(`version overflow: ${VERSION} exceeds 255`);
|
|
2683
|
+
const computed = from$3(tree.offers);
|
|
2684
|
+
if (tree.root !== computed.root) throw new EncodeError(`root mismatch: expected ${computed.root}, got ${tree.root}`);
|
|
2685
|
+
if (domain) {
|
|
2686
|
+
const mismatched = tree.offers.find((offer) => BigInt(offer.chainId) !== domain.chainId);
|
|
2687
|
+
if (mismatched) throw new EncodeError(`chainId mismatch: expected ${domain.chainId}, got ${mismatched.chainId}`);
|
|
2688
|
+
}
|
|
2689
|
+
};
|
|
2690
|
+
const encodeUnsignedBytes = (tree) => {
|
|
2691
|
+
const offersPayload = tree.offers.map(serialize);
|
|
2692
|
+
const compressed = (0, pako.gzip)(JSON.stringify(offersPayload));
|
|
2693
|
+
const rootBytes = (0, viem.hexToBytes)(tree.root);
|
|
2694
|
+
const encoded = new Uint8Array(1 + compressed.length + 32);
|
|
2695
|
+
encoded[0] = VERSION;
|
|
2696
|
+
encoded.set(compressed, 1);
|
|
2697
|
+
encoded.set(rootBytes, 1 + compressed.length);
|
|
2698
|
+
return encoded;
|
|
2699
|
+
};
|
|
2700
|
+
/**
|
|
2701
|
+
* Decodes hex calldata into a validated merkle tree.
|
|
2702
|
+
*
|
|
2703
|
+
* Validates signature before decompression for fail-fast rejection of invalid payloads.
|
|
2704
|
+
* Returns the tree with separately validated signature and recovered signer address.
|
|
2705
|
+
*
|
|
2706
|
+
* Validation order:
|
|
2707
|
+
* 1. Version check
|
|
2708
|
+
* 2. Signature verification (fail-fast, before decompression)
|
|
2709
|
+
* 3. Decompression (only if signature valid)
|
|
2710
|
+
* 4. Root verification (computed from offers vs embedded root)
|
|
2711
|
+
*
|
|
2712
|
+
* @example
|
|
2713
|
+
* ```typescript
|
|
2714
|
+
* const { tree, signature, signer } = await Tree.decode(calldata, { chainId, verifyingContract });
|
|
2715
|
+
* console.log(`Tree signed by ${signer} with ${tree.offers.length} offers`);
|
|
2716
|
+
* ```
|
|
2717
|
+
*
|
|
2718
|
+
* @param encoded - Hex calldata in format `0x{vv}{gzip}{root}{signature}`
|
|
2719
|
+
* @param domain - EIP-712 domain with chain id and verifying contract
|
|
2720
|
+
* @returns Validated tree, signature, and recovered signer address
|
|
2721
|
+
* @throws {DecodeError} If version invalid, signature invalid, or root mismatch
|
|
2722
|
+
*/
|
|
2723
|
+
const decode = async (encoded, domain) => {
|
|
2724
|
+
const errorFactory = (reason) => new DecodeError(reason);
|
|
2725
|
+
const normalizedDomain = normalizeSignatureDomain(domain, errorFactory);
|
|
2726
|
+
const bytes = (0, viem.hexToBytes)(encoded);
|
|
2727
|
+
if (bytes.length < 98) throw new DecodeError("payload too short");
|
|
2728
|
+
const version = bytes[0];
|
|
2729
|
+
if (version !== (VERSION & 255)) throw new DecodeError(`invalid version: expected ${VERSION}, got ${version ?? 0}`);
|
|
2730
|
+
const signature = (0, viem.bytesToHex)(bytes.slice(-65));
|
|
2731
|
+
const root = (0, viem.bytesToHex)(bytes.slice(-97, -65));
|
|
2732
|
+
assertHex(root, 32, "root");
|
|
2733
|
+
assertHex(signature, 65, "signature");
|
|
2734
|
+
const signer = await verifySignatureAndRecoverAddress({
|
|
2735
|
+
root,
|
|
2736
|
+
signature,
|
|
2737
|
+
domain: normalizedDomain,
|
|
2738
|
+
errorFactory
|
|
2739
|
+
});
|
|
2740
|
+
const compressed = bytes.slice(1, -97);
|
|
2741
|
+
let decoded;
|
|
2742
|
+
try {
|
|
2743
|
+
decoded = (0, pako.ungzip)(compressed, { to: "string" });
|
|
2744
|
+
} catch {
|
|
2745
|
+
throw new DecodeError("decompression failed");
|
|
2746
|
+
}
|
|
2747
|
+
let rawOffers;
|
|
2748
|
+
try {
|
|
2749
|
+
rawOffers = JSON.parse(decoded);
|
|
2750
|
+
} catch {
|
|
2751
|
+
throw new DecodeError("JSON parse failed");
|
|
2752
|
+
}
|
|
2753
|
+
const tree = from$3(rawOffers.map((o) => OfferSchema().parse(o)));
|
|
2754
|
+
if (root !== tree.root) throw new DecodeError(`root mismatch: expected ${tree.root}, got ${root}`);
|
|
2755
|
+
const chainIdMismatch = tree.offers.find((offer) => BigInt(offer.chainId) !== normalizedDomain.chainId);
|
|
2756
|
+
if (chainIdMismatch) throw new DecodeError(`chainId mismatch: expected ${normalizedDomain.chainId}, got ${chainIdMismatch.chainId}`);
|
|
2757
|
+
return {
|
|
2758
|
+
tree,
|
|
2759
|
+
signature,
|
|
2760
|
+
signer
|
|
2761
|
+
};
|
|
2762
|
+
};
|
|
2763
|
+
/**
|
|
2764
|
+
* Error thrown during tree building operations.
|
|
2765
|
+
* Indicates structural issues with the tree (missing offers, inconsistent state).
|
|
2766
|
+
*/
|
|
2767
|
+
var TreeError = class extends BaseError {
|
|
2768
|
+
constructor(reason) {
|
|
2769
|
+
super(`Tree error: ${reason}`);
|
|
2770
|
+
_defineProperty(this, "name", "Tree.TreeError");
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
/**
|
|
2774
|
+
* Error thrown during tree encoding.
|
|
2775
|
+
* Indicates validation failures (signature, root mismatch, mixed makers).
|
|
2776
|
+
*/
|
|
2777
|
+
var EncodeError = class extends BaseError {
|
|
2778
|
+
constructor(reason) {
|
|
2779
|
+
super(`Failed to encode tree: ${reason}`);
|
|
2780
|
+
_defineProperty(this, "name", "Tree.EncodeError");
|
|
2781
|
+
}
|
|
2782
|
+
};
|
|
2783
|
+
/**
|
|
2784
|
+
* Error thrown during tree decoding.
|
|
2785
|
+
* Indicates payload corruption, version mismatch, or validation failures.
|
|
2786
|
+
*/
|
|
2787
|
+
var DecodeError = class extends BaseError {
|
|
2788
|
+
constructor(reason) {
|
|
2789
|
+
super(`Failed to decode tree: ${reason}`);
|
|
2790
|
+
_defineProperty(this, "name", "Tree.DecodeError");
|
|
2791
|
+
}
|
|
2792
|
+
};
|
|
2793
|
+
/**
|
|
2794
|
+
* Error thrown when an invalid signature domain is supplied.
|
|
2795
|
+
*/
|
|
2796
|
+
var SignatureDomainError = class extends BaseError {
|
|
2797
|
+
constructor(reason) {
|
|
2798
|
+
super(`Invalid signature domain: ${reason}`);
|
|
2799
|
+
_defineProperty(this, "name", "Tree.SignatureDomainError");
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
|
|
2674
2803
|
//#endregion
|
|
2675
2804
|
//#region src/core/types.ts
|
|
2676
2805
|
const BrandTypeId = Symbol.for("mempool/Brand");
|
|
@@ -2836,6 +2965,21 @@ const validateOfferExample = {
|
|
|
2836
2965
|
data: "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000034cf890db685fc536e05652fb41f02090c3fb751000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000108e644e3ab01184155270aa92a00000000000"
|
|
2837
2966
|
}
|
|
2838
2967
|
};
|
|
2968
|
+
const callbackTypesRequestExample = { callbacks: [{
|
|
2969
|
+
chain_id: 1,
|
|
2970
|
+
addresses: [
|
|
2971
|
+
"0x1111111111111111111111111111111111111111",
|
|
2972
|
+
"0x3333333333333333333333333333333333333333",
|
|
2973
|
+
"0x9999999999999999999999999999999999999999"
|
|
2974
|
+
]
|
|
2975
|
+
}] };
|
|
2976
|
+
const callbackTypesResponseExample = [{
|
|
2977
|
+
chain_id: 1,
|
|
2978
|
+
sell_erc20_callback: ["0x1111111111111111111111111111111111111111"],
|
|
2979
|
+
buy_erc20: ["0x5555555555555555555555555555555555555555"],
|
|
2980
|
+
buy_vault_v1_callback: ["0x3333333333333333333333333333333333333333"],
|
|
2981
|
+
not_supported: ["0x9999999999999999999999999999999999999999"]
|
|
2982
|
+
}];
|
|
2839
2983
|
const routerStatusExample = {
|
|
2840
2984
|
status: "live",
|
|
2841
2985
|
initialized: true,
|
|
@@ -2904,6 +3048,55 @@ __decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
|
2904
3048
|
type: "string",
|
|
2905
3049
|
example: validateOfferExample.callback.data
|
|
2906
3050
|
})], ValidateCallbackRequest.prototype, "data", void 0);
|
|
3051
|
+
var CallbackTypesChainRequest = class {};
|
|
3052
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3053
|
+
type: "number",
|
|
3054
|
+
example: callbackTypesRequestExample.callbacks[0].chain_id
|
|
3055
|
+
})], CallbackTypesChainRequest.prototype, "chain_id", void 0);
|
|
3056
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3057
|
+
type: () => [String],
|
|
3058
|
+
example: callbackTypesRequestExample.callbacks[0].addresses
|
|
3059
|
+
})], CallbackTypesChainRequest.prototype, "addresses", void 0);
|
|
3060
|
+
var CallbackTypesRequest = class {};
|
|
3061
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3062
|
+
type: () => [CallbackTypesChainRequest],
|
|
3063
|
+
example: callbackTypesRequestExample.callbacks
|
|
3064
|
+
})], CallbackTypesRequest.prototype, "callbacks", void 0);
|
|
3065
|
+
var CallbackTypesChainResponse = class {};
|
|
3066
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3067
|
+
type: "number",
|
|
3068
|
+
example: callbackTypesResponseExample[0].chain_id
|
|
3069
|
+
})], CallbackTypesChainResponse.prototype, "chain_id", void 0);
|
|
3070
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3071
|
+
type: () => [String],
|
|
3072
|
+
required: false,
|
|
3073
|
+
example: callbackTypesResponseExample[0].buy_vault_v1_callback
|
|
3074
|
+
})], CallbackTypesChainResponse.prototype, "buy_vault_v1_callback", void 0);
|
|
3075
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3076
|
+
type: () => [String],
|
|
3077
|
+
required: false,
|
|
3078
|
+
example: callbackTypesResponseExample[0].sell_erc20_callback
|
|
3079
|
+
})], CallbackTypesChainResponse.prototype, "sell_erc20_callback", void 0);
|
|
3080
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3081
|
+
type: () => [String],
|
|
3082
|
+
required: false,
|
|
3083
|
+
example: callbackTypesResponseExample[0].buy_erc20
|
|
3084
|
+
})], CallbackTypesChainResponse.prototype, "buy_erc20", void 0);
|
|
3085
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3086
|
+
type: () => [String],
|
|
3087
|
+
example: callbackTypesResponseExample[0].not_supported
|
|
3088
|
+
})], CallbackTypesChainResponse.prototype, "not_supported", void 0);
|
|
3089
|
+
var CallbackTypesSuccessResponse = class extends SuccessResponse {};
|
|
3090
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3091
|
+
type: "string",
|
|
3092
|
+
nullable: true,
|
|
3093
|
+
example: "maturity:1:1730415600:end_of_next_month"
|
|
3094
|
+
})], CallbackTypesSuccessResponse.prototype, "cursor", void 0);
|
|
3095
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3096
|
+
type: () => [CallbackTypesChainResponse],
|
|
3097
|
+
description: "Callback types grouped by chain.",
|
|
3098
|
+
example: callbackTypesResponseExample
|
|
3099
|
+
})], CallbackTypesSuccessResponse.prototype, "data", void 0);
|
|
2907
3100
|
var AskResponse = class {};
|
|
2908
3101
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
2909
3102
|
type: "string",
|
|
@@ -3068,7 +3261,8 @@ var OfferListResponse = class extends SuccessResponse {};
|
|
|
3068
3261
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3069
3262
|
type: "string",
|
|
3070
3263
|
nullable: true,
|
|
3071
|
-
example: offerCursorExample
|
|
3264
|
+
example: offerCursorExample,
|
|
3265
|
+
description: "Pagination cursor. Offer hash (0x...) for maker queries; base64url-encoded cursor for obligation queries."
|
|
3072
3266
|
})], OfferListResponse.prototype, "cursor", void 0);
|
|
3073
3267
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3074
3268
|
type: () => [OfferListItemResponse],
|
|
@@ -3439,6 +3633,28 @@ ValidateController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"
|
|
|
3439
3633
|
description: "Bad Request",
|
|
3440
3634
|
type: BadRequestResponse
|
|
3441
3635
|
})], ValidateController);
|
|
3636
|
+
let CallbacksController = class CallbacksController {
|
|
3637
|
+
async resolveCallbackTypes() {}
|
|
3638
|
+
};
|
|
3639
|
+
__decorate([
|
|
3640
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3641
|
+
methods: ["post"],
|
|
3642
|
+
path: "/v1/callbacks",
|
|
3643
|
+
summary: "Resolve callback types",
|
|
3644
|
+
description: "Returns callback types for callback addresses grouped by chain."
|
|
3645
|
+
}),
|
|
3646
|
+
(0, openapi_metadata_decorators.ApiBody)({ type: CallbackTypesRequest }),
|
|
3647
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3648
|
+
status: 200,
|
|
3649
|
+
description: "Success",
|
|
3650
|
+
type: CallbackTypesSuccessResponse
|
|
3651
|
+
})
|
|
3652
|
+
], CallbacksController.prototype, "resolveCallbackTypes", null);
|
|
3653
|
+
CallbacksController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"), (0, openapi_metadata_decorators.ApiResponse)({
|
|
3654
|
+
status: 400,
|
|
3655
|
+
description: "Bad Request",
|
|
3656
|
+
type: BadRequestResponse
|
|
3657
|
+
})], CallbacksController);
|
|
3442
3658
|
let OffersController = class OffersController {
|
|
3443
3659
|
async getOffers() {}
|
|
3444
3660
|
};
|
|
@@ -3560,54 +3776,227 @@ __decorate([
|
|
|
3560
3776
|
})
|
|
3561
3777
|
], HealthController.prototype, "getChainsHealth", null);
|
|
3562
3778
|
HealthController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], HealthController);
|
|
3563
|
-
const
|
|
3564
|
-
const chainConfigExample = {
|
|
3779
|
+
const configContractsExample = {
|
|
3565
3780
|
chain_id: 505050505,
|
|
3566
|
-
|
|
3567
|
-
|
|
3781
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3782
|
+
name: "mempool"
|
|
3783
|
+
};
|
|
3784
|
+
const configContractsPayloadExample = [
|
|
3785
|
+
{
|
|
3786
|
+
chain_id: 505050505,
|
|
3787
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3788
|
+
name: "mempool"
|
|
3789
|
+
},
|
|
3790
|
+
{
|
|
3791
|
+
chain_id: 505050505,
|
|
3792
|
+
address: "0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d",
|
|
3793
|
+
name: "multicall"
|
|
3794
|
+
},
|
|
3795
|
+
{
|
|
3796
|
+
chain_id: 505050505,
|
|
3797
|
+
address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
3798
|
+
name: "v2"
|
|
3799
|
+
}
|
|
3800
|
+
];
|
|
3801
|
+
const configRulesMaturityExample = {
|
|
3802
|
+
type: "maturity",
|
|
3803
|
+
chain_id: 1,
|
|
3804
|
+
name: "end_of_next_month",
|
|
3805
|
+
timestamp: 1730415600
|
|
3806
|
+
};
|
|
3807
|
+
const configRulesCallbackExample = {
|
|
3808
|
+
type: "callback",
|
|
3809
|
+
chain_id: 1,
|
|
3810
|
+
address: "0x1111111111111111111111111111111111111111",
|
|
3811
|
+
callback_type: "sell_erc20_callback"
|
|
3812
|
+
};
|
|
3813
|
+
const configRulesLoanTokenExample = {
|
|
3814
|
+
type: "loan_token",
|
|
3815
|
+
chain_id: 1,
|
|
3816
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
3817
|
+
};
|
|
3818
|
+
const configRulesOracleExample = {
|
|
3819
|
+
type: "oracle",
|
|
3820
|
+
chain_id: 1,
|
|
3821
|
+
address: "0xDddd770BADd886dF3864029e4B377B5F6a2B6b83"
|
|
3568
3822
|
};
|
|
3569
|
-
|
|
3823
|
+
const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
3824
|
+
const configRulesPayloadExample = [
|
|
3825
|
+
configRulesMaturityExample,
|
|
3826
|
+
configRulesCallbackExample,
|
|
3827
|
+
configRulesLoanTokenExample,
|
|
3828
|
+
configRulesOracleExample
|
|
3829
|
+
];
|
|
3830
|
+
const configContractNames = [
|
|
3831
|
+
"mempool",
|
|
3832
|
+
"multicall",
|
|
3833
|
+
"v2"
|
|
3834
|
+
];
|
|
3835
|
+
const configContractsCursorExample = "505050505:0xd946246695a9259f3b33a78629026f61b3ab40af";
|
|
3836
|
+
var ConfigContractResponse = class {};
|
|
3837
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3838
|
+
type: "number",
|
|
3839
|
+
example: configContractsExample.chain_id
|
|
3840
|
+
})], ConfigContractResponse.prototype, "chain_id", void 0);
|
|
3841
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3842
|
+
type: "string",
|
|
3843
|
+
example: configContractsExample.address
|
|
3844
|
+
})], ConfigContractResponse.prototype, "address", void 0);
|
|
3845
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3846
|
+
type: "string",
|
|
3847
|
+
enum: configContractNames,
|
|
3848
|
+
example: configContractsExample.name
|
|
3849
|
+
})], ConfigContractResponse.prototype, "name", void 0);
|
|
3850
|
+
var ConfigContractsSuccessResponse = class extends SuccessResponse {};
|
|
3570
3851
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3571
3852
|
type: "string",
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3853
|
+
nullable: true,
|
|
3854
|
+
example: null
|
|
3855
|
+
})], ConfigContractsSuccessResponse.prototype, "cursor", void 0);
|
|
3856
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3857
|
+
type: () => [ConfigContractResponse],
|
|
3858
|
+
description: "Indexer contract configuration for all indexed chains.",
|
|
3859
|
+
example: configContractsPayloadExample
|
|
3860
|
+
})], ConfigContractsSuccessResponse.prototype, "data", void 0);
|
|
3861
|
+
var ConfigRulesMeta = class {};
|
|
3862
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3863
|
+
type: "string",
|
|
3864
|
+
example: timestampExample
|
|
3865
|
+
})], ConfigRulesMeta.prototype, "timestamp", void 0);
|
|
3866
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3867
|
+
type: "string",
|
|
3868
|
+
example: configRulesChecksumExample
|
|
3869
|
+
})], ConfigRulesMeta.prototype, "checksum", void 0);
|
|
3870
|
+
var ConfigRulesRuleResponse = class {};
|
|
3871
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3872
|
+
type: "string",
|
|
3873
|
+
example: configRulesMaturityExample.type
|
|
3874
|
+
})], ConfigRulesRuleResponse.prototype, "type", void 0);
|
|
3575
3875
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3576
3876
|
type: "number",
|
|
3577
|
-
example:
|
|
3578
|
-
})],
|
|
3579
|
-
__decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
|
|
3877
|
+
example: configRulesMaturityExample.chain_id
|
|
3878
|
+
})], ConfigRulesRuleResponse.prototype, "chain_id", void 0);
|
|
3580
3879
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3581
|
-
type:
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3880
|
+
type: "string",
|
|
3881
|
+
example: configRulesMaturityExample.name,
|
|
3882
|
+
required: false
|
|
3883
|
+
})], ConfigRulesRuleResponse.prototype, "name", void 0);
|
|
3884
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3885
|
+
type: "number",
|
|
3886
|
+
example: configRulesMaturityExample.timestamp,
|
|
3887
|
+
required: false
|
|
3888
|
+
})], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
|
|
3889
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3890
|
+
type: "string",
|
|
3891
|
+
example: configRulesCallbackExample.address,
|
|
3892
|
+
required: false
|
|
3893
|
+
})], ConfigRulesRuleResponse.prototype, "address", void 0);
|
|
3894
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3895
|
+
type: "string",
|
|
3896
|
+
example: configRulesCallbackExample.callback_type,
|
|
3897
|
+
required: false
|
|
3898
|
+
})], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
|
|
3899
|
+
var ConfigRulesSuccessResponse = class {};
|
|
3900
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
|
|
3587
3901
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3588
3902
|
type: "string",
|
|
3589
3903
|
nullable: true,
|
|
3590
3904
|
example: null
|
|
3591
|
-
})],
|
|
3592
|
-
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3593
|
-
type: () => [
|
|
3594
|
-
description: "
|
|
3595
|
-
example:
|
|
3596
|
-
})],
|
|
3597
|
-
let
|
|
3598
|
-
async
|
|
3905
|
+
})], ConfigRulesSuccessResponse.prototype, "cursor", void 0);
|
|
3906
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3907
|
+
type: () => [ConfigRulesRuleResponse],
|
|
3908
|
+
description: "Configured rules returned by the router API.",
|
|
3909
|
+
example: configRulesPayloadExample
|
|
3910
|
+
})], ConfigRulesSuccessResponse.prototype, "data", void 0);
|
|
3911
|
+
let ConfigContractsController = class ConfigContractsController {
|
|
3912
|
+
async getConfigContracts() {}
|
|
3913
|
+
};
|
|
3914
|
+
__decorate([
|
|
3915
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3916
|
+
methods: ["get"],
|
|
3917
|
+
path: "/v1/config/contracts",
|
|
3918
|
+
summary: "Get indexer contract configuration",
|
|
3919
|
+
description: "Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains."
|
|
3920
|
+
}),
|
|
3921
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3922
|
+
name: "cursor",
|
|
3923
|
+
type: "string",
|
|
3924
|
+
required: false,
|
|
3925
|
+
example: configContractsCursorExample,
|
|
3926
|
+
description: "Pagination cursor in chain_id:address format (lowercase address)."
|
|
3927
|
+
}),
|
|
3928
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3929
|
+
name: "limit",
|
|
3930
|
+
type: "number",
|
|
3931
|
+
required: false,
|
|
3932
|
+
example: 1e3,
|
|
3933
|
+
description: "Maximum number of contracts to return (max 1000)."
|
|
3934
|
+
}),
|
|
3935
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3936
|
+
name: "chains",
|
|
3937
|
+
type: ["number"],
|
|
3938
|
+
required: false,
|
|
3939
|
+
example: "1,8453",
|
|
3940
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3941
|
+
style: "form",
|
|
3942
|
+
explode: false
|
|
3943
|
+
}),
|
|
3944
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3945
|
+
status: 200,
|
|
3946
|
+
description: "Success",
|
|
3947
|
+
type: ConfigContractsSuccessResponse
|
|
3948
|
+
})
|
|
3949
|
+
], ConfigContractsController.prototype, "getConfigContracts", null);
|
|
3950
|
+
ConfigContractsController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigContractsController);
|
|
3951
|
+
let ConfigRulesController = class ConfigRulesController {
|
|
3952
|
+
async getConfigRules() {}
|
|
3599
3953
|
};
|
|
3600
|
-
__decorate([
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3954
|
+
__decorate([
|
|
3955
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3956
|
+
methods: ["get"],
|
|
3957
|
+
path: "/v1/config/rules",
|
|
3958
|
+
summary: "Get config rules",
|
|
3959
|
+
description: "Returns configured rules for supported chains."
|
|
3960
|
+
}),
|
|
3961
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3962
|
+
name: "cursor",
|
|
3963
|
+
type: "string",
|
|
3964
|
+
required: false,
|
|
3965
|
+
example: "maturity:1:1730415600:end_of_next_month",
|
|
3966
|
+
description: "Pagination cursor in type:chain_id:<value> format."
|
|
3967
|
+
}),
|
|
3968
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3969
|
+
name: "limit",
|
|
3970
|
+
type: "number",
|
|
3971
|
+
required: false,
|
|
3972
|
+
example: 100,
|
|
3973
|
+
description: "Maximum number of rules to return (max 1000)."
|
|
3974
|
+
}),
|
|
3975
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3976
|
+
name: "types",
|
|
3977
|
+
type: ["string"],
|
|
3978
|
+
required: false,
|
|
3979
|
+
example: "maturity,loan_token,oracle",
|
|
3980
|
+
description: "Filter by rule types (comma-separated).",
|
|
3981
|
+
style: "form",
|
|
3982
|
+
explode: false
|
|
3983
|
+
}),
|
|
3984
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3985
|
+
name: "chains",
|
|
3986
|
+
type: ["number"],
|
|
3987
|
+
required: false,
|
|
3988
|
+
example: "1,8453",
|
|
3989
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3990
|
+
style: "form",
|
|
3991
|
+
explode: false
|
|
3992
|
+
}),
|
|
3993
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3994
|
+
status: 200,
|
|
3995
|
+
description: "Success",
|
|
3996
|
+
type: ConfigRulesSuccessResponse
|
|
3997
|
+
})
|
|
3998
|
+
], ConfigRulesController.prototype, "getConfigRules", null);
|
|
3999
|
+
ConfigRulesController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigRulesController);
|
|
3611
4000
|
let ObligationsController = class ObligationsController {
|
|
3612
4001
|
async getObligations() {}
|
|
3613
4002
|
async getObligation() {}
|
|
@@ -3736,16 +4125,18 @@ UsersController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"),
|
|
|
3736
4125
|
description: "Bad Request",
|
|
3737
4126
|
type: BadRequestResponse
|
|
3738
4127
|
})], UsersController);
|
|
3739
|
-
const OpenApi = async (
|
|
3740
|
-
|
|
4128
|
+
const OpenApi = async () => {
|
|
4129
|
+
return await (0, openapi_metadata.generateDocument)({
|
|
3741
4130
|
controllers: [
|
|
3742
4131
|
BooksController,
|
|
3743
|
-
|
|
4132
|
+
ConfigContractsController,
|
|
4133
|
+
ConfigRulesController,
|
|
3744
4134
|
OffersController,
|
|
3745
4135
|
ObligationsController,
|
|
3746
4136
|
HealthController,
|
|
3747
4137
|
UsersController,
|
|
3748
|
-
ValidateController
|
|
4138
|
+
ValidateController,
|
|
4139
|
+
CallbacksController
|
|
3749
4140
|
],
|
|
3750
4141
|
document: {
|
|
3751
4142
|
openapi: "3.1.0",
|
|
@@ -3777,12 +4168,6 @@ const OpenApi = async (options = {}) => {
|
|
|
3777
4168
|
]
|
|
3778
4169
|
}
|
|
3779
4170
|
});
|
|
3780
|
-
if (options.rules && options.rules.length > 0) {
|
|
3781
|
-
const rulesDescription = options.rules.map((rule) => `- **${rule.name}**: ${rule.description}`).join("\n");
|
|
3782
|
-
const validatePath = document.paths?.["/v1/validate"];
|
|
3783
|
-
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}`;
|
|
3784
|
-
}
|
|
3785
|
-
return document;
|
|
3786
4171
|
};
|
|
3787
4172
|
|
|
3788
4173
|
//#endregion
|
|
@@ -3807,6 +4192,10 @@ function from$1(position) {
|
|
|
3807
4192
|
//#region src/api/Schema/requests.ts
|
|
3808
4193
|
const MAX_LIMIT = 100;
|
|
3809
4194
|
const DEFAULT_LIMIT = 20;
|
|
4195
|
+
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
4196
|
+
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
4197
|
+
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
4198
|
+
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
3810
4199
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
3811
4200
|
* Domain layer handles semantic validation of cursor fields. */
|
|
3812
4201
|
function isValidBase64urlJson(val) {
|
|
@@ -3818,6 +4207,9 @@ function isValidBase64urlJson(val) {
|
|
|
3818
4207
|
return false;
|
|
3819
4208
|
}
|
|
3820
4209
|
}
|
|
4210
|
+
function isValidOfferHashCursor(val) {
|
|
4211
|
+
return /^0x[a-f0-9]{64}$/i.test(val);
|
|
4212
|
+
}
|
|
3821
4213
|
const csvArray = (schema) => zod.preprocess((value) => {
|
|
3822
4214
|
if (value === void 0) return void 0;
|
|
3823
4215
|
if (Array.isArray(value)) {
|
|
@@ -3840,8 +4232,49 @@ const PaginationQueryParams = zod.object({
|
|
|
3840
4232
|
example: 10
|
|
3841
4233
|
})
|
|
3842
4234
|
});
|
|
3843
|
-
const
|
|
3844
|
-
|
|
4235
|
+
const ConfigRuleTypes = zod.enum([
|
|
4236
|
+
"maturity",
|
|
4237
|
+
"callback",
|
|
4238
|
+
"loan_token",
|
|
4239
|
+
"oracle"
|
|
4240
|
+
]);
|
|
4241
|
+
const GetConfigRulesQueryParams = zod.object({
|
|
4242
|
+
cursor: zod.string().regex(/^(maturity|callback|loan_token|oracle):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
4243
|
+
description: "Pagination cursor in type:chain_id:<value> format",
|
|
4244
|
+
example: "maturity:1:1730415600:end_of_next_month"
|
|
4245
|
+
}),
|
|
4246
|
+
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(CONFIG_RULES_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_RULES_MAX_LIMIT}` })).optional().default(CONFIG_RULES_DEFAULT_LIMIT).meta({
|
|
4247
|
+
description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,
|
|
4248
|
+
example: 100
|
|
4249
|
+
}),
|
|
4250
|
+
types: csvArray(ConfigRuleTypes).meta({
|
|
4251
|
+
description: "Filter by rule types (comma-separated).",
|
|
4252
|
+
example: "maturity,loan_token,oracle"
|
|
4253
|
+
}),
|
|
4254
|
+
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4255
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4256
|
+
example: "1,8453"
|
|
4257
|
+
})
|
|
4258
|
+
});
|
|
4259
|
+
const GetConfigContractsQueryParams = zod.object({
|
|
4260
|
+
cursor: zod.string().regex(/^[1-9]\d*:0x[a-fA-F0-9]{40}$/, { message: "Cursor must be in the format chain_id:0x..." }).optional().meta({
|
|
4261
|
+
description: "Pagination cursor in chain_id:address format (lowercase address).",
|
|
4262
|
+
example: "1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4263
|
+
}),
|
|
4264
|
+
limit: zod.string().regex(/^[1-9]\d*$/, { message: "Limit must be a positive integer" }).transform((val) => Number.parseInt(val, 10)).pipe(zod.number().max(CONFIG_CONTRACTS_MAX_LIMIT, { message: `Limit cannot exceed ${CONFIG_CONTRACTS_MAX_LIMIT}` })).optional().default(CONFIG_CONTRACTS_DEFAULT_LIMIT).meta({
|
|
4265
|
+
description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,
|
|
4266
|
+
example: 1e3
|
|
4267
|
+
}),
|
|
4268
|
+
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4269
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4270
|
+
example: "1,8453"
|
|
4271
|
+
})
|
|
4272
|
+
});
|
|
4273
|
+
const GetOffersQueryParams = PaginationQueryParams.omit({ cursor: true }).extend({
|
|
4274
|
+
cursor: zod.string().optional().meta({
|
|
4275
|
+
description: "Pagination cursor. Use offer hash (0x...) for maker queries, base64url for obligation queries.",
|
|
4276
|
+
example: "eyJzaWRlIjoic2VsbCIsImN1cnJlbnRQcmljZSI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJibG9ja051bWJlciI6MSwiYXNzZXRzIjoiMTAwMDAwMDAwMDAwMDAwMDAwMCIsImhhc2giOiIweGRmZDY4NTllM2UwODJkMTkzODlhMWFlYzFiZGFkN2U4ZDkyZDk2YjFhYTc5NDBkYTkxYTMxMjVkMzFlM2JlNWIiLCJ0b3RhbFJldHVybmVkIjoxMCwibm93IjoxNjAwMDAwMDAwfQ"
|
|
4277
|
+
}),
|
|
3845
4278
|
side: zod.enum(["buy", "sell"]).optional().meta({
|
|
3846
4279
|
description: "Side of the offer. Required when using obligation_id.",
|
|
3847
4280
|
example: "buy"
|
|
@@ -3865,11 +4298,29 @@ const GetOffersQueryParams = zod.object({
|
|
|
3865
4298
|
});
|
|
3866
4299
|
return;
|
|
3867
4300
|
}
|
|
3868
|
-
if (hasMaker)
|
|
4301
|
+
if (hasMaker) {
|
|
4302
|
+
if (val.cursor !== void 0 && !isValidOfferHashCursor(val.cursor)) ctx.addIssue({
|
|
4303
|
+
code: "custom",
|
|
4304
|
+
path: ["cursor"],
|
|
4305
|
+
message: "Cursor must be a 32-byte hex offer hash when filtering by maker"
|
|
4306
|
+
});
|
|
4307
|
+
return;
|
|
4308
|
+
}
|
|
3869
4309
|
if (!hasObligation || !hasSide) ctx.addIssue({
|
|
3870
4310
|
code: "custom",
|
|
3871
4311
|
message: "Must provide either maker or both obligation_id and side"
|
|
3872
4312
|
});
|
|
4313
|
+
if (val.cursor !== void 0 && !isValidBase64urlJson(val.cursor)) ctx.addIssue({
|
|
4314
|
+
code: "custom",
|
|
4315
|
+
path: ["cursor"],
|
|
4316
|
+
message: "Invalid cursor format. Must be a valid base64url-encoded cursor object"
|
|
4317
|
+
});
|
|
4318
|
+
}).transform((val) => {
|
|
4319
|
+
if (val.maker && val.cursor) return {
|
|
4320
|
+
...val,
|
|
4321
|
+
cursor: val.cursor.toLowerCase()
|
|
4322
|
+
};
|
|
4323
|
+
return val;
|
|
3873
4324
|
});
|
|
3874
4325
|
const GetObligationsQueryParams = zod.object({
|
|
3875
4326
|
...PaginationQueryParams.shape,
|
|
@@ -3942,6 +4393,16 @@ const GetBookParams = zod.object({
|
|
|
3942
4393
|
})
|
|
3943
4394
|
});
|
|
3944
4395
|
const ValidateOffersBody = zod.object({ offers: zod.array(zod.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
|
|
4396
|
+
const CallbackTypesBody = zod.object({ callbacks: zod.array(zod.object({
|
|
4397
|
+
chain_id: zod.number().int().positive().meta({
|
|
4398
|
+
description: "Chain id.",
|
|
4399
|
+
example: 1
|
|
4400
|
+
}),
|
|
4401
|
+
addresses: zod.array(zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "Callback address must be a valid 20-byte address" }).transform((val) => val.toLowerCase())).meta({
|
|
4402
|
+
description: "Callback contract addresses.",
|
|
4403
|
+
example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
|
|
4404
|
+
})
|
|
4405
|
+
}).strict()) }).strict();
|
|
3945
4406
|
const GetUserPositionsParams = zod.object({
|
|
3946
4407
|
...PaginationQueryParams.shape,
|
|
3947
4408
|
user_address: zod.string().regex(/^0x[a-fA-F0-9]{40}$/, { error: "User address must be a valid 20-byte address" }).transform((val) => val.toLowerCase()).meta({
|
|
@@ -3953,11 +4414,14 @@ const schemas = {
|
|
|
3953
4414
|
get_health: HealthQueryParams,
|
|
3954
4415
|
get_health_collectors: HealthQueryParams,
|
|
3955
4416
|
get_health_chains: HealthQueryParams,
|
|
4417
|
+
get_config_contracts: GetConfigContractsQueryParams,
|
|
4418
|
+
get_config_rules: GetConfigRulesQueryParams,
|
|
3956
4419
|
get_offers: GetOffersQueryParams,
|
|
3957
4420
|
get_obligations: GetObligationsQueryParams,
|
|
3958
4421
|
get_obligation: GetObligationParams,
|
|
3959
4422
|
get_book: GetBookParams,
|
|
3960
4423
|
validate_offers: ValidateOffersBody,
|
|
4424
|
+
callback_types: CallbackTypesBody,
|
|
3961
4425
|
get_user_positions: GetUserPositionsParams
|
|
3962
4426
|
};
|
|
3963
4427
|
function parse(action, query) {
|
|
@@ -3972,11 +4436,13 @@ function safeParse(action, query, error) {
|
|
|
3972
4436
|
var Schema_exports = /* @__PURE__ */ __exportAll({
|
|
3973
4437
|
BookResponse: () => BookResponse_exports,
|
|
3974
4438
|
BooksController: () => BooksController,
|
|
4439
|
+
CallbacksController: () => CallbacksController,
|
|
3975
4440
|
ChainHealth: () => ChainHealth,
|
|
3976
4441
|
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
3977
4442
|
CollectorHealth: () => CollectorHealth,
|
|
3978
4443
|
CollectorsHealthResponse: () => CollectorsHealthResponse,
|
|
3979
|
-
|
|
4444
|
+
ConfigContractsController: () => ConfigContractsController,
|
|
4445
|
+
ConfigRulesController: () => ConfigRulesController,
|
|
3980
4446
|
HealthController: () => HealthController,
|
|
3981
4447
|
ObligationResponse: () => ObligationResponse_exports,
|
|
3982
4448
|
ObligationsController: () => ObligationsController,
|
|
@@ -4182,12 +4648,14 @@ function createHttpClient(config) {
|
|
|
4182
4648
|
const fetchFn = config.fetchFn ?? fetch;
|
|
4183
4649
|
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
4184
4650
|
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
4651
|
+
const baseHeaders = config.originSecret ? { "x-origin-verify": config.originSecret } : void 0;
|
|
4185
4652
|
const request = async (path, init) => {
|
|
4186
4653
|
const controller = new AbortController();
|
|
4187
4654
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4188
4655
|
try {
|
|
4189
4656
|
return await fetchFn(`${baseUrl}${path}`, {
|
|
4190
4657
|
...init,
|
|
4658
|
+
headers: mergeHeaders(baseHeaders, init.headers),
|
|
4191
4659
|
signal: controller.signal
|
|
4192
4660
|
});
|
|
4193
4661
|
} finally {
|
|
@@ -4206,12 +4674,20 @@ function createHttpClient(config) {
|
|
|
4206
4674
|
body: json
|
|
4207
4675
|
};
|
|
4208
4676
|
};
|
|
4209
|
-
const
|
|
4210
|
-
const
|
|
4677
|
+
const getConfigRules = async (query) => {
|
|
4678
|
+
const params = new URLSearchParams();
|
|
4679
|
+
if (query?.cursor) params.set("cursor", query.cursor);
|
|
4680
|
+
if (query?.limit !== void 0) params.set("limit", query.limit.toString());
|
|
4681
|
+
if (query?.types !== void 0) {
|
|
4682
|
+
const typesValue = Array.isArray(query.types) ? query.types.join(",") : query.types;
|
|
4683
|
+
if (typesValue.length > 0) params.set("types", typesValue);
|
|
4684
|
+
}
|
|
4685
|
+
const response = await request(params.size > 0 ? `/v1/config/rules?${params.toString()}` : "/v1/config/rules", { method: "GET" });
|
|
4211
4686
|
const json = await response.json();
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4687
|
+
return {
|
|
4688
|
+
statusCode: response.status,
|
|
4689
|
+
body: json
|
|
4690
|
+
};
|
|
4215
4691
|
};
|
|
4216
4692
|
const isAllowed = async (offers) => {
|
|
4217
4693
|
const { statusCode, body } = await validate({ offers: offers.map((offer) => toSnakeCase(offer)) });
|
|
@@ -4239,13 +4715,31 @@ function createHttpClient(config) {
|
|
|
4239
4715
|
issues: []
|
|
4240
4716
|
};
|
|
4241
4717
|
};
|
|
4718
|
+
const getCallbackTypes = async (requestPayload) => {
|
|
4719
|
+
const response = await request("/v1/callbacks", {
|
|
4720
|
+
method: "POST",
|
|
4721
|
+
headers: { "content-type": "application/json" },
|
|
4722
|
+
body: JSON.stringify(requestPayload)
|
|
4723
|
+
});
|
|
4724
|
+
const json = await response.json();
|
|
4725
|
+
if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
|
|
4726
|
+
if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
|
|
4727
|
+
return json.data;
|
|
4728
|
+
};
|
|
4242
4729
|
return {
|
|
4243
4730
|
baseUrl,
|
|
4244
4731
|
validate,
|
|
4732
|
+
getConfigRules,
|
|
4245
4733
|
isAllowed,
|
|
4246
|
-
|
|
4734
|
+
getCallbackTypes
|
|
4247
4735
|
};
|
|
4248
4736
|
}
|
|
4737
|
+
function mergeHeaders(base, extra) {
|
|
4738
|
+
if (!base && !extra) return void 0;
|
|
4739
|
+
const merged = new Headers(base ?? void 0);
|
|
4740
|
+
if (extra) for (const [key, value] of new Headers(extra).entries()) merged.set(key, value);
|
|
4741
|
+
return merged;
|
|
4742
|
+
}
|
|
4249
4743
|
function normalizeBaseUrl(url) {
|
|
4250
4744
|
return url.trim().replace(/\/+$/, "");
|
|
4251
4745
|
}
|
|
@@ -4341,16 +4835,26 @@ async function run(parameters) {
|
|
|
4341
4835
|
};
|
|
4342
4836
|
}
|
|
4343
4837
|
|
|
4838
|
+
//#endregion
|
|
4839
|
+
//#region src/gatekeeper/Gatekeeper.ts
|
|
4840
|
+
var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
4841
|
+
/**
|
|
4842
|
+
* Create a gatekeeper instance with the provided rules.
|
|
4843
|
+
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
4844
|
+
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
4845
|
+
*/
|
|
4846
|
+
function create(parameters) {
|
|
4847
|
+
const { rules } = parameters;
|
|
4848
|
+
return { isAllowed: async (offers) => {
|
|
4849
|
+
return await run({
|
|
4850
|
+
items: offers,
|
|
4851
|
+
rules
|
|
4852
|
+
});
|
|
4853
|
+
} };
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4344
4856
|
//#endregion
|
|
4345
4857
|
//#region src/gatekeeper/GateConfig.ts
|
|
4346
|
-
var GateConfig_exports = /* @__PURE__ */ __exportAll({
|
|
4347
|
-
assets: () => assets,
|
|
4348
|
-
configs: () => configs,
|
|
4349
|
-
getCallback: () => getCallback,
|
|
4350
|
-
getCallbackAddresses: () => getCallbackAddresses,
|
|
4351
|
-
getCallbackType: () => getCallbackType,
|
|
4352
|
-
getCallbackTypeAddresses: () => getCallbackTypeAddresses
|
|
4353
|
-
});
|
|
4354
4858
|
/**
|
|
4355
4859
|
* Returns the callback configuration for a given chain and callback type, if it exists.
|
|
4356
4860
|
*
|
|
@@ -4373,17 +4877,6 @@ function getCallbackType(chain, address) {
|
|
|
4373
4877
|
return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
|
|
4374
4878
|
}
|
|
4375
4879
|
/**
|
|
4376
|
-
* Returns the callback addresses for a given chain and callback type, if it exists.
|
|
4377
|
-
* @param chain - Chain name for which to read the validation configuration
|
|
4378
|
-
* @param type - Callback type to retrieve
|
|
4379
|
-
* @returns The matching callback addresses or an empty array if not configured
|
|
4380
|
-
*/
|
|
4381
|
-
function getCallbackTypeAddresses(chain, type) {
|
|
4382
|
-
if (type === Type$1.BuyWithEmptyCallback) return [];
|
|
4383
|
-
const match = configs[chain].callbacks?.find((c) => c.type === type);
|
|
4384
|
-
return match && "addresses" in match ? match.addresses : [];
|
|
4385
|
-
}
|
|
4386
|
-
/**
|
|
4387
4880
|
* Returns the list of allowed non-empty callback addresses for a chain.
|
|
4388
4881
|
*
|
|
4389
4882
|
* @param chain - Chain name
|
|
@@ -4397,13 +4890,18 @@ const assets = {
|
|
|
4397
4890
|
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
4398
4891
|
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
|
4399
4892
|
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
4400
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
4893
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
4894
|
+
"0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c",
|
|
4895
|
+
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
|
|
4401
4896
|
],
|
|
4402
4897
|
[ChainId.BASE.toString()]: [
|
|
4403
4898
|
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
4404
4899
|
"0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
|
|
4405
4900
|
"0x4200000000000000000000000000000000000006",
|
|
4406
|
-
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
4901
|
+
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
|
|
4902
|
+
"0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
4903
|
+
"0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
|
|
4904
|
+
"0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"
|
|
4407
4905
|
],
|
|
4408
4906
|
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
4409
4907
|
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
@@ -4419,6 +4917,43 @@ const assets = {
|
|
|
4419
4917
|
"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"
|
|
4420
4918
|
]
|
|
4421
4919
|
};
|
|
4920
|
+
const oracles = {
|
|
4921
|
+
[ChainId.ETHEREUM.toString()]: [
|
|
4922
|
+
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
4923
|
+
"0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
|
|
4924
|
+
"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
|
|
4925
|
+
"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
|
|
4926
|
+
"0xbD60A6770b27E084E8617335ddE769241B0e71D8",
|
|
4927
|
+
"0xAe12416c1F21B0698c27fe042D9309C83baC6597"
|
|
4928
|
+
],
|
|
4929
|
+
[ChainId.BASE.toString()]: [
|
|
4930
|
+
"0xD09048c8B568Dbf5f189302beA26c9edABFC4858",
|
|
4931
|
+
"0xFEa2D58cEfCb9fcb597723c6bAE66fFE4193aFE4",
|
|
4932
|
+
"0x05D2618404668D725B66c0f32B39e4EC15B393dC",
|
|
4933
|
+
"0xE1bb8E5b4930eC9FeC7f7943FCF6227649F14B37",
|
|
4934
|
+
"0x663BECd10daE6C4A3Dcd89F1d76c1174199639B9",
|
|
4935
|
+
"0x10b95702a0ce895972C91e432C4f7E19811D320E",
|
|
4936
|
+
"0x8C87DbD7A0c647A4291592Bc2994dbF95880fE2F",
|
|
4937
|
+
"0x4A11590e5326138B514E08A9B52202D42077Ca65",
|
|
4938
|
+
"0xa54122f0E0766258377Ffe732e454A3248f454F4"
|
|
4939
|
+
],
|
|
4940
|
+
[ChainId["ETHEREUM-VIRTUAL-TESTNET"].toString()]: [
|
|
4941
|
+
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
4942
|
+
"0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
|
|
4943
|
+
"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
|
|
4944
|
+
"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
|
|
4945
|
+
"0xbD60A6770b27E084E8617335ddE769241B0e71D8",
|
|
4946
|
+
"0xAe12416c1F21B0698c27fe042D9309C83baC6597"
|
|
4947
|
+
],
|
|
4948
|
+
[ChainId.ANVIL.toString()]: [
|
|
4949
|
+
"0xDddd770BADd886dF3864029e4B377B5F6a2B6b83",
|
|
4950
|
+
"0x9CB3f4276bcD149b3668e1a645a964bC12877b89",
|
|
4951
|
+
"0x48F7E36EB6B826B2dF4B2E630B62Cd25e89E40e2",
|
|
4952
|
+
"0x6Eb9F4128CeBc8B885A4d8562Db1Addf097f7348",
|
|
4953
|
+
"0xbD60A6770b27E084E8617335ddE769241B0e71D8",
|
|
4954
|
+
"0xAe12416c1F21B0698c27fe042D9309C83baC6597"
|
|
4955
|
+
]
|
|
4956
|
+
};
|
|
4422
4957
|
const configs = {
|
|
4423
4958
|
ethereum: {
|
|
4424
4959
|
callbacks: [
|
|
@@ -4482,30 +5017,6 @@ const configs = {
|
|
|
4482
5017
|
}
|
|
4483
5018
|
};
|
|
4484
5019
|
|
|
4485
|
-
//#endregion
|
|
4486
|
-
//#region src/gatekeeper/Gatekeeper.ts
|
|
4487
|
-
var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
4488
|
-
/**
|
|
4489
|
-
* Create a gatekeeper instance with the provided rules.
|
|
4490
|
-
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
4491
|
-
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
4492
|
-
*/
|
|
4493
|
-
function create(parameters) {
|
|
4494
|
-
const { rules } = parameters;
|
|
4495
|
-
return {
|
|
4496
|
-
isAllowed: async (offers) => {
|
|
4497
|
-
return await run({
|
|
4498
|
-
items: offers,
|
|
4499
|
-
rules
|
|
4500
|
-
});
|
|
4501
|
-
},
|
|
4502
|
-
getRules: async () => rules.map((rule) => ({
|
|
4503
|
-
name: rule.name,
|
|
4504
|
-
description: rule.description
|
|
4505
|
-
}))
|
|
4506
|
-
};
|
|
4507
|
-
}
|
|
4508
|
-
|
|
4509
5020
|
//#endregion
|
|
4510
5021
|
//#region src/gatekeeper/Rules.ts
|
|
4511
5022
|
var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -4513,6 +5024,7 @@ var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
|
4513
5024
|
callback: () => callback,
|
|
4514
5025
|
chains: () => chains,
|
|
4515
5026
|
maturity: () => maturity,
|
|
5027
|
+
oracle: () => oracle,
|
|
4516
5028
|
sameMaker: () => sameMaker,
|
|
4517
5029
|
token: () => token,
|
|
4518
5030
|
validity: () => validity
|
|
@@ -4651,6 +5163,16 @@ const token = ({ assetsByChainId }) => single("token", "Validates that offer loa
|
|
|
4651
5163
|
if (offer.collaterals.some((collateral) => !allowedAssets.includes(collateral.asset.toLowerCase()))) return { message: "Collateral is not allowed" };
|
|
4652
5164
|
});
|
|
4653
5165
|
/**
|
|
5166
|
+
* A validation rule that checks if the offer's oracle addresses are allowed for its chain.
|
|
5167
|
+
* @param oraclesByChainId - Allowed oracles indexed by chain id.
|
|
5168
|
+
* @returns The issue that was found. If the offer is valid, this will be undefined.
|
|
5169
|
+
*/
|
|
5170
|
+
const oracle = ({ oraclesByChainId }) => single("oracle", "Validates that offer collateral oracles are in the allowed oracle list for the offer chain", (offer) => {
|
|
5171
|
+
const allowedOracles = oraclesByChainId[offer.chainId]?.map((oracle) => oracle.toLowerCase());
|
|
5172
|
+
if (!allowedOracles || allowedOracles.length === 0) return { message: `No allowed oracles for chain ${offer.chainId}` };
|
|
5173
|
+
if (offer.collaterals.some((collateral) => !allowedOracles.includes(collateral.oracle.toLowerCase()))) return { message: "Oracle is not allowed" };
|
|
5174
|
+
});
|
|
5175
|
+
/**
|
|
4654
5176
|
* A batch validation rule that ensures all offers in a tree have the same maker address.
|
|
4655
5177
|
* Returns an issue only for the first non-conforming offer.
|
|
4656
5178
|
* This rule is signing-agnostic; signer verification is handled at the collector level.
|
|
@@ -4681,7 +5203,11 @@ const amountMutualExclusivity = () => single("amount_mutual_exclusivity", "Valid
|
|
|
4681
5203
|
//#region src/gatekeeper/morphoRules.ts
|
|
4682
5204
|
const morphoRules = (chains$2) => {
|
|
4683
5205
|
const assetsByChainId = {};
|
|
4684
|
-
|
|
5206
|
+
const oraclesByChainId = {};
|
|
5207
|
+
for (const chain of chains$2) {
|
|
5208
|
+
assetsByChainId[chain.id] = assets[chain.id.toString()] ?? [];
|
|
5209
|
+
oraclesByChainId[chain.id] = oracles[chain.id.toString()] ?? [];
|
|
5210
|
+
}
|
|
4685
5211
|
return [
|
|
4686
5212
|
sameMaker(),
|
|
4687
5213
|
amountMutualExclusivity(),
|
|
@@ -4695,7 +5221,8 @@ const morphoRules = (chains$2) => {
|
|
|
4695
5221
|
],
|
|
4696
5222
|
allowedAddresses: chains$2.flatMap((c) => getCallbackAddresses(c.name))
|
|
4697
5223
|
}),
|
|
4698
|
-
token({ assetsByChainId })
|
|
5224
|
+
token({ assetsByChainId }),
|
|
5225
|
+
oracle({ oraclesByChainId })
|
|
4699
5226
|
];
|
|
4700
5227
|
};
|
|
4701
5228
|
|
|
@@ -4706,6 +5233,7 @@ function from(parameters) {
|
|
|
4706
5233
|
const config = {
|
|
4707
5234
|
client: parameters.client,
|
|
4708
5235
|
mempoolAddress: parameters.mempoolAddress,
|
|
5236
|
+
morphoAddress: parameters.morphoAddress,
|
|
4709
5237
|
blockWindow: parameters.blockWindow
|
|
4710
5238
|
};
|
|
4711
5239
|
return {
|
|
@@ -4723,11 +5251,18 @@ function from(parameters) {
|
|
|
4723
5251
|
*/
|
|
4724
5252
|
async function add(config, offers) {
|
|
4725
5253
|
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
4726
|
-
const tree = from$
|
|
5254
|
+
const tree = from$3(offers.map((o) => from$9(o)));
|
|
4727
5255
|
const chainId = await getChainId(config.client);
|
|
4728
5256
|
for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
|
|
4729
|
-
const
|
|
4730
|
-
const
|
|
5257
|
+
const signatureDomain$1 = resolveSignatureDomain(config, chainId);
|
|
5258
|
+
const signature = await config.client.signTypedData({
|
|
5259
|
+
account: config.client.account,
|
|
5260
|
+
domain: signatureDomain(signatureDomain$1),
|
|
5261
|
+
types: signatureTypes,
|
|
5262
|
+
primaryType: "Root",
|
|
5263
|
+
message: { root: tree.root }
|
|
5264
|
+
});
|
|
5265
|
+
const encoded = await encode(tree, signature, signatureDomain$1);
|
|
4731
5266
|
try {
|
|
4732
5267
|
return await config.client.sendTransaction({
|
|
4733
5268
|
chain: config.client.chain,
|
|
@@ -4766,6 +5301,7 @@ const getChainId = async (client) => {
|
|
|
4766
5301
|
};
|
|
4767
5302
|
async function* streamOffers(config, parameters) {
|
|
4768
5303
|
const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
|
|
5304
|
+
const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));
|
|
4769
5305
|
const stream = streamLogs({
|
|
4770
5306
|
client: config.client.extend(viem.publicActions),
|
|
4771
5307
|
contractAddress: config.mempoolAddress,
|
|
@@ -4797,7 +5333,7 @@ async function* streamOffers(config, parameters) {
|
|
|
4797
5333
|
if (!log) continue;
|
|
4798
5334
|
const [payload] = (0, viem.decodeAbiParameters)([{ type: "bytes" }], log.data);
|
|
4799
5335
|
try {
|
|
4800
|
-
const { tree } = await decode
|
|
5336
|
+
const { tree } = await decode(payload, signatureDomain);
|
|
4801
5337
|
for (const offer of tree.offers) {
|
|
4802
5338
|
if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
|
|
4803
5339
|
offers.push(offer);
|
|
@@ -4832,6 +5368,21 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
4832
5368
|
_defineProperty(this, "name", "Mempool.ChainIdMismatchError");
|
|
4833
5369
|
}
|
|
4834
5370
|
};
|
|
5371
|
+
const resolveSignatureDomain = (config, chainId) => {
|
|
5372
|
+
const chain = config.client.chain;
|
|
5373
|
+
const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
|
|
5374
|
+
if (!verifyingContract || verifyingContract.toLowerCase() === viem.zeroAddress) throw new MissingMorphoAddressError();
|
|
5375
|
+
return {
|
|
5376
|
+
chainId,
|
|
5377
|
+
verifyingContract
|
|
5378
|
+
};
|
|
5379
|
+
};
|
|
5380
|
+
var MissingMorphoAddressError = class extends BaseError {
|
|
5381
|
+
constructor() {
|
|
5382
|
+
super("Morpho address is required to verify root signatures (zero address is invalid).");
|
|
5383
|
+
_defineProperty(this, "name", "Mempool.MissingMorphoAddressError");
|
|
5384
|
+
}
|
|
5385
|
+
};
|
|
4835
5386
|
|
|
4836
5387
|
//#endregion
|
|
4837
5388
|
//#region src/mempool/MempoolClient.ts
|
|
@@ -5045,12 +5596,6 @@ Object.defineProperty(exports, 'Format', {
|
|
|
5045
5596
|
return Format_exports;
|
|
5046
5597
|
}
|
|
5047
5598
|
});
|
|
5048
|
-
Object.defineProperty(exports, 'GateConfig', {
|
|
5049
|
-
enumerable: true,
|
|
5050
|
-
get: function () {
|
|
5051
|
-
return GateConfig_exports;
|
|
5052
|
-
}
|
|
5053
|
-
});
|
|
5054
5599
|
Object.defineProperty(exports, 'Gatekeeper', {
|
|
5055
5600
|
enumerable: true,
|
|
5056
5601
|
get: function () {
|