|
1 | 1 | import { Protocol } from "@src/evm/enums"; |
2 | 2 | import { releasesQueries } from "@src/evm/releases/queries"; |
| 3 | +import { createContractsQueries } from "@src/internal/factories/queries"; |
3 | 4 | import type { Sablier } from "@src/types"; |
4 | | -import _ from "lodash"; |
5 | 5 | import { catalog } from "./catalog"; |
6 | 6 |
|
7 | | -export const contractsQueries = { |
8 | | - /** |
9 | | - * Get a single contract using the following options: |
10 | | - * |
11 | | - * - { chainId, contractName, release } |
12 | | - * - { chainId, contractAddress, protocol } |
13 | | - * - { chainId, contractAddress, release } |
14 | | - * - { chainId, contractAddress, protocol, release } |
15 | | - * |
16 | | - * Note: If a contract address exists in multiple releases for the same protocol, you must specify the release. |
17 | | - */ |
18 | | - get: (opts: { |
19 | | - chainId: number; |
20 | | - contractAddress?: string; |
21 | | - contractName?: string; |
22 | | - protocol?: Sablier.EVM.Protocol; |
23 | | - release?: Sablier.EVM.Release; |
24 | | - }): Sablier.EVM.Contract | undefined => { |
25 | | - const { chainId, contractAddress, contractName, protocol, release } = opts; |
26 | | - |
27 | | - // Validation |
28 | | - if (contractAddress && contractName) { |
29 | | - throw new Error("Sablier SDK: Cannot specify both contractAddress and contractName"); |
30 | | - } |
31 | | - |
32 | | - // Query by name requires release |
33 | | - if (contractName) { |
34 | | - if (!release) { |
35 | | - throw new Error("Sablier SDK: contractName requires release to be specified"); |
36 | | - } |
37 | | - const dep = _.find(release.deployments, { chainId }); |
38 | | - return dep ? _.find(dep.contracts, { name: contractName }) : undefined; |
39 | | - } |
40 | | - |
41 | | - // Query by address |
42 | | - if (contractAddress) { |
43 | | - const address = contractAddress.toLowerCase(); |
44 | | - |
45 | | - // Scoped to specific release |
46 | | - if (release) { |
47 | | - const dep = _.find(release.deployments, { chainId }); |
48 | | - return dep ? _.find(dep.contracts, (c) => c.address.toLowerCase() === address) : undefined; |
49 | | - } |
50 | | - |
51 | | - // Scoped to protocol - check for duplicates across releases |
52 | | - if (protocol) { |
53 | | - const releases = releasesQueries.getAll({ protocol }); |
54 | | - const matches = releases.filter((rel) => { |
55 | | - const dep = _.find(rel.deployments, { chainId }); |
56 | | - return dep && _.some(dep.contracts, (c) => c.address.toLowerCase() === address); |
57 | | - }); |
58 | | - |
59 | | - if (matches.length > 1) { |
60 | | - const versions = matches.map((r) => r.version).join(", "); |
61 | | - throw new Error( |
62 | | - `Sablier SDK: Contract ${contractAddress} exists in multiple releases (${versions}) for "${protocol}". ` + |
63 | | - `Specify release: { chainId, contractAddress, release }`, |
64 | | - ); |
65 | | - } |
66 | | - |
67 | | - return _.get(catalog, [protocol, chainId, address]); |
68 | | - } |
69 | | - |
70 | | - // Fallback: search all protocols |
71 | | - return ( |
72 | | - _.get(catalog, [Protocol.Airdrops, chainId, address]) || |
73 | | - _.get(catalog, [Protocol.Flow, chainId, address]) || |
74 | | - _.get(catalog, [Protocol.Legacy, chainId, address]) || |
75 | | - _.get(catalog, [Protocol.Lockup, chainId, address]) |
76 | | - ); |
77 | | - } |
78 | | - |
79 | | - return undefined; |
80 | | - }, |
81 | | - /** |
82 | | - * Get many contracts. |
83 | | - * - no options ⇒ all |
84 | | - * - { chainId } ⇒ all for that chain |
85 | | - * - { protocol } ⇒ all for that protocol |
86 | | - * - { protocol, chainId } ⇒ all for that protocol and chain |
87 | | - * - { release } ⇒ all deployments of that release |
88 | | - * - { release, chainId } ⇒ all for that release and chain |
89 | | - */ |
90 | | - getAll: (opts?: { |
91 | | - chainId?: number; |
92 | | - protocol?: Sablier.EVM.Protocol; |
93 | | - release?: Sablier.EVM.Release; |
94 | | - }): Sablier.EVM.Contract[] | undefined => { |
95 | | - const { protocol, chainId, release } = opts || {}; |
96 | | - |
97 | | - if (protocol && release) { |
98 | | - throw new Error("Sablier SDK: Cannot specify both protocol and release as query options"); |
99 | | - } |
100 | | - |
101 | | - // by protocol |
102 | | - if (protocol) { |
103 | | - const releases = releasesQueries.getAll({ protocol }); |
104 | | - let deps = _.flatMap(releases, (r) => r.deployments); |
105 | | - if (chainId) { |
106 | | - deps = _.filter(deps, (d) => d.chainId === chainId); |
107 | | - if (deps.length === 0) return undefined; |
108 | | - } |
109 | | - return _.flatMap(deps, (d) => d.contracts); |
110 | | - } |
111 | | - |
112 | | - // by explicit release |
113 | | - if (release) { |
114 | | - let deps = release.deployments; |
115 | | - if (chainId) { |
116 | | - deps = _.filter(deps, (d) => d.chainId === chainId); |
117 | | - if (deps.length === 0) return undefined; |
118 | | - } |
119 | | - return _.flatMap(deps, (d) => d.contracts); |
120 | | - } |
121 | | - |
122 | | - // by chain id |
123 | | - if (chainId) { |
124 | | - const deps = _.flatMap(releasesQueries.getAll(), (r) => r.deployments); |
125 | | - const filtered = _.filter(deps, (d) => d.chainId === chainId); |
126 | | - return _.flatMap(filtered, (d) => d.contracts); |
127 | | - } |
128 | | - |
129 | | - // no filters → all |
130 | | - return _.flatMap(releasesQueries.getAll(), (r) => r.deployments.flatMap((d) => d.contracts)); |
131 | | - }, |
132 | | -}; |
| 7 | +export const contractsQueries = createContractsQueries< |
| 8 | + Sablier.EVM.Protocol, |
| 9 | + Sablier.EVM.Contract, |
| 10 | + Sablier.EVM.Deployment, |
| 11 | + Sablier.EVM.Release, |
| 12 | + Sablier.EVM.ContractCatalog |
| 13 | +>({ |
| 14 | + catalog, |
| 15 | + contractsField: "contracts", |
| 16 | + normalizeAddress: (address) => address.toLowerCase(), |
| 17 | + protocols: [Protocol.Airdrops, Protocol.Flow, Protocol.Legacy, Protocol.Lockup], |
| 18 | + releasesQueries, |
| 19 | +}); |
0 commit comments