Compare commits
374
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a7bbf8665 | ||
|
|
f97ddf4c7f | ||
|
|
66c53360cd | ||
|
|
bd1fcbae32 | ||
|
|
e196264172 | ||
|
|
c9deda6f4b | ||
|
|
b91d3e9901 | ||
|
|
d248aa2c5a | ||
|
|
8f3b685ad2 | ||
|
|
26349f311d | ||
|
|
2897576513 | ||
|
|
07fb1b5ffa | ||
|
|
300a3c6f04 | ||
|
|
26367c04f3 | ||
|
|
39e2af6f2f | ||
|
|
a5ba9e4fbf | ||
|
|
c9b0131acd | ||
|
|
34b315993c | ||
|
|
14d9a71c92 | ||
|
|
7f5311222b | ||
|
|
b4847dd134 | ||
|
|
cf82c3b58c | ||
|
|
a17326634e | ||
|
|
70c4a119d6 | ||
|
|
f0443bd989 | ||
|
|
73462ef108 | ||
|
|
27c225a512 | ||
|
|
cb1c9937fa | ||
|
|
588b210601 | ||
|
|
7e483ec97f | ||
|
|
c902901cff | ||
|
|
205018f6e1 | ||
|
|
269e68c0a1 | ||
|
|
2888efc065 | ||
|
|
c753641570 | ||
|
|
4b0e63dcc0 | ||
|
|
6979810de5 | ||
|
|
4c37af49aa | ||
|
|
7858632429 | ||
|
|
0647f12498 | ||
|
|
3e1c4045e7 | ||
|
|
3ba8ba4288 | ||
|
|
dfd120a3a9 | ||
|
|
262edc6a46 | ||
|
|
4f79053ec3 | ||
|
|
2a91113a76 | ||
|
|
b103872daf | ||
|
|
7f54012ec6 | ||
|
|
df36e27f32 | ||
|
|
8c0dc9c880 | ||
|
|
074a3eb01c | ||
|
|
a5d0be939a | ||
|
|
5ec0f064d2 | ||
|
|
becbb63736 | ||
|
|
5ee700e804 | ||
|
|
67b145b94d | ||
|
|
c0a6d2f182 | ||
|
|
fd9816556f | ||
|
|
2a3cd62dc9 | ||
|
|
c9bf4f05c1 | ||
|
|
9f5adc5c5c | ||
|
|
d01e6396d1 | ||
|
|
2283d21027 | ||
|
|
ab36d84f1c | ||
|
|
a9f2ff73c9 | ||
|
|
9a7b2098ee | ||
|
|
2b96f71e19 | ||
|
|
3b6b0746b3 | ||
|
|
b0ec1d8083 | ||
|
|
0af916e42e | ||
|
|
fbde927a0c | ||
|
|
952009cd73 | ||
|
|
580e77b170 | ||
|
|
d275493c59 | ||
|
|
256ee0d5ec | ||
|
|
b4e295d885 | ||
|
|
fa48ab6942 | ||
|
|
cbf486c210 | ||
|
|
247cf57d37 | ||
|
|
b1e8c8e231 | ||
|
|
06b4f29831 | ||
|
|
0a5eb19d67 | ||
|
|
4ed662e841 | ||
|
|
75587c8b38 | ||
|
|
51b3604021 | ||
|
|
5340085823 | ||
|
|
aface46d74 | ||
|
|
5835b62496 | ||
|
|
7ae9f4cda1 | ||
|
|
3152d4e9b4 | ||
|
|
277cfd5ce1 | ||
|
|
72fa3d2225 | ||
|
|
9a329178ef | ||
|
|
01cc54087b | ||
|
|
09b3b339e6 | ||
|
|
aa6bdd0809 | ||
|
|
ff4fb7d360 | ||
|
|
9acf6854df | ||
|
|
a9f9a40345 | ||
|
|
8e6e55b154 | ||
|
|
37b88e3bc3 | ||
|
|
385895ca92 | ||
|
|
5e58c79926 | ||
|
|
2025b8cb8d | ||
|
|
cc5e2ec51f | ||
|
|
0402b8bb37 | ||
|
|
5fe3cec894 | ||
|
|
98009cb3ca | ||
|
|
60fbb767c1 | ||
|
|
5a02c5ec02 | ||
|
|
48ca58b7aa | ||
|
|
046cd0bb5d | ||
|
|
7cb55e7051 | ||
|
|
4939a3d0ba | ||
|
|
550c80fdfa | ||
|
|
79ebbbcad9 | ||
|
|
d665954fee | ||
|
|
a8258b5c15 | ||
|
|
b8086435a4 | ||
|
|
6cc4b8d28b | ||
|
|
02ab92cc5c | ||
|
|
b6b52ea56b | ||
|
|
da95dce580 | ||
|
|
44dbf283c9 | ||
|
+1 |
d844714609 | ||
|
|
5cea8436c1 | ||
|
|
dac8fa7d98 | ||
|
|
7a6534d1a9 | ||
|
|
d5aee62bf4 | ||
|
|
0bfdedd4ba | ||
|
|
c5761b99e9 | ||
|
|
42d9ab68d9 | ||
|
|
fd0650dcac | ||
|
|
ddb3dabe69 | ||
|
|
b96a228273 | ||
|
|
781e26d896 | ||
|
|
f7392138ee | ||
|
|
5eb6fc1bf3 | ||
|
|
7dc685bbec | ||
|
|
4915ac50f8 | ||
|
|
d724ad85c5 | ||
|
|
1d32b299a0 | ||
|
|
cfa7ecbc9a | ||
|
|
8dd7540c45 | ||
|
|
07c7d97c28 | ||
|
|
47e931e0dd | ||
|
|
0407b2c2f3 | ||
|
|
55ffb176f2 | ||
|
|
a9093bcf28 | ||
|
|
db964131b4 | ||
|
|
4393b22805 | ||
|
|
b28c3a5a67 | ||
|
|
4068219145 | ||
|
|
03d1a6d73b | ||
|
|
fd74d79180 | ||
|
|
35f20ceb4f | ||
|
|
db68bd04cd | ||
|
|
3df86ad16f | ||
|
|
4389083ca3 | ||
|
|
4961b597a0 | ||
|
|
7e044c664d | ||
|
|
498df5d69a | ||
|
|
b8d4930305 | ||
|
|
2c0bb07899 | ||
|
|
72ada47596 | ||
|
|
dc9eee735c | ||
|
|
b4aee9b591 | ||
|
|
b5c6eedb38 | ||
|
|
8672c8533c | ||
|
|
bb207473f8 | ||
|
|
10b3a717da | ||
|
|
aa81bedaf2 | ||
|
|
b4676e1b4e | ||
|
|
0135a7790c | ||
|
|
2d088d367c | ||
|
|
546353a479 | ||
|
|
9daf044926 | ||
|
|
7054f9f016 | ||
|
|
a3bb17cb33 | ||
|
|
d03645aefd | ||
|
|
53626f8100 | ||
|
|
8a389f1295 | ||
|
|
4e5eb13b82 | ||
|
|
2b11353909 | ||
|
|
5882091eab | ||
|
|
8fc5f204b0 | ||
|
|
c953571588 | ||
|
|
edcd22d612 | ||
|
|
0d5503aae9 | ||
|
|
998e521733 | ||
|
|
be606dd3c9 | ||
|
|
d794b8f9f4 | ||
|
|
21b29490d4 | ||
|
|
7b1d62b323 | ||
|
|
e78da6b36c | ||
|
|
ed711c8cb2 | ||
|
|
05a7495a13 | ||
|
|
11bb053246 | ||
|
|
efb3546ec8 | ||
|
|
0a5d2b5bdd | ||
|
|
ac3e019cd1 | ||
|
|
3c5dc4804a | ||
|
|
30ac3aef84 | ||
|
|
ef4cb09219 | ||
|
|
ad7dae3b16 | ||
|
|
0fd8aa04a9 | ||
|
|
620e89dc25 | ||
|
|
86d33c4b3e | ||
|
|
d43f6171d9 | ||
|
|
06ca1c407d | ||
|
|
c578a437cc | ||
|
|
0c5b03b8d6 | ||
|
|
9af346eead | ||
|
|
d9fb134ad4 | ||
|
|
1c7264b403 | ||
|
|
a140ee99b2 | ||
|
|
6e1fe6e582 | ||
|
|
536b0f1240 | ||
|
|
b626782b0e | ||
|
|
1d76334dd3 | ||
|
|
d498c79a91 | ||
|
|
736b45ac8e | ||
|
|
b5e1d3bb2b | ||
|
|
6816219ac1 | ||
|
|
48065bcd91 | ||
|
|
a388d07a3d | ||
|
|
483e2b9109 | ||
|
|
f7f4f20737 | ||
|
|
6aa6f7e0bd | ||
|
|
d4d9550713 | ||
|
|
3cb298ac4b | ||
|
|
c747670b98 | ||
|
|
c08e6ba988 | ||
|
|
60fb188943 | ||
|
|
1ce8558df4 | ||
|
|
3ce5f9a0c3 | ||
|
|
3d615a62d0 | ||
|
|
6ce366f59e | ||
|
|
8a2d92046a | ||
|
|
45ae105ed3 | ||
|
|
23d61cfeff | ||
|
|
990c665de9 | ||
|
|
08eaefcf0b | ||
|
|
3d62278aba | ||
|
|
3ab7d1e975 | ||
|
|
c6f44722f9 | ||
|
|
e0ce4a3759 | ||
|
|
04416e7c93 | ||
|
|
5166b24a48 | ||
|
|
bb7ca20e49 | ||
|
|
f41f1a2958 | ||
|
|
d9b7360d1d | ||
|
|
8941b22682 | ||
|
|
f61beace93 | ||
|
|
08403dd9da | ||
|
|
36f3191f3e | ||
|
|
7d2a446ece | ||
|
|
ab575726fe | ||
|
|
8e28b0f5e7 | ||
|
|
e7f1ce43b0 | ||
|
|
224b7241dc | ||
|
|
a0eee749a2 | ||
|
|
20bbad1abc | ||
|
|
a430160e6b | ||
|
|
5745481584 | ||
|
|
afdedb1feb | ||
|
|
01293857fa | ||
|
|
ecdcf82cf3 | ||
|
|
12b07aad9a | ||
|
|
c0e2c9457f | ||
|
|
654b8ab351 | ||
|
|
a5578abf66 | ||
|
|
541e488d5b | ||
|
|
088f2567f6 | ||
|
|
6803e8ca09 | ||
|
|
d60e544a24 | ||
|
|
cc20f93e17 | ||
|
|
329bccec4b | ||
|
|
02d55a063e | ||
|
|
73bee2bed1 | ||
|
|
2a443365bd | ||
|
|
ed47fd5310 | ||
|
|
2a0294d8e6 | ||
|
|
65ecf072eb | ||
|
|
9ce3eb6aad | ||
|
|
e32faeb57a | ||
|
|
6a19426200 | ||
|
|
2bcad4b716 | ||
|
|
193de1e9d8 | ||
|
|
645b0303cc | ||
|
|
16232de9ea | ||
|
|
52056edfd6 | ||
|
|
dec4c4a8cf | ||
|
|
9a015a23cd | ||
|
|
15ef4779e0 | ||
|
|
b8498c2a10 | ||
|
|
56f85e57df | ||
|
|
197a6838f6 | ||
|
|
3bf7f37593 | ||
|
|
6803c3e97c | ||
|
|
b672860397 | ||
|
|
ab14cd8938 | ||
|
|
8687d6ac3a | ||
|
|
a5f16b6dc5 | ||
|
|
6a91b6a025 | ||
|
|
54cfd6d891 | ||
|
|
522453fd56 | ||
|
|
0cba69ca40 | ||
|
|
96b43b8488 | ||
|
|
b4c9515937 | ||
|
|
9b20fc9ad2 | ||
|
|
51bbd3d1bc | ||
|
|
356f7aa643 | ||
|
|
2283e71aca | ||
|
|
90ab9ab031 | ||
|
|
6aee041343 | ||
|
|
21627c03d1 | ||
|
|
ce36322b38 | ||
|
|
564eaccf48 | ||
|
|
aa9e952cb5 | ||
|
|
85a6162137 | ||
|
|
e93aa70ef0 | ||
|
|
6e86123403 | ||
|
|
c60658ed8c | ||
|
|
df5f016d31 | ||
|
|
89102b0c89 | ||
|
|
e1846c4469 | ||
|
|
cc56037e64 | ||
|
|
23d90b3e77 | ||
|
|
6745078947 | ||
|
|
55d1f5c550 | ||
|
|
b694f3c300 | ||
|
|
217879ace1 | ||
|
|
35984362b0 | ||
|
|
bdabbef71a | ||
|
|
2f1df0b535 | ||
|
|
da57610802 | ||
|
|
119e785461 | ||
|
|
5f1e6abb39 | ||
|
|
59206233e1 | ||
|
|
4f99ccb49c | ||
|
|
292a321a95 | ||
|
|
74f898ac28 | ||
|
|
431445e3c6 | ||
|
|
fd7111d544 | ||
|
|
f3b2ae3f6d | ||
|
|
f5ae61aeba | ||
|
|
37e0af5753 | ||
|
|
a034b0321f | ||
|
|
8ffc597c06 | ||
|
|
8eecf4c2d5 | ||
|
|
32cc54423e | ||
|
|
bd86661f54 | ||
|
|
ee4c7de25c | ||
|
|
c68a4bdd1f | ||
|
|
68fa1896f7 | ||
|
|
e21bdd0328 | ||
|
|
c85810eee3 | ||
|
|
d24a6146d8 | ||
|
|
e94b7fdfed | ||
|
|
98efd090f6 | ||
|
|
189daf0280 | ||
|
|
f7b352a585 | ||
|
|
56ad0867bd | ||
|
|
d565100614 | ||
|
|
edaa5b2e6c | ||
|
|
77123a9a5a | ||
|
|
6fd10f94b4 | ||
|
|
afae0873b0 | ||
|
|
4a1d758110 | ||
|
|
c6e74ef0b0 | ||
|
|
bba9767adf | ||
|
|
a5e509438d | ||
|
|
f461290216 |
@@ -0,0 +1,6 @@
|
||||
# rename this file to .env and fill in the values
|
||||
# this is not required to build the packages but will significantly increase test performance
|
||||
|
||||
# used for unit tests that hit real IPFS gateway
|
||||
# get a secret key from https://thirdweb.com/create-api-key
|
||||
TW_SECRET_KEY=""
|
||||
@@ -59,9 +59,15 @@ To begin:
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
If you are on windows, use the `--ignore-scripts` flag
|
||||
```
|
||||
pnpm install --ignore-scripts
|
||||
```
|
||||
|
||||
Now you have got the repo on your local machine, and you're ready to start making your changes!
|
||||
|
||||
<br/>
|
||||
|
||||
### Test Your Changes
|
||||
|
||||
We use [yalc](https://github.com/wclr/yalc) to test changes locally.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
## Problem solved
|
||||
|
||||
Short description of the bug fixed or feature added
|
||||
|
||||
## Changes made
|
||||
|
||||
- [ ] Public API changes: list the public API changes made if any
|
||||
- [ ] Internal API changes: explain the internal logic changes
|
||||
|
||||
## How to test
|
||||
|
||||
- [ ] Automated tests: link to unit test file
|
||||
- [ ] Manual tests: step by step instructions on how to test
|
||||
@@ -17,6 +17,7 @@ concurrency:
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
TW_SECRET_KEY: ${{ secrets.TW_SECRET_KEY }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -131,3 +132,4 @@ jobs:
|
||||
run: pnpm e2e
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
CLI_E2E_API_KEY: ${{ secrets.CLI_E2E_API_KEY }}
|
||||
|
||||
@@ -17,6 +17,7 @@ yalc.lock
|
||||
build/
|
||||
playwright-report/
|
||||
.vscode/
|
||||
.env/
|
||||
|
||||
# Artifacts
|
||||
packages/cli/artifacts/
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Description | Latest Version |
|
||||
| --------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/react](./packages/react-native) | Ultimate collection of React hooks for your native web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| Package | Description | Latest Version |
|
||||
| ---------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/react-native](./packages/react-native) | Ultimate collection of React hooks for your native mobile web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
+29
-10
@@ -31,25 +31,44 @@
|
||||
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs",
|
||||
"explain:major": "node ./scripts/changeset-explain-major.mjs"
|
||||
},
|
||||
"packageManager": "pnpm@8.1.0",
|
||||
"packageManager": "pnpm@8.6.12",
|
||||
"dependencies": {
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.1",
|
||||
"@changesets/get-dependents-graph": "^1.3.5",
|
||||
"@changesets/get-release-plan": "^3.0.16",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
"@changesets/get-dependents-graph": "^1.3.6",
|
||||
"@changesets/get-release-plan": "^3.0.17",
|
||||
"@changesets/parse": "^0.3.16",
|
||||
"@manypkg/cli": "^0.20.0",
|
||||
"@manypkg/cli": "^0.21.0",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@playwright/test": "1.31.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/node": "^18.15.11",
|
||||
"eslint": "^8.37.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@types/node": "^18.17.1",
|
||||
"eslint": "^8.45.0",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.7",
|
||||
"turbo": "^1.9.8",
|
||||
"prettier": "^3.0.0",
|
||||
"turbo": "^1.10.12",
|
||||
"yalc": "1.0.0-pre.53"
|
||||
},
|
||||
"manypkg": {
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"cross-fetch@>=3.0.0 <3.1.5": ">=3.1.5",
|
||||
"got@<11.8.5": ">=11.8.5",
|
||||
"glob-parent@<5.1.2": ">=5.1.2",
|
||||
"node-fetch@<2.6.7": ">=2.6.7",
|
||||
"nth-check@<2.0.1": ">=2.0.1",
|
||||
"socket.io-parser@>=4.0.4 <4.2.3": ">=4.2.3",
|
||||
"fast-xml-parser@<4.2.4": ">=4.2.4",
|
||||
"@openzeppelin/contracts@>=4.3.0 <4.9.1": ">=4.9.1",
|
||||
"@openzeppelin/contracts@>=4.7.0 <4.9.2": ">=4.9.2",
|
||||
"xml2js@<0.5.0": ">=0.5.0",
|
||||
"engine.io@>=5.1.0 <6.4.2": ">=6.4.2",
|
||||
"semver@<7.5.2": ">=7.5.2",
|
||||
"json5@<1.0.2": ">=1.0.2",
|
||||
"protobufjs@>=6.10.0 <7.2.4": ">=7.2.4",
|
||||
"tough-cookie@<4.1.3": ">=4.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,308 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 3.2.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.17
|
||||
|
||||
## 3.2.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.16
|
||||
|
||||
## 3.2.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`07fb1b5f`](https://github.com/thirdweb-dev/js/commit/07fb1b5ffa4c170e252df31070852ddb9a81dec9)]:
|
||||
- @thirdweb-dev/wallets@1.1.15
|
||||
|
||||
## 3.2.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`39e2af6f`](https://github.com/thirdweb-dev/js/commit/39e2af6f2f4d933dca1b3de4a37de76375bafd74)]:
|
||||
- @thirdweb-dev/wallets@1.1.14
|
||||
|
||||
## 3.2.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2)]:
|
||||
- @thirdweb-dev/wallets@1.1.13
|
||||
|
||||
## 3.2.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed)]:
|
||||
- @thirdweb-dev/wallets@1.1.12
|
||||
|
||||
## 3.2.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c)]:
|
||||
- @thirdweb-dev/wallets@1.1.11
|
||||
|
||||
## 3.2.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1392](https://github.com/thirdweb-dev/js/pull/1392) [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose functions from auth and update useAuth
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.10
|
||||
|
||||
## 3.2.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.9
|
||||
|
||||
## 3.2.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb)]:
|
||||
- @thirdweb-dev/wallets@1.1.8
|
||||
|
||||
## 3.2.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e), [`b0ec1d80`](https://github.com/thirdweb-dev/js/commit/b0ec1d80839efccad11b50afbf2216c2c132cf7e)]:
|
||||
- @thirdweb-dev/wallets@1.1.7
|
||||
|
||||
## 3.2.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fbde927a`](https://github.com/thirdweb-dev/js/commit/fbde927a0cb36a6269e045d8e577536f23164ef7)]:
|
||||
- @thirdweb-dev/wallets@1.1.6
|
||||
|
||||
## 3.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/wallets@1.1.5
|
||||
|
||||
## 3.2.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1409](https://github.com/thirdweb-dev/js/pull/1409) [`b1e8c8e2`](https://github.com/thirdweb-dev/js/commit/b1e8c8e231013182eb46c16d0c441ee0f3bdfdb2) Thanks [@jnsdls](https://github.com/jnsdls)! - update dependencies
|
||||
|
||||
- [#1410](https://github.com/thirdweb-dev/js/pull/1410) [`247cf57d`](https://github.com/thirdweb-dev/js/commit/247cf57d375a4ec0bc6867e0b65a262c94a9e2f2) Thanks [@jnsdls](https://github.com/jnsdls)! - expose `getToken()` helper function
|
||||
|
||||
- Updated dependencies [[`06b4f298`](https://github.com/thirdweb-dev/js/commit/06b4f2983161fc9ff5913fd05dacf17260902576), [`b1e8c8e2`](https://github.com/thirdweb-dev/js/commit/b1e8c8e231013182eb46c16d0c441ee0f3bdfdb2), [`2025b8cb`](https://github.com/thirdweb-dev/js/commit/2025b8cb8d5157c03314e5db47a0d50382519c41), [`385895ca`](https://github.com/thirdweb-dev/js/commit/385895ca928a5276586f0a370fabdcece7620d83), [`9acf6854`](https://github.com/thirdweb-dev/js/commit/9acf6854dfdc5c0be768e660c1f174e017b06a9c), [`48ca58b7`](https://github.com/thirdweb-dev/js/commit/48ca58b7aa45348b928932b9c7b76b3dc233e429), [`60fbb767`](https://github.com/thirdweb-dev/js/commit/60fbb767c18ffe1e49792c6ac8e808792acf594c), [`277cfd5c`](https://github.com/thirdweb-dev/js/commit/277cfd5ce1f3a576d29c95492c735b46a00c164e), [`2025b8cb`](https://github.com/thirdweb-dev/js/commit/2025b8cb8d5157c03314e5db47a0d50382519c41), [`cc5e2ec5`](https://github.com/thirdweb-dev/js/commit/cc5e2ec51fce09af05be33811eb46980825829ee), [`7ae9f4cd`](https://github.com/thirdweb-dev/js/commit/7ae9f4cda1a2009dd414f836757bec8202c83172)]:
|
||||
- @thirdweb-dev/wallets@1.1.4
|
||||
|
||||
## 3.2.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.3
|
||||
|
||||
## 3.2.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.2
|
||||
|
||||
## 3.2.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.1
|
||||
|
||||
## 3.2.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b)]:
|
||||
- @thirdweb-dev/wallets@1.1.0
|
||||
|
||||
## 3.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c5761b99`](https://github.com/thirdweb-dev/js/commit/c5761b99e9797772481506e90cbfa5c35a05bd1d), [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220)]:
|
||||
- @thirdweb-dev/wallets@1.0.12
|
||||
|
||||
## 3.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.11
|
||||
|
||||
## 3.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.10
|
||||
|
||||
## 3.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.9
|
||||
|
||||
## 3.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.8
|
||||
|
||||
## 3.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.7
|
||||
|
||||
## 3.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.6
|
||||
|
||||
## 3.2.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`10b3a717`](https://github.com/thirdweb-dev/js/commit/10b3a717da606632a05769ac821bdd21d6b63a03), [`b4aee9b5`](https://github.com/thirdweb-dev/js/commit/b4aee9b59121bab5f9b3d9b7ecdc4bcb4cd66f58)]:
|
||||
- @thirdweb-dev/wallets@1.0.5
|
||||
|
||||
## 3.2.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
|
||||
|
||||
- Updated dependencies [[`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2)]:
|
||||
- @thirdweb-dev/wallets@1.0.4
|
||||
|
||||
## 3.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
|
||||
- @thirdweb-dev/wallets@1.0.3
|
||||
|
||||
## 3.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
|
||||
- @thirdweb-dev/wallets@1.0.2
|
||||
|
||||
## 3.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
|
||||
- @thirdweb-dev/wallets@1.0.1
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1250](https://github.com/thirdweb-dev/js/pull/1250) [`d43f6171`](https://github.com/thirdweb-dev/js/commit/d43f6171d910e31b748b171b012174390aac3fff) Thanks [@adam-maj](https://github.com/adam-maj)! - Allow setting login payload validity duration
|
||||
|
||||
- Updated dependencies [[`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc)]:
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f)]:
|
||||
- @thirdweb-dev/wallets@0.3.3
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3cb298ac`](https://github.com/thirdweb-dev/js/commit/3cb298ac4b04d295899b5ac77c7fc5869ec2f5f2), [`3ce5f9a0`](https://github.com/thirdweb-dev/js/commit/3ce5f9a0c3fc7e99b5abf691a87048ab8475f6b1), [`a388d07a`](https://github.com/thirdweb-dev/js/commit/a388d07a3d449e56dc53fed9600931022f4a15e1), [`1ce8558d`](https://github.com/thirdweb-dev/js/commit/1ce8558df47186bcba5ee8564fdb04583bf115dd), [`60fb1889`](https://github.com/thirdweb-dev/js/commit/60fb18894372f14d9cd815fa9a239926d31bb273)]:
|
||||
- @thirdweb-dev/wallets@0.3.2
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3d62278a`](https://github.com/thirdweb-dev/js/commit/3d62278aba79101ae1158fb726d6ddfed505c939)]:
|
||||
- @thirdweb-dev/wallets@0.3.1
|
||||
|
||||
## 3.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1150](https://github.com/thirdweb-dev/js/pull/1150) [`d60e544a`](https://github.com/thirdweb-dev/js/commit/d60e544a240b93312743e62096ee2dc77d0c1bd1) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for multipled logged in accounts and token refreshing to auth
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1165](https://github.com/thirdweb-dev/js/pull/1165) [`088f2567`](https://github.com/thirdweb-dev/js/commit/088f2567f615360edd44776b20ae0bedff250f43) Thanks [@adam-maj](https://github.com/adam-maj)! - Include chain id in login payload
|
||||
|
||||
- Updated dependencies [[`654b8ab3`](https://github.com/thirdweb-dev/js/commit/654b8ab35184e02127a5a47f05d78606dd5b29ca), [`329bccec`](https://github.com/thirdweb-dev/js/commit/329bccec4b88b02db5bac6c1415158928843376a)]:
|
||||
- @thirdweb-dev/wallets@0.3.0
|
||||
|
||||
## 3.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1126](https://github.com/thirdweb-dev/js/pull/1126) [`ab14cd89`](https://github.com/thirdweb-dev/js/commit/ab14cd89385aefad7f32e20a22baa9fce42b98e2) Thanks [@adam-maj](https://github.com/adam-maj)! - Add expiration date to cookie
|
||||
|
||||
- Updated dependencies [[`2a443365`](https://github.com/thirdweb-dev/js/commit/2a443365bdc3d47d0f41fc895f70256dcde423f5), [`197a6838`](https://github.com/thirdweb-dev/js/commit/197a6838f69ae8b9ad46524e7c469fc757d0a2cb)]:
|
||||
- @thirdweb-dev/wallets@0.2.26
|
||||
|
||||
## 3.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1114](https://github.com/thirdweb-dev/js/pull/1114) [`2283e71a`](https://github.com/thirdweb-dev/js/commit/2283e71acaaf3d15eb2d6121682f1d2a81eec4f3) Thanks [@adam-maj](https://github.com/adam-maj)! - Switch to server-side payload generation
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1111](https://github.com/thirdweb-dev/js/pull/1111) [`21627c03`](https://github.com/thirdweb-dev/js/commit/21627c03d1bb1658fee19b12d580faa6c7f048d9) Thanks [@adam-maj](https://github.com/adam-maj)! - Update expiration dates for auth
|
||||
|
||||
- Updated dependencies [[`9b20fc9a`](https://github.com/thirdweb-dev/js/commit/9b20fc9ad2d303edc31f44fbd2ea3b4dcf35d11e)]:
|
||||
- @thirdweb-dev/wallets@0.2.25
|
||||
|
||||
## 3.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1101](https://github.com/thirdweb-dev/js/pull/1101) [`e1846c44`](https://github.com/thirdweb-dev/js/commit/e1846c44696bcb25a6a137d63e117e7d2ce9d979) Thanks [@adam-maj](https://github.com/adam-maj)! - Bump invalid before with 5 minute window
|
||||
|
||||
- [#1098](https://github.com/thirdweb-dev/js/pull/1098) [`67450789`](https://github.com/thirdweb-dev/js/commit/67450789473b6008b86453ee4f4c7b99461223a6) Thanks [@MananTank](https://github.com/MananTank)! - add sideEffects: false in package.json
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@0.2.24
|
||||
|
||||
## 3.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`68fa1896`](https://github.com/thirdweb-dev/js/commit/68fa1896f75d3514e00cc380924fd8bc623064f0), [`292a321a`](https://github.com/thirdweb-dev/js/commit/292a321a95ed2d847097eed205353dd69eeb8d54), [`f3b2ae3f`](https://github.com/thirdweb-dev/js/commit/f3b2ae3f6d9c66356c521d3b9c2a6c096dbb4b57), [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`35984362`](https://github.com/thirdweb-dev/js/commit/35984362b0a60e5b9c3d3c9731450a8f47deb1c4)]:
|
||||
- @thirdweb-dev/wallets@0.2.23
|
||||
|
||||
## 3.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+21
-20
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.0.21",
|
||||
"version": "3.2.34",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
@@ -54,6 +54,7 @@
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/auth",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "preconstruct build",
|
||||
"format": "prettier --write 'src/**/*'",
|
||||
@@ -79,41 +80,41 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
"@microsoft/api-extractor": "^7.29.2",
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@microsoft/api-documenter": "^7.22.30",
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@swc-node/register": "^1.5.1",
|
||||
"@swc/core": "^1.3.23",
|
||||
"@swc-node/register": "^1.6.6",
|
||||
"@swc/core": "^1.3.71",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/chai": "^4.3.5",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||
"@typescript-eslint/parser": "^6.2.0",
|
||||
"chai": "^4.3.6",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"eslint": "^8.21.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.2",
|
||||
"express": "^4.18.1",
|
||||
"mocha": "^10.2.0",
|
||||
"next": "^12.2.0",
|
||||
"next-auth": "^4.20.1",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.7.4"
|
||||
"next": "^12.3.4",
|
||||
"next-auth": "^4.22.3",
|
||||
"prettier": "^3.0.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
const THIRDWEB_AUTH_COOKIE_PREFIX = `thirdweb_auth`;
|
||||
export const THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX = `${THIRDWEB_AUTH_COOKIE_PREFIX}_token`;
|
||||
export const THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE = `${THIRDWEB_AUTH_COOKIE_PREFIX}_active_account`;
|
||||
|
||||
export const THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS = 60 * 10;
|
||||
export const THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS = 60 * 60 * 24;
|
||||
export const THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS = 5;
|
||||
+78
-370
@@ -1,22 +1,28 @@
|
||||
import {
|
||||
LoginOptions,
|
||||
LoginPayload,
|
||||
GenerateOptions,
|
||||
LoginPayloadData,
|
||||
LoginPayloadDataSchema,
|
||||
AuthenticationPayloadDataSchema,
|
||||
AuthenticationPayloadData,
|
||||
LoginOptionsSchema,
|
||||
VerifyOptionsSchema,
|
||||
VerifyOptions,
|
||||
GenerateOptionsSchema,
|
||||
AuthenticateOptionsSchema,
|
||||
AuthenticateOptions,
|
||||
User,
|
||||
Json,
|
||||
} from "./schema";
|
||||
import { isBrowser } from "./utils";
|
||||
authenticateJWT,
|
||||
generateJWT,
|
||||
parseJWT,
|
||||
refreshJWT,
|
||||
} from "./functions/jwt";
|
||||
import {
|
||||
buildAndSignLoginPayload,
|
||||
buildLoginPayload,
|
||||
signLoginPayload,
|
||||
verifyLoginPayload,
|
||||
} from "./functions/login";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { Json, User } from "./schema/common";
|
||||
import {
|
||||
LoginOptionsWithOptionalDomain,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
} from "./schema/login";
|
||||
import { VerifyOptionsWithOptionalDomain } from "./schema/verify";
|
||||
import { GenerateOptionsWithOptionalDomain } from "./schema/generate";
|
||||
import {
|
||||
AuthenticateOptionsWithOptionalDomain,
|
||||
AuthenticationPayload,
|
||||
} from "./schema/authenticate";
|
||||
|
||||
export class ThirdwebAuth {
|
||||
private domain: string;
|
||||
@@ -31,380 +37,82 @@ export class ThirdwebAuth {
|
||||
this.wallet = wallet;
|
||||
}
|
||||
|
||||
public async login(options?: LoginOptions): Promise<LoginPayload> {
|
||||
const parsedOptions = LoginOptionsSchema.parse(options);
|
||||
|
||||
let chainId: string | undefined = parsedOptions?.chainId;
|
||||
if (!chainId && this.wallet.getChainId) {
|
||||
try {
|
||||
chainId = (await this.wallet.getChainId()).toString();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
const payloadData = LoginPayloadDataSchema.parse({
|
||||
type: this.wallet.type,
|
||||
domain: parsedOptions?.domain || this.domain,
|
||||
address: await this.wallet.getAddress(),
|
||||
statement: parsedOptions?.statement,
|
||||
version: parsedOptions?.version,
|
||||
uri: parsedOptions?.uri,
|
||||
chain_id: chainId,
|
||||
nonce: parsedOptions?.nonce,
|
||||
expiration_time:
|
||||
parsedOptions?.expirationTime || new Date(Date.now() + 1000 * 60 * 5),
|
||||
invalid_before: parsedOptions?.invalidBefore,
|
||||
resources: parsedOptions?.resources,
|
||||
public async payload(
|
||||
options?: LoginOptionsWithOptionalDomain,
|
||||
): Promise<LoginPayloadData> {
|
||||
return buildLoginPayload({
|
||||
wallet: this.wallet,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
const message = this.generateMessage(payloadData);
|
||||
const signature = await this.wallet.signMessage(message);
|
||||
public async loginWithPayload(
|
||||
payload: LoginPayloadData,
|
||||
): Promise<LoginPayload> {
|
||||
return signLoginPayload({ wallet: this.wallet, payload });
|
||||
}
|
||||
|
||||
return {
|
||||
payload: payloadData,
|
||||
signature,
|
||||
};
|
||||
public async login(
|
||||
options?: LoginOptionsWithOptionalDomain,
|
||||
): Promise<LoginPayload> {
|
||||
return buildAndSignLoginPayload({
|
||||
wallet: this.wallet,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async verify(
|
||||
payload: LoginPayload,
|
||||
options?: VerifyOptions,
|
||||
options?: VerifyOptionsWithOptionalDomain,
|
||||
): Promise<string> {
|
||||
const parsedOptions = VerifyOptionsSchema.parse(options);
|
||||
|
||||
if (payload.payload.type !== this.wallet.type) {
|
||||
throw new Error(
|
||||
`Expected chain type '${this.wallet.type}' does not match chain type on payload '${payload.payload.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the intended domain matches the domain of the payload
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
if (payload.payload.domain !== domain) {
|
||||
throw new Error(
|
||||
`Expected domain '${domain}' does not match domain on payload '${payload.payload.domain}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the payload statement matches the expected statement
|
||||
if (parsedOptions?.statement) {
|
||||
if (payload.payload.statement !== parsedOptions.statement) {
|
||||
throw new Error(
|
||||
`Expected statement '${parsedOptions.statement}' does not match statement on payload '${payload.payload.statement}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended URI matches the URI of the payload
|
||||
if (parsedOptions?.uri) {
|
||||
if (payload.payload.uri !== parsedOptions.uri) {
|
||||
throw new Error(
|
||||
`Expected URI '${parsedOptions.uri}' does not match URI on payload '${payload.payload.uri}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended version matches the version of the payload
|
||||
if (parsedOptions?.version) {
|
||||
if (payload.payload.version !== parsedOptions.version) {
|
||||
throw new Error(
|
||||
`Expected version '${parsedOptions.version}' does not match version on payload '${payload.payload.version}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended chain ID matches the chain ID of the payload
|
||||
if (parsedOptions?.chainId) {
|
||||
if (payload.payload.chain_id !== parsedOptions.chainId) {
|
||||
throw new Error(
|
||||
`Expected chain ID '${parsedOptions.chainId}' does not match chain ID on payload '${payload.payload.chain_id}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the payload nonce is valid
|
||||
if (parsedOptions?.validateNonce !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateNonce(payload.payload.nonce);
|
||||
} catch (err) {
|
||||
throw new Error(`Login request nonce is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that it isn't before the invalid before time
|
||||
const currentTime = new Date();
|
||||
if (currentTime < new Date(payload.payload.invalid_before)) {
|
||||
throw new Error(`Login request is not yet valid`);
|
||||
}
|
||||
|
||||
// Check that the payload hasn't expired
|
||||
if (currentTime > new Date(payload.payload.expiration_time)) {
|
||||
throw new Error(`Login request has expired`);
|
||||
}
|
||||
|
||||
// Check that the specified resources are present on the payload
|
||||
if (parsedOptions?.resources) {
|
||||
const missingResources = parsedOptions.resources.filter(
|
||||
(resource) => !payload.payload.resources?.includes(resource),
|
||||
);
|
||||
if (missingResources.length > 0) {
|
||||
throw new Error(
|
||||
`Login request is missing required resources: ${missingResources.join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the signing address is the claimed wallet address
|
||||
const message = this.generateMessage(payload.payload);
|
||||
const chainId =
|
||||
this.wallet.type === "evm" && payload.payload.chain_id
|
||||
? parseInt(payload.payload.chain_id)
|
||||
: undefined;
|
||||
const verified = await this.verifySignature(
|
||||
message,
|
||||
payload.signature,
|
||||
payload.payload.address,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`Signer address does not match payload address '${payload.payload.address.toLowerCase()}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return payload.payload.address;
|
||||
return verifyLoginPayload({
|
||||
wallet: this.wallet,
|
||||
payload,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async generate(
|
||||
payload: LoginPayload,
|
||||
options?: GenerateOptions,
|
||||
options?: GenerateOptionsWithOptionalDomain,
|
||||
): Promise<string> {
|
||||
if (isBrowser()) {
|
||||
throw new Error(
|
||||
"Authentication tokens should not be generated in the browser, as they must be signed by a server-side admin wallet.",
|
||||
);
|
||||
}
|
||||
|
||||
const parsedOptions = GenerateOptionsSchema.parse(options);
|
||||
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
const userAddress = await this.verify(payload, {
|
||||
domain,
|
||||
...parsedOptions?.verifyOptions,
|
||||
return generateJWT({
|
||||
wallet: this.wallet,
|
||||
payload,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async refresh(jwt: string, expirationTime?: Date): Promise<string> {
|
||||
return refreshJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: { expirationTime },
|
||||
});
|
||||
|
||||
let session: Json | undefined = undefined;
|
||||
if (typeof parsedOptions?.session === "function") {
|
||||
const sessionTrigger = (await parsedOptions.session(userAddress)) as Json;
|
||||
if (sessionTrigger) {
|
||||
session = sessionTrigger;
|
||||
}
|
||||
} else {
|
||||
session = parsedOptions?.session;
|
||||
}
|
||||
|
||||
const adminAddress = await this.wallet.getAddress();
|
||||
const payloadData = AuthenticationPayloadDataSchema.parse({
|
||||
iss: adminAddress,
|
||||
sub: userAddress,
|
||||
aud: domain,
|
||||
nbf: parsedOptions?.invalidBefore || new Date(),
|
||||
exp:
|
||||
parsedOptions?.expirationTime ||
|
||||
new Date(Date.now() + 1000 * 60 * 60 * 5),
|
||||
iat: new Date(),
|
||||
jti: parsedOptions?.tokenId,
|
||||
ctx: session,
|
||||
});
|
||||
|
||||
const message = JSON.stringify(payloadData);
|
||||
const signature = await this.wallet.signMessage(message);
|
||||
|
||||
// Header used for JWT token specifying hash algorithm
|
||||
const header = {
|
||||
// Specify ECDSA with SHA-256 for hashing algorithm
|
||||
alg: "ES256",
|
||||
typ: "JWT",
|
||||
};
|
||||
|
||||
const encodedHeader = Buffer.from(JSON.stringify(header)).toString(
|
||||
"base64",
|
||||
);
|
||||
const encodedData = Buffer.from(JSON.stringify(payloadData))
|
||||
.toString("base64")
|
||||
.replace(/=/g, "");
|
||||
const encodedSignature = Buffer.from(signature).toString("base64");
|
||||
|
||||
// Generate a JWT token with base64 encoded header, payload, and signature
|
||||
const token = `${encodedHeader}.${encodedData}.${encodedSignature}`;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate With Token
|
||||
* @remarks Server-side function that authenticates the provided JWT token. This function verifies that
|
||||
* the provided authentication token is valid and returns the address of the authenticated wallet.
|
||||
*
|
||||
* @param domain - The domain of the server-side application doing authentication
|
||||
* @param token - The authentication token being used
|
||||
* @returns The address of the authenticated wallet
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const domain = "example.com";
|
||||
* const loginPayload = await sdk.auth.login(domain);
|
||||
* const token = await sdk.auth.generateAuthToken(domain, loginPayload);
|
||||
*
|
||||
* // Authenticate the token and get the address of authenticating users wallet
|
||||
* const address = sdk.auth.authenticate(domain, token);
|
||||
* ```
|
||||
*/
|
||||
public async authenticate<TSession extends Json = Json>(
|
||||
token: string,
|
||||
options?: AuthenticateOptions,
|
||||
jwt: string,
|
||||
options?: AuthenticateOptionsWithOptionalDomain,
|
||||
): Promise<User<TSession>> {
|
||||
if (isBrowser()) {
|
||||
throw new Error(
|
||||
"Should not authenticate tokens in the browser, as they must be verified by the server-side admin wallet.",
|
||||
);
|
||||
}
|
||||
|
||||
const parsedOptions = AuthenticateOptionsSchema.parse(options);
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
|
||||
const encodedPayload = token.split(".")[1];
|
||||
const encodedSignature = token.split(".")[2];
|
||||
const payload: AuthenticationPayloadData = JSON.parse(
|
||||
Buffer.from(encodedPayload, "base64").toString(),
|
||||
);
|
||||
const signature = Buffer.from(encodedSignature, "base64").toString();
|
||||
|
||||
// Check that the payload unique ID is valid
|
||||
if (parsedOptions?.validateTokenId !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateTokenId(payload.jti);
|
||||
} catch (err) {
|
||||
throw new Error(`Token ID is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the token audience matches the domain
|
||||
if (payload.aud !== domain) {
|
||||
throw new Error(
|
||||
`Expected token to be for the domain '${domain}', but found token with domain '${payload.aud}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token is past the invalid before time
|
||||
const currentTime = Math.floor(new Date().getTime() / 1000);
|
||||
if (currentTime < payload.nbf) {
|
||||
throw new Error(
|
||||
`This token is invalid before epoch time '${payload.nbf}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token hasn't expired
|
||||
if (currentTime > payload.exp) {
|
||||
throw new Error(
|
||||
`This token expired at epoch time '${payload.exp}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the connected wallet matches the token issuer
|
||||
const connectedAddress = await this.wallet.getAddress();
|
||||
if (connectedAddress.toLowerCase() !== payload.iss.toLowerCase()) {
|
||||
throw new Error(
|
||||
`Expected the connected wallet address '${connectedAddress}' to match the token issuer address '${payload.iss}'`,
|
||||
);
|
||||
}
|
||||
|
||||
let chainId: number | undefined = undefined;
|
||||
if (this.wallet.getChainId) {
|
||||
try {
|
||||
chainId = await this.wallet.getChainId();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
const verified = await this.verifySignature(
|
||||
JSON.stringify(payload),
|
||||
signature,
|
||||
connectedAddress,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`The connected wallet address '${connectedAddress}' did not sign the token`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
address: payload.sub,
|
||||
session: payload.ctx as TSession | undefined,
|
||||
};
|
||||
return authenticateJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
private async verifySignature(
|
||||
message: string,
|
||||
signature: string,
|
||||
address: string,
|
||||
chainId?: number,
|
||||
) {
|
||||
return this.wallet.verifySignature(message, signature, address, chainId);
|
||||
public parseToken(jwt: string): AuthenticationPayload {
|
||||
return parseJWT(jwt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a EIP-4361 & CAIP-122 compliant message to sign based on the login payload
|
||||
*/
|
||||
private generateMessage(payload: LoginPayloadData): string {
|
||||
const typeField = payload.type === "evm" ? "Ethereum" : "Solana";
|
||||
const header = `${payload.domain} wants you to sign in with your ${typeField} account:`;
|
||||
let prefix = [header, payload.address].join("\n");
|
||||
prefix = [prefix, payload.statement].join("\n\n");
|
||||
if (payload.statement) {
|
||||
prefix += "\n";
|
||||
}
|
||||
|
||||
const suffixArray = [];
|
||||
if (payload.uri) {
|
||||
const uriField = `URI: ${payload.uri}`;
|
||||
suffixArray.push(uriField);
|
||||
}
|
||||
|
||||
const versionField = `Version: ${payload.version}`;
|
||||
suffixArray.push(versionField);
|
||||
|
||||
if (payload.chain_id) {
|
||||
const chainField = `Chain ID: ` + payload.chain_id || "1";
|
||||
suffixArray.push(chainField);
|
||||
}
|
||||
|
||||
const nonceField = `Nonce: ${payload.nonce}`;
|
||||
suffixArray.push(nonceField);
|
||||
|
||||
const issuedAtField = `Issued At: ${payload.issued_at}`;
|
||||
suffixArray.push(issuedAtField);
|
||||
|
||||
const expiryField = `Expiration Time: ${payload.expiration_time}`;
|
||||
suffixArray.push(expiryField);
|
||||
|
||||
if (payload.invalid_before) {
|
||||
const invalidBeforeField = `Not Before: ${payload.invalid_before}`;
|
||||
suffixArray.push(invalidBeforeField);
|
||||
}
|
||||
|
||||
if (payload.resources) {
|
||||
suffixArray.push(
|
||||
[`Resources:`, ...payload.resources.map((x) => `- ${x}`)].join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
const suffix = suffixArray.join("\n");
|
||||
return [prefix, suffix].join("\n");
|
||||
private formatOptions<TOptions extends { domain?: string }>(
|
||||
options?: TOptions,
|
||||
): Omit<TOptions, "domain"> & { domain: string } {
|
||||
return options
|
||||
? { ...options, domain: options?.domain || this.domain }
|
||||
: ({ domain: this.domain } as Omit<TOptions, "domain"> & {
|
||||
domain: string;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
import {
|
||||
AuthenticateOptionsSchema,
|
||||
AuthenticationPayload,
|
||||
AuthenticationPayloadData,
|
||||
AuthenticationPayloadDataSchema,
|
||||
} from "../schema/authenticate";
|
||||
import { Json, User } from "../schema/common";
|
||||
import {
|
||||
BuildJwtParams,
|
||||
RefreshJwtParams,
|
||||
GenerateJwtParams,
|
||||
AuthenticateJwtParams,
|
||||
} from "../schema/functions";
|
||||
import { GenerateOptionsSchema } from "../schema/generate";
|
||||
import { RefreshOptionsSchema } from "../schema/refresh";
|
||||
import { verifyLoginPayload } from "./login";
|
||||
|
||||
function isBrowser() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
function base64encode(data: string): string {
|
||||
if (isBrowser()) {
|
||||
return window.btoa(data);
|
||||
}
|
||||
|
||||
return Buffer.from(data).toString("base64").replace(/=/g, "");
|
||||
}
|
||||
|
||||
function base64decode(data: string): string {
|
||||
if (isBrowser()) {
|
||||
return window.atob(data);
|
||||
}
|
||||
|
||||
return Buffer.from(data, "base64").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build JWT token based on the authentication payload
|
||||
*/
|
||||
async function buildJWT({ wallet, payload }: BuildJwtParams): Promise<string> {
|
||||
const payloadData = AuthenticationPayloadDataSchema.parse(payload);
|
||||
|
||||
const message = JSON.stringify(payloadData);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
// Header used for JWT token specifying hash algorithm
|
||||
const header = {
|
||||
// Specify ECDSA with SHA-256 for hashing algorithm
|
||||
alg: "ES256",
|
||||
typ: "JWT",
|
||||
};
|
||||
|
||||
const encodedHeader = base64encode(JSON.stringify(header));
|
||||
const encodedData = base64encode(JSON.stringify(payloadData));
|
||||
const encodedSignature = base64encode(signature);
|
||||
|
||||
// Generate a JWT with base64 encoded header, payload, and signature
|
||||
const jwt = `${encodedHeader}.${encodedData}.${encodedSignature}`;
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new JWT using a login payload
|
||||
*/
|
||||
export async function generateJWT({
|
||||
wallet,
|
||||
payload,
|
||||
options,
|
||||
}: GenerateJwtParams): Promise<string> {
|
||||
const parsedOptions = GenerateOptionsSchema.parse(options);
|
||||
const userAddress = await verifyLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
options: {
|
||||
domain: parsedOptions.domain,
|
||||
...parsedOptions.verifyOptions,
|
||||
},
|
||||
});
|
||||
|
||||
let session: Json | undefined = undefined;
|
||||
if (typeof parsedOptions?.session === "function") {
|
||||
const sessionTrigger = (await parsedOptions.session(userAddress)) as Json;
|
||||
if (sessionTrigger) {
|
||||
session = sessionTrigger;
|
||||
}
|
||||
} else {
|
||||
session = parsedOptions?.session;
|
||||
}
|
||||
|
||||
const adminAddress = await wallet.getAddress();
|
||||
return buildJWT({
|
||||
wallet,
|
||||
payload: {
|
||||
iss: adminAddress,
|
||||
sub: userAddress,
|
||||
aud: parsedOptions.domain,
|
||||
nbf: parsedOptions?.invalidBefore || new Date(),
|
||||
exp: parsedOptions.expirationTime,
|
||||
iat: new Date(),
|
||||
jti: parsedOptions?.tokenId,
|
||||
ctx: session,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse data from an encoded auth JWT
|
||||
*/
|
||||
export function parseJWT(jwt: string): AuthenticationPayload {
|
||||
const encodedPayload = jwt.split(".")[1];
|
||||
const encodedSignature = jwt.split(".")[2];
|
||||
const payload: AuthenticationPayloadData = JSON.parse(
|
||||
base64decode(encodedPayload),
|
||||
);
|
||||
const signature = base64decode(encodedSignature);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an existing JWT
|
||||
*/
|
||||
export async function refreshJWT({
|
||||
wallet,
|
||||
jwt,
|
||||
options,
|
||||
}: RefreshJwtParams): Promise<string> {
|
||||
const { payload } = parseJWT(jwt);
|
||||
const parsedOptions = RefreshOptionsSchema.parse(options);
|
||||
return buildJWT({
|
||||
wallet,
|
||||
payload: {
|
||||
iss: payload.iss,
|
||||
sub: payload.sub,
|
||||
aud: payload.aud,
|
||||
nbf: new Date(),
|
||||
exp: parsedOptions.expirationTime,
|
||||
iat: new Date(),
|
||||
ctx: payload.ctx,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a JWT and extract the user's info
|
||||
*/
|
||||
export async function authenticateJWT<TSession extends Json = Json>({
|
||||
wallet,
|
||||
jwt,
|
||||
options,
|
||||
}: AuthenticateJwtParams): Promise<User<TSession>> {
|
||||
const parsedOptions = AuthenticateOptionsSchema.parse(options);
|
||||
const { payload, signature } = parseJWT(jwt);
|
||||
|
||||
// Check that the payload unique ID is valid
|
||||
if (parsedOptions?.validateTokenId !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateTokenId(payload.jti);
|
||||
} catch (err) {
|
||||
throw new Error(`Token ID is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the token audience matches the domain
|
||||
if (payload.aud !== parsedOptions.domain) {
|
||||
throw new Error(
|
||||
`Expected token to be for the domain '${parsedOptions.domain}', but found token with domain '${payload.aud}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token is past the invalid before time
|
||||
const currentTime = Math.floor(new Date().getTime() / 1000);
|
||||
if (currentTime < payload.nbf) {
|
||||
throw new Error(
|
||||
`This token is invalid before epoch time '${payload.nbf}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token hasn't expired
|
||||
if (currentTime > payload.exp) {
|
||||
throw new Error(
|
||||
`This token expired at epoch time '${payload.exp}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the connected wallet matches the token issuer
|
||||
const issuerAddress = parsedOptions.issuerAddress
|
||||
? parsedOptions.issuerAddress
|
||||
: await wallet.getAddress();
|
||||
if (issuerAddress.toLowerCase() !== payload.iss.toLowerCase()) {
|
||||
throw new Error(
|
||||
`The expected issuer address '${issuerAddress}' did not match the token issuer address '${payload.iss}'`,
|
||||
);
|
||||
}
|
||||
|
||||
let chainId: number | undefined = undefined;
|
||||
if (wallet.getChainId) {
|
||||
try {
|
||||
chainId = await wallet.getChainId();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
const verified = await wallet.verifySignature(
|
||||
JSON.stringify(payload),
|
||||
signature,
|
||||
issuerAddress,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`The expected signer address '${issuerAddress}' did not sign the token`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
address: payload.sub,
|
||||
session: payload.ctx as TSession | undefined,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
import {
|
||||
BuildLoginPayloadParams,
|
||||
SignLoginPayloadParams,
|
||||
VerifyLoginPayloadParams,
|
||||
} from "../schema/functions";
|
||||
import {
|
||||
LoginOptionsSchema,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
LoginPayloadDataSchema,
|
||||
} from "../schema/login";
|
||||
import { VerifyOptionsSchema } from "../schema/verify";
|
||||
|
||||
/**
|
||||
* Create an EIP-4361 & CAIP-122 compliant message to sign based on the login payload
|
||||
*/
|
||||
function createLoginMessage(payload: LoginPayloadData): string {
|
||||
const typeField = payload.type === "evm" ? "Ethereum" : "Solana";
|
||||
const header = `${payload.domain} wants you to sign in with your ${typeField} account:`;
|
||||
let prefix = [header, payload.address].join("\n");
|
||||
prefix = [prefix, payload.statement].join("\n\n");
|
||||
if (payload.statement) {
|
||||
prefix += "\n";
|
||||
}
|
||||
|
||||
const suffixArray = [];
|
||||
if (payload.uri) {
|
||||
const uriField = `URI: ${payload.uri}`;
|
||||
suffixArray.push(uriField);
|
||||
}
|
||||
|
||||
const versionField = `Version: ${payload.version}`;
|
||||
suffixArray.push(versionField);
|
||||
|
||||
if (payload.chain_id) {
|
||||
const chainField = `Chain ID: ` + payload.chain_id || "1";
|
||||
suffixArray.push(chainField);
|
||||
}
|
||||
|
||||
const nonceField = `Nonce: ${payload.nonce}`;
|
||||
suffixArray.push(nonceField);
|
||||
|
||||
const issuedAtField = `Issued At: ${payload.issued_at}`;
|
||||
suffixArray.push(issuedAtField);
|
||||
|
||||
const expiryField = `Expiration Time: ${payload.expiration_time}`;
|
||||
suffixArray.push(expiryField);
|
||||
|
||||
if (payload.invalid_before) {
|
||||
const invalidBeforeField = `Not Before: ${payload.invalid_before}`;
|
||||
suffixArray.push(invalidBeforeField);
|
||||
}
|
||||
|
||||
if (payload.resources) {
|
||||
suffixArray.push(
|
||||
[`Resources:`, ...payload.resources.map((x) => `- ${x}`)].join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
const suffix = suffixArray.join("\n");
|
||||
return [prefix, suffix].join("\n");
|
||||
}
|
||||
|
||||
export async function buildLoginPayload({
|
||||
wallet,
|
||||
options,
|
||||
}: BuildLoginPayloadParams): Promise<LoginPayloadData> {
|
||||
const parsedOptions = LoginOptionsSchema.parse(options);
|
||||
|
||||
let chainId: string | undefined = parsedOptions?.chainId;
|
||||
if (!chainId && wallet.getChainId) {
|
||||
try {
|
||||
chainId = (await wallet.getChainId()).toString();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
return LoginPayloadDataSchema.parse({
|
||||
type: wallet.type,
|
||||
domain: parsedOptions.domain,
|
||||
address: parsedOptions?.address || (await wallet.getAddress()),
|
||||
statement: parsedOptions?.statement,
|
||||
version: parsedOptions?.version,
|
||||
uri: parsedOptions?.uri,
|
||||
chain_id: chainId,
|
||||
nonce: parsedOptions?.nonce,
|
||||
expiration_time: parsedOptions.expirationTime,
|
||||
invalid_before: parsedOptions.invalidBefore,
|
||||
resources: parsedOptions?.resources,
|
||||
});
|
||||
}
|
||||
|
||||
export async function signLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
}: SignLoginPayloadParams): Promise<LoginPayload> {
|
||||
const message = createLoginMessage(payload);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
|
||||
export async function buildAndSignLoginPayload({
|
||||
wallet,
|
||||
options,
|
||||
}: BuildLoginPayloadParams): Promise<LoginPayload> {
|
||||
const payload = await buildLoginPayload({ wallet, options });
|
||||
return signLoginPayload({ wallet, payload });
|
||||
}
|
||||
|
||||
export async function verifyLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
options,
|
||||
}: VerifyLoginPayloadParams): Promise<string> {
|
||||
const parsedOptions = VerifyOptionsSchema.parse(options);
|
||||
|
||||
if (payload.payload.type !== wallet.type) {
|
||||
throw new Error(
|
||||
`Expected chain type '${wallet.type}' does not match chain type on payload '${payload.payload.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the intended domain matches the domain of the payload
|
||||
if (payload.payload.domain !== parsedOptions.domain) {
|
||||
throw new Error(
|
||||
`Expected domain '${parsedOptions.domain}' does not match domain on payload '${payload.payload.domain}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the payload statement matches the expected statement
|
||||
if (parsedOptions?.statement) {
|
||||
if (payload.payload.statement !== parsedOptions.statement) {
|
||||
throw new Error(
|
||||
`Expected statement '${parsedOptions.statement}' does not match statement on payload '${payload.payload.statement}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended URI matches the URI of the payload
|
||||
if (parsedOptions?.uri) {
|
||||
if (payload.payload.uri !== parsedOptions.uri) {
|
||||
throw new Error(
|
||||
`Expected URI '${parsedOptions.uri}' does not match URI on payload '${payload.payload.uri}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended version matches the version of the payload
|
||||
if (parsedOptions?.version) {
|
||||
if (payload.payload.version !== parsedOptions.version) {
|
||||
throw new Error(
|
||||
`Expected version '${parsedOptions.version}' does not match version on payload '${payload.payload.version}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended chain ID matches the chain ID of the payload
|
||||
if (parsedOptions?.chainId) {
|
||||
if (payload.payload.chain_id !== parsedOptions.chainId) {
|
||||
throw new Error(
|
||||
`Expected chain ID '${parsedOptions.chainId}' does not match chain ID on payload '${payload.payload.chain_id}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the payload nonce is valid
|
||||
if (parsedOptions?.validateNonce !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateNonce(payload.payload.nonce);
|
||||
} catch (err) {
|
||||
throw new Error(`Login request nonce is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that it isn't before the invalid before time
|
||||
const currentTime = new Date();
|
||||
if (currentTime < new Date(payload.payload.invalid_before)) {
|
||||
throw new Error(`Login request is not yet valid`);
|
||||
}
|
||||
|
||||
// Check that the payload hasn't expired
|
||||
if (currentTime > new Date(payload.payload.expiration_time)) {
|
||||
throw new Error(`Login request has expired`);
|
||||
}
|
||||
|
||||
// Check that the specified resources are present on the payload
|
||||
if (parsedOptions?.resources) {
|
||||
const missingResources = parsedOptions.resources.filter(
|
||||
(resource) => !payload.payload.resources?.includes(resource),
|
||||
);
|
||||
if (missingResources.length > 0) {
|
||||
throw new Error(
|
||||
`Login request is missing required resources: ${missingResources.join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the signing address is the claimed wallet address
|
||||
const message = createLoginMessage(payload.payload);
|
||||
const chainId =
|
||||
wallet.type === "evm" && payload.payload.chain_id
|
||||
? parseInt(payload.payload.chain_id)
|
||||
: undefined;
|
||||
const verified = await wallet.verifySignature(
|
||||
message,
|
||||
payload.signature,
|
||||
payload.payload.address,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`Signer address does not match payload address '${payload.payload.address.toLowerCase()}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return payload.payload.address;
|
||||
}
|
||||
@@ -1,2 +1,25 @@
|
||||
// Export thirdweb auth class
|
||||
export { ThirdwebAuth } from "./auth";
|
||||
export * from "./schema";
|
||||
|
||||
// Export individual auth functions
|
||||
export {
|
||||
generateJWT,
|
||||
parseJWT,
|
||||
refreshJWT,
|
||||
authenticateJWT,
|
||||
} from "./functions/jwt";
|
||||
export {
|
||||
buildLoginPayload,
|
||||
signLoginPayload,
|
||||
buildAndSignLoginPayload,
|
||||
verifyLoginPayload,
|
||||
} from "./functions/login";
|
||||
|
||||
// Export schema files individually
|
||||
export * from "./schema/authenticate";
|
||||
export * from "./schema/common";
|
||||
export * from "./schema/functions";
|
||||
export * from "./schema/generate";
|
||||
export * from "./schema/login";
|
||||
export * from "./schema/refresh";
|
||||
export * from "./schema/verify";
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
import { utils, BigNumber } from "ethers";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { z } from "zod";
|
||||
|
||||
export const AddressSchema = z.string().refine(
|
||||
(arg) => utils.isAddress(arg),
|
||||
(out) => {
|
||||
return {
|
||||
message: `${out} is not a valid address`,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const RawDateSchema = z.date().transform((i) => {
|
||||
return BigNumber.from(Math.floor(i.getTime() / 1000));
|
||||
});
|
||||
|
||||
export const AccountTypeSchema = z.union([
|
||||
z.literal("evm"),
|
||||
z.literal("solana"),
|
||||
]);
|
||||
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
type Literal = z.infer<typeof literalSchema>;
|
||||
export type Json = Literal | { [key: string]: Json } | Json[];
|
||||
const JsonSchema: z.ZodType<Json> = z.lazy(
|
||||
() => z.union([literalSchema, z.array(JsonSchema), z.record(JsonSchema)]),
|
||||
{ invalid_type_error: "Provided value was not valid JSON" },
|
||||
);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
nonce: z.string().optional(),
|
||||
expirationTime: z.date().optional(),
|
||||
invalidBefore: z.date().optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginPayloadDataSchema = z.object({
|
||||
type: AccountTypeSchema,
|
||||
domain: z.string(),
|
||||
address: z.string(),
|
||||
statement: z
|
||||
.string()
|
||||
.default(
|
||||
"Please ensure that the domain above matches the URL of the current website.",
|
||||
),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().default("1"),
|
||||
chain_id: z.string().optional(),
|
||||
nonce: z.string().default(uuidv4()),
|
||||
issued_at: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
expiration_time: z.date().transform((d) => d.toISOString()),
|
||||
invalid_before: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginPayloadSchema = z.object({
|
||||
payload: LoginPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
const VerifyOptionsSchemaRequired = z.object({
|
||||
domain: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
validateNonce: z.function().args(z.string()).optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const VerifyOptionsSchema = VerifyOptionsSchemaRequired.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const GenerateOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
tokenId: z.string().optional(),
|
||||
expirationTime: z.date().optional(),
|
||||
invalidBefore: z.date().optional(),
|
||||
session: z.union([JsonSchema, z.function().args(z.string())]).optional(),
|
||||
verifyOptions: VerifyOptionsSchemaRequired.omit({
|
||||
domain: true,
|
||||
}).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticationPayloadDataSchema = z.object({
|
||||
iss: z.string(),
|
||||
sub: z.string(),
|
||||
aud: z.string(),
|
||||
exp: RawDateSchema.transform((b) => b.toNumber()),
|
||||
nbf: RawDateSchema.transform((b) => b.toNumber()),
|
||||
iat: RawDateSchema.transform((b) => b.toNumber()),
|
||||
jti: z.string().default(uuidv4()),
|
||||
ctx: JsonSchema.optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticationPayloadSchema = z.object({
|
||||
payload: AuthenticationPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticateOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
validateTokenId: z.function().args(z.string()).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginOptions = z.input<typeof LoginOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginPayloadData = z.output<typeof LoginPayloadDataSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginPayload = z.output<typeof LoginPayloadSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type VerifyOptions = z.input<typeof VerifyOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GenerateOptions = z.input<typeof GenerateOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticationPayloadData = z.output<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticationPayload = z.output<
|
||||
typeof AuthenticationPayloadSchema
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticateOptions = z.output<typeof AuthenticateOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type User<TContext extends Json = Json> = {
|
||||
address: string;
|
||||
session?: TContext;
|
||||
};
|
||||
|
||||
export const LoginPayloadOutputSchema = LoginPayloadSchema.extend({
|
||||
payload: LoginPayloadDataSchema.extend({
|
||||
issued_at: z.string(),
|
||||
expiration_time: z.string(),
|
||||
invalid_before: z.string(),
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { AddressSchema, JsonSchema, RawDateSchema } from "./common";
|
||||
|
||||
export const AuthenticationPayloadDataSchema = z.object({
|
||||
iss: z.string(),
|
||||
sub: z.string(),
|
||||
aud: z.string(),
|
||||
exp: RawDateSchema,
|
||||
nbf: RawDateSchema,
|
||||
iat: RawDateSchema,
|
||||
jti: z.string().default(uuidv4()),
|
||||
ctx: JsonSchema.optional(),
|
||||
});
|
||||
|
||||
export const AuthenticationPayloadSchema = z.object({
|
||||
payload: AuthenticationPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
export const AuthenticateOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
issuerAddress: AddressSchema.optional(),
|
||||
validateTokenId: z.function().args(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type AuthenticationPayloadDataInput = z.input<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
export type AuthenticationPayloadData = z.output<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
export type AuthenticationPayload = z.output<
|
||||
typeof AuthenticationPayloadSchema
|
||||
>;
|
||||
|
||||
export type AuthenticateOptions = z.output<typeof AuthenticateOptionsSchema>;
|
||||
|
||||
export type AuthenticateOptionsWithOptionalDomain = Omit<
|
||||
AuthenticateOptions,
|
||||
"domain"
|
||||
> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { utils } from "ethers";
|
||||
import { z } from "zod";
|
||||
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
type Literal = z.infer<typeof literalSchema>;
|
||||
export type Json = Literal | { [key: string]: Json } | Json[];
|
||||
|
||||
export const JsonSchema: z.ZodType<Json> = z.lazy(
|
||||
() => z.union([literalSchema, z.array(JsonSchema), z.record(JsonSchema)]),
|
||||
{ invalid_type_error: "Provided value was not valid JSON" },
|
||||
);
|
||||
|
||||
export const AddressSchema = z.string().refine(
|
||||
(arg) => utils.isAddress(arg),
|
||||
(out) => {
|
||||
return {
|
||||
message: `${out} is not a valid address`,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const RawDateSchema = z.date().transform((i) => {
|
||||
return Math.floor(i.getTime() / 1000);
|
||||
});
|
||||
|
||||
export const AccountTypeSchema = z.union([
|
||||
z.literal("evm"),
|
||||
z.literal("solana"),
|
||||
]);
|
||||
|
||||
export type User<TContext extends Json = Json> = {
|
||||
address: string;
|
||||
session?: TContext;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { LoginOptions, LoginPayload, LoginPayloadData } from "./login";
|
||||
import { VerifyOptions } from "./verify";
|
||||
import {
|
||||
AuthenticateOptions,
|
||||
AuthenticationPayloadDataInput,
|
||||
} from "./authenticate";
|
||||
import { RefreshOptions } from "./refresh";
|
||||
import { GenerateOptions } from "./generate";
|
||||
|
||||
export type BuildLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
options: LoginOptions;
|
||||
};
|
||||
|
||||
export type SignLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayloadData;
|
||||
};
|
||||
|
||||
export type VerifyLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayload;
|
||||
options: VerifyOptions;
|
||||
};
|
||||
|
||||
export type BuildJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: AuthenticationPayloadDataInput;
|
||||
};
|
||||
|
||||
export type GenerateJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayload;
|
||||
options: GenerateOptions;
|
||||
};
|
||||
|
||||
export type RefreshJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
jwt: string;
|
||||
options?: RefreshOptions;
|
||||
};
|
||||
|
||||
export type AuthenticateJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
jwt: string;
|
||||
options: AuthenticateOptions;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
import { VerifyOptionsSchema } from "./verify";
|
||||
import { JsonSchema } from "./common";
|
||||
import { THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const GenerateOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
tokenId: z.string().optional(),
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
invalidBefore: z.date().optional(),
|
||||
session: z.union([JsonSchema, z.function().args(z.string())]).optional(),
|
||||
verifyOptions: VerifyOptionsSchema.omit({
|
||||
domain: true,
|
||||
}).optional(),
|
||||
});
|
||||
|
||||
export type GenerateOptions = z.input<typeof GenerateOptionsSchema>;
|
||||
|
||||
export type GenerateOptionsWithOptionalDomain = Omit<
|
||||
GenerateOptions,
|
||||
"domain"
|
||||
> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import { z } from "zod";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { AccountTypeSchema } from "./common";
|
||||
import { THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const LoginOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
address: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
nonce: z.string().optional(),
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() +
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
invalidBefore: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() -
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export const LoginPayloadDataSchema = z.object({
|
||||
type: AccountTypeSchema,
|
||||
domain: z.string(),
|
||||
address: z.string(),
|
||||
statement: z
|
||||
.string()
|
||||
.default(
|
||||
"Please ensure that the domain above matches the URL of the current website.",
|
||||
),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().default("1"),
|
||||
chain_id: z.string().optional(),
|
||||
nonce: z.string().default(uuidv4()),
|
||||
issued_at: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
expiration_time: z.date().transform((d) => d.toISOString()),
|
||||
invalid_before: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export const LoginPayloadSchema = z.object({
|
||||
payload: LoginPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
export const LoginPayloadOutputSchema = LoginPayloadSchema.extend({
|
||||
payload: LoginPayloadDataSchema.extend({
|
||||
issued_at: z.string(),
|
||||
expiration_time: z.string(),
|
||||
invalid_before: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export type LoginOptions = z.input<typeof LoginOptionsSchema>;
|
||||
|
||||
export type LoginPayloadData = z.output<typeof LoginPayloadDataSchema>;
|
||||
|
||||
export type LoginPayload = z.output<typeof LoginPayloadSchema>;
|
||||
|
||||
export type LoginOptionsWithOptionalDomain = Omit<LoginOptions, "domain"> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from "zod";
|
||||
import { THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const RefreshOptionsSchema = z.object({
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
export type RefreshOptions = z.input<typeof RefreshOptionsSchema>;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const VerifyOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
validateNonce: z.function().args(z.string()).optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type VerifyOptions = z.input<typeof VerifyOptionsSchema>;
|
||||
|
||||
export type VerifyOptionsWithOptionalDomain = Omit<VerifyOptions, "domain"> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const isBrowser = () => typeof window !== "undefined";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const isNode = () => !isBrowser();
|
||||
@@ -1,24 +1,56 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { Json } from "../../core/schema";
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { Request } from "express";
|
||||
|
||||
function getToken(req: Request): string | undefined {
|
||||
export function getCookie(req: Request, cookie: string): string | undefined {
|
||||
if (typeof req.cookies.get === "function") {
|
||||
return req.cookies.get(cookie);
|
||||
}
|
||||
|
||||
return req.cookies[cookie];
|
||||
}
|
||||
|
||||
export function getActiveCookie(req: Request): string | undefined {
|
||||
if (!req.cookies) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const activeAccount = getCookie(req, THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE);
|
||||
if (activeAccount) {
|
||||
return `${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${activeAccount}`;
|
||||
}
|
||||
|
||||
// If active account is not present, then use the old default
|
||||
return THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param req
|
||||
* @returns
|
||||
*/
|
||||
export function getToken(req: Request): string | undefined {
|
||||
if (req.headers["authorization"]) {
|
||||
const authorizationHeader = req.headers["authorization"].split(" ");
|
||||
if (authorizationHeader?.length === 2) {
|
||||
return authorizationHeader[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.cookies) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const cookie: string | undefined = !req.cookies
|
||||
? undefined
|
||||
: typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
const activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return cookie;
|
||||
return getCookie(req, activeCookie);
|
||||
}
|
||||
|
||||
export async function getUser<
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Json, ThirdwebAuth as ThirdwebAuthSDK } from "../core";
|
||||
import { getUser } from "./helpers/user";
|
||||
import payloadHandler from "./routes/payload";
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import switchAccountHandler from "./routes/switch-account";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
@@ -12,6 +14,7 @@ import cookieParser from "cookie-parser";
|
||||
import express, { Request, Response } from "express";
|
||||
|
||||
export * from "./types";
|
||||
export { getToken } from "./helpers/user";
|
||||
|
||||
const asyncHandler =
|
||||
(fn: CallableFunction) =>
|
||||
@@ -47,6 +50,13 @@ export function ThirdwebAuth<
|
||||
router.use(express.json());
|
||||
router.use(cookieMiddleware);
|
||||
|
||||
router.post(
|
||||
"/payload",
|
||||
asyncHandler((req: Request, res: Response) =>
|
||||
payloadHandler(req, res, ctx as ThirdwebAuthContext),
|
||||
),
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/login",
|
||||
asyncHandler((req: Request, res: Response) =>
|
||||
@@ -68,6 +78,13 @@ export function ThirdwebAuth<
|
||||
),
|
||||
);
|
||||
|
||||
router.post(
|
||||
"/switch-account",
|
||||
asyncHandler((req: Request, res: Response) =>
|
||||
switchAccountHandler(req, res, ctx as ThirdwebAuthContext),
|
||||
),
|
||||
);
|
||||
|
||||
return {
|
||||
authRouter: router,
|
||||
authMiddleware: cookieMiddleware,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { GenerateOptions } from "../../core";
|
||||
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
@@ -64,18 +68,34 @@ export default async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(token);
|
||||
|
||||
// Securely set httpOnly cookie on request to prevent XSS on frontend
|
||||
// And set path to / to enable thirdweb_auth_token usage on all endpoints
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", token, {
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${payload.payload.address}`,
|
||||
token,
|
||||
{
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
);
|
||||
]);
|
||||
|
||||
// Send token in body and as cookie for frontend and backend use cases
|
||||
return res.status(200).json({ token });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getUser } from "../helpers/user";
|
||||
import { getActiveCookie, getUser } from "../helpers/user";
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
import { Request, Response } from "express";
|
||||
@@ -14,6 +14,13 @@ export default async function handler(
|
||||
});
|
||||
}
|
||||
|
||||
const activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return res.status(400).json({
|
||||
error: "No logged in user to logout.",
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onLogout) {
|
||||
const user = await getUser(req, ctx);
|
||||
if (user) {
|
||||
@@ -24,7 +31,7 @@ export default async function handler(
|
||||
// Set the access token to 'none' and expire in 5 seconds
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
serialize(activeCookie, "", {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Request, Response } from "express";
|
||||
import { PayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
|
||||
export default async function handler(
|
||||
req: Request,
|
||||
res: Response,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
error: "Invalid method. Only POST supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const parsedPayload = PayloadBodySchema.safeParse(req.body);
|
||||
if (!parsedPayload.success) {
|
||||
return res.status(400).json({ error: "Please provide an address" });
|
||||
}
|
||||
|
||||
// TODO: Add nonce generation + custom expiration + invalid before
|
||||
const payload = await ctx.auth.payload({
|
||||
address: parsedPayload.data.address,
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Request, Response } from "express";
|
||||
import { ActiveBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { getCookie } from "../helpers/user";
|
||||
|
||||
export default async function handler(
|
||||
req: Request,
|
||||
res: Response,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
error: "Invalid method. Only POST supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const parsedPayload = ActiveBodySchema.safeParse(req.body);
|
||||
if (!parsedPayload.success) {
|
||||
return res.status(400).json({ error: "Please provide an address" });
|
||||
}
|
||||
|
||||
let cookieExpiration: Date;
|
||||
const cookie = getCookie(
|
||||
req,
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${parsedPayload.data.address}`,
|
||||
);
|
||||
|
||||
if (cookie) {
|
||||
// If the new account is already logged in, get the expiration time from the cookie
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(cookie);
|
||||
cookieExpiration = new Date(exp * 1000);
|
||||
} else if (ctx.authOptions?.tokenDurationInSeconds) {
|
||||
// Otherwise, if we have a token duration in seconds, set it to that
|
||||
cookieExpiration = new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds,
|
||||
);
|
||||
} else {
|
||||
// Otherwise, just default to 24 hours
|
||||
cookieExpiration = new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
);
|
||||
}
|
||||
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, parsedPayload.data.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: cookieExpiration,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
return res.status(200).end();
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
import { getUser } from "../helpers/user";
|
||||
import { serialize } from "cookie";
|
||||
import { getToken, getUser } from "../helpers/user";
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { Request, Response } from "express";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
|
||||
export default async function handler(
|
||||
req: Request,
|
||||
@@ -14,5 +20,54 @@ export default async function handler(
|
||||
}
|
||||
|
||||
const user = await getUser(req, ctx);
|
||||
|
||||
// Importantly, make sure the user was actually logged in before refreshing
|
||||
if (user) {
|
||||
const token = getToken(req);
|
||||
if (token) {
|
||||
const payload = ctx.auth.parseToken(token);
|
||||
|
||||
const refreshDate = ctx.authOptions?.refreshIntervalInSeconds
|
||||
? new Date(
|
||||
payload.payload.iat * 1000 +
|
||||
ctx.authOptions.refreshIntervalInSeconds * 1000,
|
||||
)
|
||||
: new Date(
|
||||
payload.payload.iat * 1000 +
|
||||
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS * 1000,
|
||||
);
|
||||
|
||||
if (new Date() > refreshDate) {
|
||||
const expirationTime = ctx.authOptions?.tokenDurationInSeconds
|
||||
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
|
||||
: undefined;
|
||||
const refreshedToken = await ctx.auth.refresh(token, expirationTime);
|
||||
const refreshedPayload = ctx.auth.parseToken(refreshedToken);
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${user.address}`,
|
||||
refreshedToken,
|
||||
{
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json(user);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { ThirdwebAuth } from "../../core";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core/schema";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { Request } from "express";
|
||||
import { z } from "zod";
|
||||
|
||||
export const PayloadBodySchema = z.object({
|
||||
address: z.string(),
|
||||
chainId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ActiveBodySchema = z.object({
|
||||
address: z.string(),
|
||||
});
|
||||
|
||||
export const LoginPayloadBodySchema = z.object({
|
||||
payload: LoginPayloadOutputSchema,
|
||||
});
|
||||
@@ -35,7 +44,9 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
cookieOptions?: {
|
||||
domain?: string;
|
||||
|
||||
@@ -1,9 +1,40 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { Json } from "../../core/schema";
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { GetServerSidePropsContext, NextApiRequest } from "next";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
function getToken(
|
||||
export function getCookie(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
cookie: string,
|
||||
): string | undefined {
|
||||
if (typeof req.cookies.get === "function") {
|
||||
return req.cookies.get(cookie);
|
||||
}
|
||||
|
||||
return (req.cookies as any)[cookie];
|
||||
}
|
||||
|
||||
export function getActiveCookie(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
): string | undefined {
|
||||
if (!req.cookies) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const activeAccount = getCookie(req, THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE);
|
||||
if (activeAccount) {
|
||||
return `${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${activeAccount}`;
|
||||
}
|
||||
|
||||
// If active account is not present, then use the old default
|
||||
return THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX;
|
||||
}
|
||||
|
||||
export function getToken(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
): string | undefined {
|
||||
if (!!(req as NextApiRequest).headers["authorization"]) {
|
||||
@@ -13,17 +44,18 @@ function getToken(
|
||||
if (authorizationHeader?.length === 2) {
|
||||
return authorizationHeader[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.cookies) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const cookie: string | undefined = !req.cookies
|
||||
? undefined
|
||||
: typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
const activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return cookie;
|
||||
return getCookie(req, activeCookie);
|
||||
}
|
||||
|
||||
export async function getUser<
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Json, ThirdwebAuth as ThirdwebAuthSDK } from "../core";
|
||||
import { getUser } from "./helpers/user";
|
||||
import payloadHandler from "./routes/payload";
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import switchAccountHandler from "./routes/switch-account";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
@@ -27,12 +29,16 @@ async function ThirdwebAuthRouter(
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "payload":
|
||||
return await payloadHandler(req, res, ctx);
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res, ctx);
|
||||
case "switch-account":
|
||||
return await switchAccountHandler(req, res, ctx);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { GenerateOptions } from "../../core";
|
||||
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
@@ -64,18 +68,34 @@ export default async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(token);
|
||||
|
||||
// Securely set httpOnly cookie on request to prevent XSS on frontend
|
||||
// And set path to / to enable thirdweb_auth_token usage on all endpoints
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", token, {
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${payload.payload.address}`,
|
||||
token,
|
||||
{
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
);
|
||||
]);
|
||||
|
||||
// Send token in body and as cookie for frontend and backend use cases
|
||||
return res.status(200).json({ token });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getUser } from "../helpers/user";
|
||||
import { getActiveCookie, getUser } from "../helpers/user";
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
@@ -14,6 +14,13 @@ export default async function handler(
|
||||
});
|
||||
}
|
||||
|
||||
const activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return res.status(400).json({
|
||||
error: "No logged in user to logout.",
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onLogout) {
|
||||
const user = await getUser(req, ctx);
|
||||
if (user) {
|
||||
@@ -24,7 +31,7 @@ export default async function handler(
|
||||
// Set the access token to 'none' and expire in 5 seconds
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
serialize(activeCookie, "", {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { PayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
error: "Invalid method. Only POST supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const parsedPayload = PayloadBodySchema.safeParse(req.body);
|
||||
if (!parsedPayload.success) {
|
||||
return res.status(400).json({ error: "Please provide an address" });
|
||||
}
|
||||
|
||||
// TODO: Add nonce generation + custom expiration + invalid before
|
||||
const payload = await ctx.auth.payload({
|
||||
address: parsedPayload.data.address,
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { serialize } from "cookie";
|
||||
import { getCookie } from "../helpers/user";
|
||||
import { ActiveBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({
|
||||
error: "Invalid method. Only POST supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const parsedPayload = ActiveBodySchema.safeParse(req.body);
|
||||
if (!parsedPayload.success) {
|
||||
return res.status(400).json({ error: "Please provide an address" });
|
||||
}
|
||||
|
||||
let cookieExpiration: Date;
|
||||
const cookie = getCookie(
|
||||
req,
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${parsedPayload.data.address}`,
|
||||
);
|
||||
|
||||
if (cookie) {
|
||||
// If the new account is already logged in, get the expiration time from the cookie
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(cookie);
|
||||
cookieExpiration = new Date(exp * 1000);
|
||||
} else if (ctx.authOptions?.tokenDurationInSeconds) {
|
||||
// Otherwise, if we have a token duration in seconds, set it to that
|
||||
cookieExpiration = new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds,
|
||||
);
|
||||
} else {
|
||||
// Otherwise, just default to 24 hours
|
||||
cookieExpiration = new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
);
|
||||
}
|
||||
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, parsedPayload.data.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: cookieExpiration,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
return res.status(200).end();
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
import { getUser } from "../helpers/user";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { getToken, getUser } from "../helpers/user";
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
@@ -14,5 +20,54 @@ export default async function handler(
|
||||
}
|
||||
|
||||
const user = await getUser(req, ctx);
|
||||
|
||||
// Importantly, make sure the user was actually logged in before refreshing
|
||||
if (user) {
|
||||
const token = getToken(req);
|
||||
if (token) {
|
||||
const payload = ctx.auth.parseToken(token);
|
||||
|
||||
const refreshDate = ctx.authOptions?.refreshIntervalInSeconds
|
||||
? new Date(
|
||||
payload.payload.iat * 1000 +
|
||||
ctx.authOptions.refreshIntervalInSeconds * 1000,
|
||||
)
|
||||
: new Date(
|
||||
payload.payload.iat * 1000 +
|
||||
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS * 1000,
|
||||
);
|
||||
|
||||
if (new Date() > refreshDate) {
|
||||
const expirationTime = ctx.authOptions?.tokenDurationInSeconds
|
||||
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
|
||||
: undefined;
|
||||
const refreshedToken = await ctx.auth.refresh(token, expirationTime);
|
||||
const refreshedPayload = ctx.auth.parseToken(refreshedToken);
|
||||
res.setHeader("Set-Cookie", [
|
||||
serialize(
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${user.address}`,
|
||||
refreshedToken,
|
||||
{
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json(user);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import { ThirdwebAuth } from "../../core";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core/schema";
|
||||
import { Json, LoginPayloadOutputSchema, ThirdwebAuth, User } from "../../core";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { GetServerSidePropsContext, NextApiRequest } from "next";
|
||||
import { NextRequest } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
export const PayloadBodySchema = z.object({
|
||||
address: z.string(),
|
||||
chainId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ActiveBodySchema = z.object({
|
||||
address: z.string(),
|
||||
});
|
||||
|
||||
export const LoginPayloadBodySchema = z.object({
|
||||
payload: LoginPayloadOutputSchema,
|
||||
});
|
||||
@@ -14,7 +22,12 @@ type RequestType =
|
||||
| NextRequest
|
||||
| NextApiRequest;
|
||||
|
||||
export type ThirdwebAuthRoute = "login" | "logout" | "user";
|
||||
export type ThirdwebAuthRoute =
|
||||
| "payload"
|
||||
| "login"
|
||||
| "logout"
|
||||
| "user"
|
||||
| "switch-account";
|
||||
|
||||
export type ThirdwebAuthUser<
|
||||
TData extends Json = Json,
|
||||
@@ -41,7 +54,9 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
cookieOptions?: {
|
||||
domain?: string;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { EthersWallet } from "@thirdweb-dev/wallets/evm/wallets/ethers";
|
||||
import { expect } from "chai";
|
||||
import { Wallet } from "ethers";
|
||||
|
||||
describe("Wallet Authentication", async () => {
|
||||
describe("Wallet Authentication - EVM", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
@@ -272,7 +272,7 @@ describe("Wallet Authentication", async () => {
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
`Expected the connected wallet address '${await signerWallet.getAddress()}' to match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
`The expected issuer address '${await signerWallet.getAddress()}' did not match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -350,4 +350,24 @@ describe("Wallet Authentication", async () => {
|
||||
role: "admin",
|
||||
});
|
||||
});
|
||||
|
||||
it("Should authenticate with issuer address", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
auth.updateWallet(attackerWallet);
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("The expected issuer address");
|
||||
}
|
||||
|
||||
const user = await auth.authenticate(token, {
|
||||
issuerAddress: await adminWallet.getAddress(),
|
||||
});
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("Wallet Authentication", async () => {
|
||||
describe("Wallet Authentication - Solana", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
@@ -272,7 +272,7 @@ describe("Wallet Authentication", async () => {
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
`Expected the connected wallet address '${await signerWallet.getAddress()}' to match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
`The expected issuer address '${await signerWallet.getAddress()}' did not match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,211 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1506](https://github.com/thirdweb-dev/js/pull/1506) [`f97ddf4c`](https://github.com/thirdweb-dev/js/commit/f97ddf4c7f14854f3b204ad9741b52ddb8dac736) Thanks [@jnsdls](https://github.com/jnsdls)! - add xpla chains & update chains
|
||||
|
||||
## 0.1.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1499](https://github.com/thirdweb-dev/js/pull/1499) [`8f3b685a`](https://github.com/thirdweb-dev/js/commit/8f3b685ad2bd73cb4d5d8c8aa25c04ffc10fb7cf) Thanks [@Marfuen](https://github.com/Marfuen)! - Update deploy command from CLI to use show a public gateway url temporarily. Updated chains too.
|
||||
|
||||
## 0.1.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1469](https://github.com/thirdweb-dev/js/pull/1469) [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
- [#1474](https://github.com/thirdweb-dev/js/pull/1474) [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9) Thanks [@adam-maj](https://github.com/adam-maj)! - Add back scroll-alpha-testnet
|
||||
|
||||
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Update chains
|
||||
|
||||
- [#1461](https://github.com/thirdweb-dev/js/pull/1461) [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - add xai-goerli chain and support BigInteger from Unity
|
||||
|
||||
## 0.1.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1450](https://github.com/thirdweb-dev/js/pull/1450) [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - update chains
|
||||
|
||||
## 0.1.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1436](https://github.com/thirdweb-dev/js/pull/1436) [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Updated chains
|
||||
|
||||
- [#1432](https://github.com/thirdweb-dev/js/pull/1432) [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
## 0.1.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
## 0.1.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1407](https://github.com/thirdweb-dev/js/pull/1407) [`0a5eb19d`](https://github.com/thirdweb-dev/js/commit/0a5eb19d672909027bb6c7e79ea76d431535559c) Thanks [@jnsdls](https://github.com/jnsdls)! - remove non-standard urls
|
||||
|
||||
- [#1409](https://github.com/thirdweb-dev/js/pull/1409) [`b1e8c8e2`](https://github.com/thirdweb-dev/js/commit/b1e8c8e231013182eb46c16d0c441ee0f3bdfdb2) Thanks [@jnsdls](https://github.com/jnsdls)! - update dependencies
|
||||
|
||||
- [#1376](https://github.com/thirdweb-dev/js/pull/1376) [`48ca58b7`](https://github.com/thirdweb-dev/js/commit/48ca58b7aa45348b928932b9c7b76b3dc233e429) Thanks [@iketw](https://github.com/iketw)! - Pass bundleId if present
|
||||
|
||||
- [#1399](https://github.com/thirdweb-dev/js/pull/1399) [`3152d4e9`](https://github.com/thirdweb-dev/js/commit/3152d4e9b42e2777316b1b58513657f4430cb79a) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
- [#1387](https://github.com/thirdweb-dev/js/pull/1387) [`aa6bdd08`](https://github.com/thirdweb-dev/js/commit/aa6bdd0809d1d5536c837c59b2d407ee974c1f9c) Thanks [@nkrishang](https://github.com/nkrishang)! - Simplify account permissions
|
||||
|
||||
- [#1405](https://github.com/thirdweb-dev/js/pull/1405) [`75587c8b`](https://github.com/thirdweb-dev/js/commit/75587c8b38bbbcf68d2101526e9792349cce728f) Thanks [@jnsdls](https://github.com/jnsdls)! - sort explorers (etherscan -> blockscout -> other)
|
||||
|
||||
- [#1385](https://github.com/thirdweb-dev/js/pull/1385) [`cc5e2ec5`](https://github.com/thirdweb-dev/js/commit/cc5e2ec51fce09af05be33811eb46980825829ee) Thanks [@iketw](https://github.com/iketw)! - Adds chains and improve error messages
|
||||
|
||||
- [#1378](https://github.com/thirdweb-dev/js/pull/1378) [`5a02c5ec`](https://github.com/thirdweb-dev/js/commit/5a02c5ec0288fd6dfb2b765ef70bb18e714aca19) Thanks [@MananTank](https://github.com/MananTank)! - add icon in MinimalChain
|
||||
|
||||
## 0.1.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1374](https://github.com/thirdweb-dev/js/pull/1374) [`7cb55e70`](https://github.com/thirdweb-dev/js/commit/7cb55e7051617268bba1b80146865c606ff6e66d) Thanks [@jnsdls](https://github.com/jnsdls)! -
|
||||
|
||||
## 0.1.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1371](https://github.com/thirdweb-dev/js/pull/1371) [`d665954f`](https://github.com/thirdweb-dev/js/commit/d665954fee0554985055bf06abbed8d7b8d5bc38) Thanks [@jnsdls](https://github.com/jnsdls)! - add more chains
|
||||
|
||||
## 0.1.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1366](https://github.com/thirdweb-dev/js/pull/1366) [`02ab92cc`](https://github.com/thirdweb-dev/js/commit/02ab92cc5c97f475e3b5642e5a7bdbe63ca136ee) Thanks [@jnsdls](https://github.com/jnsdls)! - new supported chains
|
||||
|
||||
- [#1358](https://github.com/thirdweb-dev/js/pull/1358) [`6cc4b8d2`](https://github.com/thirdweb-dev/js/commit/6cc4b8d28b982c5be3e1cd17d2a9a947001d1608) Thanks [@DLHTX](https://github.com/DLHTX)! - feat(chain): add iotex chain icon
|
||||
|
||||
## 0.1.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Adds support for clientId / secretKey
|
||||
|
||||
## 0.1.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1338](https://github.com/thirdweb-dev/js/pull/1338) [`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
## 0.1.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1335](https://github.com/thirdweb-dev/js/pull/1335) [`0407b2c2`](https://github.com/thirdweb-dev/js/commit/0407b2c2f39b5f3fa06e613e671623b5644b3a28) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains again
|
||||
|
||||
## 0.1.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1330](https://github.com/thirdweb-dev/js/pull/1330) [`a9093bcf`](https://github.com/thirdweb-dev/js/commit/a9093bcf287c01e3335fd780e2ccbfdb3380bf95) Thanks [@adam-maj](https://github.com/adam-maj)! - Override binance slug
|
||||
|
||||
## 0.1.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1328](https://github.com/thirdweb-dev/js/pull/1328) [`4393b228`](https://github.com/thirdweb-dev/js/commit/4393b2280505fd0b2284555d64eae6567e8401a5) Thanks [@adam-maj](https://github.com/adam-maj)! - Make base default chain
|
||||
|
||||
## 0.1.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1326](https://github.com/thirdweb-dev/js/pull/1326) [`40682191`](https://github.com/thirdweb-dev/js/commit/40682191450de08ad40b9d2957afced248657af2) Thanks [@adam-maj](https://github.com/adam-maj)! - Add base chain support
|
||||
|
||||
## 0.1.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1320](https://github.com/thirdweb-dev/js/pull/1320) [`fd74d791`](https://github.com/thirdweb-dev/js/commit/fd74d7918072cda03b52f852ebb3f8dccb84074d) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Linea mainnet support
|
||||
|
||||
- [#1315](https://github.com/thirdweb-dev/js/pull/1315) [`35f20ceb`](https://github.com/thirdweb-dev/js/commit/35f20ceb4f943e95d9566105096f06412978da7a) Thanks [@jnsdls](https://github.com/jnsdls)! - add more chains
|
||||
|
||||
## 0.1.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1299](https://github.com/thirdweb-dev/js/pull/1299) [`7e044c66`](https://github.com/thirdweb-dev/js/commit/7e044c664d8a034f5324b859ac3596860c86f9a5) Thanks [@nkrishang](https://github.com/nkrishang)! - Add ERC721LoyaltyCard and ERC721UpdatableMetadata
|
||||
|
||||
- [#1297](https://github.com/thirdweb-dev/js/pull/1297) [`b5c6eedb`](https://github.com/thirdweb-dev/js/commit/b5c6eedb38aa3c52eb97f3d25ad83e38c55afe61) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - add zksync as default chain
|
||||
|
||||
- [#1309](https://github.com/thirdweb-dev/js/pull/1309) [`4961b597`](https://github.com/thirdweb-dev/js/commit/4961b597a098dae0a4eff01a9ef268a65fe1a352) Thanks [@jnsdls](https://github.com/jnsdls)! - unblock storage domains
|
||||
|
||||
## 0.1.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
|
||||
|
||||
- [#1281](https://github.com/thirdweb-dev/js/pull/1281) [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96) Thanks [@nkrishang](https://github.com/nkrishang)! - Handle ERC4337Signer correctly for signTypedData
|
||||
|
||||
## 0.1.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1276](https://github.com/thirdweb-dev/js/pull/1276) [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad) Thanks [@MananTank](https://github.com/MananTank)! - Do not change order or RPCs in `getChainRPCs` to Fix RPC override issue
|
||||
|
||||
## 0.1.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1248](https://github.com/thirdweb-dev/js/pull/1248) [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - update chains
|
||||
|
||||
- [#1243](https://github.com/thirdweb-dev/js/pull/1243) [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19) Thanks [@therealharpaljadeja](https://github.com/therealharpaljadeja)! - update chains
|
||||
|
||||
## 0.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
|
||||
|
||||
## 0.1.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1229](https://github.com/thirdweb-dev/js/pull/1229) [`6816219a`](https://github.com/thirdweb-dev/js/commit/6816219ac13ae571a0c90db6ab389c319bc1f052) Thanks [@jnsdls](https://github.com/jnsdls)! - add/update chains
|
||||
|
||||
## 0.1.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1192](https://github.com/thirdweb-dev/js/pull/1192) [`f41f1a29`](https://github.com/thirdweb-dev/js/commit/f41f1a2958a2cedcf0496c9a3ca284d0b98f1b89) Thanks [@jnsdls](https://github.com/jnsdls)! - fix arbitrum goerli infura url
|
||||
|
||||
## 0.1.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1074](https://github.com/thirdweb-dev/js/pull/1074) [`cc20f93e`](https://github.com/thirdweb-dev/js/commit/cc20f93e178d86ee2b3f39102bbb0811de211f05) Thanks [@Marfuen](https://github.com/Marfuen)! - Enhance CLI Install command and update chains
|
||||
|
||||
- [#1185](https://github.com/thirdweb-dev/js/pull/1185) [`8e28b0f5`](https://github.com/thirdweb-dev/js/commit/8e28b0f5e75596d29273ed80269bcee6d209adb4) Thanks [@jnsdls](https://github.com/jnsdls)! - add Zora Mainnet
|
||||
|
||||
## 0.1.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1140](https://github.com/thirdweb-dev/js/pull/1140) [`16232de9`](https://github.com/thirdweb-dev/js/commit/16232de9eab9966e24e335929b2a3919346af265) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update chains
|
||||
|
||||
- [#1138](https://github.com/thirdweb-dev/js/pull/1138) [`645b0303`](https://github.com/thirdweb-dev/js/commit/645b0303cc1a9cbb0a0e9cbd67d11c3b865e4584) Thanks [@jcstein](https://github.com/jcstein)! - feat: create Taro Testnet
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1065](https://github.com/thirdweb-dev/js/pull/1065) [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a) Thanks [@iketw](https://github.com/iketw)! - [Chains] update chains
|
||||
|
||||
- [#1064](https://github.com/thirdweb-dev/js/pull/1064) [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c) Thanks [@MananTank](https://github.com/MananTank)! - Do not cache signer in wallets
|
||||
|
||||
- [#1047](https://github.com/thirdweb-dev/js/pull/1047) [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d) Thanks [@MananTank](https://github.com/MananTank)! - Fix tree-shaking issue in `@thirdweb-dev/chains`
|
||||
|
||||
- [#1090](https://github.com/thirdweb-dev/js/pull/1090) [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add base-goerli to default chains
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -10,9 +10,9 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}",
|
||||
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com"
|
||||
@@ -44,6 +44,17 @@ export default {
|
||||
"name": "etherscan",
|
||||
"url": "https://etherscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://eth.blockscout.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Optimism",
|
||||
"name": "OP Mainnet",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://mainnet.optimism.io/"
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.optimism.io",
|
||||
"https://optimism.publicnode.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -23,6 +24,17 @@ export default {
|
||||
"name": "etherscan",
|
||||
"url": "https://optimistic.etherscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://optimism.blockscout.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
|
||||
@@ -11,20 +11,24 @@ export default {
|
||||
"rpc": [
|
||||
"https://gnosis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.gnosischain.com",
|
||||
"https://rpc.gnosis.gateway.fm",
|
||||
"https://rpc.ankr.com/gnosis",
|
||||
"https://gnosischain-rpc.gateway.pokt.network",
|
||||
"https://gnosis-mainnet.public.blastapi.io",
|
||||
"https://gnosis.api.onfinality.io/public",
|
||||
"https://gnosis.blockpi.network/v1/rpc/public",
|
||||
"https://web3endpoints.com/gnosischain-mainnet",
|
||||
"https://gnosis.oat.farm",
|
||||
"wss://rpc.gnosischain.com/wss"
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com",
|
||||
"https://faucet.gimlu.com/gnosis",
|
||||
"https://stakely.io/faucet/gnosis-chain-xdai",
|
||||
"https://faucet.prussia.dev/xdai"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "xDAI",
|
||||
"symbol": "xDAI",
|
||||
"symbol": "XDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
@@ -34,19 +38,19 @@ export default {
|
||||
"slip44": 700,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "gnosisscan",
|
||||
"url": "https://gnosisscan.io",
|
||||
"name": "blockscout",
|
||||
"url": "https://gnosis.blockscout.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.com/xdai/mainnet",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"name": "gnosisscan",
|
||||
"url": "https://gnosisscan.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -11,7 +11,10 @@ export default {
|
||||
"rpc": [
|
||||
"https://gon-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://node1.testnet.gaiaopen.network",
|
||||
"http://database1.gaiaopen.network"
|
||||
"https://node1.mainnet.gon.network",
|
||||
"https://node2.mainnet.gon.network",
|
||||
"https://node3.mainnet.gon.network",
|
||||
"https://node4.mainnet.gon.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Japan Open Chain Testnet",
|
||||
"chain": "JOCT",
|
||||
"rpc": [
|
||||
"https://japan-open-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-1.testnet.japanopenchain.org:8545",
|
||||
"https://rpc-2.testnet.japanopenchain.org:8545"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Japan Open Chain Testnet Token",
|
||||
"symbol": "JOCT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.japanopenchain.org/",
|
||||
"shortName": "joct",
|
||||
"chainId": 10081,
|
||||
"networkId": 10081,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Testnet Block Explorer",
|
||||
"url": "https://explorer.testnet.japanopenchain.org",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "japan-open-chain-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Chiado Testnet",
|
||||
"chain": "CHI",
|
||||
"name": "Gnosis Chiado Testnet",
|
||||
"chain": "GNO",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeidk4swpgdyqmpz6shd5onvpaujvwiwthrhypufnwr6xh3dausz2dm",
|
||||
"width": 1800,
|
||||
@@ -9,16 +9,17 @@ export default {
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://gnosis-chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.chiadochain.net",
|
||||
"https://rpc.eu-central-2.gateway.fm/v3/gnosis/archival/chiado"
|
||||
"https://rpc.chiado.gnosis.gateway.fm",
|
||||
"wss://rpc.chiadochain.net/wss"
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Chiado xDAI",
|
||||
"symbol": "xDAI",
|
||||
"symbol": "XDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
@@ -28,16 +29,16 @@ export default {
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.chiadochain.net",
|
||||
"url": "https://gnosis-chiado.blockscout.com",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "chiado-testnet"
|
||||
"slug": "gnosis-chiado-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "MaxxChain Mainnet",
|
||||
"chain": "MaxxChain",
|
||||
"rpc": [
|
||||
"https://maxxchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.maxxchain.org",
|
||||
"https://rpc1.maxxchain.org",
|
||||
"https://rpc2.maxxchain.org"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.maxxchain.org"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Power",
|
||||
"symbol": "PWR",
|
||||
"decimals": 18
|
||||
},
|
||||
"icon": {
|
||||
"url": "ipfs://QmRhQG9TZrXDdbQeTzBmjg3pqgwaD5TKVZj8k4kaz8AoZx",
|
||||
"width": 1021,
|
||||
"height": 1021,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://www.maxxchain.org/",
|
||||
"shortName": "PWR",
|
||||
"chainId": 10201,
|
||||
"networkId": 10201,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "MaxxChain Block Explorer",
|
||||
"url": "https://explorer.maxxchain.org",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "maxxchain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Arthera Testnet",
|
||||
"chain": "AA",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYQp3e52KjkT4bYdAvB6ACEEpXs2D8DozsDitaADRY2Ak",
|
||||
"width": 1024,
|
||||
"height": 998,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://arthera-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-test.arthera.net"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.arthera.net"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Arthera",
|
||||
"symbol": "AA",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.arthera.net",
|
||||
"shortName": "aa",
|
||||
"chainId": 10243,
|
||||
"networkId": 10243,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer-test.arthera.net",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "arthera-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -20,12 +20,12 @@ export default {
|
||||
"nativeCurrency": {
|
||||
"name": "SMR",
|
||||
"symbol": "SMR",
|
||||
"decimals": 18
|
||||
"decimals": 6
|
||||
},
|
||||
"infoURL": "https://shimmer.network",
|
||||
"shortName": "shimmerevm-testnet",
|
||||
"chainId": 1071,
|
||||
"networkId": 1071,
|
||||
"chainId": 1072,
|
||||
"networkId": 1072,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "explorer",
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Mintara Testnet",
|
||||
"title": "Mintara Testnet",
|
||||
"chain": "Mintara",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeie7jzlzlpz7c3a3oh4x5joej23dj2qf3cexmchjyc72hv3fblcaja",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://mintara-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/mintara/testnet/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "MINTARA",
|
||||
"symbol": "MNTR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://playthink.co.jp",
|
||||
"shortName": "mintara-testnet",
|
||||
"chainId": 1079,
|
||||
"networkId": 1079,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "explorer",
|
||||
"url": "https://subnets-test.avax.network/mintara",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "mintara-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Mintara Mainnet",
|
||||
"title": "Mintara Mainnet",
|
||||
"chain": "Mintara",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeie7jzlzlpz7c3a3oh4x5joej23dj2qf3cexmchjyc72hv3fblcaja",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://mintara.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/mintara/mainnet/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "MINTARA",
|
||||
"symbol": "MNTR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://playthink.co.jp",
|
||||
"shortName": "mintara",
|
||||
"chainId": 1080,
|
||||
"networkId": 1080,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "explorer",
|
||||
"url": "https://subnets.avax.network/mintara",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "mintara"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Siberium Test Network",
|
||||
"chain": "SBR",
|
||||
"rpc": [
|
||||
"https://siberium-test-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.test.siberium.net"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "TestSIBR",
|
||||
"symbol": "SIBR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://siberium.net",
|
||||
"shortName": "testsbr",
|
||||
"chainId": 111000,
|
||||
"networkId": 111000,
|
||||
"icon": {
|
||||
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "svg"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Siberium Testnet Explorer - blockscout",
|
||||
"url": "https://explorer.test.siberium.net",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "svg"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "siberium-test-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Siberium",
|
||||
"symbol": "SBR",
|
||||
"symbol": "SIBR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://siberium.net",
|
||||
@@ -18,30 +18,19 @@ export default {
|
||||
"chainId": 111111,
|
||||
"networkId": 111111,
|
||||
"icon": {
|
||||
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
|
||||
"width": 1920,
|
||||
"height": 1920,
|
||||
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "svg"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Siberium Mainnet Explorer - blockscout - 1",
|
||||
"url": "https://explorer.main.siberium.net",
|
||||
"icon": {
|
||||
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
|
||||
"width": 1920,
|
||||
"height": 1920,
|
||||
"format": "svg"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Siberium Mainnet Explorer - blockscout - 2",
|
||||
"url": "https://explorer.main.siberium.net.ru",
|
||||
"icon": {
|
||||
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
|
||||
"width": 1920,
|
||||
"height": 1920,
|
||||
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "svg"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -5,9 +5,12 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://sepolia.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://sepolia.infura.io/v3/${INFURA_API_KEY}",
|
||||
"wss://sepolia.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://rpc.sepolia.org",
|
||||
"https://rpc2.sepolia.org",
|
||||
"https://rpc-sepolia.rockx.com"
|
||||
"https://rpc-sepolia.rockx.com",
|
||||
"https://rpc.sepolia.ethpandaops.io"
|
||||
],
|
||||
"faucets": [
|
||||
"http://fauceth.komputing.org?chain=11155111&address=${ADDRESS}"
|
||||
|
||||
@@ -27,9 +27,9 @@ export default {
|
||||
"name": "blockscout",
|
||||
"url": "https://coinbit-explorer.chain.sbcrypto.app",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -4,7 +4,8 @@ export default {
|
||||
"chain": "Haqq",
|
||||
"rpc": [
|
||||
"https://haqq-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.eth.haqq.network"
|
||||
"https://rpc.eth.haqq.network",
|
||||
"https://haqq-evm.publicnode.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Metachain One Mainnet",
|
||||
"chain": "METAO",
|
||||
"icon": {
|
||||
"url": "ipfs://QmTmo2QAtX5PbhX96vewnvH4Vc5H83Ft2DJGi6tAqTcFij",
|
||||
"width": 1000,
|
||||
"height": 981,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://metachain-one.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.metachain.one",
|
||||
"https://rpc2.metachain.one"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Metao",
|
||||
"symbol": "METAO",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://metachain.one",
|
||||
"shortName": "metao",
|
||||
"chainId": 112358,
|
||||
"networkId": 112358,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer.metachain.one",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "metachain-one"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Origin Testnet",
|
||||
"chain": "Origin",
|
||||
"rpc": [
|
||||
"https://origin-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://json-rpc.origin.uptick.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Origin",
|
||||
"symbol": "UOC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.uptick.network",
|
||||
"shortName": "auoc",
|
||||
"chainId": 1170,
|
||||
"networkId": 1170,
|
||||
"icon": {
|
||||
"url": "ipfs://QmRGJ6PqYHDTWuUQ6xfnK8S82NzRXiMjTnSGat9qtLuaLP",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Origin Explorer",
|
||||
"url": "https://evm-explorer.origin.uptick.network",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRGJ6PqYHDTWuUQ6xfnK8S82NzRXiMjTnSGat9qtLuaLP",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "origin-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "SatoshiChain Mainnet",
|
||||
"chain": "SATS",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRegpZQBW4o1imYNsW3d27MQjygBSU23Gf6JKje26nvs7",
|
||||
"width": 1251,
|
||||
"height": 1251,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://satoshichain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-rpc.satoshichain.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "SatoshiChain Coin",
|
||||
"symbol": "SATS",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://satoshichain.net",
|
||||
"shortName": "sats",
|
||||
"chainId": 12009,
|
||||
"networkId": 12009,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "SatoshiChain Explorer",
|
||||
"url": "https://satoshiscan.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "satoshichain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "BRC Chain Mainnet",
|
||||
"chain": "BRC",
|
||||
"rpc": [
|
||||
"https://brc-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.brcchain.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.brcchain.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "BRC Chain mainnet native token",
|
||||
"symbol": "BRC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://bridge.brcchain.io",
|
||||
"shortName": "BRC",
|
||||
"chainId": 12123,
|
||||
"networkId": 12123,
|
||||
"icon": {
|
||||
"url": "ipfs://QmX8qGX7xoZqYUpHxA85uZwQX2fgbTHvmddE1NfseDyBED",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "BRC Chain Explorer",
|
||||
"url": "https://scan.brcchain.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "brc-chain"
|
||||
} as const satisfies Chain;
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Ultron Testnet",
|
||||
"chain": "Ultron",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
"name": "Ultron Testnet Explorer",
|
||||
"url": "https://explorer.ultron-dev.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Ultron Mainnet",
|
||||
"chain": "Ultron",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
"name": "Ultron Explorer",
|
||||
"url": "https://ulxscan.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Swisstronik Testnet",
|
||||
"chain": "SWTR",
|
||||
"rpc": [
|
||||
"https://swisstronik-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://json-rpc.testnet.swisstronik.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.testnet.swisstronik.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Swisstronik",
|
||||
"symbol": "SWTR",
|
||||
"decimals": 18
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"infoURL": "https://www.swisstronik.com",
|
||||
"shortName": "swtr",
|
||||
"chainId": 1291,
|
||||
"networkId": 1291,
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeihuintkoipxalwans23vhxajbwjnozpy34ww7ia7ds7nay3rpylzi",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "svg"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Swisstronik Scout",
|
||||
"url": "https://explorer-evm.testnet.swisstronik.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "swisstronik-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Credit Smartchain Mainnet",
|
||||
"name": "Credit Smart Chain",
|
||||
"chain": "CREDIT",
|
||||
"rpc": [
|
||||
"https://credit-smartchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-rpc.cscscan.io"
|
||||
"https://credit-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.creditsmartchain.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
"infoURL": "https://creditsmartchain.com",
|
||||
"shortName": "Credit",
|
||||
"chainId": 13308,
|
||||
"networkId": 1,
|
||||
"networkId": 13308,
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
|
||||
"width": 1000,
|
||||
@@ -32,8 +32,8 @@ export default {
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "CSC Scan",
|
||||
"url": "https://explorer.cscscan.io",
|
||||
"name": "Creditscan",
|
||||
"url": "https://scan.creditsmartchain.com",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
|
||||
"width": 1000,
|
||||
@@ -44,5 +44,5 @@ export default {
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "credit-smartchain"
|
||||
"slug": "credit-smart-chain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Beam Testnet",
|
||||
"chain": "BEAM",
|
||||
"rpc": [
|
||||
"https://beam-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/beam/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Merit Circle",
|
||||
"symbol": "MC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://gaming.meritcircle.io",
|
||||
"shortName": "BEAM",
|
||||
"chainId": 13337,
|
||||
"networkId": 13337,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Beam Explorer",
|
||||
"url": "https://subnets-test.avax.network/beam",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "beam-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -27,9 +27,9 @@ export default {
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.bellecour.iex.ec",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -10,8 +10,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://polygon.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://polygon-rpc.com/",
|
||||
"https://rpc-mainnet.matic.network",
|
||||
"https://matic-mainnet.chainstacklabs.com",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Kalar Chain",
|
||||
"chain": "KLC",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreihfoy2kgf2rebaoicso7z5h7ju46z6gtr64mskkths3qbfkrtnkjm",
|
||||
"width": 190,
|
||||
"height": 170,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://kalar-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-api.kalarchain.tech"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Kalar",
|
||||
"symbol": "KLC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://kalarchain.tech",
|
||||
"shortName": "KLC",
|
||||
"chainId": 1379,
|
||||
"networkId": 1379,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "kalarscan",
|
||||
"url": "https://explorer.kalarchain.tech",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreidbzzv3lrwlzquhlpl4jcmr54sifhi5ufoek6olb5kjh3h3kvktdq",
|
||||
"width": 411,
|
||||
"height": 159,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "kalar-chain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Living Assets Mainnet",
|
||||
"chain": "LAS",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRidubY7BVwC737BQwGEttenP1npAXN7ZNryktE416uUW",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "jpg"
|
||||
},
|
||||
"rpc": [
|
||||
"https://living-assets.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://beta.mainnet.livingassets.io/rpc",
|
||||
"https://gamma.mainnet.livingassets.io/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "LAS",
|
||||
"symbol": "LAS",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://dev.livingassets.io/",
|
||||
"shortName": "LAS",
|
||||
"chainId": 1440,
|
||||
"networkId": 1440,
|
||||
"testnet": false,
|
||||
"slug": "living-assets"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Humanode Testnet 5 Israfel",
|
||||
"chain": "Humanode Testnet 5",
|
||||
"rpc": [
|
||||
"https://humanode-testnet-5-israfel.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://explorer-rpc-http.testnet5.stages.humanode.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://t.me/HumanodeTestnet5FaucetBot"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "eHMND",
|
||||
"symbol": "eHMND",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://humanode.io",
|
||||
"shortName": "hmnd-t5",
|
||||
"chainId": 14853,
|
||||
"networkId": 14853,
|
||||
"explorers": [],
|
||||
"testnet": true,
|
||||
"slug": "humanode-testnet-5-israfel"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "BEVM",
|
||||
"chain": "ChainX",
|
||||
"rpc": [
|
||||
"https://bevm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-1.bevm.io/",
|
||||
"https://rpc-2.bevm.io/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "BTC",
|
||||
"symbol": "BTC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://chainx.org",
|
||||
"shortName": "chainx",
|
||||
"chainId": 1501,
|
||||
"networkId": 1501,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "bevm scan",
|
||||
"url": "https://scan.bevm.io",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "bevm"
|
||||
} as const satisfies Chain;
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://tenet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.tenet.org"
|
||||
"https://rpc.tenet.org",
|
||||
"https://tenet-evm.publicnode.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Bubs Testnet",
|
||||
"chain": "gETH",
|
||||
"shortName": "Bubs",
|
||||
"chainId": 1582,
|
||||
"testnet": true,
|
||||
"icon": {
|
||||
"format": "svg",
|
||||
"url": "ipfs://bafybeibfpls2ealp4e5fdeoxessfjjkldgjnrcx2erph7524pg7alskk6a/1f9cb.svg",
|
||||
"width": 512,
|
||||
"height": 512
|
||||
},
|
||||
"rpc": [
|
||||
"https://bubs-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://bubs.calderachain.xyz/http"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"decimals": 18,
|
||||
"name": "Ether",
|
||||
"symbol": "gETH"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"url": "https://explorer.bubstestnet.com",
|
||||
"name": "Bubs Testnet Explorer",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://bubstestnet.com"
|
||||
],
|
||||
"infoURL": "https://bubstestnet.com",
|
||||
"networkId": 1582,
|
||||
"slug": "bubs-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ATH",
|
||||
"rpc": [
|
||||
"https://atheios.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://wallet.atheios.com:8797"
|
||||
"https://rpc.atheios.org/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
"symbol": "ATH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://atheios.com",
|
||||
"infoURL": "https://atheios.org",
|
||||
"shortName": "ath",
|
||||
"chainId": 1620,
|
||||
"networkId": 11235813,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Omni Testnet 1",
|
||||
"chain": "Omni",
|
||||
"rpc": [
|
||||
"https://omni-testnet-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-1.omni.network"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Omni",
|
||||
"symbol": "OMNI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.omni.network/",
|
||||
"shortName": "omni_testnet",
|
||||
"chainId": 165,
|
||||
"networkId": 165,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Omni Explorer",
|
||||
"url": "https://testnet-1.explorer.omni.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "omni-testnet-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://horizen-gobi-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://gobi-testnet.horizenlabs.io/ethv1"
|
||||
"https://gobi-testnet.horizenlabs.io/ethv1",
|
||||
"https://rpc.ankr.com/horizen_testnet_evm"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
|
||||
@@ -5,17 +5,23 @@ export default {
|
||||
"rpc": [
|
||||
"https://harmony-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.harmony.one",
|
||||
"https://api.s0.t.hmny.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://free-online-app.com/faucet-for-eth-evm-chains/"
|
||||
"https://a.api.s0.t.hmny.io",
|
||||
"https://api.s0.t.hmny.io",
|
||||
"https://rpc.ankr.com/harmony",
|
||||
"https://harmony.api.onfinality.io/public",
|
||||
"https://1rpc.io/one"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"ens": {
|
||||
"registry": "0x4cd2563118e57b19179d8dc033f2b0c5b5d69ff5"
|
||||
},
|
||||
"shortName": "hmy-s0",
|
||||
"chainId": 1666600000,
|
||||
"networkId": 1666600000,
|
||||
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s1",
|
||||
"chainId": 1666600001,
|
||||
"networkId": 1666600001,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/1",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s2",
|
||||
"chainId": 1666600002,
|
||||
"networkId": 1666600002,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/2",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-2"
|
||||
} as const satisfies Chain;
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s3",
|
||||
"chainId": 1666600003,
|
||||
"networkId": 1666600003,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/3",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-3"
|
||||
} as const satisfies Chain;
|
||||
@@ -21,7 +21,7 @@ export default {
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Testnet Block Explorer",
|
||||
"url": "https://explorer.pops.one",
|
||||
"url": "https://explorer.testnet.harmony.one",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,9 @@ export default {
|
||||
"https://harmony-testnet-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"faucets": [
|
||||
"https://faucet.pops.one"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
@@ -16,6 +18,13 @@ export default {
|
||||
"shortName": "hmy-b-s1",
|
||||
"chainId": 1666700001,
|
||||
"networkId": 1666700001,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.testnet.harmony.one",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Testnet Shard 2",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-testnet-shard-2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s2.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-b-s2",
|
||||
"chainId": 1666700002,
|
||||
"networkId": 1666700002,
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-2"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Testnet Shard 3",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-testnet-shard-3.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s3.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-b-s3",
|
||||
"chainId": 1666700003,
|
||||
"networkId": 1666700003,
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-3"
|
||||
} as const satisfies Chain;
|
||||
@@ -4,11 +4,9 @@ export default {
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-devnet-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.ps.hmny.io"
|
||||
],
|
||||
"faucets": [
|
||||
"http://dev.faucet.easynode.one/"
|
||||
"https://api.s0.ps.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
@@ -18,13 +16,7 @@ export default {
|
||||
"shortName": "hmy-ps-s0",
|
||||
"chainId": 1666900000,
|
||||
"networkId": 1666900000,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.ps.hmny.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "harmony-devnet-shard-0"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Devnet Shard 1",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-devnet-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.ps.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-ps-s1",
|
||||
"chainId": 1666900001,
|
||||
"networkId": 1666900001,
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "harmony-devnet-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Taiko (Alpha-2 Testnet)",
|
||||
"chain": "ETH",
|
||||
"icon": {
|
||||
"url": "ipfs://QmWMUDmNHzCtism9dYK1JooerZJ4da6kGt67HAQmLiEykc",
|
||||
"width": 1001,
|
||||
"height": 1001,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://taiko-alpha-2-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.a2.taiko.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://taiko.xyz",
|
||||
"shortName": "taiko-a2",
|
||||
"chainId": 167004,
|
||||
"networkId": 167004,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer.a2.taiko.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "taiko-alpha-2-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Taiko Grimsvotn L2",
|
||||
"chain": "ETH",
|
||||
"status": "active",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcHdmVr5VRUJq13jnM6tgah5Ge7hn3Dm14eY6vwivJ5ui",
|
||||
"width": 288,
|
||||
"height": 258,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://taiko-grimsvotn-l2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.test.taiko.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://taiko.xyz",
|
||||
"shortName": "taiko-l2",
|
||||
"chainId": 167005,
|
||||
"networkId": 167005,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer.test.taiko.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "taiko-grimsvotn-l2"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Taiko Eldfell L3",
|
||||
"chain": "ETH",
|
||||
"status": "active",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcHdmVr5VRUJq13jnM6tgah5Ge7hn3Dm14eY6vwivJ5ui",
|
||||
"width": 288,
|
||||
"height": 258,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://taiko-eldfell-l3.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.l3test.taiko.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://taiko.xyz",
|
||||
"shortName": "taiko-l3",
|
||||
"chainId": 167006,
|
||||
"networkId": 167006,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer.l3test.taiko.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "taiko-eldfell-l3"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Holesky",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://holesky.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.holesky.ethpandaops.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.holesky.ethpandaops.io",
|
||||
"https://holesky-faucet.pk910.de"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Testnet ETH",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://holesky.ethpandaops.io",
|
||||
"shortName": "holesky",
|
||||
"chainId": 17000,
|
||||
"networkId": 17000,
|
||||
"icon": {
|
||||
"url": "ipfs://QmdwQDr6vmBtXmK2TmknkEuZNoaDqTasFdZdu3DRw8b2wt",
|
||||
"width": 1000,
|
||||
"height": 1628,
|
||||
"format": "png"
|
||||
},
|
||||
"status": "incubating",
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Holesky Explorer",
|
||||
"url": "https://holesky.beaconcha.in",
|
||||
"icon": {
|
||||
"url": "ipfs://QmdwQDr6vmBtXmK2TmknkEuZNoaDqTasFdZdu3DRw8b2wt",
|
||||
"width": 1000,
|
||||
"height": 1628,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "holesky"
|
||||
} as const satisfies Chain;
|
||||
@@ -17,6 +17,13 @@ export default {
|
||||
"shortName": "TBSI",
|
||||
"chainId": 1707,
|
||||
"networkId": 1707,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://exp.blockchain.or.th",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "tbsi"
|
||||
} as const satisfies Chain;
|
||||
@@ -19,6 +19,13 @@ export default {
|
||||
"shortName": "tTBSI",
|
||||
"chainId": 1708,
|
||||
"networkId": 1708,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://exp.testnet.blockchain.or.th",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "tbsi-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -13,7 +13,6 @@ export default {
|
||||
"symbol": "GRAMS",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "TeaPartyCrypto.com",
|
||||
"shortName": "TeaParty",
|
||||
"chainId": 1773,
|
||||
"networkId": 1773,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Smart Trade Networks",
|
||||
"chain": "Smart Trade Networks",
|
||||
"rpc": [
|
||||
"https://smart-trade-networks.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://beefledgerwallet.com:8544"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "STN",
|
||||
"symbol": "STN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.smarttradenetworks.com",
|
||||
"shortName": "STN",
|
||||
"chainId": 18122,
|
||||
"networkId": 18122,
|
||||
"icon": {
|
||||
"url": "ipfs://QmRgZVpjik4cH3Sb6wLRpdnfv9kiMEZ8fugfkzTgk3bpRW",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "stnscan",
|
||||
"url": "https://stnscan.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRgZVpjik4cH3Sb6wLRpdnfv9kiMEZ8fugfkzTgk3bpRW",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "smart-trade-networks"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "MXC zkEVM Mainnet",
|
||||
"chain": "MXC zkEVM",
|
||||
"icon": {
|
||||
"url": "ipfs://QmdGCthKA11K9kCZJdbTP5WPAyq1wiRZ3REn6KG58MrWaE",
|
||||
"width": 159,
|
||||
"height": 159,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://mxc-zkevm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.mxc.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "MXC zkEVM Mainnet",
|
||||
"symbol": "MXC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://doc.mxc.com/docs/intro",
|
||||
"shortName": "MXCzkEVM",
|
||||
"chainId": 18686,
|
||||
"networkId": 18686,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "MXC zkEVM Mainnet",
|
||||
"url": "https://explorer.mxc.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "mxc-zkevm"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "WhiteBIT Network",
|
||||
"chain": "WBT",
|
||||
"rpc": [
|
||||
"https://whitebit-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.whitebit.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "WhiteBIT Coin",
|
||||
"symbol": "WBT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://whitebit.network",
|
||||
"shortName": "wbt",
|
||||
"chainId": 1875,
|
||||
"networkId": 1875,
|
||||
"icon": {
|
||||
"url": "ipfs://Qmbi6cqsQyDjkQSoxbNTTUy8WGyVEFqCtATX2aF4KLmCcZ",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "wb-explorer",
|
||||
"url": "https://explorer.whitebit.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "whitebit-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -3,9 +3,9 @@ export default {
|
||||
"name": "Lightlink Phoenix Mainnet",
|
||||
"chain": "Lightlink Phoenix Mainnet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
@@ -33,9 +33,9 @@ export default {
|
||||
"name": "phoenix",
|
||||
"url": "https://phoenix.lightlink.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -3,9 +3,9 @@ export default {
|
||||
"name": "Lightlink Pegasus Testnet",
|
||||
"chain": "Lightlink Pegasus Testnet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
@@ -35,9 +35,9 @@ export default {
|
||||
"name": "pegasus",
|
||||
"url": "https://pegasus.lightlink.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user