quantumcoin 6.14.2 → 6.14.5

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 (317) hide show
  1. package/CHANGELOG.md +442 -442
  2. package/FUNDING.json +10 -10
  3. package/LICENSE.md +21 -21
  4. package/README.md +132 -142
  5. package/SECURITY.md +34 -34
  6. package/dist/README.md +22 -22
  7. package/dist/quantumcoin.js +1127 -1324
  8. package/dist/quantumcoin.js.map +1 -1
  9. package/dist/quantumcoin.min.js +1 -1
  10. package/dist/quantumcoin.umd.js +1128 -1327
  11. package/dist/quantumcoin.umd.js.map +1 -1
  12. package/dist/quantumcoin.umd.min.js +1 -1
  13. package/dist/wordlists-extra.js +1 -1
  14. package/dist/wordlists-extra.js.map +1 -1
  15. package/dist/wordlists-extra.min.js +1 -1
  16. package/lib.commonjs/README.md +16 -16
  17. package/lib.commonjs/_version.js +1 -1
  18. package/lib.commonjs/crypto/signature.d.ts +3 -76
  19. package/lib.commonjs/crypto/signature.d.ts.map +1 -1
  20. package/lib.commonjs/crypto/signature.js +15 -199
  21. package/lib.commonjs/crypto/signature.js.map +1 -1
  22. package/lib.commonjs/crypto/signing-key.d.ts +1 -1
  23. package/lib.commonjs/crypto/signing-key.d.ts.map +1 -1
  24. package/lib.commonjs/crypto/signing-key.js +19 -10
  25. package/lib.commonjs/crypto/signing-key.js.map +1 -1
  26. package/lib.commonjs/package.json +12 -12
  27. package/lib.commonjs/providers/provider-jsonrpc.d.ts +0 -1
  28. package/lib.commonjs/providers/provider-jsonrpc.d.ts.map +1 -1
  29. package/lib.commonjs/providers/provider-jsonrpc.js +0 -1
  30. package/lib.commonjs/providers/provider-jsonrpc.js.map +1 -1
  31. package/lib.commonjs/quantumcoin.d.ts +2 -0
  32. package/lib.commonjs/quantumcoin.d.ts.map +1 -1
  33. package/lib.commonjs/quantumcoin.js +11 -5
  34. package/lib.commonjs/quantumcoin.js.map +1 -1
  35. package/lib.commonjs/transaction/address.d.ts.map +1 -1
  36. package/lib.commonjs/transaction/address.js +8 -3
  37. package/lib.commonjs/transaction/address.js.map +1 -1
  38. package/lib.commonjs/transaction/transaction.d.ts.map +1 -1
  39. package/lib.commonjs/transaction/transaction.js +7 -40
  40. package/lib.commonjs/transaction/transaction.js.map +1 -1
  41. package/lib.commonjs/wallet/json-keystore.d.ts.map +1 -1
  42. package/lib.commonjs/wallet/json-keystore.js +7 -7
  43. package/lib.commonjs/wallet/json-keystore.js.map +1 -1
  44. package/lib.commonjs/wallet/wallet.d.ts.map +1 -1
  45. package/lib.commonjs/wallet/wallet.js +2 -2
  46. package/lib.commonjs/wallet/wallet.js.map +1 -1
  47. package/lib.esm/README.md +16 -16
  48. package/lib.esm/_version.js +1 -1
  49. package/lib.esm/crypto/signature.d.ts +3 -76
  50. package/lib.esm/crypto/signature.d.ts.map +1 -1
  51. package/lib.esm/crypto/signature.js +16 -202
  52. package/lib.esm/crypto/signature.js.map +1 -1
  53. package/lib.esm/crypto/signing-key.d.ts +1 -1
  54. package/lib.esm/crypto/signing-key.d.ts.map +1 -1
  55. package/lib.esm/crypto/signing-key.js +20 -9
  56. package/lib.esm/crypto/signing-key.js.map +1 -1
  57. package/lib.esm/package.json +12 -12
  58. package/lib.esm/providers/provider-jsonrpc.d.ts +0 -1
  59. package/lib.esm/providers/provider-jsonrpc.d.ts.map +1 -1
  60. package/lib.esm/providers/provider-jsonrpc.js +0 -1
  61. package/lib.esm/providers/provider-jsonrpc.js.map +1 -1
  62. package/lib.esm/quantumcoin.d.ts +2 -0
  63. package/lib.esm/quantumcoin.d.ts.map +1 -1
  64. package/lib.esm/quantumcoin.js +6 -0
  65. package/lib.esm/quantumcoin.js.map +1 -1
  66. package/lib.esm/transaction/address.d.ts.map +1 -1
  67. package/lib.esm/transaction/address.js +8 -2
  68. package/lib.esm/transaction/address.js.map +1 -1
  69. package/lib.esm/transaction/transaction.d.ts.map +1 -1
  70. package/lib.esm/transaction/transaction.js +7 -40
  71. package/lib.esm/transaction/transaction.js.map +1 -1
  72. package/lib.esm/wallet/json-keystore.d.ts.map +1 -1
  73. package/lib.esm/wallet/json-keystore.js +11 -5
  74. package/lib.esm/wallet/json-keystore.js.map +1 -1
  75. package/lib.esm/wallet/wallet.d.ts.map +1 -1
  76. package/lib.esm/wallet/wallet.js +3 -1
  77. package/lib.esm/wallet/wallet.js.map +1 -1
  78. package/package.json +6 -5
  79. package/rollup.config.mjs +50 -50
  80. package/src.ts/_version.ts +1 -1
  81. package/src.ts/abi/abi-coder.ts +237 -237
  82. package/src.ts/abi/bytes32.ts +45 -45
  83. package/src.ts/abi/coders/abstract-coder.ts +541 -541
  84. package/src.ts/abi/coders/address.ts +36 -36
  85. package/src.ts/abi/coders/anonymous.ts +29 -29
  86. package/src.ts/abi/coders/array.ts +199 -199
  87. package/src.ts/abi/coders/boolean.ts +27 -27
  88. package/src.ts/abi/coders/bytes.ts +43 -43
  89. package/src.ts/abi/coders/fixed-bytes.ts +37 -37
  90. package/src.ts/abi/coders/null.ts +28 -28
  91. package/src.ts/abi/coders/number.ts +63 -63
  92. package/src.ts/abi/coders/string.ts +29 -29
  93. package/src.ts/abi/coders/tuple.ts +69 -69
  94. package/src.ts/abi/fragments.ts +1617 -1617
  95. package/src.ts/abi/index.ts +41 -41
  96. package/src.ts/abi/interface.ts +1271 -1271
  97. package/src.ts/abi/typed.ts +796 -796
  98. package/src.ts/address/address.ts +148 -148
  99. package/src.ts/address/checks.ts +123 -123
  100. package/src.ts/address/contract-address.ts +80 -80
  101. package/src.ts/address/index.ts +57 -57
  102. package/src.ts/constants/addresses.ts +8 -8
  103. package/src.ts/constants/hashes.ts +7 -7
  104. package/src.ts/constants/index.ts +16 -16
  105. package/src.ts/constants/numbers.ts +35 -35
  106. package/src.ts/constants/strings.ts +16 -16
  107. package/src.ts/contract/contract.ts +1120 -1120
  108. package/src.ts/contract/factory.ts +143 -143
  109. package/src.ts/contract/index.ts +31 -31
  110. package/src.ts/contract/types.ts +236 -236
  111. package/src.ts/contract/wrappers.ts +225 -225
  112. package/src.ts/crypto/crypto-browser.ts +64 -64
  113. package/src.ts/crypto/crypto.ts +4 -4
  114. package/src.ts/crypto/hmac.ts +51 -51
  115. package/src.ts/crypto/index.ts +59 -59
  116. package/src.ts/crypto/keccak.ts +54 -54
  117. package/src.ts/crypto/pbkdf2.ts +55 -55
  118. package/src.ts/crypto/random.ts +36 -36
  119. package/src.ts/crypto/ripemd160.ts +43 -43
  120. package/src.ts/crypto/scrypt.ts +114 -114
  121. package/src.ts/crypto/sha2.ts +78 -78
  122. package/src.ts/crypto/signature.ts +145 -349
  123. package/src.ts/crypto/signing-key.ts +126 -118
  124. package/src.ts/hash/authorization.ts +38 -38
  125. package/src.ts/hash/id.ts +17 -17
  126. package/src.ts/hash/index.ts +18 -18
  127. package/src.ts/hash/message.ts +51 -51
  128. package/src.ts/hash/namehash.ts +101 -101
  129. package/src.ts/hash/solidity.ts +117 -117
  130. package/src.ts/hash/typed-data.ts +658 -658
  131. package/src.ts/index.ts +12 -12
  132. package/src.ts/providers/abstract-provider.ts +1761 -1761
  133. package/src.ts/providers/abstract-signer.ts +314 -314
  134. package/src.ts/providers/community.ts +49 -49
  135. package/src.ts/providers/contracts.ts +42 -42
  136. package/src.ts/providers/default-provider.ts +96 -96
  137. package/src.ts/providers/ens-resolver.ts +606 -606
  138. package/src.ts/providers/format.ts +320 -320
  139. package/src.ts/providers/formatting.ts +418 -418
  140. package/src.ts/providers/index.ts +125 -125
  141. package/src.ts/providers/network.ts +327 -327
  142. package/src.ts/providers/pagination.ts +8 -8
  143. package/src.ts/providers/plugin-fallback.ts +35 -35
  144. package/src.ts/providers/plugins-network.ts +281 -281
  145. package/src.ts/providers/provider-browser.ts +334 -334
  146. package/src.ts/providers/provider-fallback.ts +801 -801
  147. package/src.ts/providers/provider-ipcsocket-browser.ts +3 -3
  148. package/src.ts/providers/provider-ipcsocket.ts +81 -81
  149. package/src.ts/providers/provider-jsonrpc.ts +1334 -1335
  150. package/src.ts/providers/provider-socket.ts +352 -352
  151. package/src.ts/providers/provider-websocket.ts +103 -103
  152. package/src.ts/providers/provider.ts +2136 -2136
  153. package/src.ts/providers/signer-noncemanager.ts +98 -98
  154. package/src.ts/providers/signer.ts +166 -166
  155. package/src.ts/providers/subscriber-connection.ts +74 -74
  156. package/src.ts/providers/subscriber-filterid.ts +199 -199
  157. package/src.ts/providers/subscriber-polling.ts +321 -321
  158. package/src.ts/providers/ws-browser.ts +11 -11
  159. package/src.ts/providers/ws.ts +3 -3
  160. package/src.ts/quantumcoin.ts +219 -211
  161. package/src.ts/thirdparty.d.ts +16 -16
  162. package/src.ts/transaction/accesslist.ts +43 -43
  163. package/src.ts/transaction/address.ts +35 -31
  164. package/src.ts/transaction/authorization.ts +14 -14
  165. package/src.ts/transaction/index.ts +51 -51
  166. package/src.ts/transaction/transaction.ts +1349 -1379
  167. package/src.ts/utils/base58.ts +73 -73
  168. package/src.ts/utils/base64-browser.ts +25 -25
  169. package/src.ts/utils/base64.ts +56 -56
  170. package/src.ts/utils/data.ts +199 -199
  171. package/src.ts/utils/errors.ts +793 -793
  172. package/src.ts/utils/events.ts +105 -105
  173. package/src.ts/utils/fetch.ts +970 -970
  174. package/src.ts/utils/fixednumber.ts +643 -643
  175. package/src.ts/utils/geturl-browser.ts +81 -81
  176. package/src.ts/utils/geturl.ts +134 -134
  177. package/src.ts/utils/index.ts +95 -95
  178. package/src.ts/utils/maths.ts +240 -240
  179. package/src.ts/utils/properties.ts +60 -60
  180. package/src.ts/utils/rlp-decode.ts +104 -104
  181. package/src.ts/utils/rlp-encode.ts +64 -64
  182. package/src.ts/utils/rlp.ts +20 -20
  183. package/src.ts/utils/units.ts +91 -91
  184. package/src.ts/utils/utf8.ts +325 -325
  185. package/src.ts/utils/uuid.ts +36 -36
  186. package/src.ts/wallet/base-wallet.ts +160 -160
  187. package/src.ts/wallet/index.ts +32 -32
  188. package/src.ts/wallet/json-keystore.ts +108 -106
  189. package/src.ts/wallet/utils.ts +147 -147
  190. package/src.ts/wallet/wallet.ts +138 -139
  191. package/src.ts/wordlists/bit-reader.ts +35 -35
  192. package/src.ts/wordlists/decode-owl.ts +58 -58
  193. package/src.ts/wordlists/decode-owla.ts +33 -33
  194. package/src.ts/wordlists/generation/encode-latin.ts +370 -370
  195. package/src.ts/wordlists/index.ts +26 -26
  196. package/src.ts/wordlists/lang-cz.ts +33 -33
  197. package/src.ts/wordlists/lang-en.ts +33 -33
  198. package/src.ts/wordlists/lang-es.ts +35 -35
  199. package/src.ts/wordlists/lang-fr.ts +34 -34
  200. package/src.ts/wordlists/lang-it.ts +33 -33
  201. package/src.ts/wordlists/lang-ja.ts +181 -181
  202. package/src.ts/wordlists/lang-ko.ts +104 -104
  203. package/src.ts/wordlists/lang-pt.ts +34 -34
  204. package/src.ts/wordlists/lang-zh.ts +112 -112
  205. package/src.ts/wordlists/wordlist-owl.ts +77 -77
  206. package/src.ts/wordlists/wordlist-owla.ts +41 -41
  207. package/src.ts/wordlists/wordlist.ts +59 -59
  208. package/src.ts/wordlists/wordlists-browser.ts +8 -8
  209. package/src.ts/wordlists/wordlists-extra.ts +9 -9
  210. package/src.ts/wordlists/wordlists.ts +38 -38
  211. package/dist/quantumcoin.min.js'.gz' +0 -0
  212. package/dist/quantumcoin.umd.min.js'.gz' +0 -0
  213. package/dist/wordlists-extra.min.js'.gz' +0 -0
  214. package/lib.commonjs/providers/provider-alchemy.d.ts +0 -50
  215. package/lib.commonjs/providers/provider-alchemy.d.ts.map +0 -1
  216. package/lib.commonjs/providers/provider-alchemy.js +0 -151
  217. package/lib.commonjs/providers/provider-alchemy.js.map +0 -1
  218. package/lib.commonjs/providers/provider-ankr.d.ts +0 -61
  219. package/lib.commonjs/providers/provider-ankr.d.ts.map +0 -1
  220. package/lib.commonjs/providers/provider-ankr.js +0 -137
  221. package/lib.commonjs/providers/provider-ankr.js.map +0 -1
  222. package/lib.commonjs/providers/provider-blockscout.d.ts +0 -59
  223. package/lib.commonjs/providers/provider-blockscout.d.ts.map +0 -1
  224. package/lib.commonjs/providers/provider-blockscout.js +0 -145
  225. package/lib.commonjs/providers/provider-blockscout.js.map +0 -1
  226. package/lib.commonjs/providers/provider-chainstack.d.ts +0 -46
  227. package/lib.commonjs/providers/provider-chainstack.d.ts.map +0 -1
  228. package/lib.commonjs/providers/provider-chainstack.js +0 -102
  229. package/lib.commonjs/providers/provider-chainstack.js.map +0 -1
  230. package/lib.commonjs/providers/provider-cloudflare.d.ts +0 -14
  231. package/lib.commonjs/providers/provider-cloudflare.d.ts.map +0 -1
  232. package/lib.commonjs/providers/provider-cloudflare.js +0 -26
  233. package/lib.commonjs/providers/provider-cloudflare.js.map +0 -1
  234. package/lib.commonjs/providers/provider-etherscan.d.ts +0 -147
  235. package/lib.commonjs/providers/provider-etherscan.d.ts.map +0 -1
  236. package/lib.commonjs/providers/provider-etherscan.js +0 -587
  237. package/lib.commonjs/providers/provider-etherscan.js.map +0 -1
  238. package/lib.commonjs/providers/provider-infura.d.ts +0 -101
  239. package/lib.commonjs/providers/provider-infura.d.ts.map +0 -1
  240. package/lib.commonjs/providers/provider-infura.js +0 -206
  241. package/lib.commonjs/providers/provider-infura.js.map +0 -1
  242. package/lib.commonjs/providers/provider-pocket.d.ts +0 -54
  243. package/lib.commonjs/providers/provider-pocket.d.ts.map +0 -1
  244. package/lib.commonjs/providers/provider-pocket.js +0 -109
  245. package/lib.commonjs/providers/provider-pocket.js.map +0 -1
  246. package/lib.commonjs/providers/provider-quicknode.d.ts +0 -59
  247. package/lib.commonjs/providers/provider-quicknode.d.ts.map +0 -1
  248. package/lib.commonjs/providers/provider-quicknode.js +0 -163
  249. package/lib.commonjs/providers/provider-quicknode.js.map +0 -1
  250. package/lib.commonjs/wallet/hdwallet.d.ts +0 -248
  251. package/lib.commonjs/wallet/hdwallet.d.ts.map +0 -1
  252. package/lib.commonjs/wallet/hdwallet.js +0 -505
  253. package/lib.commonjs/wallet/hdwallet.js.map +0 -1
  254. package/lib.commonjs/wallet/json-crowdsale.d.ts +0 -27
  255. package/lib.commonjs/wallet/json-crowdsale.d.ts.map +0 -1
  256. package/lib.commonjs/wallet/json-crowdsale.js +0 -60
  257. package/lib.commonjs/wallet/json-crowdsale.js.map +0 -1
  258. package/lib.commonjs/wallet/mnemonic.d.ts +0 -65
  259. package/lib.commonjs/wallet/mnemonic.d.ts.map +0 -1
  260. package/lib.commonjs/wallet/mnemonic.js +0 -169
  261. package/lib.commonjs/wallet/mnemonic.js.map +0 -1
  262. package/lib.commonjs/wallet/seedwallet.d.ts +0 -4
  263. package/lib.commonjs/wallet/seedwallet.d.ts.map +0 -1
  264. package/lib.commonjs/wallet/seedwallet.js +0 -8
  265. package/lib.commonjs/wallet/seedwallet.js.map +0 -1
  266. package/lib.esm/providers/provider-alchemy.d.ts +0 -50
  267. package/lib.esm/providers/provider-alchemy.d.ts.map +0 -1
  268. package/lib.esm/providers/provider-alchemy.js +0 -147
  269. package/lib.esm/providers/provider-alchemy.js.map +0 -1
  270. package/lib.esm/providers/provider-ankr.d.ts +0 -61
  271. package/lib.esm/providers/provider-ankr.d.ts.map +0 -1
  272. package/lib.esm/providers/provider-ankr.js +0 -133
  273. package/lib.esm/providers/provider-ankr.js.map +0 -1
  274. package/lib.esm/providers/provider-blockscout.d.ts +0 -59
  275. package/lib.esm/providers/provider-blockscout.d.ts.map +0 -1
  276. package/lib.esm/providers/provider-blockscout.js +0 -141
  277. package/lib.esm/providers/provider-blockscout.js.map +0 -1
  278. package/lib.esm/providers/provider-chainstack.d.ts +0 -46
  279. package/lib.esm/providers/provider-chainstack.d.ts.map +0 -1
  280. package/lib.esm/providers/provider-chainstack.js +0 -98
  281. package/lib.esm/providers/provider-chainstack.js.map +0 -1
  282. package/lib.esm/providers/provider-cloudflare.d.ts +0 -14
  283. package/lib.esm/providers/provider-cloudflare.d.ts.map +0 -1
  284. package/lib.esm/providers/provider-cloudflare.js +0 -22
  285. package/lib.esm/providers/provider-cloudflare.js.map +0 -1
  286. package/lib.esm/providers/provider-etherscan.d.ts +0 -147
  287. package/lib.esm/providers/provider-etherscan.d.ts.map +0 -1
  288. package/lib.esm/providers/provider-etherscan.js +0 -584
  289. package/lib.esm/providers/provider-etherscan.js.map +0 -1
  290. package/lib.esm/providers/provider-infura.d.ts +0 -101
  291. package/lib.esm/providers/provider-infura.d.ts.map +0 -1
  292. package/lib.esm/providers/provider-infura.js +0 -201
  293. package/lib.esm/providers/provider-infura.js.map +0 -1
  294. package/lib.esm/providers/provider-pocket.d.ts +0 -54
  295. package/lib.esm/providers/provider-pocket.d.ts.map +0 -1
  296. package/lib.esm/providers/provider-pocket.js +0 -105
  297. package/lib.esm/providers/provider-pocket.js.map +0 -1
  298. package/lib.esm/providers/provider-quicknode.d.ts +0 -59
  299. package/lib.esm/providers/provider-quicknode.d.ts.map +0 -1
  300. package/lib.esm/providers/provider-quicknode.js +0 -159
  301. package/lib.esm/providers/provider-quicknode.js.map +0 -1
  302. package/lib.esm/wallet/hdwallet.d.ts +0 -248
  303. package/lib.esm/wallet/hdwallet.d.ts.map +0 -1
  304. package/lib.esm/wallet/hdwallet.js +0 -498
  305. package/lib.esm/wallet/hdwallet.js.map +0 -1
  306. package/lib.esm/wallet/json-crowdsale.d.ts +0 -27
  307. package/lib.esm/wallet/json-crowdsale.d.ts.map +0 -1
  308. package/lib.esm/wallet/json-crowdsale.js +0 -55
  309. package/lib.esm/wallet/json-crowdsale.js.map +0 -1
  310. package/lib.esm/wallet/mnemonic.d.ts +0 -65
  311. package/lib.esm/wallet/mnemonic.d.ts.map +0 -1
  312. package/lib.esm/wallet/mnemonic.js +0 -165
  313. package/lib.esm/wallet/mnemonic.js.map +0 -1
  314. package/lib.esm/wallet/seedwallet.d.ts +0 -4
  315. package/lib.esm/wallet/seedwallet.d.ts.map +0 -1
  316. package/lib.esm/wallet/seedwallet.js +0 -4
  317. package/lib.esm/wallet/seedwallet.js.map +0 -1
@@ -1,606 +1,606 @@
1
- /**
2
- * ENS is a service which allows easy-to-remember names to map to
3
- * network addresses.
4
- *
5
- * @_section: api/providers/ens-resolver:ENS Resolver [about-ens-rsolver]
6
- */
7
-
8
- import { getAddress } from "../address/index.js";
9
- import { ZeroAddress } from "../constants/index.js";
10
- import { Contract } from "../contract/index.js";
11
- import { dnsEncode, namehash } from "../hash/index.js";
12
- import {
13
- hexlify, isHexString, toBeHex,
14
- defineProperties, encodeBase58,
15
- assert, assertArgument, isError,
16
- FetchRequest
17
- } from "../utils/index.js";
18
-
19
- import type { FunctionFragment } from "../abi/index.js";
20
-
21
- import type { BytesLike } from "../utils/index.js";
22
-
23
- import type { AbstractProvider, AbstractProviderPlugin } from "./abstract-provider.js";
24
- import type { EnsPlugin } from "./plugins-network.js";
25
- import type { Provider } from "./provider.js";
26
-
27
- // @TODO: This should use the fetch-data:ipfs gateway
28
- // Trim off the ipfs:// prefix and return the default gateway URL
29
- function getIpfsLink(link: string): string {
30
- if (link.match(/^ipfs:\/\/ipfs\//i)) {
31
- link = link.substring(12);
32
- } else if (link.match(/^ipfs:\/\//i)) {
33
- link = link.substring(7);
34
- } else {
35
- assertArgument(false, "unsupported IPFS format", "link", link);
36
- }
37
-
38
- return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
39
- }
40
-
41
- /**
42
- * The type of data found during a steip during avatar resolution.
43
- */
44
- export type AvatarLinkageType = "name" | "avatar" | "!avatar" | "url" | "data" | "ipfs" |
45
- "erc721" | "erc1155" | "!erc721-caip" | "!erc1155-caip" |
46
- "!owner" | "owner" | "!balance" | "balance" |
47
- "metadata-url-base" | "metadata-url-expanded" | "metadata-url" | "!metadata-url" |
48
- "!metadata" | "metadata" |
49
- "!imageUrl" | "imageUrl-ipfs" | "imageUrl" | "!imageUrl-ipfs";
50
-
51
- /**
52
- * An individual record for each step during avatar resolution.
53
- */
54
- export interface AvatarLinkage {
55
- /**
56
- * The type of linkage.
57
- */
58
- type: AvatarLinkageType;
59
-
60
- /**
61
- * The linkage value.
62
- */
63
- value: string;
64
- };
65
-
66
- /**
67
- * When resolving an avatar for an ENS name, there are many
68
- * steps involved, fetching metadata, validating results, et cetera.
69
- *
70
- * Some applications may wish to analyse this data, or use this data
71
- * to diagnose promblems, so an **AvatarResult** provides details of
72
- * each completed step during avatar resolution.
73
- */
74
- export interface AvatarResult {
75
- /**
76
- * How the [[url]] was arrived at, resolving the many steps required
77
- * for an avatar URL.
78
- */
79
- linkage: Array<AvatarLinkage>;
80
-
81
- /**
82
- * The avatar URL or null if the avatar was not set, or there was
83
- * an issue during validation (such as the address not owning the
84
- * avatar or a metadata error).
85
- */
86
- url: null | string;
87
- };
88
-
89
- /**
90
- * A provider plugin super-class for processing multicoin address types.
91
- */
92
- export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin {
93
- /**
94
- * The name.
95
- */
96
- readonly name!: string;
97
-
98
- /**
99
- * Creates a new **MulticoinProviderPluing** for %%name%%.
100
- */
101
- constructor(name: string) {
102
- defineProperties<MulticoinProviderPlugin>(this, { name });
103
- }
104
-
105
- connect(proivder: Provider): MulticoinProviderPlugin {
106
- return this;
107
- }
108
-
109
- /**
110
- * Returns ``true`` if %%coinType%% is supported by this plugin.
111
- */
112
- supportsCoinType(coinType: number): boolean {
113
- return false;
114
- }
115
-
116
- /**
117
- * Resolves to the encoded %%address%% for %%coinType%%.
118
- */
119
- async encodeAddress(coinType: number, address: string): Promise<string> {
120
- throw new Error("unsupported coin");
121
- }
122
-
123
- /**
124
- * Resolves to the decoded %%data%% for %%coinType%%.
125
- */
126
- async decodeAddress(coinType: number, data: BytesLike): Promise<string> {
127
- throw new Error("unsupported coin");
128
- }
129
- }
130
-
131
- const BasicMulticoinPluginId = "org.ethers.plugins.provider.BasicMulticoin";
132
-
133
- /**
134
- * A **BasicMulticoinProviderPlugin** provides service for common
135
- * coin types, which do not require additional libraries to encode or
136
- * decode.
137
- */
138
- export class BasicMulticoinProviderPlugin extends MulticoinProviderPlugin {
139
- /**
140
- * Creates a new **BasicMulticoinProviderPlugin**.
141
- */
142
- constructor() {
143
- super(BasicMulticoinPluginId);
144
- }
145
- }
146
-
147
- const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
148
- const matchers = [
149
- new RegExp("^(https):/\/(.*)$", "i"),
150
- new RegExp("^(data):(.*)$", "i"),
151
- matcherIpfs,
152
- new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
153
- ];
154
-
155
- /**
156
- * A connected object to a resolved ENS name resolver, which can be
157
- * used to query additional details.
158
- */
159
- export class EnsResolver {
160
- /**
161
- * The connected provider.
162
- */
163
- provider!: AbstractProvider;
164
-
165
- /**
166
- * The address of the resolver.
167
- */
168
- address!: string;
169
-
170
- /**
171
- * The name this resolver was resolved against.
172
- */
173
- name!: string;
174
-
175
- // For EIP-2544 names, the ancestor that provided the resolver
176
- #supports2544: null | Promise<boolean>;
177
-
178
- #resolver: Contract;
179
-
180
- constructor(provider: AbstractProvider, address: string, name: string) {
181
- defineProperties<EnsResolver>(this, { provider, address, name });
182
- this.#supports2544 = null;
183
-
184
- this.#resolver = new Contract(address, [
185
- "function supportsInterface(bytes4) view returns (bool)",
186
- "function resolve(bytes, bytes) view returns (bytes)",
187
- "function addr(bytes32) view returns (address)",
188
- "function addr(bytes32, uint) view returns (bytes)",
189
- "function text(bytes32, string) view returns (string)",
190
- "function contenthash(bytes32) view returns (bytes)",
191
- ], provider);
192
-
193
- }
194
-
195
- /**
196
- * Resolves to true if the resolver supports wildcard resolution.
197
- */
198
- async supportsWildcard(): Promise<boolean> {
199
- if (this.#supports2544 == null) {
200
- this.#supports2544 = (async () => {
201
- try {
202
- return await this.#resolver.supportsInterface("0x9061b923");
203
- } catch (error) {
204
- // Wildcard resolvers must understand supportsInterface
205
- // and return true.
206
- if (isError(error, "CALL_EXCEPTION")) { return false; }
207
-
208
- // Let future attempts try again...
209
- this.#supports2544 = null;
210
-
211
- throw error;
212
- }
213
- })();
214
- }
215
-
216
- return await this.#supports2544;
217
- }
218
-
219
- async #fetch(funcName: string, params?: Array<any>): Promise<null | any> {
220
- params = (params || []).slice();
221
- const iface = this.#resolver.interface;
222
-
223
- // The first parameters is always the nodehash
224
- params.unshift(namehash(this.name))
225
-
226
- let fragment: null | FunctionFragment = null;
227
- if (await this.supportsWildcard()) {
228
- fragment = iface.getFunction(funcName);
229
- assert(fragment, "missing fragment", "UNKNOWN_ERROR", {
230
- info: { funcName }
231
- });
232
-
233
- params = [
234
- dnsEncode(this.name, 255),
235
- iface.encodeFunctionData(fragment, params)
236
- ];
237
-
238
- funcName = "resolve(bytes,bytes)";
239
- }
240
-
241
- params.push({
242
- enableCcipRead: true
243
- });
244
-
245
- try {
246
- const result = await this.#resolver[funcName](...params);
247
-
248
- if (fragment) {
249
- return iface.decodeFunctionResult(fragment, result)[0];
250
- }
251
-
252
- return result;
253
- } catch (error: any) {
254
- if (!isError(error, "CALL_EXCEPTION")) { throw error; }
255
- }
256
-
257
- return null;
258
- }
259
-
260
- /**
261
- * Resolves to the address for %%coinType%% or null if the
262
- * provided %%coinType%% has not been configured.
263
- */
264
- async getAddress(coinType?: number): Promise<null | string> {
265
- if (coinType == null) { coinType = 60; }
266
- if (coinType === 60) {
267
- try {
268
- const result = await this.#fetch("addr(bytes32)");
269
-
270
- // No address
271
- if (result == null || result === ZeroAddress) { return null; }
272
-
273
- return result;
274
- } catch (error: any) {
275
- if (isError(error, "CALL_EXCEPTION")) { return null; }
276
- throw error;
277
- }
278
- }
279
-
280
- // Try decoding its EVM canonical chain as an EVM chain address first
281
- if (coinType >= 0 && coinType < 0x80000000) {
282
- let ethCoinType = coinType + 0x80000000;
283
-
284
- const data = await this.#fetch("addr(bytes32,uint)", [ ethCoinType ]);
285
- if (isHexString(data, 20)) { return getAddress(data); }
286
- }
287
-
288
- let coinPlugin: null | MulticoinProviderPlugin = null;
289
- for (const plugin of this.provider.plugins) {
290
- if (!(plugin instanceof MulticoinProviderPlugin)) { continue; }
291
- if (plugin.supportsCoinType(coinType)) {
292
- coinPlugin = plugin;
293
- break;
294
- }
295
- }
296
-
297
- if (coinPlugin == null) { return null; }
298
-
299
- // keccak256("addr(bytes32,uint256")
300
- const data = await this.#fetch("addr(bytes32,uint)", [ coinType ]);
301
-
302
- // No address
303
- if (data == null || data === "0x") { return null; }
304
-
305
- // Compute the address
306
- const address = await coinPlugin.decodeAddress(coinType, data);
307
-
308
- if (address != null) { return address; }
309
-
310
- assert(false, `invalid coin data`, "UNSUPPORTED_OPERATION", {
311
- operation: `getAddress(${ coinType })`,
312
- info: { coinType, data }
313
- });
314
- }
315
-
316
- /**
317
- * Resolves to the EIP-634 text record for %%key%%, or ``null``
318
- * if unconfigured.
319
- */
320
- async getText(key: string): Promise<null | string> {
321
- const data = await this.#fetch("text(bytes32,string)", [ key ]);
322
- if (data == null || data === "0x") { return null; }
323
- return data;
324
- }
325
-
326
- /**
327
- * Rsolves to the content-hash or ``null`` if unconfigured.
328
- */
329
- async getContentHash(): Promise<null | string> {
330
- // keccak256("contenthash()")
331
- const data = await this.#fetch("contenthash(bytes32)");
332
-
333
- // No contenthash
334
- if (data == null || data === "0x") { return null; }
335
-
336
- // IPFS (CID: 1, Type: 70=DAG-PB, 72=libp2p-key)
337
- const ipfs = data.match(/^0x(e3010170|e5010172)(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/);
338
- if (ipfs) {
339
- const scheme = (ipfs[1] === "e3010170") ? "ipfs": "ipns";
340
- const length = parseInt(ipfs[4], 16);
341
- if (ipfs[5].length === length * 2) {
342
- return `${ scheme }:/\/${ encodeBase58("0x" + ipfs[2])}`;
343
- }
344
- }
345
-
346
- // Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
347
- const swarm = data.match(/^0xe40101fa011b20([0-9a-f]*)$/)
348
- if (swarm && swarm[1].length === 64) {
349
- return `bzz:/\/${ swarm[1] }`;
350
- }
351
-
352
- assert(false, `invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
353
- operation: "getContentHash()",
354
- info: { data }
355
- });
356
- }
357
-
358
- /**
359
- * Resolves to the avatar url or ``null`` if the avatar is either
360
- * unconfigured or incorrectly configured (e.g. references an NFT
361
- * not owned by the address).
362
- *
363
- * If diagnosing issues with configurations, the [[_getAvatar]]
364
- * method may be useful.
365
- */
366
- async getAvatar(): Promise<null | string> {
367
- const avatar = await this._getAvatar();
368
- return avatar.url;
369
- }
370
-
371
- /**
372
- * When resolving an avatar, there are many steps involved, such
373
- * fetching metadata and possibly validating ownership of an
374
- * NFT.
375
- *
376
- * This method can be used to examine each step and the value it
377
- * was working from.
378
- */
379
- async _getAvatar(): Promise<AvatarResult> {
380
- const linkage: Array<AvatarLinkage> = [ { type: "name", value: this.name } ];
381
- try {
382
- // test data for ricmoo.eth
383
- //const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
384
- const avatar = await this.getText("avatar");
385
- if (avatar == null) {
386
- linkage.push({ type: "!avatar", value: "" });
387
- return { url: null, linkage };
388
- }
389
- linkage.push({ type: "avatar", value: avatar });
390
-
391
- for (let i = 0; i < matchers.length; i++) {
392
- const match = avatar.match(matchers[i]);
393
- if (match == null) { continue; }
394
-
395
- const scheme = match[1].toLowerCase();
396
-
397
- switch (scheme) {
398
- case "https":
399
- case "data":
400
- linkage.push({ type: "url", value: avatar });
401
- return { linkage, url: avatar };
402
- case "ipfs": {
403
- const url = getIpfsLink(avatar);
404
- linkage.push({ type: "ipfs", value: avatar });
405
- linkage.push({ type: "url", value: url });
406
- return { linkage, url };
407
- }
408
-
409
- case "erc721":
410
- case "erc1155": {
411
- // Depending on the ERC type, use tokenURI(uint256) or url(uint256)
412
- const selector = (scheme === "erc721") ? "tokenURI(uint256)": "uri(uint256)";
413
- linkage.push({ type: scheme, value: avatar });
414
-
415
- // The owner of this name
416
- const owner = await this.getAddress();
417
- if (owner == null) {
418
- linkage.push({ type: "!owner", value: "" });
419
- return { url: null, linkage };
420
- }
421
-
422
- const comps = (match[2] || "").split("/");
423
- if (comps.length !== 2) {
424
- linkage.push({ type: <any>`!${ scheme }caip`, value: (match[2] || "") });
425
- return { url: null, linkage };
426
- }
427
-
428
- const tokenId = comps[1];
429
-
430
- const contract = new Contract(comps[0], [
431
- // ERC-721
432
- "function tokenURI(uint) view returns (string)",
433
- "function ownerOf(uint) view returns (address)",
434
-
435
- // ERC-1155
436
- "function uri(uint) view returns (string)",
437
- "function balanceOf(address, uint256) view returns (uint)"
438
- ], this.provider);
439
-
440
- // Check that this account owns the token
441
- if (scheme === "erc721") {
442
- const tokenOwner = await contract.ownerOf(tokenId);
443
-
444
- if (owner !== tokenOwner) {
445
- linkage.push({ type: "!owner", value: tokenOwner });
446
- return { url: null, linkage };
447
- }
448
- linkage.push({ type: "owner", value: tokenOwner });
449
-
450
- } else if (scheme === "erc1155") {
451
- const balance = await contract.balanceOf(owner, tokenId);
452
- if (!balance) {
453
- linkage.push({ type: "!balance", value: "0" });
454
- return { url: null, linkage };
455
- }
456
- linkage.push({ type: "balance", value: balance.toString() });
457
- }
458
-
459
- // Call the token contract for the metadata URL
460
- let metadataUrl = await contract[selector](tokenId);
461
- if (metadataUrl == null || metadataUrl === "0x") {
462
- linkage.push({ type: "!metadata-url", value: "" });
463
- return { url: null, linkage };
464
- }
465
-
466
- linkage.push({ type: "metadata-url-base", value: metadataUrl });
467
-
468
- // ERC-1155 allows a generic {id} in the URL
469
- if (scheme === "erc1155") {
470
- metadataUrl = metadataUrl.replace("{id}", toBeHex(tokenId, 32).substring(2));
471
- linkage.push({ type: "metadata-url-expanded", value: metadataUrl });
472
- }
473
-
474
- // Transform IPFS metadata links
475
- if (metadataUrl.match(/^ipfs:/i)) {
476
- metadataUrl = getIpfsLink(metadataUrl);
477
- }
478
- linkage.push({ type: "metadata-url", value: metadataUrl });
479
-
480
- // Get the token metadata
481
- let metadata: any = { };
482
- const response = await (new FetchRequest(metadataUrl)).send();
483
- response.assertOk();
484
-
485
- try {
486
- metadata = response.bodyJson;
487
- } catch (error) {
488
- try {
489
- linkage.push({ type: "!metadata", value: response.bodyText });
490
- } catch (error) {
491
- const bytes = response.body;
492
- if (bytes) {
493
- linkage.push({ type: "!metadata", value: hexlify(bytes) });
494
- }
495
- return { url: null, linkage };
496
- }
497
- return { url: null, linkage };
498
- }
499
-
500
- if (!metadata) {
501
- linkage.push({ type: "!metadata", value: "" });
502
- return { url: null, linkage };
503
- }
504
-
505
- linkage.push({ type: "metadata", value: JSON.stringify(metadata) });
506
-
507
- // Pull the image URL out
508
- let imageUrl = metadata.image;
509
- if (typeof(imageUrl) !== "string") {
510
- linkage.push({ type: "!imageUrl", value: "" });
511
- return { url: null, linkage };
512
- }
513
-
514
- if (imageUrl.match(/^(https:\/\/|data:)/i)) {
515
- // Allow
516
- } else {
517
- // Transform IPFS link to gateway
518
- const ipfs = imageUrl.match(matcherIpfs);
519
- if (ipfs == null) {
520
- linkage.push({ type: "!imageUrl-ipfs", value: imageUrl });
521
- return { url: null, linkage };
522
- }
523
-
524
- linkage.push({ type: "imageUrl-ipfs", value: imageUrl });
525
- imageUrl = getIpfsLink(imageUrl);
526
- }
527
-
528
- linkage.push({ type: "url", value: imageUrl });
529
-
530
- return { linkage, url: imageUrl };
531
- }
532
- }
533
- }
534
- } catch (error) { }
535
-
536
- return { linkage, url: null };
537
- }
538
-
539
- static async getEnsAddress(provider: Provider): Promise<string> {
540
- const network = await provider.getNetwork();
541
-
542
- const ensPlugin = network.getPlugin<EnsPlugin>("org.ethers.plugins.network.Ens");
543
-
544
- // No ENS...
545
- assert(ensPlugin, "network does not support ENS", "UNSUPPORTED_OPERATION", {
546
- operation: "getEnsAddress", info: { network } });
547
-
548
- return ensPlugin.address;
549
- }
550
-
551
- static async #getResolver(provider: Provider, name: string): Promise<null | string> {
552
- const ensAddr = await EnsResolver.getEnsAddress(provider);
553
-
554
- try {
555
- const contract = new Contract(ensAddr, [
556
- "function resolver(bytes32) view returns (address)"
557
- ], provider);
558
-
559
- const addr = await contract.resolver(namehash(name), {
560
- enableCcipRead: true
561
- });
562
-
563
- if (addr === ZeroAddress) { return null; }
564
- return addr;
565
-
566
- } catch (error) {
567
- // ENS registry cannot throw errors on resolver(bytes32),
568
- // so probably a link error
569
- throw error;
570
- }
571
-
572
- return null;
573
- }
574
-
575
- /**
576
- * Resolve to the ENS resolver for %%name%% using %%provider%% or
577
- * ``null`` if unconfigured.
578
- */
579
- static async fromName(provider: AbstractProvider, name: string): Promise<null | EnsResolver> {
580
-
581
- let currentName = name;
582
- while (true) {
583
- if (currentName === "" || currentName === ".") { return null; }
584
-
585
- // Optimization since the eth node cannot change and does
586
- // not have a wildcard resolver
587
- if (name !== "eth" && currentName === "eth") { return null; }
588
-
589
- // Check the current node for a resolver
590
- const addr = await EnsResolver.#getResolver(provider, currentName);
591
-
592
- // Found a resolver!
593
- if (addr != null) {
594
- const resolver = new EnsResolver(provider, addr, name);
595
-
596
- // Legacy resolver found, using EIP-2544 so it isn't safe to use
597
- if (currentName !== name && !(await resolver.supportsWildcard())) { return null; }
598
-
599
- return resolver;
600
- }
601
-
602
- // Get the parent node
603
- currentName = currentName.split(".").slice(1).join(".");
604
- }
605
- }
606
- }
1
+ /**
2
+ * ENS is a service which allows easy-to-remember names to map to
3
+ * network addresses.
4
+ *
5
+ * @_section: api/providers/ens-resolver:ENS Resolver [about-ens-rsolver]
6
+ */
7
+
8
+ import { getAddress } from "../address/index.js";
9
+ import { ZeroAddress } from "../constants/index.js";
10
+ import { Contract } from "../contract/index.js";
11
+ import { dnsEncode, namehash } from "../hash/index.js";
12
+ import {
13
+ hexlify, isHexString, toBeHex,
14
+ defineProperties, encodeBase58,
15
+ assert, assertArgument, isError,
16
+ FetchRequest
17
+ } from "../utils/index.js";
18
+
19
+ import type { FunctionFragment } from "../abi/index.js";
20
+
21
+ import type { BytesLike } from "../utils/index.js";
22
+
23
+ import type { AbstractProvider, AbstractProviderPlugin } from "./abstract-provider.js";
24
+ import type { EnsPlugin } from "./plugins-network.js";
25
+ import type { Provider } from "./provider.js";
26
+
27
+ // @TODO: This should use the fetch-data:ipfs gateway
28
+ // Trim off the ipfs:// prefix and return the default gateway URL
29
+ function getIpfsLink(link: string): string {
30
+ if (link.match(/^ipfs:\/\/ipfs\//i)) {
31
+ link = link.substring(12);
32
+ } else if (link.match(/^ipfs:\/\//i)) {
33
+ link = link.substring(7);
34
+ } else {
35
+ assertArgument(false, "unsupported IPFS format", "link", link);
36
+ }
37
+
38
+ return `https:/\/gateway.ipfs.io/ipfs/${ link }`;
39
+ }
40
+
41
+ /**
42
+ * The type of data found during a steip during avatar resolution.
43
+ */
44
+ export type AvatarLinkageType = "name" | "avatar" | "!avatar" | "url" | "data" | "ipfs" |
45
+ "erc721" | "erc1155" | "!erc721-caip" | "!erc1155-caip" |
46
+ "!owner" | "owner" | "!balance" | "balance" |
47
+ "metadata-url-base" | "metadata-url-expanded" | "metadata-url" | "!metadata-url" |
48
+ "!metadata" | "metadata" |
49
+ "!imageUrl" | "imageUrl-ipfs" | "imageUrl" | "!imageUrl-ipfs";
50
+
51
+ /**
52
+ * An individual record for each step during avatar resolution.
53
+ */
54
+ export interface AvatarLinkage {
55
+ /**
56
+ * The type of linkage.
57
+ */
58
+ type: AvatarLinkageType;
59
+
60
+ /**
61
+ * The linkage value.
62
+ */
63
+ value: string;
64
+ };
65
+
66
+ /**
67
+ * When resolving an avatar for an ENS name, there are many
68
+ * steps involved, fetching metadata, validating results, et cetera.
69
+ *
70
+ * Some applications may wish to analyse this data, or use this data
71
+ * to diagnose promblems, so an **AvatarResult** provides details of
72
+ * each completed step during avatar resolution.
73
+ */
74
+ export interface AvatarResult {
75
+ /**
76
+ * How the [[url]] was arrived at, resolving the many steps required
77
+ * for an avatar URL.
78
+ */
79
+ linkage: Array<AvatarLinkage>;
80
+
81
+ /**
82
+ * The avatar URL or null if the avatar was not set, or there was
83
+ * an issue during validation (such as the address not owning the
84
+ * avatar or a metadata error).
85
+ */
86
+ url: null | string;
87
+ };
88
+
89
+ /**
90
+ * A provider plugin super-class for processing multicoin address types.
91
+ */
92
+ export abstract class MulticoinProviderPlugin implements AbstractProviderPlugin {
93
+ /**
94
+ * The name.
95
+ */
96
+ readonly name!: string;
97
+
98
+ /**
99
+ * Creates a new **MulticoinProviderPluing** for %%name%%.
100
+ */
101
+ constructor(name: string) {
102
+ defineProperties<MulticoinProviderPlugin>(this, { name });
103
+ }
104
+
105
+ connect(proivder: Provider): MulticoinProviderPlugin {
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Returns ``true`` if %%coinType%% is supported by this plugin.
111
+ */
112
+ supportsCoinType(coinType: number): boolean {
113
+ return false;
114
+ }
115
+
116
+ /**
117
+ * Resolves to the encoded %%address%% for %%coinType%%.
118
+ */
119
+ async encodeAddress(coinType: number, address: string): Promise<string> {
120
+ throw new Error("unsupported coin");
121
+ }
122
+
123
+ /**
124
+ * Resolves to the decoded %%data%% for %%coinType%%.
125
+ */
126
+ async decodeAddress(coinType: number, data: BytesLike): Promise<string> {
127
+ throw new Error("unsupported coin");
128
+ }
129
+ }
130
+
131
+ const BasicMulticoinPluginId = "org.ethers.plugins.provider.BasicMulticoin";
132
+
133
+ /**
134
+ * A **BasicMulticoinProviderPlugin** provides service for common
135
+ * coin types, which do not require additional libraries to encode or
136
+ * decode.
137
+ */
138
+ export class BasicMulticoinProviderPlugin extends MulticoinProviderPlugin {
139
+ /**
140
+ * Creates a new **BasicMulticoinProviderPlugin**.
141
+ */
142
+ constructor() {
143
+ super(BasicMulticoinPluginId);
144
+ }
145
+ }
146
+
147
+ const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
148
+ const matchers = [
149
+ new RegExp("^(https):/\/(.*)$", "i"),
150
+ new RegExp("^(data):(.*)$", "i"),
151
+ matcherIpfs,
152
+ new RegExp("^eip155:[0-9]+/(erc[0-9]+):(.*)$", "i"),
153
+ ];
154
+
155
+ /**
156
+ * A connected object to a resolved ENS name resolver, which can be
157
+ * used to query additional details.
158
+ */
159
+ export class EnsResolver {
160
+ /**
161
+ * The connected provider.
162
+ */
163
+ provider!: AbstractProvider;
164
+
165
+ /**
166
+ * The address of the resolver.
167
+ */
168
+ address!: string;
169
+
170
+ /**
171
+ * The name this resolver was resolved against.
172
+ */
173
+ name!: string;
174
+
175
+ // For EIP-2544 names, the ancestor that provided the resolver
176
+ #supports2544: null | Promise<boolean>;
177
+
178
+ #resolver: Contract;
179
+
180
+ constructor(provider: AbstractProvider, address: string, name: string) {
181
+ defineProperties<EnsResolver>(this, { provider, address, name });
182
+ this.#supports2544 = null;
183
+
184
+ this.#resolver = new Contract(address, [
185
+ "function supportsInterface(bytes4) view returns (bool)",
186
+ "function resolve(bytes, bytes) view returns (bytes)",
187
+ "function addr(bytes32) view returns (address)",
188
+ "function addr(bytes32, uint) view returns (bytes)",
189
+ "function text(bytes32, string) view returns (string)",
190
+ "function contenthash(bytes32) view returns (bytes)",
191
+ ], provider);
192
+
193
+ }
194
+
195
+ /**
196
+ * Resolves to true if the resolver supports wildcard resolution.
197
+ */
198
+ async supportsWildcard(): Promise<boolean> {
199
+ if (this.#supports2544 == null) {
200
+ this.#supports2544 = (async () => {
201
+ try {
202
+ return await this.#resolver.supportsInterface("0x9061b923");
203
+ } catch (error) {
204
+ // Wildcard resolvers must understand supportsInterface
205
+ // and return true.
206
+ if (isError(error, "CALL_EXCEPTION")) { return false; }
207
+
208
+ // Let future attempts try again...
209
+ this.#supports2544 = null;
210
+
211
+ throw error;
212
+ }
213
+ })();
214
+ }
215
+
216
+ return await this.#supports2544;
217
+ }
218
+
219
+ async #fetch(funcName: string, params?: Array<any>): Promise<null | any> {
220
+ params = (params || []).slice();
221
+ const iface = this.#resolver.interface;
222
+
223
+ // The first parameters is always the nodehash
224
+ params.unshift(namehash(this.name))
225
+
226
+ let fragment: null | FunctionFragment = null;
227
+ if (await this.supportsWildcard()) {
228
+ fragment = iface.getFunction(funcName);
229
+ assert(fragment, "missing fragment", "UNKNOWN_ERROR", {
230
+ info: { funcName }
231
+ });
232
+
233
+ params = [
234
+ dnsEncode(this.name, 255),
235
+ iface.encodeFunctionData(fragment, params)
236
+ ];
237
+
238
+ funcName = "resolve(bytes,bytes)";
239
+ }
240
+
241
+ params.push({
242
+ enableCcipRead: true
243
+ });
244
+
245
+ try {
246
+ const result = await this.#resolver[funcName](...params);
247
+
248
+ if (fragment) {
249
+ return iface.decodeFunctionResult(fragment, result)[0];
250
+ }
251
+
252
+ return result;
253
+ } catch (error: any) {
254
+ if (!isError(error, "CALL_EXCEPTION")) { throw error; }
255
+ }
256
+
257
+ return null;
258
+ }
259
+
260
+ /**
261
+ * Resolves to the address for %%coinType%% or null if the
262
+ * provided %%coinType%% has not been configured.
263
+ */
264
+ async getAddress(coinType?: number): Promise<null | string> {
265
+ if (coinType == null) { coinType = 60; }
266
+ if (coinType === 60) {
267
+ try {
268
+ const result = await this.#fetch("addr(bytes32)");
269
+
270
+ // No address
271
+ if (result == null || result === ZeroAddress) { return null; }
272
+
273
+ return result;
274
+ } catch (error: any) {
275
+ if (isError(error, "CALL_EXCEPTION")) { return null; }
276
+ throw error;
277
+ }
278
+ }
279
+
280
+ // Try decoding its EVM canonical chain as an EVM chain address first
281
+ if (coinType >= 0 && coinType < 0x80000000) {
282
+ let ethCoinType = coinType + 0x80000000;
283
+
284
+ const data = await this.#fetch("addr(bytes32,uint)", [ ethCoinType ]);
285
+ if (isHexString(data, 20)) { return getAddress(data); }
286
+ }
287
+
288
+ let coinPlugin: null | MulticoinProviderPlugin = null;
289
+ for (const plugin of this.provider.plugins) {
290
+ if (!(plugin instanceof MulticoinProviderPlugin)) { continue; }
291
+ if (plugin.supportsCoinType(coinType)) {
292
+ coinPlugin = plugin;
293
+ break;
294
+ }
295
+ }
296
+
297
+ if (coinPlugin == null) { return null; }
298
+
299
+ // keccak256("addr(bytes32,uint256")
300
+ const data = await this.#fetch("addr(bytes32,uint)", [ coinType ]);
301
+
302
+ // No address
303
+ if (data == null || data === "0x") { return null; }
304
+
305
+ // Compute the address
306
+ const address = await coinPlugin.decodeAddress(coinType, data);
307
+
308
+ if (address != null) { return address; }
309
+
310
+ assert(false, `invalid coin data`, "UNSUPPORTED_OPERATION", {
311
+ operation: `getAddress(${ coinType })`,
312
+ info: { coinType, data }
313
+ });
314
+ }
315
+
316
+ /**
317
+ * Resolves to the EIP-634 text record for %%key%%, or ``null``
318
+ * if unconfigured.
319
+ */
320
+ async getText(key: string): Promise<null | string> {
321
+ const data = await this.#fetch("text(bytes32,string)", [ key ]);
322
+ if (data == null || data === "0x") { return null; }
323
+ return data;
324
+ }
325
+
326
+ /**
327
+ * Rsolves to the content-hash or ``null`` if unconfigured.
328
+ */
329
+ async getContentHash(): Promise<null | string> {
330
+ // keccak256("contenthash()")
331
+ const data = await this.#fetch("contenthash(bytes32)");
332
+
333
+ // No contenthash
334
+ if (data == null || data === "0x") { return null; }
335
+
336
+ // IPFS (CID: 1, Type: 70=DAG-PB, 72=libp2p-key)
337
+ const ipfs = data.match(/^0x(e3010170|e5010172)(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/);
338
+ if (ipfs) {
339
+ const scheme = (ipfs[1] === "e3010170") ? "ipfs": "ipns";
340
+ const length = parseInt(ipfs[4], 16);
341
+ if (ipfs[5].length === length * 2) {
342
+ return `${ scheme }:/\/${ encodeBase58("0x" + ipfs[2])}`;
343
+ }
344
+ }
345
+
346
+ // Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
347
+ const swarm = data.match(/^0xe40101fa011b20([0-9a-f]*)$/)
348
+ if (swarm && swarm[1].length === 64) {
349
+ return `bzz:/\/${ swarm[1] }`;
350
+ }
351
+
352
+ assert(false, `invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
353
+ operation: "getContentHash()",
354
+ info: { data }
355
+ });
356
+ }
357
+
358
+ /**
359
+ * Resolves to the avatar url or ``null`` if the avatar is either
360
+ * unconfigured or incorrectly configured (e.g. references an NFT
361
+ * not owned by the address).
362
+ *
363
+ * If diagnosing issues with configurations, the [[_getAvatar]]
364
+ * method may be useful.
365
+ */
366
+ async getAvatar(): Promise<null | string> {
367
+ const avatar = await this._getAvatar();
368
+ return avatar.url;
369
+ }
370
+
371
+ /**
372
+ * When resolving an avatar, there are many steps involved, such
373
+ * fetching metadata and possibly validating ownership of an
374
+ * NFT.
375
+ *
376
+ * This method can be used to examine each step and the value it
377
+ * was working from.
378
+ */
379
+ async _getAvatar(): Promise<AvatarResult> {
380
+ const linkage: Array<AvatarLinkage> = [ { type: "name", value: this.name } ];
381
+ try {
382
+ // test data for ricmoo.eth
383
+ //const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
384
+ const avatar = await this.getText("avatar");
385
+ if (avatar == null) {
386
+ linkage.push({ type: "!avatar", value: "" });
387
+ return { url: null, linkage };
388
+ }
389
+ linkage.push({ type: "avatar", value: avatar });
390
+
391
+ for (let i = 0; i < matchers.length; i++) {
392
+ const match = avatar.match(matchers[i]);
393
+ if (match == null) { continue; }
394
+
395
+ const scheme = match[1].toLowerCase();
396
+
397
+ switch (scheme) {
398
+ case "https":
399
+ case "data":
400
+ linkage.push({ type: "url", value: avatar });
401
+ return { linkage, url: avatar };
402
+ case "ipfs": {
403
+ const url = getIpfsLink(avatar);
404
+ linkage.push({ type: "ipfs", value: avatar });
405
+ linkage.push({ type: "url", value: url });
406
+ return { linkage, url };
407
+ }
408
+
409
+ case "erc721":
410
+ case "erc1155": {
411
+ // Depending on the ERC type, use tokenURI(uint256) or url(uint256)
412
+ const selector = (scheme === "erc721") ? "tokenURI(uint256)": "uri(uint256)";
413
+ linkage.push({ type: scheme, value: avatar });
414
+
415
+ // The owner of this name
416
+ const owner = await this.getAddress();
417
+ if (owner == null) {
418
+ linkage.push({ type: "!owner", value: "" });
419
+ return { url: null, linkage };
420
+ }
421
+
422
+ const comps = (match[2] || "").split("/");
423
+ if (comps.length !== 2) {
424
+ linkage.push({ type: <any>`!${ scheme }caip`, value: (match[2] || "") });
425
+ return { url: null, linkage };
426
+ }
427
+
428
+ const tokenId = comps[1];
429
+
430
+ const contract = new Contract(comps[0], [
431
+ // ERC-721
432
+ "function tokenURI(uint) view returns (string)",
433
+ "function ownerOf(uint) view returns (address)",
434
+
435
+ // ERC-1155
436
+ "function uri(uint) view returns (string)",
437
+ "function balanceOf(address, uint256) view returns (uint)"
438
+ ], this.provider);
439
+
440
+ // Check that this account owns the token
441
+ if (scheme === "erc721") {
442
+ const tokenOwner = await contract.ownerOf(tokenId);
443
+
444
+ if (owner !== tokenOwner) {
445
+ linkage.push({ type: "!owner", value: tokenOwner });
446
+ return { url: null, linkage };
447
+ }
448
+ linkage.push({ type: "owner", value: tokenOwner });
449
+
450
+ } else if (scheme === "erc1155") {
451
+ const balance = await contract.balanceOf(owner, tokenId);
452
+ if (!balance) {
453
+ linkage.push({ type: "!balance", value: "0" });
454
+ return { url: null, linkage };
455
+ }
456
+ linkage.push({ type: "balance", value: balance.toString() });
457
+ }
458
+
459
+ // Call the token contract for the metadata URL
460
+ let metadataUrl = await contract[selector](tokenId);
461
+ if (metadataUrl == null || metadataUrl === "0x") {
462
+ linkage.push({ type: "!metadata-url", value: "" });
463
+ return { url: null, linkage };
464
+ }
465
+
466
+ linkage.push({ type: "metadata-url-base", value: metadataUrl });
467
+
468
+ // ERC-1155 allows a generic {id} in the URL
469
+ if (scheme === "erc1155") {
470
+ metadataUrl = metadataUrl.replace("{id}", toBeHex(tokenId, 32).substring(2));
471
+ linkage.push({ type: "metadata-url-expanded", value: metadataUrl });
472
+ }
473
+
474
+ // Transform IPFS metadata links
475
+ if (metadataUrl.match(/^ipfs:/i)) {
476
+ metadataUrl = getIpfsLink(metadataUrl);
477
+ }
478
+ linkage.push({ type: "metadata-url", value: metadataUrl });
479
+
480
+ // Get the token metadata
481
+ let metadata: any = { };
482
+ const response = await (new FetchRequest(metadataUrl)).send();
483
+ response.assertOk();
484
+
485
+ try {
486
+ metadata = response.bodyJson;
487
+ } catch (error) {
488
+ try {
489
+ linkage.push({ type: "!metadata", value: response.bodyText });
490
+ } catch (error) {
491
+ const bytes = response.body;
492
+ if (bytes) {
493
+ linkage.push({ type: "!metadata", value: hexlify(bytes) });
494
+ }
495
+ return { url: null, linkage };
496
+ }
497
+ return { url: null, linkage };
498
+ }
499
+
500
+ if (!metadata) {
501
+ linkage.push({ type: "!metadata", value: "" });
502
+ return { url: null, linkage };
503
+ }
504
+
505
+ linkage.push({ type: "metadata", value: JSON.stringify(metadata) });
506
+
507
+ // Pull the image URL out
508
+ let imageUrl = metadata.image;
509
+ if (typeof(imageUrl) !== "string") {
510
+ linkage.push({ type: "!imageUrl", value: "" });
511
+ return { url: null, linkage };
512
+ }
513
+
514
+ if (imageUrl.match(/^(https:\/\/|data:)/i)) {
515
+ // Allow
516
+ } else {
517
+ // Transform IPFS link to gateway
518
+ const ipfs = imageUrl.match(matcherIpfs);
519
+ if (ipfs == null) {
520
+ linkage.push({ type: "!imageUrl-ipfs", value: imageUrl });
521
+ return { url: null, linkage };
522
+ }
523
+
524
+ linkage.push({ type: "imageUrl-ipfs", value: imageUrl });
525
+ imageUrl = getIpfsLink(imageUrl);
526
+ }
527
+
528
+ linkage.push({ type: "url", value: imageUrl });
529
+
530
+ return { linkage, url: imageUrl };
531
+ }
532
+ }
533
+ }
534
+ } catch (error) { }
535
+
536
+ return { linkage, url: null };
537
+ }
538
+
539
+ static async getEnsAddress(provider: Provider): Promise<string> {
540
+ const network = await provider.getNetwork();
541
+
542
+ const ensPlugin = network.getPlugin<EnsPlugin>("org.ethers.plugins.network.Ens");
543
+
544
+ // No ENS...
545
+ assert(ensPlugin, "network does not support ENS", "UNSUPPORTED_OPERATION", {
546
+ operation: "getEnsAddress", info: { network } });
547
+
548
+ return ensPlugin.address;
549
+ }
550
+
551
+ static async #getResolver(provider: Provider, name: string): Promise<null | string> {
552
+ const ensAddr = await EnsResolver.getEnsAddress(provider);
553
+
554
+ try {
555
+ const contract = new Contract(ensAddr, [
556
+ "function resolver(bytes32) view returns (address)"
557
+ ], provider);
558
+
559
+ const addr = await contract.resolver(namehash(name), {
560
+ enableCcipRead: true
561
+ });
562
+
563
+ if (addr === ZeroAddress) { return null; }
564
+ return addr;
565
+
566
+ } catch (error) {
567
+ // ENS registry cannot throw errors on resolver(bytes32),
568
+ // so probably a link error
569
+ throw error;
570
+ }
571
+
572
+ return null;
573
+ }
574
+
575
+ /**
576
+ * Resolve to the ENS resolver for %%name%% using %%provider%% or
577
+ * ``null`` if unconfigured.
578
+ */
579
+ static async fromName(provider: AbstractProvider, name: string): Promise<null | EnsResolver> {
580
+
581
+ let currentName = name;
582
+ while (true) {
583
+ if (currentName === "" || currentName === ".") { return null; }
584
+
585
+ // Optimization since the eth node cannot change and does
586
+ // not have a wildcard resolver
587
+ if (name !== "eth" && currentName === "eth") { return null; }
588
+
589
+ // Check the current node for a resolver
590
+ const addr = await EnsResolver.#getResolver(provider, currentName);
591
+
592
+ // Found a resolver!
593
+ if (addr != null) {
594
+ const resolver = new EnsResolver(provider, addr, name);
595
+
596
+ // Legacy resolver found, using EIP-2544 so it isn't safe to use
597
+ if (currentName !== name && !(await resolver.supportsWildcard())) { return null; }
598
+
599
+ return resolver;
600
+ }
601
+
602
+ // Get the parent node
603
+ currentName = currentName.split(".").slice(1).join(".");
604
+ }
605
+ }
606
+ }