@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.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];
|
|
@@ -2643,33 +2441,364 @@ var InvalidFeesLengthError = class extends BaseError {
|
|
|
2643
2441
|
_defineProperty(this, "name", "TradingFee.InvalidFeesLengthError");
|
|
2644
2442
|
}
|
|
2645
2443
|
};
|
|
2646
|
-
|
|
2647
|
-
//#endregion
|
|
2648
|
-
//#region src/core/Transfer.ts
|
|
2649
|
-
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$
|
|
2444
|
+
|
|
2445
|
+
//#endregion
|
|
2446
|
+
//#region src/core/Transfer.ts
|
|
2447
|
+
var Transfer_exports = /* @__PURE__ */ __exportAll({ from: () => from$4 });
|
|
2448
|
+
/**
|
|
2449
|
+
* @constructor
|
|
2450
|
+
*
|
|
2451
|
+
* Creates a {@link Transfer}.
|
|
2452
|
+
* @param parameters - {@link from.Parameters}
|
|
2453
|
+
* @returns The created Transfer. {@link from.ReturnType}
|
|
2454
|
+
*
|
|
2455
|
+
* @example
|
|
2456
|
+
* ```ts
|
|
2457
|
+
* const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
|
|
2458
|
+
* ```
|
|
2459
|
+
*/
|
|
2460
|
+
function from$4(parameters) {
|
|
2461
|
+
return {
|
|
2462
|
+
id: parameters.id,
|
|
2463
|
+
chainId: parameters.chainId,
|
|
2464
|
+
contract: parameters.contract.toLowerCase(),
|
|
2465
|
+
from: parameters.from.toLowerCase(),
|
|
2466
|
+
to: parameters.to.toLowerCase(),
|
|
2467
|
+
value: parameters.value,
|
|
2468
|
+
blockNumber: parameters.blockNumber
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
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
|
+
};
|
|
2650
2783
|
/**
|
|
2651
|
-
*
|
|
2652
|
-
*
|
|
2653
|
-
* Creates a {@link Transfer}.
|
|
2654
|
-
* @param parameters - {@link from.Parameters}
|
|
2655
|
-
* @returns The created Transfer. {@link from.ReturnType}
|
|
2656
|
-
*
|
|
2657
|
-
* @example
|
|
2658
|
-
* ```ts
|
|
2659
|
-
* const transfer = Transfer.from({ id: "1", chainId: 1, contract: "0x123", from: "0x456", to: "0x789", value: 100n, blockNumber: 100n });
|
|
2660
|
-
* ```
|
|
2784
|
+
* Error thrown during tree decoding.
|
|
2785
|
+
* Indicates payload corruption, version mismatch, or validation failures.
|
|
2661
2786
|
*/
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
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
|
+
};
|
|
2673
2802
|
|
|
2674
2803
|
//#endregion
|
|
2675
2804
|
//#region src/core/types.ts
|
|
@@ -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",
|
|
@@ -3439,6 +3632,28 @@ ValidateController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"
|
|
|
3439
3632
|
description: "Bad Request",
|
|
3440
3633
|
type: BadRequestResponse
|
|
3441
3634
|
})], ValidateController);
|
|
3635
|
+
let CallbacksController = class CallbacksController {
|
|
3636
|
+
async resolveCallbackTypes() {}
|
|
3637
|
+
};
|
|
3638
|
+
__decorate([
|
|
3639
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3640
|
+
methods: ["post"],
|
|
3641
|
+
path: "/v1/callbacks",
|
|
3642
|
+
summary: "Resolve callback types",
|
|
3643
|
+
description: "Returns callback types for callback addresses grouped by chain."
|
|
3644
|
+
}),
|
|
3645
|
+
(0, openapi_metadata_decorators.ApiBody)({ type: CallbackTypesRequest }),
|
|
3646
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3647
|
+
status: 200,
|
|
3648
|
+
description: "Success",
|
|
3649
|
+
type: CallbackTypesSuccessResponse
|
|
3650
|
+
})
|
|
3651
|
+
], CallbacksController.prototype, "resolveCallbackTypes", null);
|
|
3652
|
+
CallbacksController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"), (0, openapi_metadata_decorators.ApiResponse)({
|
|
3653
|
+
status: 400,
|
|
3654
|
+
description: "Bad Request",
|
|
3655
|
+
type: BadRequestResponse
|
|
3656
|
+
})], CallbacksController);
|
|
3442
3657
|
let OffersController = class OffersController {
|
|
3443
3658
|
async getOffers() {}
|
|
3444
3659
|
};
|
|
@@ -3560,54 +3775,221 @@ __decorate([
|
|
|
3560
3775
|
})
|
|
3561
3776
|
], HealthController.prototype, "getChainsHealth", null);
|
|
3562
3777
|
HealthController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], HealthController);
|
|
3563
|
-
const
|
|
3564
|
-
const chainConfigExample = {
|
|
3778
|
+
const configContractsExample = {
|
|
3565
3779
|
chain_id: 505050505,
|
|
3566
|
-
|
|
3567
|
-
|
|
3780
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3781
|
+
name: "mempool"
|
|
3782
|
+
};
|
|
3783
|
+
const configContractsPayloadExample = [
|
|
3784
|
+
{
|
|
3785
|
+
chain_id: 505050505,
|
|
3786
|
+
address: "0xD946246695A9259F3B33a78629026F61B3Ab40aF",
|
|
3787
|
+
name: "mempool"
|
|
3788
|
+
},
|
|
3789
|
+
{
|
|
3790
|
+
chain_id: 505050505,
|
|
3791
|
+
address: "0x8A409D5D6394fC197c596d4E6E2c35e5d13f8a4d",
|
|
3792
|
+
name: "multicall"
|
|
3793
|
+
},
|
|
3794
|
+
{
|
|
3795
|
+
chain_id: 505050505,
|
|
3796
|
+
address: "0x23DFBc4B8B80C14CC5e25011B8491f268395BAd6",
|
|
3797
|
+
name: "v2"
|
|
3798
|
+
}
|
|
3799
|
+
];
|
|
3800
|
+
const configRulesMaturityExample = {
|
|
3801
|
+
type: "maturity",
|
|
3802
|
+
chain_id: 1,
|
|
3803
|
+
name: "end_of_next_month",
|
|
3804
|
+
timestamp: 1730415600
|
|
3805
|
+
};
|
|
3806
|
+
const configRulesCallbackExample = {
|
|
3807
|
+
type: "callback",
|
|
3808
|
+
chain_id: 1,
|
|
3809
|
+
address: "0x1111111111111111111111111111111111111111",
|
|
3810
|
+
callback_type: "sell_erc20_callback"
|
|
3568
3811
|
};
|
|
3569
|
-
|
|
3812
|
+
const configRulesLoanTokenExample = {
|
|
3813
|
+
type: "loan_token",
|
|
3814
|
+
chain_id: 1,
|
|
3815
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
|
3816
|
+
};
|
|
3817
|
+
const configRulesChecksumExample = "f1d2d2f924e986ac86fdf7b36c94bcdf";
|
|
3818
|
+
const configRulesPayloadExample = [
|
|
3819
|
+
configRulesMaturityExample,
|
|
3820
|
+
configRulesCallbackExample,
|
|
3821
|
+
configRulesLoanTokenExample
|
|
3822
|
+
];
|
|
3823
|
+
const configContractNames = [
|
|
3824
|
+
"mempool",
|
|
3825
|
+
"multicall",
|
|
3826
|
+
"v2"
|
|
3827
|
+
];
|
|
3828
|
+
const configContractsCursorExample = "505050505:0xd946246695a9259f3b33a78629026f61b3ab40af";
|
|
3829
|
+
var ConfigContractResponse = class {};
|
|
3830
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3831
|
+
type: "number",
|
|
3832
|
+
example: configContractsExample.chain_id
|
|
3833
|
+
})], ConfigContractResponse.prototype, "chain_id", void 0);
|
|
3834
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3835
|
+
type: "string",
|
|
3836
|
+
example: configContractsExample.address
|
|
3837
|
+
})], ConfigContractResponse.prototype, "address", void 0);
|
|
3838
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3839
|
+
type: "string",
|
|
3840
|
+
enum: configContractNames,
|
|
3841
|
+
example: configContractsExample.name
|
|
3842
|
+
})], ConfigContractResponse.prototype, "name", void 0);
|
|
3843
|
+
var ConfigContractsSuccessResponse = class extends SuccessResponse {};
|
|
3844
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3845
|
+
type: "string",
|
|
3846
|
+
nullable: true,
|
|
3847
|
+
example: null
|
|
3848
|
+
})], ConfigContractsSuccessResponse.prototype, "cursor", void 0);
|
|
3849
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3850
|
+
type: () => [ConfigContractResponse],
|
|
3851
|
+
description: "Indexer contract configuration for all indexed chains.",
|
|
3852
|
+
example: configContractsPayloadExample
|
|
3853
|
+
})], ConfigContractsSuccessResponse.prototype, "data", void 0);
|
|
3854
|
+
var ConfigRulesMeta = class {};
|
|
3855
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3856
|
+
type: "string",
|
|
3857
|
+
example: timestampExample
|
|
3858
|
+
})], ConfigRulesMeta.prototype, "timestamp", void 0);
|
|
3859
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3860
|
+
type: "string",
|
|
3861
|
+
example: configRulesChecksumExample
|
|
3862
|
+
})], ConfigRulesMeta.prototype, "checksum", void 0);
|
|
3863
|
+
var ConfigRulesRuleResponse = class {};
|
|
3570
3864
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3571
3865
|
type: "string",
|
|
3572
|
-
example:
|
|
3573
|
-
})],
|
|
3574
|
-
var ConfigDataResponse = class {};
|
|
3866
|
+
example: configRulesMaturityExample.type
|
|
3867
|
+
})], ConfigRulesRuleResponse.prototype, "type", void 0);
|
|
3575
3868
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3576
3869
|
type: "number",
|
|
3577
|
-
example:
|
|
3578
|
-
})],
|
|
3579
|
-
__decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigContractsResponse })], ConfigDataResponse.prototype, "contracts", void 0);
|
|
3870
|
+
example: configRulesMaturityExample.chain_id
|
|
3871
|
+
})], ConfigRulesRuleResponse.prototype, "chain_id", void 0);
|
|
3580
3872
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3581
|
-
type:
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3873
|
+
type: "string",
|
|
3874
|
+
example: configRulesMaturityExample.name,
|
|
3875
|
+
required: false
|
|
3876
|
+
})], ConfigRulesRuleResponse.prototype, "name", void 0);
|
|
3877
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3878
|
+
type: "number",
|
|
3879
|
+
example: configRulesMaturityExample.timestamp,
|
|
3880
|
+
required: false
|
|
3881
|
+
})], ConfigRulesRuleResponse.prototype, "timestamp", void 0);
|
|
3882
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3883
|
+
type: "string",
|
|
3884
|
+
example: configRulesCallbackExample.address,
|
|
3885
|
+
required: false
|
|
3886
|
+
})], ConfigRulesRuleResponse.prototype, "address", void 0);
|
|
3887
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3888
|
+
type: "string",
|
|
3889
|
+
example: configRulesCallbackExample.callback_type,
|
|
3890
|
+
required: false
|
|
3891
|
+
})], ConfigRulesRuleResponse.prototype, "callback_type", void 0);
|
|
3892
|
+
var ConfigRulesSuccessResponse = class {};
|
|
3893
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({ type: () => ConfigRulesMeta })], ConfigRulesSuccessResponse.prototype, "meta", void 0);
|
|
3587
3894
|
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3588
3895
|
type: "string",
|
|
3589
3896
|
nullable: true,
|
|
3590
3897
|
example: null
|
|
3591
|
-
})],
|
|
3592
|
-
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3593
|
-
type: () => [
|
|
3594
|
-
description: "
|
|
3595
|
-
example:
|
|
3596
|
-
})],
|
|
3597
|
-
let
|
|
3598
|
-
async
|
|
3898
|
+
})], ConfigRulesSuccessResponse.prototype, "cursor", void 0);
|
|
3899
|
+
__decorate([(0, openapi_metadata_decorators.ApiProperty)({
|
|
3900
|
+
type: () => [ConfigRulesRuleResponse],
|
|
3901
|
+
description: "Configured rules returned by the router API.",
|
|
3902
|
+
example: configRulesPayloadExample
|
|
3903
|
+
})], ConfigRulesSuccessResponse.prototype, "data", void 0);
|
|
3904
|
+
let ConfigContractsController = class ConfigContractsController {
|
|
3905
|
+
async getConfigContracts() {}
|
|
3906
|
+
};
|
|
3907
|
+
__decorate([
|
|
3908
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3909
|
+
methods: ["get"],
|
|
3910
|
+
path: "/v1/config/contracts",
|
|
3911
|
+
summary: "Get indexer contract configuration",
|
|
3912
|
+
description: "Returns contract addresses used by indexers (mempool, v2) and multicall for indexed chains."
|
|
3913
|
+
}),
|
|
3914
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3915
|
+
name: "cursor",
|
|
3916
|
+
type: "string",
|
|
3917
|
+
required: false,
|
|
3918
|
+
example: configContractsCursorExample,
|
|
3919
|
+
description: "Pagination cursor in chain_id:address format (lowercase address)."
|
|
3920
|
+
}),
|
|
3921
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3922
|
+
name: "limit",
|
|
3923
|
+
type: "number",
|
|
3924
|
+
required: false,
|
|
3925
|
+
example: 1e3,
|
|
3926
|
+
description: "Maximum number of contracts to return (max 1000)."
|
|
3927
|
+
}),
|
|
3928
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3929
|
+
name: "chains",
|
|
3930
|
+
type: ["number"],
|
|
3931
|
+
required: false,
|
|
3932
|
+
example: "1,8453",
|
|
3933
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3934
|
+
style: "form",
|
|
3935
|
+
explode: false
|
|
3936
|
+
}),
|
|
3937
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3938
|
+
status: 200,
|
|
3939
|
+
description: "Success",
|
|
3940
|
+
type: ConfigContractsSuccessResponse
|
|
3941
|
+
})
|
|
3942
|
+
], ConfigContractsController.prototype, "getConfigContracts", null);
|
|
3943
|
+
ConfigContractsController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigContractsController);
|
|
3944
|
+
let ConfigRulesController = class ConfigRulesController {
|
|
3945
|
+
async getConfigRules() {}
|
|
3599
3946
|
};
|
|
3600
|
-
__decorate([
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3947
|
+
__decorate([
|
|
3948
|
+
(0, openapi_metadata_decorators.ApiOperation)({
|
|
3949
|
+
methods: ["get"],
|
|
3950
|
+
path: "/v1/config/rules",
|
|
3951
|
+
summary: "Get config rules",
|
|
3952
|
+
description: "Returns configured rules for supported chains."
|
|
3953
|
+
}),
|
|
3954
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3955
|
+
name: "cursor",
|
|
3956
|
+
type: "string",
|
|
3957
|
+
required: false,
|
|
3958
|
+
example: "maturity:1:1730415600:end_of_next_month",
|
|
3959
|
+
description: "Pagination cursor in type:chain_id:<value> format."
|
|
3960
|
+
}),
|
|
3961
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3962
|
+
name: "limit",
|
|
3963
|
+
type: "number",
|
|
3964
|
+
required: false,
|
|
3965
|
+
example: 100,
|
|
3966
|
+
description: "Maximum number of rules to return (max 1000)."
|
|
3967
|
+
}),
|
|
3968
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3969
|
+
name: "types",
|
|
3970
|
+
type: ["string"],
|
|
3971
|
+
required: false,
|
|
3972
|
+
example: "maturity,loan_token",
|
|
3973
|
+
description: "Filter by rule types (comma-separated).",
|
|
3974
|
+
style: "form",
|
|
3975
|
+
explode: false
|
|
3976
|
+
}),
|
|
3977
|
+
(0, openapi_metadata_decorators.ApiQuery)({
|
|
3978
|
+
name: "chains",
|
|
3979
|
+
type: ["number"],
|
|
3980
|
+
required: false,
|
|
3981
|
+
example: "1,8453",
|
|
3982
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
3983
|
+
style: "form",
|
|
3984
|
+
explode: false
|
|
3985
|
+
}),
|
|
3986
|
+
(0, openapi_metadata_decorators.ApiResponse)({
|
|
3987
|
+
status: 200,
|
|
3988
|
+
description: "Success",
|
|
3989
|
+
type: ConfigRulesSuccessResponse
|
|
3990
|
+
})
|
|
3991
|
+
], ConfigRulesController.prototype, "getConfigRules", null);
|
|
3992
|
+
ConfigRulesController = __decorate([(0, openapi_metadata_decorators.ApiTags)("System")], ConfigRulesController);
|
|
3611
3993
|
let ObligationsController = class ObligationsController {
|
|
3612
3994
|
async getObligations() {}
|
|
3613
3995
|
async getObligation() {}
|
|
@@ -3736,16 +4118,18 @@ UsersController = __decorate([(0, openapi_metadata_decorators.ApiTags)("Make"),
|
|
|
3736
4118
|
description: "Bad Request",
|
|
3737
4119
|
type: BadRequestResponse
|
|
3738
4120
|
})], UsersController);
|
|
3739
|
-
const OpenApi = async (
|
|
3740
|
-
|
|
4121
|
+
const OpenApi = async () => {
|
|
4122
|
+
return await (0, openapi_metadata.generateDocument)({
|
|
3741
4123
|
controllers: [
|
|
3742
4124
|
BooksController,
|
|
3743
|
-
|
|
4125
|
+
ConfigContractsController,
|
|
4126
|
+
ConfigRulesController,
|
|
3744
4127
|
OffersController,
|
|
3745
4128
|
ObligationsController,
|
|
3746
4129
|
HealthController,
|
|
3747
4130
|
UsersController,
|
|
3748
|
-
ValidateController
|
|
4131
|
+
ValidateController,
|
|
4132
|
+
CallbacksController
|
|
3749
4133
|
],
|
|
3750
4134
|
document: {
|
|
3751
4135
|
openapi: "3.1.0",
|
|
@@ -3777,12 +4161,6 @@ const OpenApi = async (options = {}) => {
|
|
|
3777
4161
|
]
|
|
3778
4162
|
}
|
|
3779
4163
|
});
|
|
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
4164
|
};
|
|
3787
4165
|
|
|
3788
4166
|
//#endregion
|
|
@@ -3807,6 +4185,10 @@ function from$1(position) {
|
|
|
3807
4185
|
//#region src/api/Schema/requests.ts
|
|
3808
4186
|
const MAX_LIMIT = 100;
|
|
3809
4187
|
const DEFAULT_LIMIT = 20;
|
|
4188
|
+
const CONFIG_RULES_MAX_LIMIT = 1e3;
|
|
4189
|
+
const CONFIG_RULES_DEFAULT_LIMIT = 100;
|
|
4190
|
+
const CONFIG_CONTRACTS_MAX_LIMIT = 1e3;
|
|
4191
|
+
const CONFIG_CONTRACTS_DEFAULT_LIMIT = 1e3;
|
|
3810
4192
|
/** Validate cursor is a valid base64url-encoded JSON object.
|
|
3811
4193
|
* Domain layer handles semantic validation of cursor fields. */
|
|
3812
4194
|
function isValidBase64urlJson(val) {
|
|
@@ -3840,6 +4222,43 @@ const PaginationQueryParams = zod.object({
|
|
|
3840
4222
|
example: 10
|
|
3841
4223
|
})
|
|
3842
4224
|
});
|
|
4225
|
+
const ConfigRuleTypes = zod.enum([
|
|
4226
|
+
"maturity",
|
|
4227
|
+
"callback",
|
|
4228
|
+
"loan_token"
|
|
4229
|
+
]);
|
|
4230
|
+
const GetConfigRulesQueryParams = zod.object({
|
|
4231
|
+
cursor: zod.string().regex(/^(maturity|callback|loan_token):[1-9]\d*:.+$/, { message: "Cursor must be in the format type:chain_id:<value>" }).optional().meta({
|
|
4232
|
+
description: "Pagination cursor in type:chain_id:<value> format",
|
|
4233
|
+
example: "maturity:1:1730415600:end_of_next_month"
|
|
4234
|
+
}),
|
|
4235
|
+
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({
|
|
4236
|
+
description: `Limit maximum: ${CONFIG_RULES_MAX_LIMIT}. Default: ${CONFIG_RULES_DEFAULT_LIMIT}`,
|
|
4237
|
+
example: 100
|
|
4238
|
+
}),
|
|
4239
|
+
types: csvArray(ConfigRuleTypes).meta({
|
|
4240
|
+
description: "Filter by rule types (comma-separated).",
|
|
4241
|
+
example: "maturity,loan_token"
|
|
4242
|
+
}),
|
|
4243
|
+
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4244
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4245
|
+
example: "1,8453"
|
|
4246
|
+
})
|
|
4247
|
+
});
|
|
4248
|
+
const GetConfigContractsQueryParams = zod.object({
|
|
4249
|
+
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({
|
|
4250
|
+
description: "Pagination cursor in chain_id:address format (lowercase address).",
|
|
4251
|
+
example: "1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4252
|
+
}),
|
|
4253
|
+
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({
|
|
4254
|
+
description: `Limit maximum: ${CONFIG_CONTRACTS_MAX_LIMIT}. Default: ${CONFIG_CONTRACTS_DEFAULT_LIMIT}`,
|
|
4255
|
+
example: 1e3
|
|
4256
|
+
}),
|
|
4257
|
+
chains: csvArray(zod.string().regex(/^[1-9]\d*$/, { message: "Chain must be a positive integer" }).transform((val) => Number.parseInt(val, 10))).meta({
|
|
4258
|
+
description: "Filter by chain IDs (comma-separated).",
|
|
4259
|
+
example: "1,8453"
|
|
4260
|
+
})
|
|
4261
|
+
});
|
|
3843
4262
|
const GetOffersQueryParams = zod.object({
|
|
3844
4263
|
...PaginationQueryParams.shape,
|
|
3845
4264
|
side: zod.enum(["buy", "sell"]).optional().meta({
|
|
@@ -3942,6 +4361,16 @@ const GetBookParams = zod.object({
|
|
|
3942
4361
|
})
|
|
3943
4362
|
});
|
|
3944
4363
|
const ValidateOffersBody = zod.object({ offers: zod.array(zod.unknown()).min(1, { message: "'offers' must contain at least 1 offer" }) }).strict();
|
|
4364
|
+
const CallbackTypesBody = zod.object({ callbacks: zod.array(zod.object({
|
|
4365
|
+
chain_id: zod.number().int().positive().meta({
|
|
4366
|
+
description: "Chain id.",
|
|
4367
|
+
example: 1
|
|
4368
|
+
}),
|
|
4369
|
+
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({
|
|
4370
|
+
description: "Callback contract addresses.",
|
|
4371
|
+
example: ["0x1111111111111111111111111111111111111111", "0x3333333333333333333333333333333333333333"]
|
|
4372
|
+
})
|
|
4373
|
+
}).strict()) }).strict();
|
|
3945
4374
|
const GetUserPositionsParams = zod.object({
|
|
3946
4375
|
...PaginationQueryParams.shape,
|
|
3947
4376
|
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 +4382,14 @@ const schemas = {
|
|
|
3953
4382
|
get_health: HealthQueryParams,
|
|
3954
4383
|
get_health_collectors: HealthQueryParams,
|
|
3955
4384
|
get_health_chains: HealthQueryParams,
|
|
4385
|
+
get_config_contracts: GetConfigContractsQueryParams,
|
|
4386
|
+
get_config_rules: GetConfigRulesQueryParams,
|
|
3956
4387
|
get_offers: GetOffersQueryParams,
|
|
3957
4388
|
get_obligations: GetObligationsQueryParams,
|
|
3958
4389
|
get_obligation: GetObligationParams,
|
|
3959
4390
|
get_book: GetBookParams,
|
|
3960
4391
|
validate_offers: ValidateOffersBody,
|
|
4392
|
+
callback_types: CallbackTypesBody,
|
|
3961
4393
|
get_user_positions: GetUserPositionsParams
|
|
3962
4394
|
};
|
|
3963
4395
|
function parse(action, query) {
|
|
@@ -3972,11 +4404,13 @@ function safeParse(action, query, error) {
|
|
|
3972
4404
|
var Schema_exports = /* @__PURE__ */ __exportAll({
|
|
3973
4405
|
BookResponse: () => BookResponse_exports,
|
|
3974
4406
|
BooksController: () => BooksController,
|
|
4407
|
+
CallbacksController: () => CallbacksController,
|
|
3975
4408
|
ChainHealth: () => ChainHealth,
|
|
3976
4409
|
ChainsHealthResponse: () => ChainsHealthResponse,
|
|
3977
4410
|
CollectorHealth: () => CollectorHealth,
|
|
3978
4411
|
CollectorsHealthResponse: () => CollectorsHealthResponse,
|
|
3979
|
-
|
|
4412
|
+
ConfigContractsController: () => ConfigContractsController,
|
|
4413
|
+
ConfigRulesController: () => ConfigRulesController,
|
|
3980
4414
|
HealthController: () => HealthController,
|
|
3981
4415
|
ObligationResponse: () => ObligationResponse_exports,
|
|
3982
4416
|
ObligationsController: () => ObligationsController,
|
|
@@ -4182,12 +4616,14 @@ function createHttpClient(config) {
|
|
|
4182
4616
|
const fetchFn = config.fetchFn ?? fetch;
|
|
4183
4617
|
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
4184
4618
|
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
4619
|
+
const baseHeaders = config.originSecret ? { "x-origin-verify": config.originSecret } : void 0;
|
|
4185
4620
|
const request = async (path, init) => {
|
|
4186
4621
|
const controller = new AbortController();
|
|
4187
4622
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4188
4623
|
try {
|
|
4189
4624
|
return await fetchFn(`${baseUrl}${path}`, {
|
|
4190
4625
|
...init,
|
|
4626
|
+
headers: mergeHeaders(baseHeaders, init.headers),
|
|
4191
4627
|
signal: controller.signal
|
|
4192
4628
|
});
|
|
4193
4629
|
} finally {
|
|
@@ -4206,12 +4642,20 @@ function createHttpClient(config) {
|
|
|
4206
4642
|
body: json
|
|
4207
4643
|
};
|
|
4208
4644
|
};
|
|
4209
|
-
const
|
|
4210
|
-
const
|
|
4645
|
+
const getConfigRules = async (query) => {
|
|
4646
|
+
const params = new URLSearchParams();
|
|
4647
|
+
if (query?.cursor) params.set("cursor", query.cursor);
|
|
4648
|
+
if (query?.limit !== void 0) params.set("limit", query.limit.toString());
|
|
4649
|
+
if (query?.types !== void 0) {
|
|
4650
|
+
const typesValue = Array.isArray(query.types) ? query.types.join(",") : query.types;
|
|
4651
|
+
if (typesValue.length > 0) params.set("types", typesValue);
|
|
4652
|
+
}
|
|
4653
|
+
const response = await request(params.size > 0 ? `/v1/config/rules?${params.toString()}` : "/v1/config/rules", { method: "GET" });
|
|
4211
4654
|
const json = await response.json();
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4655
|
+
return {
|
|
4656
|
+
statusCode: response.status,
|
|
4657
|
+
body: json
|
|
4658
|
+
};
|
|
4215
4659
|
};
|
|
4216
4660
|
const isAllowed = async (offers) => {
|
|
4217
4661
|
const { statusCode, body } = await validate({ offers: offers.map((offer) => toSnakeCase(offer)) });
|
|
@@ -4239,13 +4683,31 @@ function createHttpClient(config) {
|
|
|
4239
4683
|
issues: []
|
|
4240
4684
|
};
|
|
4241
4685
|
};
|
|
4686
|
+
const getCallbackTypes = async (requestPayload) => {
|
|
4687
|
+
const response = await request("/v1/callbacks", {
|
|
4688
|
+
method: "POST",
|
|
4689
|
+
headers: { "content-type": "application/json" },
|
|
4690
|
+
body: JSON.stringify(requestPayload)
|
|
4691
|
+
});
|
|
4692
|
+
const json = await response.json();
|
|
4693
|
+
if (!response.ok) throw new Error(`Gatekeeper callbacks request failed: ${extractErrorMessage(json) ?? response.statusText}`);
|
|
4694
|
+
if (!("data" in json) || !Array.isArray(json.data)) throw new Error("Gatekeeper callbacks response is invalid.");
|
|
4695
|
+
return json.data;
|
|
4696
|
+
};
|
|
4242
4697
|
return {
|
|
4243
4698
|
baseUrl,
|
|
4244
4699
|
validate,
|
|
4700
|
+
getConfigRules,
|
|
4245
4701
|
isAllowed,
|
|
4246
|
-
|
|
4702
|
+
getCallbackTypes
|
|
4247
4703
|
};
|
|
4248
4704
|
}
|
|
4705
|
+
function mergeHeaders(base, extra) {
|
|
4706
|
+
if (!base && !extra) return void 0;
|
|
4707
|
+
const merged = new Headers(base ?? void 0);
|
|
4708
|
+
if (extra) for (const [key, value] of new Headers(extra).entries()) merged.set(key, value);
|
|
4709
|
+
return merged;
|
|
4710
|
+
}
|
|
4249
4711
|
function normalizeBaseUrl(url) {
|
|
4250
4712
|
return url.trim().replace(/\/+$/, "");
|
|
4251
4713
|
}
|
|
@@ -4341,16 +4803,26 @@ async function run(parameters) {
|
|
|
4341
4803
|
};
|
|
4342
4804
|
}
|
|
4343
4805
|
|
|
4806
|
+
//#endregion
|
|
4807
|
+
//#region src/gatekeeper/Gatekeeper.ts
|
|
4808
|
+
var Gatekeeper_exports = /* @__PURE__ */ __exportAll({ create: () => create });
|
|
4809
|
+
/**
|
|
4810
|
+
* Create a gatekeeper instance with the provided rules.
|
|
4811
|
+
* @param parameters - Gatekeeper parameters. {@link GatekeeperParameters}
|
|
4812
|
+
* @returns Gatekeeper instance. {@link Gatekeeper}
|
|
4813
|
+
*/
|
|
4814
|
+
function create(parameters) {
|
|
4815
|
+
const { rules } = parameters;
|
|
4816
|
+
return { isAllowed: async (offers) => {
|
|
4817
|
+
return await run({
|
|
4818
|
+
items: offers,
|
|
4819
|
+
rules
|
|
4820
|
+
});
|
|
4821
|
+
} };
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4344
4824
|
//#endregion
|
|
4345
4825
|
//#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
4826
|
/**
|
|
4355
4827
|
* Returns the callback configuration for a given chain and callback type, if it exists.
|
|
4356
4828
|
*
|
|
@@ -4373,17 +4845,6 @@ function getCallbackType(chain, address) {
|
|
|
4373
4845
|
return configs[chain].callbacks?.find((c) => c.type !== Type$1.BuyWithEmptyCallback && c.addresses.includes(address?.toLowerCase()))?.type;
|
|
4374
4846
|
}
|
|
4375
4847
|
/**
|
|
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
4848
|
* Returns the list of allowed non-empty callback addresses for a chain.
|
|
4388
4849
|
*
|
|
4389
4850
|
* @param chain - Chain name
|
|
@@ -4482,30 +4943,6 @@ const configs = {
|
|
|
4482
4943
|
}
|
|
4483
4944
|
};
|
|
4484
4945
|
|
|
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
4946
|
//#endregion
|
|
4510
4947
|
//#region src/gatekeeper/Rules.ts
|
|
4511
4948
|
var Rules_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -4706,6 +5143,7 @@ function from(parameters) {
|
|
|
4706
5143
|
const config = {
|
|
4707
5144
|
client: parameters.client,
|
|
4708
5145
|
mempoolAddress: parameters.mempoolAddress,
|
|
5146
|
+
morphoAddress: parameters.morphoAddress,
|
|
4709
5147
|
blockWindow: parameters.blockWindow
|
|
4710
5148
|
};
|
|
4711
5149
|
return {
|
|
@@ -4723,11 +5161,18 @@ function from(parameters) {
|
|
|
4723
5161
|
*/
|
|
4724
5162
|
async function add(config, offers) {
|
|
4725
5163
|
if (!config.client.account) throw new WalletAccountNotSetError();
|
|
4726
|
-
const tree = from$
|
|
5164
|
+
const tree = from$3(offers.map((o) => from$9(o)));
|
|
4727
5165
|
const chainId = await getChainId(config.client);
|
|
4728
5166
|
for (const offer of tree.offers) if (chainId !== offer.chainId) throw new ChainIdMismatchError(offer.chainId, chainId);
|
|
4729
|
-
const
|
|
4730
|
-
const
|
|
5167
|
+
const signatureDomain$1 = resolveSignatureDomain(config, chainId);
|
|
5168
|
+
const signature = await config.client.signTypedData({
|
|
5169
|
+
account: config.client.account,
|
|
5170
|
+
domain: signatureDomain(signatureDomain$1),
|
|
5171
|
+
types: signatureTypes,
|
|
5172
|
+
primaryType: "Root",
|
|
5173
|
+
message: { root: tree.root }
|
|
5174
|
+
});
|
|
5175
|
+
const encoded = await encode(tree, signature, signatureDomain$1);
|
|
4731
5176
|
try {
|
|
4732
5177
|
return await config.client.sendTransaction({
|
|
4733
5178
|
chain: config.client.chain,
|
|
@@ -4766,6 +5211,7 @@ const getChainId = async (client) => {
|
|
|
4766
5211
|
};
|
|
4767
5212
|
async function* streamOffers(config, parameters) {
|
|
4768
5213
|
const { loanToken, blockNumberGte, blockNumberLte, order = "desc", options: { maxBatchSize = DEFAULT_BATCH_SIZE, blockWindow = config.blockWindow } = {} } = parameters;
|
|
5214
|
+
const signatureDomain = resolveSignatureDomain(config, await getChainId(config.client));
|
|
4769
5215
|
const stream = streamLogs({
|
|
4770
5216
|
client: config.client.extend(viem.publicActions),
|
|
4771
5217
|
contractAddress: config.mempoolAddress,
|
|
@@ -4797,7 +5243,7 @@ async function* streamOffers(config, parameters) {
|
|
|
4797
5243
|
if (!log) continue;
|
|
4798
5244
|
const [payload] = (0, viem.decodeAbiParameters)([{ type: "bytes" }], log.data);
|
|
4799
5245
|
try {
|
|
4800
|
-
const { tree } = await decode
|
|
5246
|
+
const { tree } = await decode(payload, signatureDomain);
|
|
4801
5247
|
for (const offer of tree.offers) {
|
|
4802
5248
|
if (loanToken && offer.loanToken.toLowerCase() !== loanToken.toLowerCase()) continue;
|
|
4803
5249
|
offers.push(offer);
|
|
@@ -4832,6 +5278,21 @@ var ChainIdMismatchError = class extends BaseError {
|
|
|
4832
5278
|
_defineProperty(this, "name", "Mempool.ChainIdMismatchError");
|
|
4833
5279
|
}
|
|
4834
5280
|
};
|
|
5281
|
+
const resolveSignatureDomain = (config, chainId) => {
|
|
5282
|
+
const chain = config.client.chain;
|
|
5283
|
+
const verifyingContract = config.morphoAddress ?? chain?.custom?.morpho?.address ?? getChain(chainId)?.custom.morpho.address;
|
|
5284
|
+
if (!verifyingContract || verifyingContract.toLowerCase() === viem.zeroAddress) throw new MissingMorphoAddressError();
|
|
5285
|
+
return {
|
|
5286
|
+
chainId,
|
|
5287
|
+
verifyingContract
|
|
5288
|
+
};
|
|
5289
|
+
};
|
|
5290
|
+
var MissingMorphoAddressError = class extends BaseError {
|
|
5291
|
+
constructor() {
|
|
5292
|
+
super("Morpho address is required to verify root signatures (zero address is invalid).");
|
|
5293
|
+
_defineProperty(this, "name", "Mempool.MissingMorphoAddressError");
|
|
5294
|
+
}
|
|
5295
|
+
};
|
|
4835
5296
|
|
|
4836
5297
|
//#endregion
|
|
4837
5298
|
//#region src/mempool/MempoolClient.ts
|
|
@@ -5045,12 +5506,6 @@ Object.defineProperty(exports, 'Format', {
|
|
|
5045
5506
|
return Format_exports;
|
|
5046
5507
|
}
|
|
5047
5508
|
});
|
|
5048
|
-
Object.defineProperty(exports, 'GateConfig', {
|
|
5049
|
-
enumerable: true,
|
|
5050
|
-
get: function () {
|
|
5051
|
-
return GateConfig_exports;
|
|
5052
|
-
}
|
|
5053
|
-
});
|
|
5054
5509
|
Object.defineProperty(exports, 'Gatekeeper', {
|
|
5055
5510
|
enumerable: true,
|
|
5056
5511
|
get: function () {
|