essential-eth 1.0.0 → 1.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.
@@ -26,7 +26,7 @@ function toChecksumAddress(address) {
26
26
  }
27
27
 
28
28
  // src/logger/package-version.ts
29
- var version = "1.0.0";
29
+ var version = "1.1.0";
30
30
 
31
31
  // src/logger/logger.ts
32
32
  var Logger = class {
package/dist/index.cjs CHANGED
@@ -522,7 +522,7 @@ function buildRPCPostBody(method, params) {
522
522
  }
523
523
 
524
524
  // src/logger/package-version.ts
525
- var version = "1.0.0";
525
+ var version = "1.1.0";
526
526
 
527
527
  // src/logger/logger.ts
528
528
  var Logger = class {
@@ -1486,6 +1486,82 @@ var BaseProvider = class {
1486
1486
  }
1487
1487
  return toChecksumAddress(rawAddress);
1488
1488
  }
1489
+ /**
1490
+ * Performs reverse ENS resolution to get the ENS name associated with an address.
1491
+ *
1492
+ * Performs the full ENS reverse resolution process:
1493
+ * 1. Formats the address as a reverse lookup: `{address}.addr.reverse`
1494
+ * 2. Computes the namehash of the reverse name
1495
+ * 3. Queries the ENS Registry for the resolver contract
1496
+ * 4. Queries the resolver for the name
1497
+ * 5. Verifies the name resolves back to the original address (per ENSIP-3)
1498
+ *
1499
+ * * [Identical](/docs/api#isd) to [`viem.getEnsName`](https://viem.sh/docs/ens/actions/getEnsName) in viem
1500
+ * @param address the Ethereum address to look up (e.g. '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
1501
+ * @returns the ENS name the address resolves to, or null if not found or verification fails
1502
+ * @example
1503
+ * ```javascript
1504
+ * await provider.lookupAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
1505
+ * // 'vitalik.eth'
1506
+ * ```
1507
+ * @example
1508
+ * ```javascript
1509
+ * await provider.lookupAddress('0x0000000000000000000000000000000000000000');
1510
+ * // null
1511
+ * ```
1512
+ */
1513
+ async lookupAddress(address) {
1514
+ const ENS_REGISTRY = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
1515
+ const RESOLVER_SELECTOR = "0x0178b8bf";
1516
+ const NAME_SELECTOR = "0x691f3431";
1517
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000000000000000000000000000";
1518
+ const addressLower = address.toLowerCase();
1519
+ const addressWithoutPrefix = addressLower.startsWith("0x") ? addressLower.slice(2) : addressLower;
1520
+ const reverseName = `${addressWithoutPrefix}.addr.reverse`;
1521
+ const node = namehash(reverseName);
1522
+ const nodeWithoutPrefix = node.slice(2);
1523
+ const resolverData = RESOLVER_SELECTOR + nodeWithoutPrefix;
1524
+ const resolverResult = await this.call({
1525
+ to: ENS_REGISTRY,
1526
+ data: resolverData
1527
+ });
1528
+ if (!resolverResult || resolverResult === ZERO_ADDRESS) {
1529
+ return null;
1530
+ }
1531
+ const resolverAddress = "0x" + resolverResult.slice(26);
1532
+ if (resolverAddress === "0x0000000000000000000000000000000000000000" || resolverAddress === "0x" + "0".repeat(resolverResult.length - 2)) {
1533
+ return null;
1534
+ }
1535
+ const nameData = NAME_SELECTOR + nodeWithoutPrefix;
1536
+ const nameResult = await this.call({
1537
+ to: resolverAddress,
1538
+ data: nameData
1539
+ });
1540
+ if (!nameResult || nameResult === ZERO_ADDRESS) {
1541
+ return null;
1542
+ }
1543
+ const lengthHex = nameResult.slice(2 + 64, 2 + 128);
1544
+ const length = parseInt(lengthHex, 16);
1545
+ if (length === 0) {
1546
+ return null;
1547
+ }
1548
+ const dataHex = nameResult.slice(2 + 128);
1549
+ const name = dataHex.slice(0, length * 2).match(/.{1,2}/g)?.map((byte) => String.fromCharCode(parseInt(byte, 16))).join("");
1550
+ if (!name) {
1551
+ return null;
1552
+ }
1553
+ try {
1554
+ const verifyAddress = await this.resolveName(name);
1555
+ const normalizedAddress = addressLower.startsWith("0x") ? addressLower : "0x" + addressLower;
1556
+ const normalizedVerifyAddress = verifyAddress?.toLowerCase();
1557
+ if (normalizedVerifyAddress !== normalizedAddress) {
1558
+ return null;
1559
+ }
1560
+ } catch {
1561
+ return null;
1562
+ }
1563
+ return name;
1564
+ }
1489
1565
  };
1490
1566
 
1491
1567
  // src/providers/JsonRpcProvider.ts
@@ -1520,7 +1596,7 @@ function jsonRpcProvider(rpcUrl) {
1520
1596
  // src/providers/AlchemyProvider.ts
1521
1597
  var AlchemyProvider = class extends JsonRpcProvider {
1522
1598
  constructor(apiKey, network = "mainnet") {
1523
- const alchemyUrl = `https://eth-${network}.alchemyapi.io/v2/${apiKey}`;
1599
+ const alchemyUrl = `https://eth-${network}.g.alchemy.com/v2/${apiKey}`;
1524
1600
  super(alchemyUrl);
1525
1601
  }
1526
1602
  };
package/dist/index.d.ts CHANGED
@@ -195,6 +195,7 @@ declare abstract class BaseProvider {
195
195
  getLogs(filter: Filter | FilterByBlockHash): Promise<Array<Log>>;
196
196
  call(transaction: TransactionRequest, blockTag?: BlockTag): Promise<string>;
197
197
  resolveName(name: string): Promise<string | null>;
198
+ lookupAddress(address: string): Promise<string | null>;
198
199
  }
199
200
 
200
201
  declare class JsonRpcProvider extends BaseProvider {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { keccak256, toUtf8Bytes, logger, encodeData, decodeRPCResponse, arrayify, hexlify, toChecksumAddress, hexToDecimal } from './chunk-CLIQ4S3P.js';
2
- export { arrayify, computeAddress, computePublicKey, concat, hashMessage, hexConcat, hexDataLength, hexDataSlice, hexStripZeros, hexValue, hexZeroPad, hexlify, isAddress, isBytes, isBytesLike, isHexString, keccak256, pack, solidityKeccak256, splitSignature, stripZeros, toChecksumAddress, toUtf8Bytes, zeroPad } from './chunk-CLIQ4S3P.js';
1
+ import { keccak256, toUtf8Bytes, logger, encodeData, decodeRPCResponse, arrayify, hexlify, toChecksumAddress, hexToDecimal } from './chunk-4V2QY6OK.js';
2
+ export { arrayify, computeAddress, computePublicKey, concat, hashMessage, hexConcat, hexDataLength, hexDataSlice, hexStripZeros, hexValue, hexZeroPad, hexlify, isAddress, isBytes, isBytesLike, isHexString, keccak256, pack, solidityKeccak256, splitSignature, stripZeros, toChecksumAddress, toUtf8Bytes, zeroPad } from './chunk-4V2QY6OK.js';
3
3
  import { formatFixed, toBigInt, parseFixed } from './chunk-GFWRB7PT.js';
4
4
  export { etherToGwei, etherToWei, gweiToEther, weiToEther } from './chunk-GFWRB7PT.js';
5
5
  import unfetch from 'isomorphic-unfetch';
@@ -896,6 +896,82 @@ var BaseProvider = class {
896
896
  }
897
897
  return toChecksumAddress(rawAddress);
898
898
  }
899
+ /**
900
+ * Performs reverse ENS resolution to get the ENS name associated with an address.
901
+ *
902
+ * Performs the full ENS reverse resolution process:
903
+ * 1. Formats the address as a reverse lookup: `{address}.addr.reverse`
904
+ * 2. Computes the namehash of the reverse name
905
+ * 3. Queries the ENS Registry for the resolver contract
906
+ * 4. Queries the resolver for the name
907
+ * 5. Verifies the name resolves back to the original address (per ENSIP-3)
908
+ *
909
+ * * [Identical](/docs/api#isd) to [`viem.getEnsName`](https://viem.sh/docs/ens/actions/getEnsName) in viem
910
+ * @param address the Ethereum address to look up (e.g. '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
911
+ * @returns the ENS name the address resolves to, or null if not found or verification fails
912
+ * @example
913
+ * ```javascript
914
+ * await provider.lookupAddress('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
915
+ * // 'vitalik.eth'
916
+ * ```
917
+ * @example
918
+ * ```javascript
919
+ * await provider.lookupAddress('0x0000000000000000000000000000000000000000');
920
+ * // null
921
+ * ```
922
+ */
923
+ async lookupAddress(address) {
924
+ const ENS_REGISTRY = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
925
+ const RESOLVER_SELECTOR = "0x0178b8bf";
926
+ const NAME_SELECTOR = "0x691f3431";
927
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000000000000000000000000000";
928
+ const addressLower = address.toLowerCase();
929
+ const addressWithoutPrefix = addressLower.startsWith("0x") ? addressLower.slice(2) : addressLower;
930
+ const reverseName = `${addressWithoutPrefix}.addr.reverse`;
931
+ const node = namehash(reverseName);
932
+ const nodeWithoutPrefix = node.slice(2);
933
+ const resolverData = RESOLVER_SELECTOR + nodeWithoutPrefix;
934
+ const resolverResult = await this.call({
935
+ to: ENS_REGISTRY,
936
+ data: resolverData
937
+ });
938
+ if (!resolverResult || resolverResult === ZERO_ADDRESS) {
939
+ return null;
940
+ }
941
+ const resolverAddress = "0x" + resolverResult.slice(26);
942
+ if (resolverAddress === "0x0000000000000000000000000000000000000000" || resolverAddress === "0x" + "0".repeat(resolverResult.length - 2)) {
943
+ return null;
944
+ }
945
+ const nameData = NAME_SELECTOR + nodeWithoutPrefix;
946
+ const nameResult = await this.call({
947
+ to: resolverAddress,
948
+ data: nameData
949
+ });
950
+ if (!nameResult || nameResult === ZERO_ADDRESS) {
951
+ return null;
952
+ }
953
+ const lengthHex = nameResult.slice(2 + 64, 2 + 128);
954
+ const length = parseInt(lengthHex, 16);
955
+ if (length === 0) {
956
+ return null;
957
+ }
958
+ const dataHex = nameResult.slice(2 + 128);
959
+ const name = dataHex.slice(0, length * 2).match(/.{1,2}/g)?.map((byte) => String.fromCharCode(parseInt(byte, 16))).join("");
960
+ if (!name) {
961
+ return null;
962
+ }
963
+ try {
964
+ const verifyAddress = await this.resolveName(name);
965
+ const normalizedAddress = addressLower.startsWith("0x") ? addressLower : "0x" + addressLower;
966
+ const normalizedVerifyAddress = verifyAddress?.toLowerCase();
967
+ if (normalizedVerifyAddress !== normalizedAddress) {
968
+ return null;
969
+ }
970
+ } catch {
971
+ return null;
972
+ }
973
+ return name;
974
+ }
899
975
  };
900
976
 
901
977
  // src/providers/JsonRpcProvider.ts
@@ -930,7 +1006,7 @@ function jsonRpcProvider(rpcUrl) {
930
1006
  // src/providers/AlchemyProvider.ts
931
1007
  var AlchemyProvider = class extends JsonRpcProvider {
932
1008
  constructor(apiKey, network = "mainnet") {
933
- const alchemyUrl = `https://eth-${network}.alchemyapi.io/v2/${apiKey}`;
1009
+ const alchemyUrl = `https://eth-${network}.g.alchemy.com/v2/${apiKey}`;
934
1010
  super(alchemyUrl);
935
1011
  }
936
1012
  };
package/dist/utils.js CHANGED
@@ -1,2 +1,2 @@
1
- export { arrayify, computeAddress, computePublicKey, concat, hashMessage, hexConcat, hexDataLength, hexDataSlice, hexStripZeros, hexValue, hexZeroPad, hexlify, isAddress, isBytes, isBytesLike, isHexString, keccak256, pack, solidityKeccak256, splitSignature, stripZeros, toChecksumAddress, toUtf8Bytes, zeroPad } from './chunk-CLIQ4S3P.js';
1
+ export { arrayify, computeAddress, computePublicKey, concat, hashMessage, hexConcat, hexDataLength, hexDataSlice, hexStripZeros, hexValue, hexZeroPad, hexlify, isAddress, isBytes, isBytesLike, isHexString, keccak256, pack, solidityKeccak256, splitSignature, stripZeros, toChecksumAddress, toUtf8Bytes, zeroPad } from './chunk-4V2QY6OK.js';
2
2
  export { etherToGwei, etherToWei, gweiToEther, weiToEther } from './chunk-GFWRB7PT.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "essential-eth",
3
3
  "description": "Ultralight JS for Ethereum",
4
- "version": "1.0.0",
4
+ "version": "1.1.0",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
7
7
  "type": "module",
package/readme.md CHANGED
@@ -27,10 +27,10 @@
27
27
 
28
28
  Measured with esbuild. Smaller is better.
29
29
 
30
- | What you import | essential-eth@1.0.0 | ethers@6.16.0 | viem@2.45.1 | web3@4.16.0 | ox@0.12.0 |
30
+ | What you import | essential-eth@1.1.0 | ethers@6.16.0 | viem@2.45.1 | web3@4.16.0 | ox@0.12.0 |
31
31
  | ---------------------------------------- | :-----------------: | :-----------: | :---------: | :---------: | :------------: |
32
- | **Full library** | **42.2 kB** 🏆 | 394.0 kB | 348.3 kB | 495.8 kB | 612.8 kB |
33
- | **Provider** (getBalance, getBlock, etc) | 29.9 kB | 260.0 kB | 269.5 kB | 454.5 kB | **10.9 kB** 🏆 |
32
+ | **Full library** | **43.1 kB** 🏆 | 394.0 kB | 348.3 kB | 495.8 kB | 612.8 kB |
33
+ | **Provider** (getBalance, getBlock, etc) | 30.8 kB | 260.0 kB | 269.5 kB | 454.5 kB | **10.9 kB** 🏆 |
34
34
  | **Contract** (read-only calls) | **24.8 kB** 🏆 | 86.6 kB | 179.8 kB | 264.9 kB | 49.9 kB |
35
35
  | **Conversions** (wei, gwei, ether) | **1.2 kB** 🏆 | 10.4 kB | 2.7 kB | 454.5 kB | 3.7 kB |
36
36
 
@@ -174,7 +174,7 @@ Browsers:
174
174
  ```html
175
175
 
176
176
  <!-- index.html -->
177
- <script src="https://unpkg.com/essential-eth@1.0.0"></script>
177
+ <script src="https://unpkg.com/essential-eth@1.1.0"></script>
178
178
  ```
179
179
 
180
180