@mento-protocol/config 0.1.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.
Files changed (45) hide show
  1. package/aggregators.json +120 -0
  2. package/chain-metadata.json +22 -0
  3. package/deployment-namespaces.json +6 -0
  4. package/dist/aggregators.d.ts +30 -0
  5. package/dist/aggregators.d.ts.map +1 -0
  6. package/dist/aggregators.js +88 -0
  7. package/dist/chains.d.ts +7 -0
  8. package/dist/chains.d.ts.map +1 -0
  9. package/dist/chains.js +29 -0
  10. package/dist/deployment-namespaces.d.ts +7 -0
  11. package/dist/deployment-namespaces.d.ts.map +1 -0
  12. package/dist/deployment-namespaces.js +12 -0
  13. package/dist/erc20-abi.d.ts +25 -0
  14. package/dist/erc20-abi.d.ts.map +1 -0
  15. package/dist/erc20-abi.js +32 -0
  16. package/dist/format.d.ts +3 -0
  17. package/dist/format.d.ts.map +1 -0
  18. package/dist/format.js +12 -0
  19. package/dist/fx-calendar.d.ts +22 -0
  20. package/dist/fx-calendar.d.ts.map +1 -0
  21. package/dist/fx-calendar.js +27 -0
  22. package/dist/oracle-reporters.d.ts +13 -0
  23. package/dist/oracle-reporters.d.ts.map +1 -0
  24. package/dist/oracle-reporters.js +65 -0
  25. package/dist/protocol-fee.d.ts +2 -0
  26. package/dist/protocol-fee.d.ts.map +1 -0
  27. package/dist/protocol-fee.js +13 -0
  28. package/dist/rebalance-abi.d.ts +182 -0
  29. package/dist/rebalance-abi.d.ts.map +1 -0
  30. package/dist/rebalance-abi.js +188 -0
  31. package/dist/rebalance-enrichment.d.ts +137 -0
  32. package/dist/rebalance-enrichment.d.ts.map +1 -0
  33. package/dist/rebalance-enrichment.js +96 -0
  34. package/dist/thresholds.d.ts +25 -0
  35. package/dist/thresholds.d.ts.map +1 -0
  36. package/dist/thresholds.js +33 -0
  37. package/dist/tokens.d.ts +15 -0
  38. package/dist/tokens.d.ts.map +1 -0
  39. package/dist/tokens.js +107 -0
  40. package/dist/units.d.ts +16 -0
  41. package/dist/units.d.ts.map +1 -0
  42. package/dist/units.js +25 -0
  43. package/fx-calendar.json +7 -0
  44. package/oracle-reporters.json +123 -0
  45. package/package.json +109 -0
@@ -0,0 +1,120 @@
1
+ {
2
+ "$comment": "Per-chain aggregator/router contract addresses → canonical name. All addresses lowercased. Verified on-chain via celoscan / monadscan (bytecode + tx history) on 2026-05-04 (cluster-7dc08ec28f299c06 expanded 2026-05-08). Adding a new aggregator: lookup canonical address in the project's docs, verify on the explorer, add here. Removing an entry retroactively re-classifies historical AggregatorDailySnapshot rows as 'unknown' — handle via re-sync.",
3
+ "$clusters": {
4
+ "$comment": "Multi-contract operators on a single deployer EOA. Naming convention: `cluster-<first-16-hex-of-deployer-EOA>` (16 hex chars = 64 bits, collision-free in practice for the foreseeable cluster count). Tag each contract in the per-chain block below with the same `name: cluster-...`. The cluster label is purely a fact about on-chain deploy provenance — no inference about the operator's identity (MEV / MM / arb / etc.) — added so the volume UI can group volume by operator and link to the deployer for follow-up research. The `chainId` field on each cluster entry is informational (where the contracts have been observed); it does NOT constrain placement and a cross-chain deployer would extend the cluster's contract list across multiple per-chain blocks. Adding a cluster: 1) confirm two or more in-our-data contracts share a deployer EOA via celoscan, 2) add the cluster entry here, 3) tag each contract address with the cluster name in the per-chain block.",
5
+ "cluster-7dc08ec28f299c06": {
6
+ "chainId": 42220,
7
+ "deployer": "0x7dc08ec28f299c062d2941de1f9cfb741df8f022",
8
+ "explorerUrl": "https://celoscan.io/address/0x7dc08ec28f299c062d2941de1f9cfb741df8f022",
9
+ "$note": "Operator of a 16-contract MEV fleet on Celo, funded by Binance, deploying via CREATE3 factory 0xba5ed099633d3b313e4d5f7bdc1305d3c28ba5ed. The fleet is code iteration (one fresh build per contract, unique bytecode hash per address, runtime sizes 18–26 KB) — NOT a defensive rotation. A major refactor on 2026-03-29 took success rates from ~37% to >99.7% on Mento legs. Worth re-checking quarterly for new contracts deployed by the operator EOA."
10
+ }
11
+ },
12
+ "42220": {
13
+ "0xbe729350f8cdfc19db6866e8579841188ee57f67": {
14
+ "name": "mento-router-v2",
15
+ "source": "https://celoscan.io/address/0xBE729350F8CdFC19DB6866e8579841188eE57f67",
16
+ "$note": "Original verified MentoRouter on Celo (deployed 2024-05-29). Not in @mento-protocol/contracts — that package only ships the active deployment (Routerv300 at 0x4861840…). Lives here because we still see traffic via this address from the legacy Mento UI / older SDK builds; without this entry it'd land in the v2 volume table's `unknown` bucket."
17
+ },
18
+ "0xce16f69375520ab01377ce7b88f5ba8c48f8d666": {
19
+ "name": "squid",
20
+ "source": "https://docs.squidrouter.com/additional-resources/contracts"
21
+ },
22
+ "0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae": {
23
+ "name": "lifi",
24
+ "source": "https://li.quest/v1/chains?chainTypes=EVM"
25
+ },
26
+ "0xdef1c0ded9bec7f1a1670819833240f027b25eff": {
27
+ "name": "0x",
28
+ "source": "https://github.com/0xProject/protocol/blob/main/packages/contract-addresses/addresses.json"
29
+ },
30
+ "0x6352a56caadc4f1e25cd6c75970fa768a3304e64": {
31
+ "name": "openocean",
32
+ "source": "https://apis.openocean.finance/developer/apis/supported-chains"
33
+ },
34
+ "0xdec876911cbe9428265af0d12132c52ee8642a99": {
35
+ "name": "openocean",
36
+ "source": "https://apis.openocean.finance/developer/apis/supported-chains",
37
+ "$note": "Per-leg executor that the Exchange Proxy at 0x6352a56c…04E64 delegates to. Same deterministic CREATE2 address on 9+ chains (Arbitrum, Avalanche, Base, BSC, Ethereum, Flare, HyperEVM, Optimism, Polygon — Arkham-attested as the OpenOcean entity on every one)."
38
+ },
39
+ "0xf184a8498f4bad5ca6ef538b72142411588792a3": {
40
+ "name": "cluster-7dc08ec28f299c06",
41
+ "source": "https://celoscan.io/address/0xf184a8498f4bad5ca6ef538b72142411588792a3"
42
+ },
43
+ "0xea99a75e309868a59074e9b0441c14ba62c6ea28": {
44
+ "name": "cluster-7dc08ec28f299c06",
45
+ "source": "https://celoscan.io/address/0xea99a75e309868a59074e9b0441c14ba62c6ea28"
46
+ },
47
+ "0x953b7173200229f255f83b6f4fa448d753b79301": {
48
+ "name": "cluster-7dc08ec28f299c06",
49
+ "source": "https://celoscan.io/address/0x953b7173200229f255f83b6f4fa448d753b79301"
50
+ },
51
+ "0xf023c10a9adb0553ce07d37f367630e4e84a944e": {
52
+ "name": "cluster-7dc08ec28f299c06",
53
+ "source": "https://celoscan.io/address/0xf023c10a9adb0553ce07d37f367630e4e84a944e"
54
+ },
55
+ "0x187c35dbbc8055b267303dd7b351e708f4c5d3bf": {
56
+ "name": "cluster-7dc08ec28f299c06",
57
+ "source": "https://celoscan.io/address/0x187c35dbbc8055b267303dd7b351e708f4c5d3bf"
58
+ },
59
+ "0x9bfbcd07ea9c3cdc30057d7629beb589fe2d854d": {
60
+ "name": "cluster-7dc08ec28f299c06",
61
+ "source": "https://celoscan.io/address/0x9bfbcd07ea9c3cdc30057d7629beb589fe2d854d"
62
+ },
63
+ "0xfe8237bcba52339d818c9c9c3c94481196e4b653": {
64
+ "name": "cluster-7dc08ec28f299c06",
65
+ "source": "https://celoscan.io/address/0xfe8237bcba52339d818c9c9c3c94481196e4b653"
66
+ },
67
+ "0x35f629410baffd35c482a1f77cfb0ec2f0a75c76": {
68
+ "name": "cluster-7dc08ec28f299c06",
69
+ "source": "https://celoscan.io/address/0x35f629410baffd35c482a1f77cfb0ec2f0a75c76"
70
+ },
71
+ "0x1bbcc3dad88fe33248a9ab6600fe72235c51d7ce": {
72
+ "name": "cluster-7dc08ec28f299c06",
73
+ "source": "https://celoscan.io/address/0x1bbcc3dad88fe33248a9ab6600fe72235c51d7ce"
74
+ },
75
+ "0x48d5be40f43fd70ed9329dc0e83b8c5d3a3364f4": {
76
+ "name": "cluster-7dc08ec28f299c06",
77
+ "source": "https://celoscan.io/address/0x48d5be40f43fd70ed9329dc0e83b8c5d3a3364f4"
78
+ },
79
+ "0x93acb2d456edeffa2e2ea97efc4fa4d17c39d4b8": {
80
+ "name": "cluster-7dc08ec28f299c06",
81
+ "source": "https://celoscan.io/address/0x93acb2d456edeffa2e2ea97efc4fa4d17c39d4b8"
82
+ },
83
+ "0xef6956414006e161fca5f048331d91e472077e9b": {
84
+ "name": "cluster-7dc08ec28f299c06",
85
+ "source": "https://celoscan.io/address/0xef6956414006e161fca5f048331d91e472077e9b"
86
+ },
87
+ "0x00d1cda22d867e2d2f22931b5567e93cc1e047cd": {
88
+ "name": "cluster-7dc08ec28f299c06",
89
+ "source": "https://celoscan.io/address/0x00d1cda22d867e2d2f22931b5567e93cc1e047cd"
90
+ },
91
+ "0x2e73e4a7f4c2ee4fb5d5d2fd823821e3975237d7": {
92
+ "name": "cluster-7dc08ec28f299c06",
93
+ "source": "https://celoscan.io/address/0x2e73e4a7f4c2ee4fb5d5d2fd823821e3975237d7"
94
+ },
95
+ "0x6f9fe2b0acf50874dcb49faefff62382381bf622": {
96
+ "name": "cluster-7dc08ec28f299c06",
97
+ "source": "https://celoscan.io/address/0x6f9fe2b0acf50874dcb49faefff62382381bf622"
98
+ },
99
+ "0xc2068e03ca948f54348899eeda1417a901d76285": {
100
+ "name": "cluster-7dc08ec28f299c06",
101
+ "source": "https://celoscan.io/address/0xc2068e03ca948f54348899eeda1417a901d76285"
102
+ }
103
+ },
104
+ "143": {
105
+ "0x026f252016a7c47cdef1f05a3fc9e20c92a49c37": {
106
+ "name": "lifi",
107
+ "source": "https://li.quest/v1/chains?chainTypes=EVM",
108
+ "$note": "Non-default LI.FI diamond on Monad — not the 0x1231… address used on most chains."
109
+ },
110
+ "0x0000000000001ff3684f28c67538d4d072c22734": {
111
+ "name": "0x",
112
+ "source": "https://docs.0x.org/introduction/0x-cheat-sheet",
113
+ "$note": "0x V2 AllowanceHolder. Per-pair Settler contracts rotate and are not stable enough to track here; AllowanceHolder is the stable entry point."
114
+ },
115
+ "0x6352a56caadc4f1e25cd6c75970fa768a3304e64": {
116
+ "name": "openocean",
117
+ "source": "https://apis.openocean.finance/developer/apis/supported-chains"
118
+ }
119
+ }
120
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "42220": {
3
+ "slug": "celo",
4
+ "label": "Celo",
5
+ "explorerBaseUrl": "https://celoscan.io"
6
+ },
7
+ "143": {
8
+ "slug": "monad",
9
+ "label": "Monad",
10
+ "explorerBaseUrl": "https://monadscan.com"
11
+ },
12
+ "11142220": {
13
+ "slug": "celo-sepolia",
14
+ "label": "Celo Sepolia",
15
+ "explorerBaseUrl": "https://celo-sepolia.blockscout.com"
16
+ },
17
+ "10143": {
18
+ "slug": "monad-testnet",
19
+ "label": "Monad Testnet",
20
+ "explorerBaseUrl": "https://testnet.monadscan.com"
21
+ }
22
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "42220": "mainnet",
3
+ "11142220": "testnet-v2-rc5",
4
+ "143": "mainnet",
5
+ "10143": "testnet-v2-rc5"
6
+ }
@@ -0,0 +1,30 @@
1
+ type RawClusterMetadata = {
2
+ chainId: number;
3
+ deployer: string;
4
+ explorerUrl: string;
5
+ $note?: string;
6
+ };
7
+ export type AggregatorClusterMetadata = {
8
+ chainId: number;
9
+ deployer: string;
10
+ explorerUrl: string;
11
+ note?: string;
12
+ };
13
+ export declare function _buildClusterMap(raw: unknown): Record<string, RawClusterMetadata>;
14
+ /** Aggregator name (e.g. "squid") for a given (chainId, address), or null
15
+ * when the address isn't a known aggregator on that chain. */
16
+ export declare function getAggregatorName(chainId: number, address: string): string | null;
17
+ /** First registered address for a given (chainId, aggregator name), or null
18
+ * when no entry matches. Use this when test fixtures or scripts need the
19
+ * canonical address for a known aggregator — keeps the address literal in
20
+ * one place. Returns the first match if a name has multiple addresses on
21
+ * the same chain (e.g. openocean's per-leg executor). */
22
+ export declare function getAggregatorAddress(chainId: number, name: string): string | null;
23
+ /** All `(address → aggregatorName)` entries for a chain, in insertion order
24
+ * (matches JSON key order). Use this to enumerate or filter aggregators —
25
+ * e.g. dashboard widgets, forensic scripts, monitoring jobs. */
26
+ export declare function aggregatorsByChain(chainId: number): ReadonlyMap<string, string>;
27
+ export declare function getClusterMetadata(aggregatorName: string): AggregatorClusterMetadata | undefined;
28
+ export declare function clusterNames(): string[];
29
+ export {};
30
+ //# sourceMappingURL=aggregators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregators.d.ts","sourceRoot":"","sources":["../src/aggregators.ts"],"names":[],"mappings":"AASA,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAQF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAiCF,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,OAAO,GACX,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CASpC;AAMD;+DAC+D;AAC/D,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,IAAI,CAEf;AAED;;;;0DAI0D;AAC1D,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAMf;AAED;;iEAEiE;AACjE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GACd,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAE7B;AAED,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,MAAM,GACrB,yBAAyB,GAAG,SAAS,CASvC;AAED,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC"}
@@ -0,0 +1,88 @@
1
+ // Canonical aggregator/router registry — chain → address → {name, source}.
2
+ // Source of truth for both the indexer's swap classifier and any UI / forensic
3
+ // tooling that needs to look up an aggregator by name or address. The
4
+ // `indexer-envio/config/aggregators.json` file is a vendored copy of this
5
+ // (indexer builds outside the pnpm workspace); a parity test in
6
+ // `indexer-envio/test/aggregators-parity.test.ts` keeps the two in lockstep.
7
+ import aggregatorsJson from "../aggregators.json" with { type: "json" };
8
+ // The JSON mixes per-chain blocks with `$comment` / `$clusters` keys at the
9
+ // top level, and `$clusters` itself mixes the cluster entries with a nested
10
+ // `$comment`. TypeScript can't express that heterogeneous shape cleanly, so
11
+ // we go through `unknown` once and validate the slices we use at runtime.
12
+ const ROOT = aggregatorsJson;
13
+ // Per-chain `Map<lowercaseAddress, aggregatorName>` derived from the JSON.
14
+ // Built once at module load so consumers can do constant-time lookups.
15
+ const ADDRESSES_BY_CHAIN = (() => {
16
+ const out = new Map();
17
+ for (const [key, value] of Object.entries(ROOT)) {
18
+ if (key.startsWith("$"))
19
+ continue; // skip $comment, $clusters
20
+ const chainId = Number(key);
21
+ if (!Number.isFinite(chainId))
22
+ continue;
23
+ const inner = new Map();
24
+ for (const [addr, entry] of Object.entries(value)) {
25
+ // Per-chain blocks only ever hold address-keyed entries — `$comment`
26
+ // / `$clusters` live at the top level, not inside a chain block — so
27
+ // no `$`-prefix filter is needed here.
28
+ inner.set(addr.toLowerCase(), entry.name);
29
+ }
30
+ out.set(chainId, inner);
31
+ }
32
+ return out;
33
+ })();
34
+ // Exposed for unit tests so we can exercise the "missing/malformed
35
+ // $clusters" branch without mocking the JSON import. The module's own
36
+ // CLUSTERS map is built by calling this with `ROOT.$clusters`.
37
+ export function _buildClusterMap(raw) {
38
+ const out = {};
39
+ if (raw == null || typeof raw !== "object")
40
+ return out;
41
+ for (const [name, value] of Object.entries(raw)) {
42
+ if (name.startsWith("$"))
43
+ continue;
44
+ if (value == null || typeof value !== "object")
45
+ continue;
46
+ out[name] = value;
47
+ }
48
+ return out;
49
+ }
50
+ const CLUSTERS = _buildClusterMap(ROOT.$clusters);
51
+ /** Aggregator name (e.g. "squid") for a given (chainId, address), or null
52
+ * when the address isn't a known aggregator on that chain. */
53
+ export function getAggregatorName(chainId, address) {
54
+ return ADDRESSES_BY_CHAIN.get(chainId)?.get(address.toLowerCase()) ?? null;
55
+ }
56
+ /** First registered address for a given (chainId, aggregator name), or null
57
+ * when no entry matches. Use this when test fixtures or scripts need the
58
+ * canonical address for a known aggregator — keeps the address literal in
59
+ * one place. Returns the first match if a name has multiple addresses on
60
+ * the same chain (e.g. openocean's per-leg executor). */
61
+ export function getAggregatorAddress(chainId, name) {
62
+ const lower = name.toLowerCase();
63
+ for (const [addr, entryName] of ADDRESSES_BY_CHAIN.get(chainId) ?? []) {
64
+ if (entryName.toLowerCase() === lower)
65
+ return addr;
66
+ }
67
+ return null;
68
+ }
69
+ /** All `(address → aggregatorName)` entries for a chain, in insertion order
70
+ * (matches JSON key order). Use this to enumerate or filter aggregators —
71
+ * e.g. dashboard widgets, forensic scripts, monitoring jobs. */
72
+ export function aggregatorsByChain(chainId) {
73
+ return ADDRESSES_BY_CHAIN.get(chainId) ?? new Map();
74
+ }
75
+ export function getClusterMetadata(aggregatorName) {
76
+ const meta = CLUSTERS[aggregatorName];
77
+ if (!meta)
78
+ return undefined;
79
+ return {
80
+ chainId: meta.chainId,
81
+ deployer: meta.deployer,
82
+ explorerUrl: meta.explorerUrl,
83
+ ...(meta.$note !== undefined && { note: meta.$note }),
84
+ };
85
+ }
86
+ export function clusterNames() {
87
+ return Object.keys(CLUSTERS).sort();
88
+ }
@@ -0,0 +1,7 @@
1
+ export declare function hasChain(chainId: number): boolean;
2
+ export declare function chainSlug(chainId: number): string;
3
+ export declare function chainLabel(chainId: number): string;
4
+ export declare function explorerBaseUrl(chainId: number): string | null;
5
+ export declare function explorerAddressUrl(chainId: number, address: string): string | null;
6
+ export declare function explorerTxUrl(chainId: number, txHash: string): string | null;
7
+ //# sourceMappingURL=chains.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../src/chains.ts"],"names":[],"mappings":"AAkBA,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,IAAI,CAGf;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5E"}
package/dist/chains.js ADDED
@@ -0,0 +1,29 @@
1
+ import chainMetadataJson from "../chain-metadata.json" with { type: "json" };
2
+ const CHAIN_METADATA = chainMetadataJson;
3
+ function entry(chainId) {
4
+ return CHAIN_METADATA[String(chainId)];
5
+ }
6
+ // True when the chainId has an entry in chain-metadata.json. Callers that
7
+ // need to detect "missing chain" should use this instead of comparing
8
+ // `chainSlug(id) === String(id)` — `chainSlug` is pass-through on miss
9
+ // and that sentinel string can collide with valid future slugs.
10
+ export function hasChain(chainId) {
11
+ return entry(chainId) !== undefined;
12
+ }
13
+ export function chainSlug(chainId) {
14
+ return entry(chainId)?.slug ?? String(chainId);
15
+ }
16
+ export function chainLabel(chainId) {
17
+ return entry(chainId)?.label ?? chainSlug(chainId);
18
+ }
19
+ export function explorerBaseUrl(chainId) {
20
+ return entry(chainId)?.explorerBaseUrl ?? null;
21
+ }
22
+ export function explorerAddressUrl(chainId, address) {
23
+ const base = explorerBaseUrl(chainId);
24
+ return base ? `${base}/address/${address}` : null;
25
+ }
26
+ export function explorerTxUrl(chainId, txHash) {
27
+ const base = explorerBaseUrl(chainId);
28
+ return base ? `${base}/tx/${txHash}` : null;
29
+ }
@@ -0,0 +1,7 @@
1
+ export declare const DEPLOYMENT_NAMESPACE_CHAIN_IDS: readonly ["42220", "11142220", "143", "10143"];
2
+ export type DeploymentNamespaceChainId = (typeof DEPLOYMENT_NAMESPACE_CHAIN_IDS)[number];
3
+ export type DeploymentNamespaceByChainId = Readonly<Record<DeploymentNamespaceChainId, string>>;
4
+ export declare const DEPLOYMENT_NAMESPACES: DeploymentNamespaceByChainId;
5
+ export declare function deploymentNamespace(chainId: number): string | null;
6
+ export default DEPLOYMENT_NAMESPACES;
7
+ //# sourceMappingURL=deployment-namespaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-namespaces.d.ts","sourceRoot":"","sources":["../src/deployment-namespaces.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,8BAA8B,gDAKjC,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC;AAClD,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CACjD,MAAM,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAC3C,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,4BACV,CAAC;AAE3B,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE;AAED,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import deploymentNamespacesJson from "../deployment-namespaces.json" with { type: "json" };
2
+ export const DEPLOYMENT_NAMESPACE_CHAIN_IDS = [
3
+ "42220",
4
+ "11142220",
5
+ "143",
6
+ "10143",
7
+ ];
8
+ export const DEPLOYMENT_NAMESPACES = deploymentNamespacesJson;
9
+ export function deploymentNamespace(chainId) {
10
+ return (DEPLOYMENT_NAMESPACES[String(chainId)] ?? null);
11
+ }
12
+ export default DEPLOYMENT_NAMESPACES;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ERC20 ABI fragments shared by every consumer that walks pool/token contracts
3
+ * (ui-dashboard's pool-detail probe, metrics-bridge's reserve-collateral
4
+ * enrichment). String-array form rather than viem-typed ABI so the
5
+ * shared-config package stays viem-free — consumers feed this list into
6
+ * `parseAbi(...)` to materialise a typed ABI on their side.
7
+ *
8
+ * Drift between the dashboard and the bridge here is harmless (ERC20 +
9
+ * pool-pair shapes are stable interfaces) but duplicating selectors verbatim
10
+ * across packages was ~30 LOC of pure copy-paste. Single canonical list
11
+ * keeps `function symbol()` / `function decimals()` etc. in lockstep.
12
+ *
13
+ * Implementation note: the `as const` annotation preserves literal types so
14
+ * `parseAbi(ERC20_ABI_SOURCES)` produces a strongly-typed ABI on the consumer
15
+ * side rather than collapsing to `string[]`.
16
+ */
17
+ export declare const ERC20_ABI_SOURCES: readonly ["function balanceOf(address account) external view returns (uint256)", "function decimals() external view returns (uint8)", "function symbol() external view returns (string)", "function totalSupply() external view returns (uint256)"];
18
+ /**
19
+ * Pool-pair token-getter ABI. `function token0() / token1()` — used during
20
+ * reserve-collateral enrichment to identify the non-debt leg of the pool.
21
+ * Stable across every FPMM pool implementation, kept here for parity with
22
+ * the ERC20 fragments.
23
+ */
24
+ export declare const POOL_PAIR_ABI_SOURCES: readonly ["function token0() external view returns (address)", "function token1() external view returns (address)"];
25
+ //# sourceMappingURL=erc20-abi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"erc20-abi.d.ts","sourceRoot":"","sources":["../src/erc20-abi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,qPAKpB,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,qHAGxB,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ERC20 ABI fragments shared by every consumer that walks pool/token contracts
3
+ * (ui-dashboard's pool-detail probe, metrics-bridge's reserve-collateral
4
+ * enrichment). String-array form rather than viem-typed ABI so the
5
+ * shared-config package stays viem-free — consumers feed this list into
6
+ * `parseAbi(...)` to materialise a typed ABI on their side.
7
+ *
8
+ * Drift between the dashboard and the bridge here is harmless (ERC20 +
9
+ * pool-pair shapes are stable interfaces) but duplicating selectors verbatim
10
+ * across packages was ~30 LOC of pure copy-paste. Single canonical list
11
+ * keeps `function symbol()` / `function decimals()` etc. in lockstep.
12
+ *
13
+ * Implementation note: the `as const` annotation preserves literal types so
14
+ * `parseAbi(ERC20_ABI_SOURCES)` produces a strongly-typed ABI on the consumer
15
+ * side rather than collapsing to `string[]`.
16
+ */
17
+ export const ERC20_ABI_SOURCES = [
18
+ "function balanceOf(address account) external view returns (uint256)",
19
+ "function decimals() external view returns (uint8)",
20
+ "function symbol() external view returns (string)",
21
+ "function totalSupply() external view returns (uint256)",
22
+ ];
23
+ /**
24
+ * Pool-pair token-getter ABI. `function token0() / token1()` — used during
25
+ * reserve-collateral enrichment to identify the non-debt leg of the pool.
26
+ * Stable across every FPMM pool implementation, kept here for parity with
27
+ * the ERC20 fragments.
28
+ */
29
+ export const POOL_PAIR_ABI_SOURCES = [
30
+ "function token0() external view returns (address)",
31
+ "function token1() external view returns (address)",
32
+ ];
@@ -0,0 +1,3 @@
1
+ export declare function poolIdAddress(poolId: string): string;
2
+ export declare function shortAddress(address: string): string;
3
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AACA,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGpD;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD"}
package/dist/format.js ADDED
@@ -0,0 +1,12 @@
1
+ // `42220-0xabc` → `0xabc`. Input returned unchanged if no dash.
2
+ export function poolIdAddress(poolId) {
3
+ const dash = poolId.indexOf("-");
4
+ return dash >= 0 ? poolId.slice(dash + 1) : poolId;
5
+ }
6
+ // `0x93e15a22…ead61` → `0x93e1…ad61`. Keeps 4 leading + 4 trailing nibbles
7
+ // so both ends stay distinguishable in Slack without eating 40+ chars.
8
+ export function shortAddress(address) {
9
+ if (!address.startsWith("0x") || address.length < 12)
10
+ return address;
11
+ return `${address.slice(0, 6)}…${address.slice(-4)}`;
12
+ }
@@ -0,0 +1,22 @@
1
+ export type FxCalendarConfig = {
2
+ fxCloseDay: number;
3
+ fxCloseHourUtc: number;
4
+ fxReopenDay: number;
5
+ fxReopenHourUtc: number;
6
+ anchorFri2100UnixSec: number;
7
+ };
8
+ export declare function assertFxCalendarConfig(value: unknown): asserts value is FxCalendarConfig;
9
+ export declare const FX_CALENDAR: {
10
+ fxCloseDay: number;
11
+ fxCloseHourUtc: number;
12
+ fxReopenDay: number;
13
+ fxReopenHourUtc: number;
14
+ anchorFri2100UnixSec: number;
15
+ };
16
+ export declare const FX_CLOSE_DAY: number;
17
+ export declare const FX_CLOSE_HOUR_UTC: number;
18
+ export declare const FX_REOPEN_DAY: number;
19
+ export declare const FX_REOPEN_HOUR_UTC: number;
20
+ export declare const ANCHOR_FRI_2100_UNIX_SEC: number;
21
+ export default FX_CALENDAR;
22
+ //# sourceMappingURL=fx-calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-calendar.d.ts","sourceRoot":"","sources":["../src/fx-calendar.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAUF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,KAAK,IAAI,gBAAgB,CAWnC;AAID,eAAO,MAAM,WAAW;;;;;;CAAiB,CAAC;AAE1C,eAAO,MAAM,YAAY,QAAyB,CAAC;AACnD,eAAO,MAAM,iBAAiB,QAA6B,CAAC;AAC5D,eAAO,MAAM,aAAa,QAA0B,CAAC;AACrD,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,wBAAwB,QAAmC,CAAC;AAEzE,eAAe,WAAW,CAAC"}
@@ -0,0 +1,27 @@
1
+ import fxCalendarJson from "../fx-calendar.json" with { type: "json" };
2
+ const FX_CALENDAR_NUMBER_FIELDS = [
3
+ "fxCloseDay",
4
+ "fxCloseHourUtc",
5
+ "fxReopenDay",
6
+ "fxReopenHourUtc",
7
+ "anchorFri2100UnixSec",
8
+ ];
9
+ export function assertFxCalendarConfig(value) {
10
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
11
+ throw new TypeError("fx-calendar.json must be an object");
12
+ }
13
+ const record = value;
14
+ for (const field of FX_CALENDAR_NUMBER_FIELDS) {
15
+ if (typeof record[field] !== "number") {
16
+ throw new TypeError(`fx-calendar.json field ${field} must be a number`);
17
+ }
18
+ }
19
+ }
20
+ assertFxCalendarConfig(fxCalendarJson);
21
+ export const FX_CALENDAR = fxCalendarJson;
22
+ export const FX_CLOSE_DAY = FX_CALENDAR.fxCloseDay;
23
+ export const FX_CLOSE_HOUR_UTC = FX_CALENDAR.fxCloseHourUtc;
24
+ export const FX_REOPEN_DAY = FX_CALENDAR.fxReopenDay;
25
+ export const FX_REOPEN_HOUR_UTC = FX_CALENDAR.fxReopenHourUtc;
26
+ export const ANCHOR_FRI_2100_UNIX_SEC = FX_CALENDAR.anchorFri2100UnixSec;
27
+ export default FX_CALENDAR;
@@ -0,0 +1,13 @@
1
+ export declare const ORACLE_REPORTER_TYPES: readonly ["CHAINLINK", "REDSTONE", "BRIDGED", "MANUAL"];
2
+ export type OracleReporterType = (typeof ORACLE_REPORTER_TYPES)[number];
3
+ export declare function getRateFeedPair(chainId: number, feedAddress: string): string | null;
4
+ export declare function getRateFeedReporterType(chainId: number, feedAddress: string): OracleReporterType | null;
5
+ export declare function getChainlinkDataFeedUrl(chainId: number, pair: string, slugOverride?: string): string | null;
6
+ export declare function getRateFeedChainlinkDataFeedUrl(chainId: number, feedAddress: string): string | null;
7
+ export declare function getOracleReporterType(chainId: number, reporterAddress: string): OracleReporterType;
8
+ export declare function describeRateFeed(chainId: number, feedAddress: string, reporters: ReadonlyArray<string>): {
9
+ pair: string;
10
+ reporterTypes: OracleReporterType[];
11
+ };
12
+ export declare function knownRateFeedsByChain(chainId: number): ReadonlyMap<string, string>;
13
+ //# sourceMappingURL=oracle-reporters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oracle-reporters.d.ts","sourceRoot":"","sources":["../src/oracle-reporters.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,yDAKxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAgDxE,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAEf;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,kBAAkB,GAAG,IAAI,CAG3B;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,GACtB,kBAAkB,CAIpB;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,GAC/B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,kBAAkB,EAAE,CAAC;CACrC,CAOA;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GACd,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAW7B"}
@@ -0,0 +1,65 @@
1
+ import oracleReportersJson from "../oracle-reporters.json" with { type: "json" };
2
+ export const ORACLE_REPORTER_TYPES = [
3
+ "CHAINLINK",
4
+ "REDSTONE",
5
+ "BRIDGED",
6
+ "MANUAL",
7
+ ];
8
+ const ROOT = oracleReportersJson;
9
+ const REPORTER_TYPE_SET = new Set(ORACLE_REPORTER_TYPES);
10
+ const CHAINLINK_FEED_PATH_BY_CHAIN = {
11
+ 42220: "celo/mainnet",
12
+ 143: "monad/monad",
13
+ };
14
+ function chainEntry(chainId) {
15
+ return ROOT[String(chainId)];
16
+ }
17
+ function normalizeAddress(address) {
18
+ return address.toLowerCase();
19
+ }
20
+ function feedEntry(chainId, feedAddress) {
21
+ return chainEntry(chainId)?.feeds?.[normalizeAddress(feedAddress)];
22
+ }
23
+ function isReporterType(value) {
24
+ return value !== undefined && REPORTER_TYPE_SET.has(value);
25
+ }
26
+ export function getRateFeedPair(chainId, feedAddress) {
27
+ return feedEntry(chainId, feedAddress)?.pair ?? null;
28
+ }
29
+ export function getRateFeedReporterType(chainId, feedAddress) {
30
+ const raw = feedEntry(chainId, feedAddress)?.type;
31
+ return isReporterType(raw) ? raw : null;
32
+ }
33
+ export function getChainlinkDataFeedUrl(chainId, pair, slugOverride) {
34
+ const path = CHAINLINK_FEED_PATH_BY_CHAIN[chainId];
35
+ if (!path)
36
+ return null;
37
+ const slug = slugOverride ?? pair.toLowerCase().replace(/\//g, "-");
38
+ return `https://data.chain.link/feeds/${path}/${slug}`;
39
+ }
40
+ export function getRateFeedChainlinkDataFeedUrl(chainId, feedAddress) {
41
+ const entry = feedEntry(chainId, feedAddress);
42
+ return entry?.type === "CHAINLINK"
43
+ ? getChainlinkDataFeedUrl(chainId, entry.pair, entry.chainlinkSlug)
44
+ : null;
45
+ }
46
+ export function getOracleReporterType(chainId, reporterAddress) {
47
+ const raw = chainEntry(chainId)?.reporters?.[normalizeAddress(reporterAddress)]?.type;
48
+ return isReporterType(raw) ? raw : "MANUAL";
49
+ }
50
+ export function describeRateFeed(chainId, feedAddress, reporters) {
51
+ return {
52
+ pair: getRateFeedPair(chainId, feedAddress) ?? "Unknown",
53
+ reporterTypes: reporters.map((reporter) => getOracleReporterType(chainId, reporter)),
54
+ };
55
+ }
56
+ export function knownRateFeedsByChain(chainId) {
57
+ const feeds = chainEntry(chainId)?.feeds;
58
+ if (!feeds) {
59
+ return new Map();
60
+ }
61
+ return new Map(Object.entries(feeds).map(([address, entry]) => [
62
+ normalizeAddress(address),
63
+ entry.pair,
64
+ ]));
65
+ }
@@ -0,0 +1,2 @@
1
+ export declare const PROTOCOL_FEE_RECIPIENT_ADDRESS: `0x${string}`;
2
+ //# sourceMappingURL=protocol-fee.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol-fee.d.ts","sourceRoot":"","sources":["../src/protocol-fee.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,8BAA8B,EACT,KAAK,MAAM,EAAE,CAAC"}
@@ -0,0 +1,13 @@
1
+ // Address that receives all protocol fees across every chain. The same
2
+ // address by Mento's deterministic-deploy convention — the contracts package
3
+ // publishes it as `YieldSplitAddress` on Celo mainnet and `ProtocolFeeRecipient`
4
+ // on every other namespace. Derived from `@mento-protocol/contracts` so we
5
+ // don't have to chase address changes through the dashboard + indexer + URLs.
6
+ import contractsData from "@mento-protocol/contracts/contracts.json" with { type: "json" };
7
+ const SOURCE = contractsData["42220"]?.mainnet
8
+ ?.YieldSplitAddress;
9
+ if (!SOURCE) {
10
+ throw new Error("YieldSplitAddress missing from @mento-protocol/contracts at 42220/mainnet — " +
11
+ "package contract may have been renamed; update shared-config/src/protocol-fee.ts");
12
+ }
13
+ export const PROTOCOL_FEE_RECIPIENT_ADDRESS = SOURCE.address.toLowerCase();