Merge branch 'release/v2022.02.03-otterscan'

This commit is contained in:
Willian Mitsuda 2022-02-22 15:38:47 -03:00
commit fd9778443d
23 changed files with 552 additions and 296 deletions

View File

@ -4,3 +4,4 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
open-pull-requests-limit: 20

View File

@ -74,9 +74,11 @@ All methods are prefixed with the `ots_` namespace in order to make it clear it
| `ots_getTransactionError` | Extract the transaction raw error output. | In order to get the error message or custom error from a failed transaction, you need to get its error output and decoded it. This info is not exposed through standard APIs. | | `ots_getTransactionError` | Extract the transaction raw error output. | In order to get the error message or custom error from a failed transaction, you need to get its error output and decoded it. This info is not exposed through standard APIs. |
| `ots_traceTransaction` | Extract all variations of calls, contract creation and self-destructs and returns a call tree. | This is an optimized version of tracing; regular tracing returns lots of data, and custom tracing using a JS tracer could be slow. | | `ots_traceTransaction` | Extract all variations of calls, contract creation and self-destructs and returns a call tree. | This is an optimized version of tracing; regular tracing returns lots of data, and custom tracing using a JS tracer could be slow. |
| `ots_getBlockDetails` | Tailor-made and expanded version of `eth_getBlock*` for block details page in Otterscan. | The standard `eth_getBlock*` is quite verbose and it doesn't bring all info we need. We explicitly remove the transaction list (unnecessary for that page and also this call doesn't scale well), log blooms and other unnecessary fields. We add issuance and block fees info and return all of this in just one call. | | `ots_getBlockDetails` | Tailor-made and expanded version of `eth_getBlock*` for block details page in Otterscan. | The standard `eth_getBlock*` is quite verbose and it doesn't bring all info we need. We explicitly remove the transaction list (unnecessary for that page and also this call doesn't scale well), log blooms and other unnecessary fields. We add issuance and block fees info and return all of this in just one call. |
| `ots_getBlockDetailsByHash` | Same as `ots_getBlockDetails`, but it accepts a block hash as parameter. | |
| `ots_getBlockTransactions` | Get paginated transactions for a certain block. Also remove some verbose fields like logs. | As block size increases, getting all transactions from a block at once doesn't scale, so the first point here is to add pagination support. The second point is that receipts may have big, unnecessary information, like logs. So we cap all of them to save network bandwidth. | | `ots_getBlockTransactions` | Get paginated transactions for a certain block. Also remove some verbose fields like logs. | As block size increases, getting all transactions from a block at once doesn't scale, so the first point here is to add pagination support. The second point is that receipts may have big, unnecessary information, like logs. So we cap all of them to save network bandwidth. |
| `ots_searchTransactionsBefore` and `ots_searchTransactionsAfter` | Gets paginated inbound/outbound transaction calls for a certain address. | There is no native support for any kind of transaction search in the standard JSON-RPC API. We don't want to introduce an additional indexer middleware in Otterscan, so we implemented in-node search. | | `ots_searchTransactionsBefore` and `ots_searchTransactionsAfter` | Gets paginated inbound/outbound transaction calls for a certain address. | There is no native support for any kind of transaction search in the standard JSON-RPC API. We don't want to introduce an additional indexer middleware in Otterscan, so we implemented in-node search. |
| `ots_getTransactionBySenderAndNonce` | Gets the transaction hash for a certain sender address, given its nonce. | There is no native support for this search in the standard JSON-RPC API. Otterscan needs it to allow user navigation between nonces from the same sender address. | | `ots_getTransactionBySenderAndNonce` | Gets the transaction hash for a certain sender address, given its nonce. | There is no native support for this search in the standard JSON-RPC API. Otterscan needs it to allow user navigation between nonces from the same sender address. |
| `ots_getContractCreator` | Gets the transaction hash and the address who created a contract. | No way to get this info from the standard JSON-RPC API. |
## Method details ## Method details
@ -335,3 +337,40 @@ Response:
"result": "0x021304206b2517c3f8f2df07014a55b79aac2ae097488fa807cc88eccd851a50" "result": "0x021304206b2517c3f8f2df07014a55b79aac2ae097488fa807cc88eccd851a50"
} }
``` ```
### `ots_getContractCreator`
Given an ETH contract address, returns the tx hash and the direct address who created the contract.
If the address is an EOA or a destroyed contract, it returns `null`.
Parameters:
1. `address` - The ETH address that may contain a contract.
Returns:
- `object` containing the following attributes, or `null` if the address does not contain a contract.
- `hash` - The tx hash of the transaction who created the contract.
- `creator` - The address who directly created the contract. Note that for simple transactions that directly deploy a contract this corresponds to the EOA in the `from` field of the transaction. For deployer contracts, i.e., the contract is created as a result of a method call, this corresponds to the address of the contract who created it.
Example: get who created the Uniswap V3 Router contract.
Request:
```
$ curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0", "id": 1, "method":"ots_getContractCreator","params":["0xE592427A0AEce92De3Edee1F18E0157C05861564"]}' http://127.0.0.1:8545
```
Response:
```
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"hash": "0xe881c43cd88063e84a1d0283f41ee5348239b259c0d17a7e2e4552da3f4b2bc7",
"creator": "0x6c9fc64a53c1b71fb3f9af64d1ae3a4931a5f4e9"
}
}
```

336
package-lock.json generated
View File

@ -10,31 +10,31 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@blackbox-vision/react-qr-reader": "^5.0.0", "@blackbox-vision/react-qr-reader": "^5.0.0",
"@chainlink/contracts": "^0.2.2", "@chainlink/contracts": "^0.4.0",
"@craco/craco": "^6.4.3", "@craco/craco": "^6.4.3",
"@fontsource/fira-code": "^4.5.2", "@fontsource/fira-code": "^4.5.5",
"@fontsource/roboto": "^4.5.1", "@fontsource/roboto": "^4.5.3",
"@fontsource/roboto-mono": "^4.5.0", "@fontsource/roboto-mono": "^4.5.3",
"@fontsource/space-grotesk": "^4.5.0", "@fontsource/space-grotesk": "^4.5.3",
"@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.16", "@fortawesome/react-fontawesome": "^0.1.17",
"@headlessui/react": "^1.4.2", "@headlessui/react": "^1.4.3",
"@testing-library/jest-dom": "^5.16.1", "@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",
"@types/node": "^16.11.14", "@types/node": "^16.11.14",
"@types/react": "^17.0.38", "@types/react": "^17.0.39",
"@types/react-blockies": "^1.4.1", "@types/react-blockies": "^1.4.1",
"@types/react-dom": "^17.0.11", "@types/react-dom": "^17.0.11",
"@types/react-highlight": "^0.12.5", "@types/react-highlight": "^0.12.5",
"@types/react-syntax-highlighter": "^13.5.2", "@types/react-syntax-highlighter": "^13.5.2",
"chart.js": "^3.7.0", "chart.js": "^3.7.1",
"ethers": "^5.5.2", "ethers": "^5.5.4",
"highlightjs-solidity": "^2.0.3", "highlightjs-solidity": "^2.0.4",
"react": "^17.0.2", "react": "^17.0.2",
"react-blockies": "^1.4.1", "react-blockies": "^1.4.1",
"react-chartjs-2": "^4.0.0", "react-chartjs-2": "^4.0.0",
@ -46,9 +46,9 @@
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-syntax-highlighter": "^15.4.5", "react-syntax-highlighter": "^15.4.5",
"serve": "^13.0.2", "serve": "^13.0.2",
"swr": "^1.1.2", "swr": "^1.2.1",
"typescript": "^4.5.4", "typescript": "^4.5.5",
"use-keyboard-shortcut": "^1.1.2", "use-keyboard-shortcut": "^1.1.3",
"web-vitals": "^1.0.1" "web-vitals": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
@ -1229,9 +1229,9 @@
} }
}, },
"node_modules/@chainlink/contracts": { "node_modules/@chainlink/contracts": {
"version": "0.2.2", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.2.2.tgz", "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.4.0.tgz",
"integrity": "sha512-wxXPbt7O3aZaUSG34ufFASC5amRSL6eeYCqsa+2gpqbB8Hk7B7FydEDCI5dqvAC444TlFskPHcVbizCZkRHPpw==" "integrity": "sha512-yZGeCBd7d+qxfw9r/JxtPzsW2kCc6MorPRZ/tDKnaJI98H99j5P2Fosfehmcwk6wVZlz+0Bp4kS1y480nw3Zow=="
}, },
"node_modules/@cnakazawa/watch": { "node_modules/@cnakazawa/watch": {
"version": "1.0.4", "version": "1.0.4",
@ -1775,9 +1775,9 @@
] ]
}, },
"node_modules/@ethersproject/networks": { "node_modules/@ethersproject/networks": {
"version": "5.5.1", "version": "5.5.2",
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.1.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz",
"integrity": "sha512-tYRDM4zZtSUcKnD4UMuAlj7SeXH/k5WC4SP2u1Pn57++JdXHkRu2zwNkgNogZoxHzhm9Q6qqurDBVptHOsW49Q==", "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -1830,9 +1830,9 @@
} }
}, },
"node_modules/@ethersproject/providers": { "node_modules/@ethersproject/providers": {
"version": "5.5.1", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.1.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz",
"integrity": "sha512-2zdD5sltACDWhjUE12Kucg2PcgM6V2q9JMyVvObtVGnzJu+QSmibbP+BHQyLWZUBfLApx2942+7DC5D+n4wBQQ==", "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -1886,9 +1886,9 @@
} }
}, },
"node_modules/@ethersproject/random": { "node_modules/@ethersproject/random": {
"version": "5.5.0", "version": "5.5.1",
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.0.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz",
"integrity": "sha512-egGYZwZ/YIFKMHcoBUo8t3a8Hb/TKYX8BCBoLjudVCZh892welR3jOxgOmb48xznc9bTcMm7Tpwc1gHC1PFNFQ==", "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -2132,24 +2132,24 @@
} }
}, },
"node_modules/@fontsource/fira-code": { "node_modules/@fontsource/fira-code": {
"version": "4.5.2", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-4.5.2.tgz", "resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-4.5.5.tgz",
"integrity": "sha512-wNUvcqmm1dZYTbJlkbFZL9Huu7p+Hwaa4CLNTPql3CG90Rh9dSi43wNg5AnVHxjAhWQOGlCpSrEswnnHu1CkxA==" "integrity": "sha512-bwsPmA5HW11SR0oIkgqSJYI3A8KP8aQLRCCH/EnR9gLHRuTFi1iG7GQ3wDTKy/AhECQJAKjXZ+mkVKlMxUaYCQ=="
}, },
"node_modules/@fontsource/roboto": { "node_modules/@fontsource/roboto": {
"version": "4.5.1", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.1.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.3.tgz",
"integrity": "sha512-3mhfL+eNPG/woMNqwD/OHaW5qMpeGEBsDwzmhFmjB1yUV+M+M9P0NhP/AyHvnGz3DrqkvZ7CPzNMa+UkVLeELg==" "integrity": "sha512-NUvBTj332dFRdiVkLlavXbDGoD2zyyeGYmMyrXOnctg/3e4pq95+rJgNfUP+k4v8UBk2L1aomGw9dDjbRdAmTg=="
}, },
"node_modules/@fontsource/roboto-mono": { "node_modules/@fontsource/roboto-mono": {
"version": "4.5.0", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/roboto-mono/-/roboto-mono-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto-mono/-/roboto-mono-4.5.3.tgz",
"integrity": "sha512-/6Gm6fJjBHZiFNyvzIKGJkVuyifoc1aoTel+pkzdhxNh7yNhFyokCoChdbbqZEpGKpqs5uld74G5TJthUVFyjw==" "integrity": "sha512-ELuIIUBo1kq2hFmOXjWv9o2VbM22Pct2F0T+D8f5T0MxDKIqkh0m1JMs9bbTzMjc+wVvyJ6LU5EiNkO26kLlKA=="
}, },
"node_modules/@fontsource/space-grotesk": { "node_modules/@fontsource/space-grotesk": {
"version": "4.5.0", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/space-grotesk/-/space-grotesk-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@fontsource/space-grotesk/-/space-grotesk-4.5.3.tgz",
"integrity": "sha512-Kdnq5m31DsJ8l/VCpZGz4QpIxLLvNVh4MyVGY0PmDh7aY9aM5rmO2NF49dJ0749gLPgMW6Moc/xjgW95G0MbMg==" "integrity": "sha512-uhCiGA3DXiT7BLCcbKzSDlgUp6Pct50+WObzLJvee8qnA2ezH/cfWlIU3+3ydc1poxQuR6+jJN2Cd8XjpOB9lg=="
}, },
"node_modules/@fortawesome/fontawesome-common-types": { "node_modules/@fortawesome/fontawesome-common-types": {
"version": "0.2.36", "version": "0.2.36",
@ -2209,11 +2209,11 @@
} }
}, },
"node_modules/@fortawesome/react-fontawesome": { "node_modules/@fortawesome/react-fontawesome": {
"version": "0.1.16", "version": "0.1.17",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz", "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz",
"integrity": "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA==", "integrity": "sha512-dX43Z5IvMaW7fwzU8farosYjKNGfRb2HB/DgjVBHeJZ/NSnuuaujPPx0YOdcAq+n3mqn70tyCde2HM1mqbhiuw==",
"dependencies": { "dependencies": {
"prop-types": "^15.7.2" "prop-types": "^15.8.1"
}, },
"peerDependencies": { "peerDependencies": {
"@fortawesome/fontawesome-svg-core": "~1 || >=1.3.0-beta1", "@fortawesome/fontawesome-svg-core": "~1 || >=1.3.0-beta1",
@ -2250,9 +2250,9 @@
} }
}, },
"node_modules/@headlessui/react": { "node_modules/@headlessui/react": {
"version": "1.4.2", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.2.tgz", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.3.tgz",
"integrity": "sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==", "integrity": "sha512-n2IQkaaw0aAAlQS5MEXsM4uRK+w18CrM72EqnGRl/UBOQeQajad8oiKXR9Nk15jOzTFQjpxzrZMf1NxHidFBiw==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@ -2970,9 +2970,9 @@
} }
}, },
"node_modules/@testing-library/jest-dom": { "node_modules/@testing-library/jest-dom": {
"version": "5.16.1", "version": "5.16.2",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.1.tgz", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.2.tgz",
"integrity": "sha512-ajUJdfDIuTCadB79ukO+0l8O+QwN0LiSxDaYUTI4LndbbUsGi6rWU1SCexXzBA2NSjlVB9/vbkasQIL3tmPBjw==", "integrity": "sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.9.2", "@babel/runtime": "^7.9.2",
"@types/testing-library__jest-dom": "^5.9.1", "@types/testing-library__jest-dom": "^5.9.1",
@ -3233,9 +3233,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "17.0.38", "version": "17.0.39",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
"integrity": "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
@ -5689,9 +5689,9 @@
} }
}, },
"node_modules/chart.js": { "node_modules/chart.js": {
"version": "3.7.0", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz",
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA=="
}, },
"node_modules/check-types": { "node_modules/check-types": {
"version": "11.1.2", "version": "11.1.2",
@ -8201,9 +8201,9 @@
} }
}, },
"node_modules/ethers": { "node_modules/ethers": {
"version": "5.5.2", "version": "5.5.4",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.2.tgz", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz",
"integrity": "sha512-EF5W+6Wwcu6BqVwpgmyR5U2+L4c1FQzlM/02dkZOugN3KF0cG9bzHZP+TDJglmPm2/IzCEJDT7KBxzayk7SAHw==", "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -8230,11 +8230,11 @@
"@ethersproject/json-wallets": "5.5.0", "@ethersproject/json-wallets": "5.5.0",
"@ethersproject/keccak256": "5.5.0", "@ethersproject/keccak256": "5.5.0",
"@ethersproject/logger": "5.5.0", "@ethersproject/logger": "5.5.0",
"@ethersproject/networks": "5.5.1", "@ethersproject/networks": "5.5.2",
"@ethersproject/pbkdf2": "5.5.0", "@ethersproject/pbkdf2": "5.5.0",
"@ethersproject/properties": "5.5.0", "@ethersproject/properties": "5.5.0",
"@ethersproject/providers": "5.5.1", "@ethersproject/providers": "5.5.3",
"@ethersproject/random": "5.5.0", "@ethersproject/random": "5.5.1",
"@ethersproject/rlp": "5.5.0", "@ethersproject/rlp": "5.5.0",
"@ethersproject/sha2": "5.5.0", "@ethersproject/sha2": "5.5.0",
"@ethersproject/signing-key": "5.5.0", "@ethersproject/signing-key": "5.5.0",
@ -8755,14 +8755,15 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.13.2", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh" "url": "https://github.com/sponsors/RubenVerborgh"
} }
], ],
"license": "MIT",
"engines": { "engines": {
"node": ">=4.0" "node": ">=4.0"
}, },
@ -9362,9 +9363,9 @@
} }
}, },
"node_modules/highlightjs-solidity": { "node_modules/highlightjs-solidity": {
"version": "2.0.3", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.3.tgz", "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.4.tgz",
"integrity": "sha512-tjFm5dtIE61VQBzjlZmkCtY5fLs3CaEABbVuUNyXeW+UuOCsxMg3MsPFy0kCelHP74hPpkoqDejLrbnV1axAIw==" "integrity": "sha512-jsmfDXrjjxt4LxWfzp27j4CX6qYk6B8uK8sxzEDyGts8Ut1IuVlFCysAu6n5RrgHnuEKA+SCIcGPweO7qlPhCg=="
}, },
"node_modules/history": { "node_modules/history": {
"version": "5.2.0", "version": "5.2.0",
@ -11151,8 +11152,9 @@
} }
}, },
"node_modules/jsdom/node_modules/ws": { "node_modules/jsdom/node_modules/ws": {
"version": "7.4.3", "version": "7.5.6",
"license": "MIT", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz",
"integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==",
"engines": { "engines": {
"node": ">=8.3.0" "node": ">=8.3.0"
}, },
@ -11934,9 +11936,9 @@
"optional": true "optional": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.1.23", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
"bin": { "bin": {
"nanoid": "bin/nanoid.cjs" "nanoid": "bin/nanoid.cjs"
}, },
@ -14109,12 +14111,13 @@
} }
}, },
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.7.2", "version": "15.8.1",
"license": "MIT", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": { "dependencies": {
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"react-is": "^16.8.1" "react-is": "^16.13.1"
} }
}, },
"node_modules/prop-types/node_modules/react-is": { "node_modules/prop-types/node_modules/react-is": {
@ -17207,9 +17210,9 @@
} }
}, },
"node_modules/swr": { "node_modules/swr": {
"version": "1.1.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/swr/-/swr-1.1.2.tgz", "resolved": "https://registry.npmjs.org/swr/-/swr-1.2.1.tgz",
"integrity": "sha512-UsM0eo5T+kRPyWFZtWRx2XR5qzohs/LS4lDC0GCyLpCYFmsfTk28UCVDbOE9+KtoXY4FnwHYiF+ZYEU3hnJ1lQ==", "integrity": "sha512-1cuWXqJqXcFwbgONGCY4PHZ8v05009JdHsC3CIC6u7d00kgbMswNr1sHnnhseOBxtzVqcCNpOHEgVDciRer45w==",
"peerDependencies": { "peerDependencies": {
"react": "^16.11.0 || ^17.0.0 || ^18.0.0" "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
} }
@ -18130,9 +18133,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.5.4", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -18354,8 +18357,9 @@
} }
}, },
"node_modules/url-parse": { "node_modules/url-parse": {
"version": "1.5.1", "version": "1.5.7",
"license": "MIT", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
"dependencies": { "dependencies": {
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
@ -18373,12 +18377,12 @@
} }
}, },
"node_modules/use-keyboard-shortcut": { "node_modules/use-keyboard-shortcut": {
"version": "1.1.2", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.2.tgz", "resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.3.tgz",
"integrity": "sha512-VrAu1avPLuFHShGo1RiPtCZ6htwsnLRlZc/w4+jmK99HCvIGG5WThz1KsoGgP8KCxP5c8a+pDjtnCgBg+3bXzA==", "integrity": "sha512-3xGUkPMu0WEYAAoIkt39F6MVNqw37mb+IMVUmqLVYT7mLlB9WWp+qGWzZ4WhmbfKtM1/lIP8BiZkXSE8wwfXzQ==",
"peerDependencies": { "peerDependencies": {
"react": "^16.8.0", "react": ">=16.8",
"react-dom": "^16.8.0" "react-dom": ">=16.8"
} }
}, },
"node_modules/util": { "node_modules/util": {
@ -19173,8 +19177,9 @@
} }
}, },
"node_modules/webpack/node_modules/ssri": { "node_modules/webpack/node_modules/ssri": {
"version": "6.0.1", "version": "6.0.2",
"license": "ISC", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
"integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"dependencies": { "dependencies": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
} }
@ -19502,8 +19507,9 @@
} }
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "6.2.1", "version": "6.2.2",
"license": "MIT", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"dependencies": { "dependencies": {
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
@ -20407,9 +20413,9 @@
} }
}, },
"@chainlink/contracts": { "@chainlink/contracts": {
"version": "0.2.2", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.2.2.tgz", "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.4.0.tgz",
"integrity": "sha512-wxXPbt7O3aZaUSG34ufFASC5amRSL6eeYCqsa+2gpqbB8Hk7B7FydEDCI5dqvAC444TlFskPHcVbizCZkRHPpw==" "integrity": "sha512-yZGeCBd7d+qxfw9r/JxtPzsW2kCc6MorPRZ/tDKnaJI98H99j5P2Fosfehmcwk6wVZlz+0Bp4kS1y480nw3Zow=="
}, },
"@cnakazawa/watch": { "@cnakazawa/watch": {
"version": "1.0.4", "version": "1.0.4",
@ -20721,9 +20727,9 @@
"integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==" "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg=="
}, },
"@ethersproject/networks": { "@ethersproject/networks": {
"version": "5.5.1", "version": "5.5.2",
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.1.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz",
"integrity": "sha512-tYRDM4zZtSUcKnD4UMuAlj7SeXH/k5WC4SP2u1Pn57++JdXHkRu2zwNkgNogZoxHzhm9Q6qqurDBVptHOsW49Q==", "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==",
"requires": { "requires": {
"@ethersproject/logger": "^5.5.0" "@ethersproject/logger": "^5.5.0"
} }
@ -20746,9 +20752,9 @@
} }
}, },
"@ethersproject/providers": { "@ethersproject/providers": {
"version": "5.5.1", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.1.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz",
"integrity": "sha512-2zdD5sltACDWhjUE12Kucg2PcgM6V2q9JMyVvObtVGnzJu+QSmibbP+BHQyLWZUBfLApx2942+7DC5D+n4wBQQ==", "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==",
"requires": { "requires": {
"@ethersproject/abstract-provider": "^5.5.0", "@ethersproject/abstract-provider": "^5.5.0",
"@ethersproject/abstract-signer": "^5.5.0", "@ethersproject/abstract-signer": "^5.5.0",
@ -20780,9 +20786,9 @@
} }
}, },
"@ethersproject/random": { "@ethersproject/random": {
"version": "5.5.0", "version": "5.5.1",
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.0.tgz", "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz",
"integrity": "sha512-egGYZwZ/YIFKMHcoBUo8t3a8Hb/TKYX8BCBoLjudVCZh892welR3jOxgOmb48xznc9bTcMm7Tpwc1gHC1PFNFQ==", "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==",
"requires": { "requires": {
"@ethersproject/bytes": "^5.5.0", "@ethersproject/bytes": "^5.5.0",
"@ethersproject/logger": "^5.5.0" "@ethersproject/logger": "^5.5.0"
@ -20916,24 +20922,24 @@
} }
}, },
"@fontsource/fira-code": { "@fontsource/fira-code": {
"version": "4.5.2", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-4.5.2.tgz", "resolved": "https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-4.5.5.tgz",
"integrity": "sha512-wNUvcqmm1dZYTbJlkbFZL9Huu7p+Hwaa4CLNTPql3CG90Rh9dSi43wNg5AnVHxjAhWQOGlCpSrEswnnHu1CkxA==" "integrity": "sha512-bwsPmA5HW11SR0oIkgqSJYI3A8KP8aQLRCCH/EnR9gLHRuTFi1iG7GQ3wDTKy/AhECQJAKjXZ+mkVKlMxUaYCQ=="
}, },
"@fontsource/roboto": { "@fontsource/roboto": {
"version": "4.5.1", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.1.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.3.tgz",
"integrity": "sha512-3mhfL+eNPG/woMNqwD/OHaW5qMpeGEBsDwzmhFmjB1yUV+M+M9P0NhP/AyHvnGz3DrqkvZ7CPzNMa+UkVLeELg==" "integrity": "sha512-NUvBTj332dFRdiVkLlavXbDGoD2zyyeGYmMyrXOnctg/3e4pq95+rJgNfUP+k4v8UBk2L1aomGw9dDjbRdAmTg=="
}, },
"@fontsource/roboto-mono": { "@fontsource/roboto-mono": {
"version": "4.5.0", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/roboto-mono/-/roboto-mono-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto-mono/-/roboto-mono-4.5.3.tgz",
"integrity": "sha512-/6Gm6fJjBHZiFNyvzIKGJkVuyifoc1aoTel+pkzdhxNh7yNhFyokCoChdbbqZEpGKpqs5uld74G5TJthUVFyjw==" "integrity": "sha512-ELuIIUBo1kq2hFmOXjWv9o2VbM22Pct2F0T+D8f5T0MxDKIqkh0m1JMs9bbTzMjc+wVvyJ6LU5EiNkO26kLlKA=="
}, },
"@fontsource/space-grotesk": { "@fontsource/space-grotesk": {
"version": "4.5.0", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/@fontsource/space-grotesk/-/space-grotesk-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@fontsource/space-grotesk/-/space-grotesk-4.5.3.tgz",
"integrity": "sha512-Kdnq5m31DsJ8l/VCpZGz4QpIxLLvNVh4MyVGY0PmDh7aY9aM5rmO2NF49dJ0749gLPgMW6Moc/xjgW95G0MbMg==" "integrity": "sha512-uhCiGA3DXiT7BLCcbKzSDlgUp6Pct50+WObzLJvee8qnA2ezH/cfWlIU3+3ydc1poxQuR6+jJN2Cd8XjpOB9lg=="
}, },
"@fortawesome/fontawesome-common-types": { "@fortawesome/fontawesome-common-types": {
"version": "0.2.36", "version": "0.2.36",
@ -20973,11 +20979,11 @@
} }
}, },
"@fortawesome/react-fontawesome": { "@fortawesome/react-fontawesome": {
"version": "0.1.16", "version": "0.1.17",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz", "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz",
"integrity": "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA==", "integrity": "sha512-dX43Z5IvMaW7fwzU8farosYjKNGfRb2HB/DgjVBHeJZ/NSnuuaujPPx0YOdcAq+n3mqn70tyCde2HM1mqbhiuw==",
"requires": { "requires": {
"prop-types": "^15.7.2" "prop-types": "^15.8.1"
} }
}, },
"@hapi/address": { "@hapi/address": {
@ -21005,9 +21011,9 @@
} }
}, },
"@headlessui/react": { "@headlessui/react": {
"version": "1.4.2", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.2.tgz", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.4.3.tgz",
"integrity": "sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==", "integrity": "sha512-n2IQkaaw0aAAlQS5MEXsM4uRK+w18CrM72EqnGRl/UBOQeQajad8oiKXR9Nk15jOzTFQjpxzrZMf1NxHidFBiw==",
"requires": {} "requires": {}
}, },
"@istanbuljs/load-nyc-config": { "@istanbuljs/load-nyc-config": {
@ -21436,9 +21442,9 @@
} }
}, },
"@testing-library/jest-dom": { "@testing-library/jest-dom": {
"version": "5.16.1", "version": "5.16.2",
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.1.tgz", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.2.tgz",
"integrity": "sha512-ajUJdfDIuTCadB79ukO+0l8O+QwN0LiSxDaYUTI4LndbbUsGi6rWU1SCexXzBA2NSjlVB9/vbkasQIL3tmPBjw==", "integrity": "sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug==",
"requires": { "requires": {
"@babel/runtime": "^7.9.2", "@babel/runtime": "^7.9.2",
"@types/testing-library__jest-dom": "^5.9.1", "@types/testing-library__jest-dom": "^5.9.1",
@ -21643,9 +21649,9 @@
"version": "1.5.4" "version": "1.5.4"
}, },
"@types/react": { "@types/react": {
"version": "17.0.38", "version": "17.0.39",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz",
"integrity": "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==",
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
@ -23348,9 +23354,9 @@
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="
}, },
"chart.js": { "chart.js": {
"version": "3.7.0", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.1.tgz",
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg==" "integrity": "sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA=="
}, },
"check-types": { "check-types": {
"version": "11.1.2" "version": "11.1.2"
@ -25004,9 +25010,9 @@
"version": "1.8.1" "version": "1.8.1"
}, },
"ethers": { "ethers": {
"version": "5.5.2", "version": "5.5.4",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.2.tgz", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz",
"integrity": "sha512-EF5W+6Wwcu6BqVwpgmyR5U2+L4c1FQzlM/02dkZOugN3KF0cG9bzHZP+TDJglmPm2/IzCEJDT7KBxzayk7SAHw==", "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==",
"requires": { "requires": {
"@ethersproject/abi": "5.5.0", "@ethersproject/abi": "5.5.0",
"@ethersproject/abstract-provider": "5.5.1", "@ethersproject/abstract-provider": "5.5.1",
@ -25023,11 +25029,11 @@
"@ethersproject/json-wallets": "5.5.0", "@ethersproject/json-wallets": "5.5.0",
"@ethersproject/keccak256": "5.5.0", "@ethersproject/keccak256": "5.5.0",
"@ethersproject/logger": "5.5.0", "@ethersproject/logger": "5.5.0",
"@ethersproject/networks": "5.5.1", "@ethersproject/networks": "5.5.2",
"@ethersproject/pbkdf2": "5.5.0", "@ethersproject/pbkdf2": "5.5.0",
"@ethersproject/properties": "5.5.0", "@ethersproject/properties": "5.5.0",
"@ethersproject/providers": "5.5.1", "@ethersproject/providers": "5.5.3",
"@ethersproject/random": "5.5.0", "@ethersproject/random": "5.5.1",
"@ethersproject/rlp": "5.5.0", "@ethersproject/rlp": "5.5.0",
"@ethersproject/sha2": "5.5.0", "@ethersproject/sha2": "5.5.0",
"@ethersproject/signing-key": "5.5.0", "@ethersproject/signing-key": "5.5.0",
@ -25419,7 +25425,9 @@
} }
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.13.2" "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
}, },
"for-in": { "for-in": {
"version": "1.0.2" "version": "1.0.2"
@ -25797,9 +25805,9 @@
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
}, },
"highlightjs-solidity": { "highlightjs-solidity": {
"version": "2.0.3", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.3.tgz", "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.4.tgz",
"integrity": "sha512-tjFm5dtIE61VQBzjlZmkCtY5fLs3CaEABbVuUNyXeW+UuOCsxMg3MsPFy0kCelHP74hPpkoqDejLrbnV1axAIw==" "integrity": "sha512-jsmfDXrjjxt4LxWfzp27j4CX6qYk6B8uK8sxzEDyGts8Ut1IuVlFCysAu6n5RrgHnuEKA+SCIcGPweO7qlPhCg=="
}, },
"history": { "history": {
"version": "5.2.0", "version": "5.2.0",
@ -26966,7 +26974,9 @@
} }
}, },
"ws": { "ws": {
"version": "7.4.3", "version": "7.5.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz",
"integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==",
"requires": {} "requires": {}
} }
} }
@ -27468,9 +27478,9 @@
"optional": true "optional": true
}, },
"nanoid": { "nanoid": {
"version": "3.1.23", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA=="
}, },
"nanomatch": { "nanomatch": {
"version": "1.2.13", "version": "1.2.13",
@ -28936,11 +28946,13 @@
} }
}, },
"prop-types": { "prop-types": {
"version": "15.7.2", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": { "requires": {
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"react-is": "^16.8.1" "react-is": "^16.13.1"
}, },
"dependencies": { "dependencies": {
"react-is": { "react-is": {
@ -31079,9 +31091,9 @@
} }
}, },
"swr": { "swr": {
"version": "1.1.2", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/swr/-/swr-1.1.2.tgz", "resolved": "https://registry.npmjs.org/swr/-/swr-1.2.1.tgz",
"integrity": "sha512-UsM0eo5T+kRPyWFZtWRx2XR5qzohs/LS4lDC0GCyLpCYFmsfTk28UCVDbOE9+KtoXY4FnwHYiF+ZYEU3hnJ1lQ==", "integrity": "sha512-1cuWXqJqXcFwbgONGCY4PHZ8v05009JdHsC3CIC6u7d00kgbMswNr1sHnnhseOBxtzVqcCNpOHEgVDciRer45w==",
"requires": {} "requires": {}
}, },
"symbol-tree": { "symbol-tree": {
@ -31712,9 +31724,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.5.4", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==" "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA=="
}, },
"unicode-canonical-property-names-ecmascript": { "unicode-canonical-property-names-ecmascript": {
"version": "1.0.4" "version": "1.0.4"
@ -31854,7 +31866,9 @@
} }
}, },
"url-parse": { "url-parse": {
"version": "1.5.1", "version": "1.5.7",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
"requires": { "requires": {
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
@ -31864,9 +31878,9 @@
"version": "3.1.1" "version": "3.1.1"
}, },
"use-keyboard-shortcut": { "use-keyboard-shortcut": {
"version": "1.1.2", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.2.tgz", "resolved": "https://registry.npmjs.org/use-keyboard-shortcut/-/use-keyboard-shortcut-1.1.3.tgz",
"integrity": "sha512-VrAu1avPLuFHShGo1RiPtCZ6htwsnLRlZc/w4+jmK99HCvIGG5WThz1KsoGgP8KCxP5c8a+pDjtnCgBg+3bXzA==", "integrity": "sha512-3xGUkPMu0WEYAAoIkt39F6MVNqw37mb+IMVUmqLVYT7mLlB9WWp+qGWzZ4WhmbfKtM1/lIP8BiZkXSE8wwfXzQ==",
"requires": {} "requires": {}
}, },
"util": { "util": {
@ -32174,7 +32188,9 @@
} }
}, },
"ssri": { "ssri": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
"integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"requires": { "requires": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
} }
@ -32662,7 +32678,9 @@
} }
}, },
"ws": { "ws": {
"version": "6.2.1", "version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"requires": { "requires": {
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }

View File

@ -5,31 +5,31 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@blackbox-vision/react-qr-reader": "^5.0.0", "@blackbox-vision/react-qr-reader": "^5.0.0",
"@chainlink/contracts": "^0.2.2", "@chainlink/contracts": "^0.4.0",
"@craco/craco": "^6.4.3", "@craco/craco": "^6.4.3",
"@fontsource/fira-code": "^4.5.2", "@fontsource/fira-code": "^4.5.5",
"@fontsource/roboto": "^4.5.1", "@fontsource/roboto": "^4.5.3",
"@fontsource/roboto-mono": "^4.5.0", "@fontsource/roboto-mono": "^4.5.3",
"@fontsource/space-grotesk": "^4.5.0", "@fontsource/space-grotesk": "^4.5.3",
"@fortawesome/fontawesome-svg-core": "^1.2.36", "@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4", "@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.16", "@fortawesome/react-fontawesome": "^0.1.17",
"@headlessui/react": "^1.4.2", "@headlessui/react": "^1.4.3",
"@testing-library/jest-dom": "^5.16.1", "@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",
"@types/node": "^16.11.14", "@types/node": "^16.11.14",
"@types/react": "^17.0.38", "@types/react": "^17.0.39",
"@types/react-blockies": "^1.4.1", "@types/react-blockies": "^1.4.1",
"@types/react-dom": "^17.0.11", "@types/react-dom": "^17.0.11",
"@types/react-highlight": "^0.12.5", "@types/react-highlight": "^0.12.5",
"@types/react-syntax-highlighter": "^13.5.2", "@types/react-syntax-highlighter": "^13.5.2",
"chart.js": "^3.7.0", "chart.js": "^3.7.1",
"ethers": "^5.5.2", "ethers": "^5.5.4",
"highlightjs-solidity": "^2.0.3", "highlightjs-solidity": "^2.0.4",
"react": "^17.0.2", "react": "^17.0.2",
"react-blockies": "^1.4.1", "react-blockies": "^1.4.1",
"react-chartjs-2": "^4.0.0", "react-chartjs-2": "^4.0.0",
@ -41,9 +41,9 @@
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-syntax-highlighter": "^15.4.5", "react-syntax-highlighter": "^15.4.5",
"serve": "^13.0.2", "serve": "^13.0.2",
"swr": "^1.1.2", "swr": "^1.2.1",
"typescript": "^4.5.4", "typescript": "^4.5.5",
"use-keyboard-shortcut": "^1.1.2", "use-keyboard-shortcut": "^1.1.3",
"web-vitals": "^1.0.1" "web-vitals": "^1.0.1"
}, },
"scripts": { "scripts": {

View File

@ -100,7 +100,10 @@ const Address: React.FC = () => {
return ( return (
<StandardFrame> <StandardFrame>
{error ? ( {error ? (
<AddressOrENSNameNotFound addressOrENSName={addressOrName} /> <AddressOrENSNameNotFound
addressOrENSName={addressOrName}
supportsENS={provider?.network.ensAddress !== undefined}
/>
) : ( ) : (
checksummedAddress && ( checksummedAddress && (
<> <>

View File

@ -25,6 +25,7 @@ import { useLatestBlockNumber } from "./useLatestBlock";
import { blockTxsURL } from "./url"; import { blockTxsURL } from "./url";
import { useBlockData } from "./useErigonHooks"; import { useBlockData } from "./useErigonHooks";
import { useETHUSDOracle } from "./usePriceOracle"; import { useETHUSDOracle } from "./usePriceOracle";
import BlockNotFound from "./components/BlockNotFound";
const Block: React.FC = () => { const Block: React.FC = () => {
const { provider } = useContext(RuntimeContext); const { provider } = useContext(RuntimeContext);
@ -35,10 +36,10 @@ const Block: React.FC = () => {
const block = useBlockData(provider, blockNumberOrHash); const block = useBlockData(provider, blockNumberOrHash);
useEffect(() => { useEffect(() => {
if (block) { if (block !== undefined) {
document.title = `Block #${block.number} | Otterscan`; document.title = `Block #${blockNumberOrHash} | Otterscan`;
} }
}, [block]); }, [blockNumberOrHash, block]);
const extraStr = useMemo(() => { const extraStr = useMemo(() => {
try { try {
@ -71,6 +72,9 @@ const Block: React.FC = () => {
)} )}
</div> </div>
</StandardSubtitle> </StandardSubtitle>
{block === null && (
<BlockNotFound blockNumberOrHash={blockNumberOrHash} />
)}
{block && ( {block && (
<ContentFrame> <ContentFrame>
<InfoRow title="Block Height"> <InfoRow title="Block Height">

View File

@ -44,7 +44,9 @@ const Header: React.FC = () => {
className="w-full border-t border-b border-l rounded-l focus:outline-none px-2 py-1 text-sm" className="w-full border-t border-b border-l rounded-l focus:outline-none px-2 py-1 text-sm"
type="text" type="text"
size={60} size={60}
placeholder='Type "/" to search by address / txn hash / block number / ENS name' placeholder={`Type "/" to search by address / txn hash / block number${
provider?.network.ensAddress ? " / ENS name" : ""
}`}
onChange={handleChange} onChange={handleChange}
ref={searchRef} ref={searchRef}
/> />

View File

@ -39,7 +39,9 @@ const Home: React.FC = () => {
className="w-full border-l border-t border-b rounded-l focus:outline-none px-2 py-1" className="w-full border-l border-t border-b rounded-l focus:outline-none px-2 py-1"
type="text" type="text"
size={50} size={50}
placeholder="Search by address / txn hash / block number / ENS name" placeholder={`Search by address / txn hash / block number${
provider?.network.ensAddress ? " / ENS name" : ""
}`}
onChange={handleChange} onChange={handleChange}
ref={searchRef} ref={searchRef}
autoFocus autoFocus
@ -62,6 +64,7 @@ const Home: React.FC = () => {
</form> </form>
<div className="mx-auto h-32"> <div className="mx-auto h-32">
<div className="text-lg text-link-blue hover:text-link-blue-hover font-bold"> <div className="text-lg text-link-blue hover:text-link-blue-hover font-bold">
{provider?.network.chainId !== 11155111 && (
<NavLink to="/special/london"> <NavLink to="/special/london">
<div className="flex space-x-2 items-baseline text-orange-500 hover:text-orange-700 hover:underline"> <div className="flex space-x-2 items-baseline text-orange-500 hover:text-orange-700 hover:underline">
<span> <span>
@ -73,6 +76,7 @@ const Home: React.FC = () => {
</span> </span>
</div> </div>
</NavLink> </NavLink>
)}
</div> </div>
{latestBlock && ( {latestBlock && (
<NavLink <NavLink

View File

@ -10,6 +10,7 @@ import { useLatestBlock } from "./useLatestBlock";
const ETH_FEED_DECIMALS = 8; const ETH_FEED_DECIMALS = 8;
// TODO: reduce duplication with useETHUSDOracle
const PriceBox: React.FC = () => { const PriceBox: React.FC = () => {
const { provider } = useContext(RuntimeContext); const { provider } = useContext(RuntimeContext);
const latestBlock = useLatestBlock(provider); const latestBlock = useLatestBlock(provider);

View File

@ -17,6 +17,8 @@ const WarningHeader: React.FC = () => {
chainMsg = "Görli Testnet"; chainMsg = "Görli Testnet";
} else if (chainId === 42) { } else if (chainId === 42) {
chainMsg = "Kovan Testnet"; chainMsg = "Kovan Testnet";
} else if (chainId === 11155111) {
chainMsg = "Sepolia Testnet";
} }
return ( return (
<div className="w-full bg-orange-400 text-white text-center font-bold px-2 py-1"> <div className="w-full bg-orange-400 text-white text-center font-bold px-2 py-1">

View File

@ -1,6 +1,12 @@
import React, { useContext, useEffect, useMemo, useState } from "react"; import React, { useContext, useEffect, useMemo, useState } from "react";
import { BlockTag } from "@ethersproject/providers"; import { BlockTag } from "@ethersproject/providers";
import ContentFrame from "../ContentFrame"; import ContentFrame from "../ContentFrame";
import InfoRow from "../components/InfoRow";
import TransactionValue from "../components/TransactionValue";
import ETH2USDValue from "../components/ETH2USDValue";
import TransactionAddress from "../components/TransactionAddress";
import Copy from "../components/Copy";
import TransactionLink from "../components/TransactionLink";
import PendingResults from "../search/PendingResults"; import PendingResults from "../search/PendingResults";
import ResultHeader from "../search/ResultHeader"; import ResultHeader from "../search/ResultHeader";
import { SearchController } from "../search/search"; import { SearchController } from "../search/search";
@ -11,8 +17,9 @@ import { SelectionContext, useSelection } from "../useSelection";
import { useMultipleETHUSDOracle } from "../usePriceOracle"; import { useMultipleETHUSDOracle } from "../usePriceOracle";
import { RuntimeContext } from "../useRuntime"; import { RuntimeContext } from "../useRuntime";
import { useParams, useSearchParams } from "react-router-dom"; import { useParams, useSearchParams } from "react-router-dom";
import { ChecksummedAddress } from "../types"; import { ChecksummedAddress, ProcessedTransaction } from "../types";
import { useContractsMetadata } from "../hooks"; import { useContractsMetadata } from "../hooks";
import { useAddressBalance, useContractCreator } from "../useErigonHooks";
type AddressTransactionResultsProps = { type AddressTransactionResultsProps = {
address: ChecksummedAddress; address: ChecksummedAddress;
@ -95,9 +102,12 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
// TODO: dedup blockTags // TODO: dedup blockTags
const blockTags: BlockTag[] = useMemo(() => { const blockTags: BlockTag[] = useMemo(() => {
if (!page) { if (!page) {
return []; return ["latest"];
} }
return page.map((t) => t.blockNumber);
const blockTags: BlockTag[] = page.map((t) => t.blockNumber);
blockTags.push("latest");
return blockTags;
}, [page]); }, [page]);
const priceMap = useMultipleETHUSDOracle(provider, blockTags); const priceMap = useMultipleETHUSDOracle(provider, blockTags);
@ -117,32 +127,47 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
return _addresses; return _addresses;
}, [address, page]); }, [address, page]);
const metadatas = useContractsMetadata(addresses, provider); const metadatas = useContractsMetadata(addresses, provider);
const balance = useAddressBalance(provider, address);
const creator = useContractCreator(provider, address);
return ( return (
<ContentFrame tabs> <ContentFrame tabs>
<div className="flex justify-between items-baseline py-3"> <SelectionContext.Provider value={selectionCtx}>
<div className="text-sm text-gray-500"> {balance && (
{page === undefined ? ( <InfoRow title="Balance">
<>Waiting for search results...</> <div className="space-x-2">
) : ( <TransactionValue value={balance} />
<>{page.length} transactions on this page</> {!balance.isZero() && priceMap["latest"] !== undefined && (
<span className="px-2 border-green-200 border rounded-lg bg-green-100 text-green-600">
<ETH2USDValue
ethAmount={balance}
eth2USDValue={priceMap["latest"]}
/>
</span>
)} )}
</div> </div>
<UndefinedPageControl </InfoRow>
address={address} )}
isFirst={controller?.isFirst} {creator && (
isLast={controller?.isLast} <InfoRow title="Contract creator">
prevHash={page?.[0]?.hash ?? ""} <div className="flex divide-x-2 divide-dotted divide-gray-300">
nextHash={page?.[page.length - 1]?.hash ?? ""} <div className="flex items-baseline space-x-2 -ml-1 mr-3">
disabled={controller === undefined} <TransactionAddress address={creator.creator} />
/> <Copy value={creator.creator} />
</div> </div>
<div className="flex items-baseline pl-3">
<TransactionLink txHash={creator.hash} />
</div>
</div>
</InfoRow>
)}
<NavBar address={address} page={page} controller={controller} />
<ResultHeader <ResultHeader
feeDisplay={feeDisplay} feeDisplay={feeDisplay}
feeDisplayToggler={feeDisplayToggler} feeDisplayToggler={feeDisplayToggler}
/> />
{page ? ( {page ? (
<SelectionContext.Provider value={selectionCtx}> <>
{page.map((tx) => ( {page.map((tx) => (
<TransactionItem <TransactionItem
key={tx.hash} key={tx.hash}
@ -153,6 +178,23 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
metadatas={metadatas} metadatas={metadatas}
/> />
))} ))}
<NavBar address={address} page={page} controller={controller} />
</>
) : (
<PendingResults />
)}
</SelectionContext.Provider>
</ContentFrame>
);
};
type NavBarProps = {
address: ChecksummedAddress;
page: ProcessedTransaction[] | undefined;
controller: SearchController | undefined;
};
const NavBar: React.FC<NavBarProps> = ({ address, page, controller }) => (
<div className="flex justify-between items-baseline py-3"> <div className="flex justify-between items-baseline py-3">
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500">
{page === undefined ? ( {page === undefined ? (
@ -170,12 +212,6 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
disabled={controller === undefined} disabled={controller === undefined}
/> />
</div> </div>
</SelectionContext.Provider>
) : (
<PendingResults />
)}
</ContentFrame>
); );
};
export default AddressTransactionResults; export default AddressTransactionResults;

View File

@ -17,10 +17,15 @@ export class CompositeAddressResolver<T = any>
address: string address: string
): Promise<SelectedResolvedName<T> | undefined> { ): Promise<SelectedResolvedName<T> | undefined> {
for (const r of this.resolvers) { for (const r of this.resolvers) {
try {
const resolvedAddress = await r.resolveAddress(provider, address); const resolvedAddress = await r.resolveAddress(provider, address);
if (resolvedAddress !== undefined) { if (resolvedAddress !== undefined) {
return [r, resolvedAddress]; return [r, resolvedAddress];
} }
} catch (err) {
console.warn(`Error while trying to resolve addr ${address}`);
console.warn(err);
}
} }
return null; return null;

View File

@ -19,23 +19,38 @@ import { HardcodedAddressResolver } from "./HardcodedAddressResolver";
export type ResolvedAddresses = Record<string, SelectedResolvedName<any>>; export type ResolvedAddresses = Record<string, SelectedResolvedName<any>>;
// Create and configure the main resolver // Create and configure the main resolver
export const ensResolver = new ENSAddressResolver(); const ensResolver = new ENSAddressResolver();
export const uniswapV1Resolver = new UniswapV1Resolver(); const uniswapV1Resolver = new UniswapV1Resolver();
export const uniswapV2Resolver = new UniswapV2Resolver(); const uniswapV2Resolver = new UniswapV2Resolver();
export const uniswapV3Resolver = new UniswapV3Resolver(); const uniswapV3Resolver = new UniswapV3Resolver();
export const ercTokenResolver = new ERCTokenResolver(); const ercTokenResolver = new ERCTokenResolver();
export const hardcodedResolver = new HardcodedAddressResolver(); const hardcodedResolver = new HardcodedAddressResolver();
const _mainResolver = new CompositeAddressResolver(); const _mainnetResolver = new CompositeAddressResolver();
_mainResolver.addResolver(ensResolver); _mainnetResolver.addResolver(ensResolver);
_mainResolver.addResolver(uniswapV3Resolver); _mainnetResolver.addResolver(uniswapV3Resolver);
_mainResolver.addResolver(uniswapV2Resolver); _mainnetResolver.addResolver(uniswapV2Resolver);
_mainResolver.addResolver(uniswapV1Resolver); _mainnetResolver.addResolver(uniswapV1Resolver);
_mainResolver.addResolver(ercTokenResolver); _mainnetResolver.addResolver(ercTokenResolver);
_mainResolver.addResolver(hardcodedResolver); _mainnetResolver.addResolver(hardcodedResolver);
export const mainResolver: IAddressResolver<SelectedResolvedName<any>> = const _defaultResolver = new CompositeAddressResolver();
_mainResolver; _defaultResolver.addResolver(hardcodedResolver);
const resolvers: Record<number, IAddressResolver<SelectedResolvedName<any>>> = {
1: _mainnetResolver,
0: _defaultResolver,
};
export const getResolver = (
chainId: number
): IAddressResolver<SelectedResolvedName<any>> => {
const resolver = resolvers[chainId];
if (resolver === undefined) {
return resolver[0]; // default MAGIC NUMBER
}
return resolver;
};
export const resolverRendererRegistry = new Map< export const resolverRendererRegistry = new Map<
IAddressResolver<any>, IAddressResolver<any>,

View File

@ -4,16 +4,19 @@ import ContentFrame from "../ContentFrame";
type AddressOrENSNameNotFoundProps = { type AddressOrENSNameNotFoundProps = {
addressOrENSName: string; addressOrENSName: string;
supportsENS: boolean;
}; };
const AddressOrENSNameNotFound: React.FC<AddressOrENSNameNotFoundProps> = ({ const AddressOrENSNameNotFound: React.FC<AddressOrENSNameNotFoundProps> = ({
addressOrENSName, addressOrENSName,
supportsENS,
}) => ( }) => (
<> <>
<StandardSubtitle>Transaction Details</StandardSubtitle> <StandardSubtitle>Transaction Details</StandardSubtitle>
<ContentFrame> <ContentFrame>
<div className="py-4 text-sm"> <div className="py-4 text-sm">
"{addressOrENSName}" is not an ETH address or ENS name. "{addressOrENSName}" is not an ETH address
{supportsENS && " or ENS name"}.
</div> </div>
</ContentFrame> </ContentFrame>
</> </>

View File

@ -0,0 +1,14 @@
import React from "react";
import ContentFrame from "../ContentFrame";
type BlockNotFoundProps = {
blockNumberOrHash: string;
};
const BlockNotFound: React.FC<BlockNotFoundProps> = ({ blockNumberOrHash }) => (
<ContentFrame>
<div className="py-4 text-sm">Block "{blockNumberOrHash}" not found.</div>
</ContentFrame>
);
export default React.memo(BlockNotFound);

View File

@ -22,7 +22,7 @@ const Copy: React.FC<CopyProps> = ({ value, rounded }) => {
return ( return (
<button <button
className={`text-gray-500 focus:outline-none ${ className={`self-center flex flex-no-wrap justify-center items-center space-x-1 text-gray-500 focus:outline-none ${
rounded rounded
? "transition-colors transition-shadows bg-gray-200 hover:bg-gray-500 hover:text-gray-200 hover:shadow w-7 h-7 rounded-full text-xs" ? "transition-colors transition-shadows bg-gray-200 hover:bg-gray-500 hover:text-gray-200 hover:shadow w-7 h-7 rounded-full text-xs"
: "text-sm" : "text-sm"
@ -34,10 +34,10 @@ const Copy: React.FC<CopyProps> = ({ value, rounded }) => {
rounded ? ( rounded ? (
<FontAwesomeIcon icon={faCheck} size="1x" /> <FontAwesomeIcon icon={faCheck} size="1x" />
) : ( ) : (
<div className="space-x-1"> <>
<FontAwesomeIcon icon={faCheckCircle} size="1x" /> <FontAwesomeIcon icon={faCheckCircle} size="1x" />
{!rounded && <span>Copied</span>} <span className="self-baseline">Copied</span>
</div> </>
) )
) : ( ) : (
<FontAwesomeIcon icon={faCopy} size="1x" /> <FontAwesomeIcon icon={faCopy} size="1x" />

View File

@ -7,6 +7,13 @@ type ETH2USDValueProps = {
eth2USDValue: BigNumber; eth2USDValue: BigNumber;
}; };
/**
* Basic display of ETH -> USD values WITHOUT box decoration, only
* text formatting.
*
* USD amounts are displayed commified with 2 decimals places and $ prefix,
* i.e., "$1,000.00".
*/
const ETH2USDValue: React.FC<ETH2USDValueProps> = ({ const ETH2USDValue: React.FC<ETH2USDValueProps> = ({
ethAmount, ethAmount,
eth2USDValue, eth2USDValue,

View File

@ -7,6 +7,7 @@ type FormatterBalanceProps = {
decimals?: number; decimals?: number;
}; };
// TODO: remove duplication with TransactionValue component
const FormattedBalance: React.FC<FormatterBalanceProps> = ({ const FormattedBalance: React.FC<FormatterBalanceProps> = ({
value, value,
decimals = 18, decimals = 18,

View File

@ -6,22 +6,34 @@ type TransactionValueProps = {
value: BigNumber; value: BigNumber;
decimals?: number; decimals?: number;
hideUnit?: boolean; hideUnit?: boolean;
unitName?: string;
}; };
/**
* Standard component for displaying balances. It:
*
* - Commify non-decimal parts, i.e., 1,000,000.00
* - Light gray absolute zero values
* - Cut out decimal part is it is 0 to reduce UI clutter, i.e., show
* 123 instead of 123.00
*
* TODO: remove duplication with FormattedBalance
*/
const TransactionValue: React.FC<TransactionValueProps> = ({ const TransactionValue: React.FC<TransactionValueProps> = ({
value, value,
decimals = 18, decimals = 18,
hideUnit, hideUnit,
unitName = "ETH",
}) => { }) => {
const formattedValue = formatValue(value, decimals); const formattedValue = formatValue(value, decimals);
return ( return (
<span <span
className={`text-sm ${value.isZero() ? "text-gray-400" : ""}`} className={`text-sm ${value.isZero() ? "text-gray-400" : ""}`}
title={`${formattedValue} Ether`} title={`${formattedValue} ${unitName}`}
> >
<span className={`font-balance`}>{formattedValue}</span> <span className={`font-balance`}>{formattedValue}</span>
{!hideUnit && " Ether"} {!hideUnit && ` ${unitName}`}
</span> </span>
); );
}; };

View File

@ -1,3 +1,3 @@
export const MIN_API_LEVEL = 6; export const MIN_API_LEVEL = 8;
export const PAGE_SIZE = 25; export const PAGE_SIZE = 25;

View File

@ -75,6 +75,9 @@ const Blocks: React.FC<BlocksProps> = ({ latestBlock, targetBlockNumber }) => {
if (_blocks.length > 0 && blockNumber === _blocks[0].number) { if (_blocks.length > 0 && blockNumber === _blocks[0].number) {
return _blocks; return _blocks;
} }
if (extBlock === null) {
return _blocks;
}
// Leave the last block because of transition animation // Leave the last block because of transition animation
const newBlocks = [extBlock, ..._blocks].slice( const newBlocks = [extBlock, ..._blocks].slice(

View File

@ -36,19 +36,24 @@ export interface ExtendedBlock extends Block {
export const readBlock = async ( export const readBlock = async (
provider: JsonRpcProvider, provider: JsonRpcProvider,
blockNumberOrHash: string blockNumberOrHash: string
) => { ): Promise<ExtendedBlock | null> => {
let blockPromise: Promise<any>; let blockPromise: Promise<any>;
if (isHexString(blockNumberOrHash, 32)) { if (isHexString(blockNumberOrHash, 32)) {
// TODO: fix blockPromise = provider.send("ots_getBlockDetailsByHash", [
blockPromise = provider.send("eth_getBlockByHash", [
blockNumberOrHash, blockNumberOrHash,
false,
]); ]);
} else { } else {
blockPromise = provider.send("ots_getBlockDetails", [blockNumberOrHash]); const blockNumber = parseInt(blockNumberOrHash);
if (isNaN(blockNumber) || blockNumber < 0) {
return null;
}
blockPromise = provider.send("ots_getBlockDetails", [blockNumber]);
} }
const _rawBlock = await blockPromise; const _rawBlock = await blockPromise;
if (_rawBlock === null) {
return null;
}
const _block = provider.formatter.block(_rawBlock.block); const _block = provider.formatter.block(_rawBlock.block);
const _rawIssuance = _rawBlock.issuance; const _rawIssuance = _rawBlock.issuance;
@ -162,11 +167,11 @@ export const useBlockTransactions = (
export const useBlockData = ( export const useBlockData = (
provider: JsonRpcProvider | undefined, provider: JsonRpcProvider | undefined,
blockNumberOrHash: string blockNumberOrHash: string
) => { ): ExtendedBlock | null | undefined => {
const [block, setBlock] = useState<ExtendedBlock>(); const [block, setBlock] = useState<ExtendedBlock | null | undefined>();
useEffect(() => { useEffect(() => {
if (!provider) { if (!provider) {
return; return undefined;
} }
const _readBlock = async () => { const _readBlock = async () => {
@ -201,7 +206,7 @@ export const useTxData = (
return; return;
} }
let _block: ExtendedBlock | undefined; let _block: ExtendedBlock | null | undefined;
if (_response.blockNumber) { if (_response.blockNumber) {
_block = await readBlock(provider, _response.blockNumber.toString()); _block = await readBlock(provider, _response.blockNumber.toString());
} }
@ -600,3 +605,77 @@ export const useTransactionBySenderAndNonce = (
} }
return data; return data;
}; };
type ContractCreatorKey = {
type: "cc";
network: number;
address: ChecksummedAddress;
};
type ContractCreator = {
hash: string;
creator: ChecksummedAddress;
};
export const useContractCreator = (
provider: JsonRpcProvider | undefined,
address: ChecksummedAddress | undefined
): ContractCreator | null | undefined => {
const { data, error } = useSWR<
ContractCreator | null | undefined,
any,
ContractCreatorKey | null
>(
provider && address
? {
type: "cc",
network: provider.network.chainId,
address,
}
: null,
getContractCreatorFetcher(provider!)
);
if (error) {
return undefined;
}
return data as ContractCreator;
};
const getContractCreatorFetcher =
(provider: JsonRpcProvider) =>
async ({
network,
address,
}: ContractCreatorKey): Promise<ContractCreator | null | undefined> => {
const result = (await provider.send("ots_getContractCreator", [
address,
])) as ContractCreator;
// Empty or success
if (result) {
result.creator = provider.formatter.address(result.creator);
}
return result;
};
export const useAddressBalance = (
provider: JsonRpcProvider | undefined,
address: ChecksummedAddress | undefined
): BigNumber | null | undefined => {
const [balance, setBalance] = useState<BigNumber | undefined>();
useEffect(() => {
if (!provider || !address) {
return undefined;
}
const readBalance = async () => {
const _balance = await provider.getBalance(address);
setBalance(_balance);
};
readBalance();
}, [provider, address]);
return balance;
};

View File

@ -2,7 +2,7 @@ import { useState, useEffect, useContext } from "react";
import { BaseProvider } from "@ethersproject/providers"; import { BaseProvider } from "@ethersproject/providers";
import { getAddress, isAddress } from "@ethersproject/address"; import { getAddress, isAddress } from "@ethersproject/address";
import useSWRImmutable from "swr/immutable"; import useSWRImmutable from "swr/immutable";
import { mainResolver } from "./api/address-resolver"; import { getResolver } from "./api/address-resolver";
import { SelectedResolvedName } from "./api/address-resolver/CompositeAddressResolver"; import { SelectedResolvedName } from "./api/address-resolver/CompositeAddressResolver";
import { RuntimeContext } from "./useRuntime"; import { RuntimeContext } from "./useRuntime";
import { ChecksummedAddress } from "./types"; import { ChecksummedAddress } from "./types";
@ -48,6 +48,7 @@ export const useAddressOrENS = (
if (!provider) { if (!provider) {
return; return;
} }
if (provider.network.ensAddress) {
const resolveName = async () => { const resolveName = async () => {
const resolvedAddress = await provider.resolveName(addressOrName); const resolvedAddress = await provider.resolveName(addressOrName);
if (resolvedAddress !== null) { if (resolvedAddress !== null) {
@ -61,6 +62,11 @@ export const useAddressOrENS = (
} }
}; };
resolveName(); resolveName();
} else {
setENS(false);
setError(true);
setChecksummedAddress(undefined);
}
}, [provider, addressOrName, urlFixer]); }, [provider, addressOrName, urlFixer]);
return [checksummedAddress, isENS, error]; return [checksummedAddress, isENS, error];
@ -76,7 +82,8 @@ export const useResolvedAddress = (
if (!provider) { if (!provider) {
return undefined; return undefined;
} }
return mainResolver.resolveAddress(provider, address); const resolver = getResolver(provider.network.chainId);
return resolver.resolveAddress(provider, address);
}; };
const { data, error } = useSWRImmutable(address, fetcher); const { data, error } = useSWRImmutable(address, fetcher);