@raac/rpc 2.0.0-beta.0 → 2.0.0-beta.1

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.
@@ -98,6 +98,7 @@ const getContractAddress_1 = __importDefault(require("./contracts/getContractAdd
98
98
  const getContract_1 = __importDefault(require("./contracts/getContract"));
99
99
  const findContract_1 = require("./contracts/findContract");
100
100
  const decodeCall_1 = require("./contracts/decodeCall");
101
+ const resolveName_1 = require("./contracts/resolveName");
101
102
  // House Prices
102
103
  const getLatestPrice_1 = __importDefault(require("./contracts/housePrices/getLatestPrice"));
103
104
  const setOracle_1 = __importDefault(require("./contracts/housePrices/setOracle"));
@@ -457,6 +458,8 @@ class RPCLibrary {
457
458
  getContract: getContract_1.default,
458
459
  findContract: findContract_1.findContract,
459
460
  decodeCall: decodeCall_1.decodeCall,
461
+ resolveName: resolveName_1.resolveName,
462
+ resolveNames: resolveName_1.resolveNames,
460
463
  feeCollector: {
461
464
  claimRewardFromPool: claimRewardFromPool_1.default,
462
465
  },
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // @ts-ignore
7
+ const _1_json_1 = __importDefault(require("./1.json"));
8
+ const _8453_json_1 = __importDefault(require("./8453.json"));
9
+ const _17000_json_1 = __importDefault(require("./17000.json"));
10
+ const _11155111_json_1 = __importDefault(require("./11155111.json"));
11
+ const _18453_json_1 = __importDefault(require("./18453.json"));
12
+ /**
13
+ * Curated, off-chain-known addresses per chain (wallets, external protocols),
14
+ * keyed by checksummed address. Empty until entries are reviewed and added -
15
+ * see resolveName.ts for why this ships empty rather than with guessed data.
16
+ */
17
+ const registries = {
18
+ 1: _1_json_1.default,
19
+ 8453: _8453_json_1.default,
20
+ 17000: _17000_json_1.default,
21
+ 11155111: _11155111_json_1.default,
22
+ 18453: _18453_json_1.default,
23
+ };
24
+ exports.default = registries;
@@ -50,6 +50,21 @@ function listContracts(chainId) {
50
50
  }
51
51
  return found;
52
52
  }
53
+ const contractsByAddress = new Map();
54
+ /** Address -> entry index for a chain, built on first use. First match wins, as in `listContracts`. */
55
+ function getContractIndex(chainId) {
56
+ const key = String(chainId);
57
+ let index = contractsByAddress.get(key);
58
+ if (!index) {
59
+ index = {};
60
+ for (const entry of listContracts(chainId)) {
61
+ if (!(entry.address in index))
62
+ index[entry.address] = entry;
63
+ }
64
+ contractsByAddress.set(key, index);
65
+ }
66
+ return index;
67
+ }
53
68
  /**
54
69
  * Finds a contract by address in the chain config.
55
70
  * Reads the chain config only; no RPC call is made.
@@ -61,8 +76,7 @@ function listContracts(chainId) {
61
76
  const findContract = (chainId, address) => {
62
77
  if (!ethers_1.ethers.isAddress(address))
63
78
  return null;
64
- const target = ethers_1.ethers.getAddress(address);
65
- return listContracts(chainId).find((c) => c.address === target) ?? null;
79
+ return getContractIndex(chainId)[ethers_1.ethers.getAddress(address)] ?? null;
66
80
  };
67
81
  exports.findContract = findContract;
68
82
  exports.default = exports.findContract;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveName = resolveName;
7
+ exports.resolveNames = resolveNames;
8
+ const ethers_1 = require("ethers");
9
+ const chains_1 = __importDefault(require("../configs/chains"));
10
+ const findContract_1 = require("./findContract");
11
+ const registry_1 = __importDefault(require("../configs/registry"));
12
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
13
+ const BURN_ADDRESS = "0x000000000000000000000000000000000000dEaD";
14
+ /** Universal, chain-agnostic entries that do not belong in a per-chain registry file. */
15
+ const BUILTIN_REGISTRY = {
16
+ [ZERO_ADDRESS]: { name: "None", kind: "external" },
17
+ [ethers_1.ethers.getAddress(BURN_ADDRESS)]: { name: "Burn", kind: "external" },
18
+ };
19
+ /** address -> { name, expiresAt } | null (a confirmed miss, cached too so a repeat lookup does not re-hit the network). */
20
+ const ensCache = new Map();
21
+ const ENS_TTL_MS = 60 * 60 * 1000;
22
+ function contractInfoToAddressName(info) {
23
+ return {
24
+ address: info.address,
25
+ name: info.name,
26
+ kind: info.section === "gauges" ? "gauge" : "contract",
27
+ source: "config",
28
+ };
29
+ }
30
+ function lookupRegistry(chainId, address) {
31
+ const builtin = BUILTIN_REGISTRY[address];
32
+ if (builtin)
33
+ return { address, ...builtin, source: "registry" };
34
+ const registry = registry_1.default[String(chainId)];
35
+ const entry = registry?.[address];
36
+ if (!entry)
37
+ return null;
38
+ return { address, ...entry, source: "registry" };
39
+ }
40
+ async function lookupEns(address, provider) {
41
+ const cached = ensCache.get(address);
42
+ if (cached && cached.expiresAt > Date.now()) {
43
+ return cached.name ? { address, name: cached.name, kind: "ens", source: "ens" } : null;
44
+ }
45
+ try {
46
+ const runner = provider ?? new ethers_1.ethers.JsonRpcProvider(chains_1.default[1].rpcs[0]);
47
+ const ensName = await runner.lookupAddress(address);
48
+ // Forward-verify: an ENS reverse record is set by its owner and can point anywhere,
49
+ // so trust it only once the name's forward resolution points back to this address.
50
+ const verified = ensName && ethers_1.ethers.getAddress((await runner.resolveName(ensName)) ?? "") === address;
51
+ const name = verified ? ensName : null;
52
+ ensCache.set(address, { name, expiresAt: Date.now() + ENS_TTL_MS });
53
+ return name ? { address, name, kind: "ens", source: "ens" } : null;
54
+ }
55
+ catch {
56
+ // A broken or slow ENS lookup must not fail the rest of resolution.
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * Resolves an address to a readable name.
62
+ *
63
+ * Checks the chain config (via `findContract`), then a curated registry of
64
+ * off-chain-known addresses (wallets, external protocols), then - mainnet
65
+ * only, and only once the first two miss - an ENS reverse lookup, forward-
66
+ * verified against the name it returns.
67
+ *
68
+ * @param chainId - The chain/network to use.
69
+ * @param address - Any-case address.
70
+ * @param options - `ens: false` skips the ENS step; `provider` reuses an existing connection for it.
71
+ * @returns The resolved name, or null when nothing matches.
72
+ */
73
+ async function resolveName(chainId, address, options) {
74
+ if (!ethers_1.ethers.isAddress(address))
75
+ return null;
76
+ const target = ethers_1.ethers.getAddress(address);
77
+ const configMatch = (0, findContract_1.findContract)(chainId, target);
78
+ if (configMatch)
79
+ return contractInfoToAddressName(configMatch);
80
+ const registryMatch = lookupRegistry(chainId, target);
81
+ if (registryMatch)
82
+ return registryMatch;
83
+ if (options?.ens === false || String(chainId) !== "1")
84
+ return null;
85
+ return lookupEns(target, options?.provider);
86
+ }
87
+ /**
88
+ * Batch form of {@link resolveName}. Config and registry lookups run
89
+ * synchronously per address; only addresses that fall through to ENS pay for
90
+ * a network round trip, and those run concurrently.
91
+ *
92
+ * @param chainId - The chain/network to use.
93
+ * @param addresses - Any-case addresses.
94
+ * @param options - Same as {@link resolveName}.
95
+ * @returns A map from the (checksummed) input address to its resolved name, or null.
96
+ */
97
+ async function resolveNames(chainId, addresses, options) {
98
+ const result = {};
99
+ const pending = [];
100
+ for (const raw of addresses) {
101
+ if (!ethers_1.ethers.isAddress(raw))
102
+ continue;
103
+ const target = ethers_1.ethers.getAddress(raw);
104
+ const configMatch = (0, findContract_1.findContract)(chainId, target);
105
+ if (configMatch) {
106
+ result[target] = contractInfoToAddressName(configMatch);
107
+ continue;
108
+ }
109
+ const registryMatch = lookupRegistry(chainId, target);
110
+ if (registryMatch) {
111
+ result[target] = registryMatch;
112
+ continue;
113
+ }
114
+ if (options?.ens === false || String(chainId) !== "1") {
115
+ result[target] = null;
116
+ continue;
117
+ }
118
+ pending.push(target);
119
+ }
120
+ if (pending.length > 0) {
121
+ const ensResults = await Promise.all(pending.map((address) => lookupEns(address, options?.provider)));
122
+ pending.forEach((address, i) => {
123
+ result[address] = ensResults[i];
124
+ });
125
+ }
126
+ return result;
127
+ }
128
+ exports.default = resolveName;
@@ -44,6 +44,7 @@ import getContractAddress from "./contracts/getContractAddress";
44
44
  import getContract from "./contracts/getContract";
45
45
  import { findContract } from "./contracts/findContract";
46
46
  import { decodeCall } from "./contracts/decodeCall";
47
+ import { resolveName, resolveNames } from "./contracts/resolveName";
47
48
  import getLatestPrice from "./contracts/housePrices/getLatestPrice";
48
49
  import setOracle from "./contracts/housePrices/setOracle";
49
50
  import tick from "./minter/tick";
@@ -338,6 +339,8 @@ declare class RPCLibrary {
338
339
  getContract: typeof getContract;
339
340
  findContract: typeof findContract;
340
341
  decodeCall: typeof decodeCall;
342
+ resolveName: typeof resolveName;
343
+ resolveNames: typeof resolveNames;
341
344
  feeCollector: {
342
345
  claimRewardFromPool: typeof claimRewardFromPool;
343
346
  };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Curated, off-chain-known addresses per chain (wallets, external protocols),
3
+ * keyed by checksummed address. Empty until entries are reviewed and added -
4
+ * see resolveName.ts for why this ships empty rather than with guessed data.
5
+ */
6
+ declare const registries: {
7
+ 1: {};
8
+ 8453: {};
9
+ 17000: {};
10
+ 11155111: {};
11
+ 18453: {};
12
+ };
13
+ export default registries;
@@ -0,0 +1,42 @@
1
+ import { Provider } from "ethers";
2
+ import { ChainId } from "../configs/chains";
3
+ export interface AddressName {
4
+ /** Checksummed. */
5
+ address: string;
6
+ name: string;
7
+ kind: "contract" | "gauge" | "wallet" | "external" | "ens";
8
+ source: "config" | "registry" | "ens";
9
+ url?: string;
10
+ }
11
+ export interface ResolveNameOptions {
12
+ /** Attempt an ENS reverse lookup when nothing else matches. Mainnet only regardless of this flag. Default true. */
13
+ ens?: boolean;
14
+ /** Reuse an existing provider for the ENS lookup instead of constructing one from the chain config. */
15
+ provider?: Provider;
16
+ }
17
+ /**
18
+ * Resolves an address to a readable name.
19
+ *
20
+ * Checks the chain config (via `findContract`), then a curated registry of
21
+ * off-chain-known addresses (wallets, external protocols), then - mainnet
22
+ * only, and only once the first two miss - an ENS reverse lookup, forward-
23
+ * verified against the name it returns.
24
+ *
25
+ * @param chainId - The chain/network to use.
26
+ * @param address - Any-case address.
27
+ * @param options - `ens: false` skips the ENS step; `provider` reuses an existing connection for it.
28
+ * @returns The resolved name, or null when nothing matches.
29
+ */
30
+ export declare function resolveName(chainId: ChainId, address: string, options?: ResolveNameOptions): Promise<AddressName | null>;
31
+ /**
32
+ * Batch form of {@link resolveName}. Config and registry lookups run
33
+ * synchronously per address; only addresses that fall through to ENS pay for
34
+ * a network round trip, and those run concurrently.
35
+ *
36
+ * @param chainId - The chain/network to use.
37
+ * @param addresses - Any-case addresses.
38
+ * @param options - Same as {@link resolveName}.
39
+ * @returns A map from the (checksummed) input address to its resolved name, or null.
40
+ */
41
+ export declare function resolveNames(chainId: ChainId, addresses: string[], options?: ResolveNameOptions): Promise<Record<string, AddressName | null>>;
42
+ export default resolveName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raac/rpc",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "RPC Library for RAAC",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/types/index.d.ts",