Compare commits
449
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b89987af | ||
|
|
4bb8f5b15e | ||
|
|
914befda16 | ||
|
|
b5bbe2bd43 | ||
|
|
68288436ac | ||
|
|
d4ce855e5f | ||
|
|
47b0ed5171 | ||
|
|
00b9eea9ec | ||
|
|
bf27b88728 | ||
|
|
17fe41d42b | ||
|
|
36600decef | ||
|
|
e09221f1e0 | ||
|
|
62cc785c4a | ||
|
|
7c45941b57 | ||
|
|
7a2e0edab4 | ||
|
|
fb0cb676b9 | ||
|
|
12d85dec10 | ||
|
|
1094a03a04 | ||
|
|
6cc38b0680 | ||
|
|
7abb36a7ec | ||
|
|
6832b19fc5 | ||
|
|
1c4cbedb6a | ||
|
|
8ff87be631 | ||
|
|
e43beec36a | ||
|
|
c5b7fef5ba | ||
|
|
4c5e40ae4e | ||
|
|
ab2dfd4f5c | ||
|
|
13029e3286 | ||
|
|
44c9ccd65d | ||
|
|
7912c26323 | ||
|
|
69d68f5a25 | ||
|
|
836be52724 | ||
|
|
9f993dcc1e | ||
|
|
61760a180f | ||
|
|
a3f3e160e0 | ||
|
|
b1190914a9 | ||
|
|
e79a952061 | ||
|
|
480ed721d1 | ||
|
|
42c7436827 | ||
|
|
16e9e8b64d | ||
|
|
23ab897e32 | ||
|
|
6fcdec7c12 | ||
|
|
b734f05525 | ||
|
|
30ea9c6bf7 | ||
|
|
6de3a19b86 | ||
|
|
06e59cf916 | ||
|
|
3f3a484a3a | ||
|
|
05e52114bf | ||
|
|
1a421d3b5d | ||
|
|
97fdbc8f64 | ||
|
|
ebf4025718 | ||
|
|
a81a5285b7 | ||
|
|
95c9d56ea4 | ||
|
|
18552f3a22 | ||
|
|
9187e0f2cf | ||
|
|
20d0f53b46 | ||
|
|
0dcb15b7e6 | ||
|
|
ba49a82463 | ||
|
|
8d1b8a47e6 | ||
|
|
b90d3af5b8 | ||
|
|
c34ac468fb | ||
|
|
fefeaeef18 | ||
|
|
91c2352b03 | ||
|
|
9f454d1e08 | ||
|
|
59e5541094 | ||
|
|
8e104b443e | ||
|
|
0eed017bb9 | ||
|
|
789700cf60 | ||
|
|
570d71e8d6 | ||
|
|
961ef644d1 | ||
|
|
6fcd09ddbd | ||
|
|
a9d32f3c90 | ||
|
|
8ec0d00c75 | ||
|
+3 |
0acc530f8b | ||
|
|
7a6f516b4f | ||
|
|
7461e2a914 | ||
|
|
178609a062 | ||
|
|
8ea8f6e954 | ||
|
|
b49efc24ac | ||
|
|
6853e87a49 | ||
|
|
4197d1bf3f | ||
|
|
3faa9f21ef | ||
|
|
a75e4cc80a | ||
|
|
f7bda0904f | ||
|
|
fe7be4dd8d | ||
|
|
0f15ee5963 | ||
|
|
4fa09df6d0 | ||
|
|
b6f72c566c | ||
|
|
1934ef5fac | ||
|
|
467c9eeedc | ||
|
|
7ff0b4d547 | ||
|
|
5917e626b0 | ||
|
|
6028a88111 | ||
|
|
80def43d44 | ||
|
|
0b748f31ce | ||
|
|
0358722c1a | ||
|
|
b6267599f5 | ||
|
|
44f258d6bf | ||
|
|
4cb6e287c8 | ||
|
|
db0bbf5173 | ||
|
|
41fd6f9395 | ||
|
|
4374bd4e16 | ||
|
|
042459fe34 | ||
|
|
cc6511351f | ||
|
|
d1743a3279 | ||
|
|
f3fb440fb5 | ||
|
|
2307f11ab3 | ||
|
|
d8d48a9516 | ||
|
|
5ffbcfc302 | ||
|
|
d27a3dee83 | ||
|
|
7080ff29fc | ||
|
|
638afd8e08 | ||
|
|
947e3345ef | ||
|
|
ea51a50bfc | ||
|
|
c6f59e1b01 | ||
|
|
6d1eabe9f9 | ||
|
|
c238fde877 | ||
|
|
548601981f | ||
|
|
05481aa8c0 | ||
|
|
1cc26e43e5 | ||
|
|
99d7ec06ec | ||
|
|
ff996646b2 | ||
|
|
01260009be | ||
|
|
7dea0975ec | ||
|
|
a63f5dc7cb | ||
|
|
fd7a9f0998 | ||
|
|
246b0d4aac | ||
|
|
42ba15f2c0 | ||
|
|
aa9f48d136 | ||
|
|
64138642e8 | ||
|
|
223008b1f7 | ||
|
|
cbfd445ae7 | ||
|
|
137f46a547 | ||
|
|
1b8accde30 | ||
|
|
07544252b4 | ||
|
|
8708519cad | ||
|
|
6c30b7efc7 | ||
|
|
8b5e344f72 | ||
|
|
010955ff5c | ||
|
|
956b5645e4 | ||
|
|
068db44603 | ||
|
|
dd7d0fca2d | ||
|
|
526176c471 | ||
|
|
09120c923c | ||
|
|
d1f8e95162 | ||
|
|
6573556d0e | ||
|
|
fc62b91ee5 | ||
|
|
08e9cd206b | ||
|
|
fb0f12ae28 | ||
|
|
c710fc1c62 | ||
|
|
f41ee6fb1c | ||
|
|
513c332ed0 | ||
|
|
693f349db2 | ||
|
|
63ad0050f0 | ||
|
|
dcdb0dcb83 | ||
|
|
b3b9edca29 | ||
|
|
1fbbc2d27d | ||
|
|
4b98e487d4 | ||
|
|
95380eaed4 | ||
|
|
1f3c64d361 | ||
|
|
bb1666b92b | ||
|
|
0f12d1f903 | ||
|
|
74941603a9 | ||
|
|
4fda12aa2d | ||
|
|
e684d05e22 | ||
|
|
335744ff6d | ||
|
|
7bc40f6223 | ||
|
|
8291742ad9 | ||
|
|
fb964ecb85 | ||
|
|
7dba9f782e | ||
|
|
79f91ee2d9 | ||
|
|
2df8de0e2a | ||
|
|
ce4608bff4 | ||
|
|
125c836d88 | ||
|
|
ec36b13a30 | ||
|
|
52b1a0fcac | ||
|
|
a6c36724eb | ||
|
|
6abb845971 | ||
|
|
dc38a243c2 | ||
|
|
03a03a196d | ||
|
|
931270479e | ||
|
|
6f4c5cd746 | ||
|
|
d3c8626a5a | ||
|
|
ffb1bb0a60 | ||
|
|
9bd01de5f9 | ||
|
|
f5caf6a350 | ||
|
|
46672a490a | ||
|
|
f35fbec1be | ||
|
|
824051eb28 | ||
|
|
fde77a7e19 | ||
|
|
2ec4811f15 | ||
|
|
15fe4779f4 | ||
|
|
6d3d76cff8 | ||
|
|
04f2f7b8ff | ||
|
|
8aa5871a90 | ||
|
|
ea1861d7d9 | ||
|
|
7ebe6cde5d | ||
|
|
f64b7236bb | ||
|
|
af21d5be36 | ||
|
|
54f83a5013 | ||
|
|
6a5bbfd2f5 | ||
|
|
c5b3232e1a | ||
|
|
5dc372fc46 | ||
|
|
fd378ec3e4 | ||
|
|
0e27f15eb9 | ||
|
|
211aab9c16 | ||
|
|
eb9e9f0ce8 | ||
|
|
bd23cec7d1 | ||
|
|
c7e7ec9502 | ||
|
|
6897ad6502 | ||
|
|
ed4172dddf | ||
|
|
de05c2da17 | ||
|
|
c085d69060 | ||
|
|
c2bfc77137 | ||
|
|
81797ffde3 | ||
|
|
69e8208538 | ||
|
|
ee028e1209 | ||
|
|
b16c09df75 | ||
|
|
879d4226f6 | ||
|
|
83905ef6c6 | ||
|
|
f8c8c12ebc | ||
|
|
a9b4b0c5d8 | ||
|
|
d28b1c0f1e | ||
|
|
96e832cc80 | ||
|
|
bdb2ccc7a6 | ||
|
|
e1b05fcea3 | ||
|
|
426c75a330 | ||
|
|
a9854e69ce | ||
|
|
2097e233cb | ||
|
|
c29042b71e | ||
|
|
b5b7e5243d | ||
|
|
d5fafddea5 | ||
|
|
b6df6b8957 | ||
|
|
45112a613e | ||
|
|
ea5b9c3ecd | ||
|
|
bd18e4f5ef | ||
|
|
1018eb56a6 | ||
|
|
def6d400ab | ||
|
|
2ce89cfea9 | ||
|
|
48906a9d8e | ||
|
|
64528263f4 | ||
|
|
cbbb8ccbe3 | ||
|
|
e2e6bdd4cd | ||
|
|
d66ff413de | ||
|
|
9d553746b0 | ||
|
|
57af96c288 | ||
|
|
94bdcc142a | ||
|
|
dd3d1a87c2 | ||
|
|
4268775f9c | ||
|
|
710739c7d2 | ||
|
|
c54db48c0d | ||
|
|
903145a4ae | ||
|
|
43f188c8a7 | ||
|
|
8a3993d42b | ||
|
|
bab39980e7 | ||
|
|
48295c0604 | ||
|
|
3fd39cea0d | ||
|
|
1fe867e205 | ||
|
|
f5991387ef | ||
|
|
3f3c63c01e | ||
|
|
f80cf0e17e | ||
|
|
10b7648857 | ||
|
|
6829ee0ee9 | ||
|
|
6df24a2eb9 | ||
|
|
8b73abfd83 | ||
|
|
66c4ade868 | ||
|
|
2a873d2f80 | ||
|
|
bb320c7e97 | ||
|
|
931ee7930f | ||
|
|
f55fd291bf | ||
|
|
3056c34c64 | ||
|
|
f90427650c | ||
|
|
defe5fced3 | ||
|
|
c0070c2cc0 | ||
|
|
d50863f455 | ||
|
|
87ed24e1b4 | ||
|
|
7e564163ce | ||
|
|
0307671c63 | ||
|
|
4a7f41b3ee | ||
|
|
2f187d1375 | ||
|
|
4567faef47 | ||
|
|
d37c3a75e7 | ||
|
|
4895217142 | ||
|
|
0b59cb2e59 | ||
|
|
2088de1cac | ||
|
|
066b9cfa09 | ||
|
|
1e6f9dcc04 | ||
|
|
a023cb8cf1 | ||
|
|
a00cbaf78c | ||
|
|
d378106a85 | ||
|
|
3eb9592e10 | ||
|
|
04b6ef73e4 | ||
|
|
13ef6a50cf | ||
|
|
04c607ccde | ||
|
|
926dd7b03f | ||
|
|
e00dd12357 | ||
|
|
cdc08c5528 | ||
|
|
4df0c2ee10 | ||
|
|
48a8f9385e | ||
|
|
a91776e121 | ||
|
|
f5aed34d3c | ||
|
|
0f02706906 | ||
|
|
eb463735e2 | ||
|
|
adec589ead | ||
|
|
e5246f2667 | ||
|
|
b29ec675f9 | ||
|
|
b30566c684 | ||
|
|
182a4e7e8f | ||
|
|
8b82f3c59c | ||
|
|
f59b729f8b | ||
|
|
387dddbd87 | ||
|
|
911e14fcac | ||
|
|
cd6b07b591 | ||
|
|
154c55add5 | ||
|
|
f202f597ca | ||
|
|
91f0245be7 | ||
|
|
ae74b8ef62 | ||
|
|
5a373a7509 | ||
|
|
088547f763 | ||
|
|
586e91dbe6 | ||
|
|
f65578d637 | ||
|
|
447d984653 | ||
|
|
34a3bb8ae3 | ||
|
|
bc003c2fef | ||
|
|
c88fa57591 | ||
|
|
c12f0874b4 | ||
|
|
184c325ab2 | ||
|
|
046c9ad604 | ||
|
|
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 |
+11
-1
@@ -15,7 +15,17 @@
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": ["e2e-cra-5", "e2e-next-13", "e2e-vite-3"],
|
||||
"ignore": [
|
||||
"e2e-cra-5",
|
||||
"e2e-next-13",
|
||||
"e2e-vite-3",
|
||||
"bundlers-esbuild",
|
||||
"bundlers-vite",
|
||||
"bundlers-webpack",
|
||||
"bundlers-swc",
|
||||
"runtimes-node-commonjs",
|
||||
"runtimes-node-module"
|
||||
],
|
||||
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
|
||||
"updateInternalDependents": "always",
|
||||
"onlyUpdatePeerDependentsWhenOutOfRange": true
|
||||
|
||||
@@ -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=""
|
||||
@@ -10,7 +10,7 @@ runs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
cache: "pnpm"
|
||||
|
||||
|
||||
+21
-1
@@ -29,7 +29,6 @@ You can see a quick outline of each of the projects within this repo below, each
|
||||
| [/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> |
|
||||
| [/solana](./packages/solana) | Solana SDK for Browser, Node and React Native | <a href="https://www.npmjs.com/package/@thirdweb-dev/solana"><img src="https://img.shields.io/npm/v/@thirdweb-dev/solana?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
## How to contribute
|
||||
|
||||
@@ -107,6 +106,27 @@ In your test project, you need to:
|
||||
1. Delete the dependencies cache. If you're using Next.js, that is the `.next` directory, and if you're using CRA, that is the `node_modules/.cache` directory.
|
||||
2. Restart the development server.
|
||||
|
||||
#### Testing from npm
|
||||
|
||||
You can also test your changes by publishing a dev package to npm and adding your package as you normally do in your projects.
|
||||
|
||||
Once you have your PR up you can add a comment with the text: `/release-pr`. This will trigger a GitHub action that will publish a dev version to npm.
|
||||
|
||||
You can see the action progress in GitHub's `Actions` tab, look for the workflow: `release-pr`.
|
||||
|
||||
Once the action finishes executing, select it, click on deploy and look for the `Deploy pre-release` item. Scroll all the way to the bottom and you should see something like:
|
||||
|
||||
```
|
||||
success packages published successfully:
|
||||
🦋 @***-dev/[email protected]
|
||||
🦋 @***-dev/[email protected]
|
||||
...
|
||||
```
|
||||
|
||||
These are the versions the GH action published to npm for testing purposes. Let's assume you're working on the `@thirdweb-dev/react` package, you can then run:
|
||||
|
||||
`yarn add @thirdweb-dev/react@0.0.0-dev-06a7cb1-20230901190619` to install the dev package.
|
||||
|
||||
<br/>
|
||||
|
||||
### Publish Your Changes
|
||||
|
||||
@@ -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:
|
||||
@@ -30,6 +31,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 25
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
@@ -55,9 +61,14 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
@@ -80,9 +91,15 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
# we use bun for some test suites
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
@@ -99,7 +116,7 @@ jobs:
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/sdk/coverage/evm/lcov.info,./packages/sdk/coverage/solana/lcov.info,
|
||||
files: ./packages/sdk/coverage/evm/lcov.info
|
||||
|
||||
e2e:
|
||||
timeout-minutes: 15
|
||||
@@ -110,9 +127,15 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
# we use bun for some test suites
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
name: Release Next
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- ".changeset/**"
|
||||
- "packages/**"
|
||||
branches:
|
||||
- next
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-16
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Create @next release
|
||||
run: |
|
||||
git checkout next
|
||||
pnpm version-packages:next
|
||||
pnpm release:next
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -67,6 +67,11 @@ jobs:
|
||||
repository: ${{ fromJson(steps.get_pull_request_ref.outputs.data).head.repo.full_name }}
|
||||
ref: ${{ fromJson(steps.get_pull_request_ref.outputs.data).head.ref }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Sync chains every hour
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 * * * *" # Runs every hour
|
||||
workflow_dispatch: # Allows you to manually run the workflow from the Actions tab
|
||||
|
||||
jobs:
|
||||
sync-chains:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
|
||||
- name: Run chains sync
|
||||
run: bun run db:sync
|
||||
working-directory: ./packages/chains
|
||||
|
||||
- name: Check for Changes
|
||||
id: git-check
|
||||
run: |
|
||||
git diff --exit-code || echo "step.git-check.outputs.changes=true" >> $GITHUB_ENV
|
||||
|
||||
- name: Commit Changes
|
||||
if: env.step.git-check.outputs.changes == 'true'
|
||||
run: |
|
||||
git config --local user.email "[email protected]"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add -A
|
||||
git commit -m "chore(chains): sync from db"
|
||||
|
||||
- name: Create or Update Pull Request
|
||||
if: env.step.git-check.outputs.changes == 'true'
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
title: "chore(chains): update chains"
|
||||
branch: "sync-chains" # You can specify a different branch name if you wish
|
||||
body: "This PR was automatically created by a GitHub Action. It updates the chains package with the latest changes from the database."
|
||||
commit-message: "chore(chains): sync from db"
|
||||
+4
-1
@@ -17,6 +17,9 @@ yalc.lock
|
||||
build/
|
||||
playwright-report/
|
||||
.vscode/
|
||||
.env/
|
||||
|
||||
# Artifacts
|
||||
packages/cli/artifacts/
|
||||
packages/cli/artifacts/
|
||||
|
||||
typedoc
|
||||
@@ -20,14 +20,16 @@
|
||||
|
||||
## 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-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> |
|
||||
| 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> |
|
||||
| [/wallets](./packages/wallets) | Unified web3 Wallet library to integrate any wallet into your applications. | <a href="https://www.npmjs.com/package/@thirdweb-dev/wallets"><img src="https://img.shields.io/npm/v/@thirdweb-dev/wallets?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> |
|
||||
| [/chains](./packages/chains) | All EVM chain information as JS objects for easy handling | <a href="https://www.npmjs.com/package/@thirdweb-dev/chains"><img src="https://img.shields.io/npm/v/@thirdweb-dev/chains?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
+8
-8
@@ -7,11 +7,11 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=16.7.0"
|
||||
"node": ">=18"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"test": "turbo run test test:evm test:solana --filter=./packages/*",
|
||||
"test": "turbo run test --filter=./packages/*",
|
||||
"e2e": "turbo run e2e",
|
||||
"build": "turbo run build --filter=./packages/*",
|
||||
"build:release": "turbo run build --force --filter=./packages/*",
|
||||
@@ -26,12 +26,14 @@
|
||||
"release": "node ./scripts/pre-release.mjs && changeset publish",
|
||||
"version-packages:nightly": "node scripts/pre-nightly.mjs && changeset version --snapshot nightly",
|
||||
"release:nightly": "node ./scripts/pre-release.mjs && changeset publish --tag nightly",
|
||||
"version-packages:next": "node scripts/pre-nightly.mjs && changeset version --snapshot next",
|
||||
"release:next": "node ./scripts/pre-release.mjs && changeset publish --tag next",
|
||||
"push": "turbo run push --filter=./packages/*",
|
||||
"hotlink-init": "node ./scripts/hotlink/hotlink-init.mjs",
|
||||
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs",
|
||||
"explain:major": "node ./scripts/changeset-explain-major.mjs"
|
||||
},
|
||||
"packageManager": "pnpm@8.1.0",
|
||||
"packageManager": "pnpm@8.9.0",
|
||||
"dependencies": {
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
@@ -41,12 +43,12 @@
|
||||
"@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.16.18",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@types/node": "^18.17.1",
|
||||
"eslint": "^8.45.0",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^3.0.0",
|
||||
"turbo": "^1.10.7",
|
||||
"turbo": "^1.10.12",
|
||||
"yalc": "1.0.0-pre.53"
|
||||
},
|
||||
"manypkg": {
|
||||
@@ -54,10 +56,8 @@
|
||||
},
|
||||
"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",
|
||||
|
||||
+398
-1
@@ -1,5 +1,402 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 4.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`b5bbe2bd`](https://github.com/thirdweb-dev/js/commit/b5bbe2bd438179c38451bc2cfa20a54fc79e4f3a)]:
|
||||
- @thirdweb-dev/wallets@2.1.9
|
||||
|
||||
## 4.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1973](https://github.com/thirdweb-dev/js/pull/1973) [`36600dec`](https://github.com/thirdweb-dev/js/commit/36600decefca7b9ebb1924757b4186b559e439f6) Thanks [@assimovt](https://github.com/assimovt)! - add logging to authenticate
|
||||
|
||||
- Updated dependencies [[`1094a03a`](https://github.com/thirdweb-dev/js/commit/1094a03a04f3e7ade84af0f7a6073794c0904cb1)]:
|
||||
- @thirdweb-dev/wallets@2.1.8
|
||||
|
||||
## 4.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6832b19f`](https://github.com/thirdweb-dev/js/commit/6832b19fc5eedc7c17e69940a361840de0a84881), [`7abb36a7`](https://github.com/thirdweb-dev/js/commit/7abb36a7ec39766dd7da03015ccef401ef7a7863), [`1c4cbedb`](https://github.com/thirdweb-dev/js/commit/1c4cbedb6a3c9f9014ffbf83c02b998768958d96)]:
|
||||
- @thirdweb-dev/wallets@2.1.7
|
||||
|
||||
## 4.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ab2dfd4f`](https://github.com/thirdweb-dev/js/commit/ab2dfd4f5cf4256fa62d76f84ca804992afab1e4)]:
|
||||
- @thirdweb-dev/wallets@2.1.6
|
||||
|
||||
## 4.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`69d68f5a`](https://github.com/thirdweb-dev/js/commit/69d68f5a25877bf5ea694719d2cf4ca8388f3091)]:
|
||||
- @thirdweb-dev/wallets@2.1.5
|
||||
|
||||
## 4.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9f993dcc`](https://github.com/thirdweb-dev/js/commit/9f993dcc1e60cc087850b8fb9ce09524073ce0b5)]:
|
||||
- @thirdweb-dev/wallets@2.1.4
|
||||
|
||||
## 4.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6fcdec7c`](https://github.com/thirdweb-dev/js/commit/6fcdec7c12e4a3c0d10f3a67771e19cfad5c8ab5), [`42c74368`](https://github.com/thirdweb-dev/js/commit/42c743682739de77c264c11cc1692ed752f929a6), [`480ed721`](https://github.com/thirdweb-dev/js/commit/480ed721d1c736049fa8b6ee4cbdbdf3cce18abd), [`16e9e8b6`](https://github.com/thirdweb-dev/js/commit/16e9e8b64d7d1a97a5b32fc855479e992b7ed3a8), [`b1190914`](https://github.com/thirdweb-dev/js/commit/b1190914a97a9c4d9019c4ce8ee49ad345aed18c)]:
|
||||
- @thirdweb-dev/wallets@2.1.3
|
||||
|
||||
## 4.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1927](https://github.com/thirdweb-dev/js/pull/1927) [`05e52114`](https://github.com/thirdweb-dev/js/commit/05e52114bf4f0ee352f393ed20115a904a18c310) Thanks [@alecananian](https://github.com/alecananian)! - Update Fastify login route response to match Express/Next
|
||||
|
||||
- Updated dependencies [[`3f3a484a`](https://github.com/thirdweb-dev/js/commit/3f3a484a3aa6e9f784e4d44458461bac0d3d4c6b), [`a81a5285`](https://github.com/thirdweb-dev/js/commit/a81a5285b7ef4ddf47fd2779ab80ebbef4bd9e0e), [`30ea9c6b`](https://github.com/thirdweb-dev/js/commit/30ea9c6bf74b483a98592a1d8d64589b7f1b22a3), [`97fdbc8f`](https://github.com/thirdweb-dev/js/commit/97fdbc8f6443dcd08a7610e4437bd4c9d6b0e8c8)]:
|
||||
- @thirdweb-dev/wallets@2.1.2
|
||||
|
||||
## 4.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`20d0f53b`](https://github.com/thirdweb-dev/js/commit/20d0f53b46a2975a0a14ddaa4a377f2f758804db)]:
|
||||
- @thirdweb-dev/wallets@2.1.1
|
||||
|
||||
## 4.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0acc530f`](https://github.com/thirdweb-dev/js/commit/0acc530f8bbee59672d9705724edc278bd853d9a)]:
|
||||
- @thirdweb-dev/wallets@2.1.0
|
||||
|
||||
## 4.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3faa9f21`](https://github.com/thirdweb-dev/js/commit/3faa9f21efb1ae29a57747d6f0b8fb1151930ab4)]:
|
||||
- @thirdweb-dev/wallets@2.0.10
|
||||
|
||||
## 4.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1855](https://github.com/thirdweb-dev/js/pull/1855) [`b6f72c56`](https://github.com/thirdweb-dev/js/commit/b6f72c566c9cec5c2d0a0ebe709d6177b2af68e4) Thanks [@jnsdls](https://github.com/jnsdls)! - require minimum node version: `>=18`
|
||||
|
||||
- Updated dependencies [[`4fa09df6`](https://github.com/thirdweb-dev/js/commit/4fa09df6d0ece89e5e6f1c8f9b530a4bd6c266d7), [`4cb6e287`](https://github.com/thirdweb-dev/js/commit/4cb6e287c857e3597ae9f3c92c9c3961ca7a9f4e), [`5917e626`](https://github.com/thirdweb-dev/js/commit/5917e626b0744af369b67a2e44d9361422a8045d), [`44f258d6`](https://github.com/thirdweb-dev/js/commit/44f258d6bf801b553ca67a5dcebe213a4772e8a1), [`7ff0b4d5`](https://github.com/thirdweb-dev/js/commit/7ff0b4d54715afc86fc72e297a4d8bbe6897e49c), [`b6f72c56`](https://github.com/thirdweb-dev/js/commit/b6f72c566c9cec5c2d0a0ebe709d6177b2af68e4), [`042459fe`](https://github.com/thirdweb-dev/js/commit/042459fe3424add527209ac273913b494b5e426c)]:
|
||||
- @thirdweb-dev/wallets@2.0.9
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1801](https://github.com/thirdweb-dev/js/pull/1801) [`99d7ec06`](https://github.com/thirdweb-dev/js/commit/99d7ec06ec4f31308627edc87d3122c21a884b5a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for fastify
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1812](https://github.com/thirdweb-dev/js/pull/1812) [`c238fde8`](https://github.com/thirdweb-dev/js/commit/c238fde8777fd14b39837117e2d3fda1dd301029) Thanks [@adam-maj](https://github.com/adam-maj)! - Update to call uuidv4 to generate jti
|
||||
|
||||
- [#1811](https://github.com/thirdweb-dev/js/pull/1811) [`54860198`](https://github.com/thirdweb-dev/js/commit/548601981f6dd8706d7a9bd4ca48e4abc7723a1d) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose buildJWT function
|
||||
|
||||
- [#1812](https://github.com/thirdweb-dev/js/pull/1812) [`c238fde8`](https://github.com/thirdweb-dev/js/commit/c238fde8777fd14b39837117e2d3fda1dd301029) Thanks [@adam-maj](https://github.com/adam-maj)! - Update to use uuidv4 for default jti
|
||||
|
||||
- Updated dependencies [[`5ffbcfc3`](https://github.com/thirdweb-dev/js/commit/5ffbcfc302f74167768b196d93a328f979344036), [`d27a3dee`](https://github.com/thirdweb-dev/js/commit/d27a3dee8398d5707d2d1343c428abf8e03f67e3), [`ff996646`](https://github.com/thirdweb-dev/js/commit/ff996646b228d4d095eea04b05004dd26fc7e522), [`aa9f48d1`](https://github.com/thirdweb-dev/js/commit/aa9f48d1361194fc81146da530c95a3409bd0799), [`fd7a9f09`](https://github.com/thirdweb-dev/js/commit/fd7a9f09989e39b02a93d9dfd01cc7378e6ead53), [`2307f11a`](https://github.com/thirdweb-dev/js/commit/2307f11ab311aa4a775edd23e777d10f8015ce86), [`64138642`](https://github.com/thirdweb-dev/js/commit/64138642e84d8b56b254762eca613d443cca292b)]:
|
||||
- @thirdweb-dev/wallets@2.0.8
|
||||
|
||||
## 4.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.7
|
||||
|
||||
## 4.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.6
|
||||
|
||||
## 4.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.5
|
||||
|
||||
## 4.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.4
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
|
||||
## 4.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e)]:
|
||||
- @thirdweb-dev/wallets@2.0.2
|
||||
|
||||
## 4.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e684d05e`](https://github.com/thirdweb-dev/js/commit/e684d05e222458f02c8158eb9385d68c879dd946)]:
|
||||
- @thirdweb-dev/wallets@2.0.1
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#1630](https://github.com/thirdweb-dev/js/pull/1630) [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8) Thanks [@jnsdls](https://github.com/jnsdls)! - **Dropped Support for Solana**:
|
||||
|
||||
- We've decided to drop support for Solana across our SDKs.
|
||||
- Starting with this version of our SDKs all previous solana related functionality will be removed.
|
||||
- Previous versions of our SDKs will continue to work with Solana. However, we will not be providing any further updates or bug fixes for Solana.
|
||||
- You can read a detailed explanation of our decision [on our blog](https://blog.thirdweb.com/discontinuing-solana-support/).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8), [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8)]:
|
||||
- @thirdweb-dev/wallets@2.0.0
|
||||
|
||||
## 3.2.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.3.5
|
||||
|
||||
## 3.2.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101)]:
|
||||
- @thirdweb-dev/wallets@1.3.4
|
||||
|
||||
## 3.2.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d3d76cf`](https://github.com/thirdweb-dev/js/commit/6d3d76cff8018015faa191a1f8bd4f34506a6650), [`04f2f7b8`](https://github.com/thirdweb-dev/js/commit/04f2f7b8ff5f19345d868fc515a24ccd6ffd0ab9)]:
|
||||
- @thirdweb-dev/wallets@1.3.3
|
||||
|
||||
## 3.2.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.3.2
|
||||
|
||||
## 3.2.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`54f83a50`](https://github.com/thirdweb-dev/js/commit/54f83a5013ed65ddd5a787e13ba7e5d86625537d), [`c085d690`](https://github.com/thirdweb-dev/js/commit/c085d69060c68b3335761bdb2cc0c3e082548702), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3)]:
|
||||
- @thirdweb-dev/wallets@1.3.1
|
||||
|
||||
## 3.2.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9d553746`](https://github.com/thirdweb-dev/js/commit/9d553746b025ac489f9b8ee357372c9d01c835e1), [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`94bdcc14`](https://github.com/thirdweb-dev/js/commit/94bdcc142a7fe1e9f53273560404fa6b5ac3a7c4), [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525), [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d), [`def6d400`](https://github.com/thirdweb-dev/js/commit/def6d400ab463bda3118d4c9cb00e5cc25a415c2)]:
|
||||
- @thirdweb-dev/wallets@1.3.0
|
||||
|
||||
## 3.2.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e)]:
|
||||
- @thirdweb-dev/wallets@1.2.1
|
||||
|
||||
## 3.2.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2a873d2f`](https://github.com/thirdweb-dev/js/commit/2a873d2f80271208819bac88b32cea0b48761c8d), [`f9042765`](https://github.com/thirdweb-dev/js/commit/f90427650c037b2c437685734ddc3398ad3e2612), [`defe5fce`](https://github.com/thirdweb-dev/js/commit/defe5fced3fd738157616a9f1644c5092dcaa5a8), [`2f187d13`](https://github.com/thirdweb-dev/js/commit/2f187d13754f571b7205fc1b743efde767b1b1c8), [`931ee793`](https://github.com/thirdweb-dev/js/commit/931ee7930f16c25e4d775d2d93538a5cfe770353)]:
|
||||
- @thirdweb-dev/wallets@1.2.0
|
||||
|
||||
## 3.2.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a023cb8c`](https://github.com/thirdweb-dev/js/commit/a023cb8cf1e4f08be56a2e33c146c8d307c80f40), [`2088de1c`](https://github.com/thirdweb-dev/js/commit/2088de1cacbc903d4f18a84c21a8f27af8d06b29), [`1e6f9dcc`](https://github.com/thirdweb-dev/js/commit/1e6f9dcc04022c6a8a39d490123a3e22e52b5e0b)]:
|
||||
- @thirdweb-dev/wallets@1.1.23
|
||||
|
||||
## 3.2.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.22
|
||||
|
||||
## 3.2.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3)]:
|
||||
- @thirdweb-dev/wallets@1.1.21
|
||||
|
||||
## 3.2.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.20
|
||||
|
||||
## 3.2.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.19
|
||||
|
||||
## 3.2.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.18
|
||||
|
||||
## 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
|
||||
@@ -378,7 +775,7 @@
|
||||
|
||||
## How to upgrade
|
||||
|
||||
The `ThirdwebAuth` constructor now takes the `domain` in the constructor, and takes a more generic `wallet` interface as input. The `wallet` can be imported from the `@thirdweb-dev/wallets` package, or for more simpler use cases, from the `@thirdweb-dev/auth/evm` and `@thirdweb-dev/auth/solana` entrypoints.
|
||||
The `ThirdwebAuth` constructor now takes the `domain` in the constructor, and takes a more generic `wallet` interface as input. The `wallet` can be imported from the `@thirdweb-dev/wallets` package, or for more simpler use cases, from the `@thirdweb-dev/auth/evm` entrypoint.
|
||||
|
||||
```js
|
||||
import { PrivateKeyWallet } from "@thirdweb-dev/auth/evm";
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-fastify.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-fastify.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-auth-fastify.esm.js": "./dist/thirdweb-dev-auth-fastify.browser.esm.js"
|
||||
}
|
||||
}
|
||||
+36
-31
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.17",
|
||||
"version": "4.1.12",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
@@ -28,13 +28,6 @@
|
||||
},
|
||||
"default": "./next/dist/thirdweb-dev-auth-next.cjs.js"
|
||||
},
|
||||
"./solana": {
|
||||
"module": {
|
||||
"browser": "./solana/dist/thirdweb-dev-auth-solana.browser.esm.js",
|
||||
"default": "./solana/dist/thirdweb-dev-auth-solana.esm.js"
|
||||
},
|
||||
"default": "./solana/dist/thirdweb-dev-auth-solana.cjs.js"
|
||||
},
|
||||
"./express": {
|
||||
"module": {
|
||||
"browser": "./express/dist/thirdweb-dev-auth-express.browser.esm.js",
|
||||
@@ -42,6 +35,13 @@
|
||||
},
|
||||
"default": "./express/dist/thirdweb-dev-auth-express.cjs.js"
|
||||
},
|
||||
"./fastify": {
|
||||
"module": {
|
||||
"browser": "./fastify/dist/thirdweb-dev-auth-fastify.browser.esm.js",
|
||||
"default": "./fastify/dist/thirdweb-dev-auth-fastify.esm.js"
|
||||
},
|
||||
"default": "./fastify/dist/thirdweb-dev-auth-fastify.cjs.js"
|
||||
},
|
||||
"./next-auth": {
|
||||
"module": {
|
||||
"browser": "./next-auth/dist/thirdweb-dev-auth-next-auth.browser.esm.js",
|
||||
@@ -58,7 +58,7 @@
|
||||
"scripts": {
|
||||
"build": "preconstruct build",
|
||||
"format": "prettier --write 'src/**/*'",
|
||||
"lint": "eslint src/",
|
||||
"lint": "eslint src/ && bunx publint --strict --level warning",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/ && rm -rf node_modules/",
|
||||
"test": "mocha --config './test/.mocharc.json' --timeout 30000 --parallel './test/**/*.test.ts'",
|
||||
@@ -70,8 +70,8 @@
|
||||
"express/index.ts",
|
||||
"next/index.ts",
|
||||
"next-auth/index.ts",
|
||||
"evm/index.ts",
|
||||
"solana/index.ts"
|
||||
"fastify/index.ts",
|
||||
"evm/index.ts"
|
||||
],
|
||||
"exports": {
|
||||
"envConditions": [
|
||||
@@ -80,54 +80,51 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@microsoft/api-documenter": "^7.22.21",
|
||||
"@microsoft/api-extractor": "^7.36.0",
|
||||
"@microsoft/api-documenter": "^7.22.30",
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "^2.7.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@swc-node/register": "^1.6.6",
|
||||
"@swc/core": "^1.3.67",
|
||||
"@swc/core": "^1.3.71",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@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.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"@types/uuid": "^9.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||
"@typescript-eslint/parser": "^6.2.0",
|
||||
"chai": "^4.3.6",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.8.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",
|
||||
"fastify": "^4.24.2",
|
||||
"mocha": "^10.2.0",
|
||||
"next": "^12.3.4",
|
||||
"next-auth": "^4.22.1",
|
||||
"next-auth": "^4.22.3",
|
||||
"prettier": "^3.0.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"ethers": "^5",
|
||||
"express": "^4",
|
||||
"next": "^12 || ^13",
|
||||
"fastify": "^4.24.2",
|
||||
"next": "^12 || ^13 || ^14",
|
||||
"next-auth": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
},
|
||||
"cookie-parser": {
|
||||
"optional": true
|
||||
},
|
||||
@@ -137,6 +134,9 @@
|
||||
"express": {
|
||||
"optional": true
|
||||
},
|
||||
"fastify": {
|
||||
"optional": true
|
||||
},
|
||||
"next": {
|
||||
"optional": true
|
||||
},
|
||||
@@ -145,9 +145,14 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cookie": "^9.1.0",
|
||||
"@thirdweb-dev/wallets": "workspace:*",
|
||||
"cookie": "^0.5.0",
|
||||
"uuid": "^9.0.0",
|
||||
"zod": "^3.20.2"
|
||||
"fastify-type-provider-zod": "^1.1.9",
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-solana.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-solana.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-auth-solana.esm.js": "./dist/thirdweb-dev-auth-solana.browser.esm.js"
|
||||
}
|
||||
}
|
||||
+73
-423
@@ -1,28 +1,28 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
} from "../constants";
|
||||
authenticateJWT,
|
||||
generateJWT,
|
||||
parseJWT,
|
||||
refreshJWT,
|
||||
} from "./functions/jwt";
|
||||
import {
|
||||
LoginOptions,
|
||||
LoginPayload,
|
||||
GenerateOptions,
|
||||
LoginPayloadData,
|
||||
LoginPayloadDataSchema,
|
||||
AuthenticationPayloadDataSchema,
|
||||
AuthenticationPayloadData,
|
||||
VerifyOptionsSchema,
|
||||
VerifyOptions,
|
||||
GenerateOptionsSchema,
|
||||
AuthenticateOptionsSchema,
|
||||
AuthenticateOptions,
|
||||
User,
|
||||
Json,
|
||||
LoginOptionsSchema,
|
||||
AuthenticationPayload,
|
||||
AuthenticationPayloadDataInput,
|
||||
} from "./schema";
|
||||
import { isBrowser } from "./utils";
|
||||
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;
|
||||
@@ -37,432 +37,82 @@ export class ThirdwebAuth {
|
||||
this.wallet = wallet;
|
||||
}
|
||||
|
||||
public async payload(options?: LoginOptions): Promise<LoginPayloadData> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return LoginPayloadDataSchema.parse({
|
||||
type: this.wallet.type,
|
||||
domain: parsedOptions?.domain || this.domain,
|
||||
address: parsedOptions?.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 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
invalid_before:
|
||||
parsedOptions?.invalidBefore ||
|
||||
new Date(
|
||||
Date.now() -
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
resources: parsedOptions?.resources,
|
||||
public async payload(
|
||||
options?: LoginOptionsWithOptionalDomain,
|
||||
): Promise<LoginPayloadData> {
|
||||
return buildLoginPayload({
|
||||
wallet: this.wallet,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async loginWithPayload(
|
||||
payload: LoginPayloadData,
|
||||
): Promise<LoginPayload> {
|
||||
const message = this.generateMessage(payload);
|
||||
const signature = await this.wallet.signMessage(message);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
return signLoginPayload({ wallet: this.wallet, payload });
|
||||
}
|
||||
|
||||
public async login(options?: LoginOptions): Promise<LoginPayload> {
|
||||
const payloadData = await this.payload(options);
|
||||
return await this.loginWithPayload(payloadData);
|
||||
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,
|
||||
});
|
||||
|
||||
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();
|
||||
return this.createToken({
|
||||
iss: adminAddress,
|
||||
sub: userAddress,
|
||||
aud: domain,
|
||||
nbf: parsedOptions?.invalidBefore || new Date(),
|
||||
exp:
|
||||
parsedOptions?.expirationTime ||
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
iat: new Date(),
|
||||
jti: parsedOptions?.tokenId,
|
||||
ctx: session,
|
||||
});
|
||||
}
|
||||
|
||||
public async refresh(token: string, expirationTime?: Date): Promise<string> {
|
||||
const { payload } = this.parseToken(token);
|
||||
return this.createToken({
|
||||
iss: payload.iss,
|
||||
sub: payload.sub,
|
||||
aud: payload.aud,
|
||||
nbf: new Date(),
|
||||
exp:
|
||||
expirationTime ||
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
iat: new Date(),
|
||||
ctx: payload.ctx,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
): 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 { payload, signature } = this.parseToken(token);
|
||||
|
||||
// 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,
|
||||
};
|
||||
}
|
||||
|
||||
public parseToken(token: string): AuthenticationPayload {
|
||||
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();
|
||||
|
||||
return {
|
||||
return generateJWT({
|
||||
wallet: this.wallet,
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
private async createToken(
|
||||
payload: AuthenticationPayloadDataInput,
|
||||
): Promise<string> {
|
||||
const payloadData = AuthenticationPayloadDataSchema.parse(payload);
|
||||
|
||||
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;
|
||||
public async refresh(jwt: string, expirationTime?: Date): Promise<string> {
|
||||
return refreshJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: { expirationTime },
|
||||
});
|
||||
}
|
||||
|
||||
private async verifySignature(
|
||||
message: string,
|
||||
signature: string,
|
||||
address: string,
|
||||
chainId?: number,
|
||||
) {
|
||||
return this.wallet.verifySignature(message, signature, address, chainId);
|
||||
public async authenticate<TSession extends Json = Json>(
|
||||
jwt: string,
|
||||
options?: AuthenticateOptionsWithOptionalDomain,
|
||||
): Promise<User<TSession>> {
|
||||
return authenticateJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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";
|
||||
}
|
||||
public parseToken(jwt: string): AuthenticationPayload {
|
||||
return parseJWT(jwt);
|
||||
}
|
||||
|
||||
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,229 @@
|
||||
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
|
||||
*/
|
||||
export 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 = "Ethereum";
|
||||
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,26 @@
|
||||
// Export thirdweb auth class
|
||||
export { ThirdwebAuth } from "./auth";
|
||||
export * from "./schema";
|
||||
|
||||
// Export individual auth functions
|
||||
export {
|
||||
buildJWT,
|
||||
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,216 +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(),
|
||||
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().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
|
||||
>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type AuthenticationPayloadDataInput = z.input<
|
||||
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,31 @@
|
||||
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.literal("evm");
|
||||
|
||||
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();
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { Json } from "../../core/schema";
|
||||
import { Json } from "../../core";
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { Request } from "express";
|
||||
|
||||
@@ -28,6 +28,11 @@ export function getActiveCookie(req: Request): string | undefined {
|
||||
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(" ");
|
||||
|
||||
@@ -14,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) =>
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { GenerateOptions } from "../../core";
|
||||
import { GenerateOptionsWithOptionalDomain } from "../../core";
|
||||
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
import { Request, Response } from "express";
|
||||
@@ -41,7 +41,7 @@ export default async function handler(
|
||||
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
|
||||
: undefined;
|
||||
|
||||
const generateOptions: GenerateOptions = {
|
||||
const generateOptions: GenerateOptionsWithOptionalDomain = {
|
||||
verifyOptions: {
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
@@ -68,6 +68,10 @@ export default async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onToken) {
|
||||
await ctx.callbacks.onToken(token, req);
|
||||
}
|
||||
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(token);
|
||||
@@ -84,7 +88,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
|
||||
@@ -93,7 +97,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: cookieExpiration,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
|
||||
@@ -62,7 +62,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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";
|
||||
@@ -52,17 +52,21 @@ export type ThirdwebAuthConfig<
|
||||
domain?: string;
|
||||
path?: string;
|
||||
sameSite?: "lax" | "strict" | "none";
|
||||
secure?: boolean;
|
||||
};
|
||||
callbacks?: {
|
||||
onLogin?:
|
||||
| ((address: string, req?: Request) => void | TSession)
|
||||
| ((address: string, req?: Request) => Promise<void | TSession>);
|
||||
| ((address: string, req: Request) => void | TSession)
|
||||
| ((address: string, req: Request) => Promise<void | TSession>);
|
||||
onToken?:
|
||||
| ((token: string, req: Request) => void)
|
||||
| ((token: string, req: Request) => Promise<void>);
|
||||
onUser?:
|
||||
| ((user: User<TSession>, req?: Request) => void | TData)
|
||||
| ((user: User<TSession>, req?: Request) => Promise<void | TData>);
|
||||
| ((user: User<TSession>, req: Request) => void | TData)
|
||||
| ((user: User<TSession>, req: Request) => Promise<void | TData>);
|
||||
onLogout?:
|
||||
| ((user: User, req?: Request) => void)
|
||||
| ((user: User, req?: Request) => Promise<void>);
|
||||
| ((user: User, req: Request) => void)
|
||||
| ((user: User, req: Request) => Promise<void>);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { Json } from "../../core";
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
export function getCookie(
|
||||
req: FastifyRequest,
|
||||
cookie: string,
|
||||
): string | undefined {
|
||||
return req.cookies[cookie];
|
||||
}
|
||||
|
||||
export function getActiveCookie(req: FastifyRequest): 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: FastifyRequest): 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 activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getCookie(req, activeCookie);
|
||||
}
|
||||
|
||||
export async function getUser<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
>(
|
||||
req: FastifyRequest,
|
||||
ctx: ThirdwebAuthContext<TData, TSession>,
|
||||
): Promise<ThirdwebAuthUser<TData, TSession> | null> {
|
||||
const token = getToken(req);
|
||||
|
||||
if (!token) {
|
||||
console.error("Error: No auth token found");
|
||||
return null;
|
||||
}
|
||||
|
||||
let authenticatedUser: ThirdwebAuthUser<TData, TSession>;
|
||||
try {
|
||||
authenticatedUser = await ctx.auth.authenticate<TSession>(token, {
|
||||
validateTokenId: async (tokenId: string) => {
|
||||
if (ctx.authOptions?.validateTokenId) {
|
||||
await ctx.authOptions?.validateTokenId(tokenId);
|
||||
}
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`Authenticate Error: ${(err as Error)?.message}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ctx.callbacks?.onUser) {
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
const data = await ctx.callbacks.onUser(authenticatedUser, req);
|
||||
if (!data) {
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
return { ...authenticatedUser, data: data };
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { FastifyInstance, FastifyPluginOptions, FastifyRequest } from "fastify";
|
||||
import { Json, ThirdwebAuth as ThirdwebAuthSDK } from "../core";
|
||||
import fastifyCookie, { FastifyCookie } from "@fastify/cookie";
|
||||
import { payloadHandler } from "./routes/payload";
|
||||
import { loginHandler } from "./routes/login";
|
||||
import { userHandler } from "./routes/user";
|
||||
import { logoutHandler } from "./routes/logout";
|
||||
import { switchAccountHandler } from "./routes/switch-account";
|
||||
import {
|
||||
ZodTypeProvider,
|
||||
serializerCompiler,
|
||||
validatorCompiler,
|
||||
} from "fastify-type-provider-zod";
|
||||
import { getUser } from "./helpers/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
|
||||
export * from "./types";
|
||||
export { getToken } from "./helpers/user";
|
||||
|
||||
type ThirdwebAuthReturnType<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
> = {
|
||||
authRouter: (
|
||||
fastify: FastifyInstance,
|
||||
opts: FastifyPluginOptions,
|
||||
done: (err?: Error | undefined) => void,
|
||||
) => void;
|
||||
authMiddleware: FastifyCookie;
|
||||
getUser: (
|
||||
req: FastifyRequest,
|
||||
) => Promise<ThirdwebAuthUser<TData, TSession> | null>;
|
||||
};
|
||||
|
||||
export function ThirdwebAuth<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
>(
|
||||
cfg: ThirdwebAuthConfig<TData, TSession>,
|
||||
): ThirdwebAuthReturnType<TData, TSession> {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
auth: new ThirdwebAuthSDK(cfg.wallet, cfg.domain),
|
||||
};
|
||||
|
||||
const authRouter = async (
|
||||
fastify: FastifyInstance,
|
||||
_opts: FastifyPluginOptions,
|
||||
done: (err?: Error | undefined) => void,
|
||||
) => {
|
||||
// Setup plugin to use zod as a type provider
|
||||
fastify.setValidatorCompiler(validatorCompiler);
|
||||
fastify.setSerializerCompiler(serializerCompiler);
|
||||
const plugin = fastify.withTypeProvider<ZodTypeProvider>();
|
||||
|
||||
// Register the fastify cookie middleware with this plugin
|
||||
await plugin.register(fastifyCookie);
|
||||
|
||||
// Register individual auth endpoints
|
||||
payloadHandler(plugin, ctx as ThirdwebAuthContext);
|
||||
loginHandler(plugin, ctx as ThirdwebAuthContext);
|
||||
logoutHandler(plugin, ctx as ThirdwebAuthContext);
|
||||
userHandler(plugin, ctx as ThirdwebAuthContext);
|
||||
switchAccountHandler(plugin, ctx as ThirdwebAuthContext);
|
||||
|
||||
// Mark plugin creation as complete
|
||||
done();
|
||||
};
|
||||
|
||||
return {
|
||||
authRouter,
|
||||
authMiddleware: fastifyCookie,
|
||||
getUser: (req: FastifyRequest) => {
|
||||
return getUser<TData, TSession>(req, ctx);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
FastifyInstanceWithZod,
|
||||
LoginPayloadBodySchema,
|
||||
ThirdwebAuthContext,
|
||||
} from "../types";
|
||||
import { GenerateOptionsWithOptionalDomain } from "../../core";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { z } from "zod";
|
||||
|
||||
export const loginHandler = (
|
||||
fastify: FastifyInstanceWithZod,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) => {
|
||||
fastify.route<{
|
||||
Body: z.infer<typeof LoginPayloadBodySchema>;
|
||||
}>({
|
||||
method: "POST",
|
||||
url: "/login",
|
||||
schema: {
|
||||
body: LoginPayloadBodySchema,
|
||||
response: {
|
||||
200: z.object({
|
||||
token: z.string(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const validateNonce = async (nonce: string) => {
|
||||
if (ctx.authOptions?.validateNonce) {
|
||||
await ctx.authOptions?.validateNonce(nonce);
|
||||
}
|
||||
};
|
||||
|
||||
const getSession = async (address: string) => {
|
||||
if (ctx.callbacks?.onLogin) {
|
||||
return ctx.callbacks.onLogin(address, req);
|
||||
}
|
||||
};
|
||||
|
||||
const expirationTime = ctx.authOptions?.tokenDurationInSeconds
|
||||
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
|
||||
: undefined;
|
||||
|
||||
const generateOptions: GenerateOptionsWithOptionalDomain = {
|
||||
verifyOptions: {
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: ctx.authOptions?.chainId,
|
||||
validateNonce,
|
||||
resources: ctx.authOptions?.resources,
|
||||
},
|
||||
expirationTime,
|
||||
session: getSession,
|
||||
};
|
||||
|
||||
let token: string;
|
||||
try {
|
||||
// Generate an access token with the SDK using the signed payload
|
||||
token = await ctx.auth.generate(req.body.payload, generateOptions);
|
||||
} catch (err: any) {
|
||||
if (err.message) {
|
||||
return res.status(400).send({ error: err.message });
|
||||
} else if (typeof err === "string") {
|
||||
return res.status(400).send({ error: err });
|
||||
} else {
|
||||
return res.status(400).send({ error: "Invalid login payload" });
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onToken) {
|
||||
await ctx.callbacks.onToken(token, req);
|
||||
}
|
||||
|
||||
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.setCookie(
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${req.body.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: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
);
|
||||
res.setCookie(
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
req.body.payload.payload.address,
|
||||
{
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
);
|
||||
|
||||
// Send token in body and as cookie for frontend and backend use cases
|
||||
return res.status(200).send({ token });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { z } from "zod";
|
||||
import { getActiveCookie, getUser } from "../helpers/user";
|
||||
import {
|
||||
ErrorResponseSchema,
|
||||
FastifyInstanceWithZod,
|
||||
ThirdwebAuthContext,
|
||||
} from "../types";
|
||||
|
||||
export const logoutHandler = (
|
||||
fastify: FastifyInstanceWithZod,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) => {
|
||||
fastify.route({
|
||||
method: "POST",
|
||||
url: "/logout",
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
message: z.string(),
|
||||
}),
|
||||
400: ErrorResponseSchema,
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const activeCookie = getActiveCookie(req);
|
||||
if (!activeCookie) {
|
||||
return res.status(400).send({
|
||||
error: "No logged in user to logout.",
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onLogout) {
|
||||
const user = await getUser(req, ctx);
|
||||
if (user) {
|
||||
await ctx.callbacks.onLogout(user, req);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the access token to 'none' and expire in 5 seconds
|
||||
res.setCookie(activeCookie, "", {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
httpOnly: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
});
|
||||
|
||||
return res.status(200).send({ message: "Successfully logged out" });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
FastifyInstanceWithZod,
|
||||
PayloadBodySchema,
|
||||
ThirdwebAuthContext,
|
||||
} from "../types";
|
||||
import { z } from "zod";
|
||||
|
||||
export const payloadHandler = (
|
||||
fastify: FastifyInstanceWithZod,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) => {
|
||||
fastify.route<{
|
||||
Body: z.infer<typeof PayloadBodySchema>;
|
||||
}>({
|
||||
method: "POST",
|
||||
url: "/payload",
|
||||
schema: {
|
||||
body: PayloadBodySchema,
|
||||
response: {
|
||||
200: z.any(),
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
const payload = await ctx.auth.payload({
|
||||
address: req.body.address,
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: req.body.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).send({ payload });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
ActiveBodySchema,
|
||||
ErrorResponseSchema,
|
||||
FastifyInstanceWithZod,
|
||||
ThirdwebAuthContext,
|
||||
} from "../types";
|
||||
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";
|
||||
import { z } from "zod";
|
||||
|
||||
export const switchAccountHandler = (
|
||||
fastify: FastifyInstanceWithZod,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) => {
|
||||
fastify.route<{
|
||||
Body: z.infer<typeof ActiveBodySchema>;
|
||||
}>({
|
||||
method: "POST",
|
||||
url: "/switch-account",
|
||||
schema: {
|
||||
body: ActiveBodySchema,
|
||||
response: {
|
||||
200: z.any(),
|
||||
400: ErrorResponseSchema,
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
let cookieExpiration: Date;
|
||||
const cookie = getCookie(
|
||||
req,
|
||||
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${req.body.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.setCookie(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, req.body.address, {
|
||||
domain: ctx.cookieOptions?.domain,
|
||||
path: ctx.cookieOptions?.path || "/",
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: cookieExpiration,
|
||||
httpOnly: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
});
|
||||
|
||||
return res.status(200).send();
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import { getToken, getUser } from "../helpers/user";
|
||||
import { FastifyInstanceWithZod, ThirdwebAuthContext } from "../types";
|
||||
import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { z } from "zod";
|
||||
|
||||
export const userHandler = (
|
||||
fastify: FastifyInstanceWithZod,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) => {
|
||||
fastify.route({
|
||||
method: "GET",
|
||||
url: "/user",
|
||||
schema: {
|
||||
response: {
|
||||
200: z.any(),
|
||||
},
|
||||
},
|
||||
handler: async (req, res) => {
|
||||
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.setCookie(
|
||||
`${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: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
);
|
||||
res.setCookie(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: ctx.cookieOptions?.secure || true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).send(user);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
import { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { Json, LoginPayloadOutputSchema, ThirdwebAuth, User } from "../../core";
|
||||
import {
|
||||
FastifyBaseLogger,
|
||||
FastifyInstance,
|
||||
FastifyRequest,
|
||||
RawServerDefault,
|
||||
} from "fastify";
|
||||
import { z } from "zod";
|
||||
import { IncomingMessage, ServerResponse } from "http";
|
||||
import { ZodTypeProvider } from "fastify-type-provider-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,
|
||||
});
|
||||
|
||||
export const ErrorResponseSchema = z.object({
|
||||
error: z.string(),
|
||||
});
|
||||
|
||||
export type ThirdwebAuthUser<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
> = User<TSession> & {
|
||||
data?: TData;
|
||||
};
|
||||
|
||||
export type ThirdwebAuthConfig<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
> = {
|
||||
domain: string;
|
||||
wallet: GenericAuthWallet;
|
||||
authOptions?: {
|
||||
statement?: string;
|
||||
uri?: string;
|
||||
version?: string;
|
||||
chainId?: string;
|
||||
resources?: string[];
|
||||
validateNonce?:
|
||||
| ((nonce: string) => void)
|
||||
| ((nonce: string) => Promise<void>);
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
cookieOptions?: {
|
||||
domain?: string;
|
||||
path?: string;
|
||||
sameSite?: "lax" | "strict" | "none";
|
||||
secure?: boolean;
|
||||
};
|
||||
callbacks?: {
|
||||
onLogin?:
|
||||
| ((address: string, req: FastifyRequest) => void | TSession)
|
||||
| ((address: string, req: FastifyRequest) => Promise<void | TSession>);
|
||||
onToken?:
|
||||
| ((token: string, req: FastifyRequest) => void)
|
||||
| ((token: string, req: FastifyRequest) => Promise<void>);
|
||||
onUser?:
|
||||
| ((user: User<TSession>, req: FastifyRequest) => void | TData)
|
||||
| ((user: User<TSession>, req: FastifyRequest) => Promise<void | TData>);
|
||||
onLogout?:
|
||||
| ((user: User, req: FastifyRequest) => void)
|
||||
| ((user: User, req: FastifyRequest) => Promise<void>);
|
||||
};
|
||||
};
|
||||
|
||||
export type ThirdwebAuthContext<
|
||||
TData extends Json = Json,
|
||||
TSession extends Json = Json,
|
||||
> = Omit<Omit<ThirdwebAuthConfig<TData, TSession>, "wallet">, "domain"> & {
|
||||
auth: ThirdwebAuth;
|
||||
};
|
||||
|
||||
export type FastifyInstanceWithZod = FastifyInstance<
|
||||
RawServerDefault,
|
||||
IncomingMessage,
|
||||
ServerResponse<IncomingMessage>,
|
||||
FastifyBaseLogger,
|
||||
ZodTypeProvider
|
||||
>;
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { Json } from "../../core/schema";
|
||||
import { Json } from "../../core";
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { GetServerSidePropsContext, NextApiRequest } from "next";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
|
||||
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
|
||||
} from "../../constants";
|
||||
import { GenerateOptions } from "../../core";
|
||||
import { GenerateOptionsWithOptionalDomain } from "../../core";
|
||||
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
@@ -41,7 +41,7 @@ export default async function handler(
|
||||
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
|
||||
: undefined;
|
||||
|
||||
const generateOptions: GenerateOptions = {
|
||||
const generateOptions: GenerateOptionsWithOptionalDomain = {
|
||||
verifyOptions: {
|
||||
statement: ctx.authOptions?.statement,
|
||||
uri: ctx.authOptions?.uri,
|
||||
@@ -68,6 +68,10 @@ export default async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.callbacks?.onToken) {
|
||||
await ctx.callbacks.onToken(token, req);
|
||||
}
|
||||
|
||||
const {
|
||||
payload: { exp },
|
||||
} = ctx.auth.parseToken(token);
|
||||
@@ -84,7 +88,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
|
||||
@@ -93,7 +97,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: cookieExpiration,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
},
|
||||
),
|
||||
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
|
||||
@@ -62,7 +62,7 @@ export default async function handler(
|
||||
sameSite: ctx.cookieOptions?.sameSite || "none",
|
||||
expires: new Date(refreshedPayload.payload.exp * 1000),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
secure: ctx.cookieOptions?.secure || true,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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";
|
||||
@@ -63,23 +62,27 @@ export type ThirdwebAuthConfig<
|
||||
domain?: string;
|
||||
path?: string;
|
||||
sameSite?: "lax" | "strict" | "none";
|
||||
secure?: boolean;
|
||||
};
|
||||
callbacks?: {
|
||||
onLogin?:
|
||||
| ((address: string, req?: NextApiRequest) => void | TSession)
|
||||
| ((address: string, req?: NextApiRequest) => Promise<void | TSession>);
|
||||
| ((address: string, req: NextApiRequest) => void | TSession)
|
||||
| ((address: string, req: NextApiRequest) => Promise<void | TSession>);
|
||||
onToken?:
|
||||
| ((token: string, req: NextApiRequest) => void)
|
||||
| ((token: string, req: NextApiRequest) => Promise<void>);
|
||||
onUser?:
|
||||
| (<TRequestType extends RequestType = RequestType>(
|
||||
user: User<TSession>,
|
||||
req?: TRequestType,
|
||||
req: TRequestType,
|
||||
) => void | TData)
|
||||
| (<TRequestType extends RequestType = RequestType>(
|
||||
user: User<TSession>,
|
||||
req?: TRequestType,
|
||||
req: TRequestType,
|
||||
) => Promise<void | TData>);
|
||||
onLogout?:
|
||||
| ((user: User, req?: NextApiRequest) => void)
|
||||
| ((user: User, req?: NextApiRequest) => Promise<void>);
|
||||
| ((user: User, req: NextApiRequest) => void)
|
||||
| ((user: User, req: NextApiRequest) => Promise<void>);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { ThirdwebAuth } from "../core";
|
||||
import { LoginPayload, VerifyOptions } from "../core/schema";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
|
||||
const authMap = new Map<string, ThirdwebAuth>();
|
||||
let wallet: KeypairWallet;
|
||||
|
||||
export async function verifyLogin(
|
||||
domain: string,
|
||||
payload: LoginPayload,
|
||||
options?: Omit<VerifyOptions, "domain">,
|
||||
) {
|
||||
wallet = wallet || new KeypairWallet(Keypair.generate());
|
||||
let auth: ThirdwebAuth;
|
||||
if (!authMap.has(domain)) {
|
||||
auth = new ThirdwebAuth(wallet, domain);
|
||||
authMap.set(domain, auth);
|
||||
} else {
|
||||
auth = authMap.get(domain) as ThirdwebAuth;
|
||||
}
|
||||
|
||||
try {
|
||||
const address = await auth.verify(payload, options);
|
||||
return { address, error: undefined };
|
||||
} catch (err: any) {
|
||||
return { address: undefined, error: err.message };
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,353 +0,0 @@
|
||||
import { ThirdwebAuth } from "../src/core";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("Wallet Authentication", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
before(async () => {
|
||||
const [adminSigner, signerSigner, attackerSigner] = [
|
||||
Keypair.generate(),
|
||||
Keypair.generate(),
|
||||
Keypair.generate(),
|
||||
];
|
||||
|
||||
adminWallet = new KeypairWallet(adminSigner);
|
||||
signerWallet = new KeypairWallet(signerSigner);
|
||||
attackerWallet = new KeypairWallet(attackerSigner);
|
||||
|
||||
auth = new ThirdwebAuth(signerWallet, "thirdweb.com");
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
auth.updateWallet(signerWallet);
|
||||
});
|
||||
|
||||
it("Should verify logged in wallet", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload);
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should verify logged in wallet with chain ID and expiration", async () => {
|
||||
const payload = await auth.login({
|
||||
expirationTime: new Date(Date.now() + 1000 * 60 * 5),
|
||||
chainId: "137",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
chainId: "137",
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should verify payload with resources", async () => {
|
||||
const payload = await auth.login({
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload without necessary resources", async () => {
|
||||
const payload = await auth.login({
|
||||
resources: ["https://example.com"],
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Login request is missing required resources: https://test.com",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should verify payload with customized statement", async () => {
|
||||
const payload = await auth.login({
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect statement", async () => {
|
||||
const payload = await auth.login({
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
statement: "Please sign again!",
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.include(
|
||||
"Expected statement 'Please sign again!' does not match statement on payload",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject invalid nonce", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
validateNonce: (nonce: string) => {
|
||||
if (nonce === payload.payload.nonce) {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal("Login request nonce is invalid");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should accept valid nonce", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
validateNonce: (nonce: string) => {
|
||||
if (nonce !== payload.payload.nonce) {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect domain", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, { domain: "test.thirdweb.com" });
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Expected domain 'test.thirdweb.com' does not match domain on payload 'thirdweb.com'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject expired login payload", async () => {
|
||||
const payload = await auth.login({
|
||||
expirationTime: new Date(Date.now() - 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal("Login request has expired");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect chain ID", async () => {
|
||||
const payload = await auth.login({
|
||||
chainId: "1",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
chainId: "137",
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Expected chain ID '137' does not match chain ID on payload '1'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect signer", async () => {
|
||||
const payload = await auth.login();
|
||||
payload.payload.address = await attackerWallet.getAddress();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("does not match payload address");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should generate valid authentication token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject token with incorrect domain", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
try {
|
||||
await auth.authenticate(token, { domain: "test.thirdweb.com" });
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
"Expected token to be for the domain 'test.thirdweb.com', but found token with domain 'thirdweb.com'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject token before invalid before", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
invalidBefore: new Date(Date.now() + 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("This token is invalid before");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject expired authentication token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
expirationTime: new Date(Date.now() - 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("This token expired");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject if admin address is not connected wallet address", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
auth.updateWallet(signerWallet);
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
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()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should accept token with valid token ID", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
tokenId: "test",
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token, {
|
||||
validateTokenId: (tokenId: string) => {
|
||||
if (tokenId !== "test") {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject token with invalid token ID", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
tokenId: "test",
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token, {
|
||||
validateTokenId: (tokenId: string) => {
|
||||
if (tokenId !== "invalid") {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("Token ID is invalid");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should propagate session on token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
session: { role: "admin" },
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
expect(user.session).to.deep.equal({ role: "admin" });
|
||||
});
|
||||
|
||||
it("Should call session callback function", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
session: (address: string) => {
|
||||
return { address, role: "admin" };
|
||||
},
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
expect(user.session).to.deep.equal({
|
||||
address: await signerWallet.getAddress(),
|
||||
role: "admin",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,200 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1967](https://github.com/thirdweb-dev/js/pull/1967) [`47b0ed51`](https://github.com/thirdweb-dev/js/commit/47b0ed5171be5608ae23c19481a1b04948443c6a) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add Arbitrum Sepolia to defaultChains
|
||||
|
||||
- [#1990](https://github.com/thirdweb-dev/js/pull/1990) [`d4ce855e`](https://github.com/thirdweb-dev/js/commit/d4ce855e5f5e6c4206a3efa250e92e690ae87281) Thanks [@jnsdls](https://github.com/jnsdls)! - deprecate `allChains` `getChainById` and `getChainBySlug`
|
||||
|
||||
all of these would (necessarily) pull in every single chain in the package (>600kb)
|
||||
|
||||
instead these can be replaced with their async variants:
|
||||
|
||||
- `allChains` -> `await fetchChains()`
|
||||
- `getChainById(chainId)` -> `await getChainByIdAsync(chainId)`
|
||||
- `getChainBySlug(chainSlug)` -> `await getChainBySlugAsync(chainSlug)`
|
||||
|
||||
these async functions will return the same data as their sync counterparts, but without having to pull in every single chain at build-time.
|
||||
|
||||
## 0.1.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1911](https://github.com/thirdweb-dev/js/pull/1911) [`0dcb15b7`](https://github.com/thirdweb-dev/js/commit/0dcb15b7e647acd038b0ec8b1a2b200808aae00e) Thanks [@iketw](https://github.com/iketw)! - Syncs Chains
|
||||
|
||||
## 0.1.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1865](https://github.com/thirdweb-dev/js/pull/1865) [`a75e4cc8`](https://github.com/thirdweb-dev/js/commit/a75e4cc80a5a36bf6baeeb40e8ae3be485d35618) Thanks [@jnsdls](https://github.com/jnsdls)! - sync chains
|
||||
|
||||
## 0.1.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1843](https://github.com/thirdweb-dev/js/pull/1843) [`6028a881`](https://github.com/thirdweb-dev/js/commit/6028a88111d9071155370c7aeaf22d4ee0c3ec93) Thanks [@jnsdls](https://github.com/jnsdls)! - sync chains
|
||||
|
||||
- [#1855](https://github.com/thirdweb-dev/js/pull/1855) [`b6f72c56`](https://github.com/thirdweb-dev/js/commit/b6f72c566c9cec5c2d0a0ebe709d6177b2af68e4) Thanks [@jnsdls](https://github.com/jnsdls)! - require minimum node version: `>=18`
|
||||
|
||||
- [#1805](https://github.com/thirdweb-dev/js/pull/1805) [`cc651135`](https://github.com/thirdweb-dev/js/commit/cc6511351fea568246ddf49f687a5616d484d2a4) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Spicy Chain deployments
|
||||
|
||||
## 0.1.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1783](https://github.com/thirdweb-dev/js/pull/1783) [`137f46a5`](https://github.com/thirdweb-dev/js/commit/137f46a5470d2b5f9d7f9eda9b2d839a53ddeb64) Thanks [@jnsdls](https://github.com/jnsdls)! - sync chains
|
||||
|
||||
## 0.1.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1702](https://github.com/thirdweb-dev/js/pull/1702) [`f64b7236`](https://github.com/thirdweb-dev/js/commit/f64b7236bbcc5b15fea582db22f120d71d9e126f) Thanks [@jnsdls](https://github.com/jnsdls)! - updated chains
|
||||
|
||||
## 0.1.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1631](https://github.com/thirdweb-dev/js/pull/1631) [`dd3d1a87`](https://github.com/thirdweb-dev/js/commit/dd3d1a87c2dadbadecc9ac3722941a8992bc8131) Thanks [@jnsdls](https://github.com/jnsdls)! - add & update chains
|
||||
|
||||
- [#1662](https://github.com/thirdweb-dev/js/pull/1662) [`d5fafdde`](https://github.com/thirdweb-dev/js/commit/d5fafddea58bc307c9b514a1c9578cafd18b5861) Thanks [@jnsdls](https://github.com/jnsdls)! - added & updated chains
|
||||
|
||||
## 0.1.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1534](https://github.com/thirdweb-dev/js/pull/1534) [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - feat(chains): add new chain information
|
||||
|
||||
## 0.1.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1607](https://github.com/thirdweb-dev/js/pull/1607) [`8b73abfd`](https://github.com/thirdweb-dev/js/commit/8b73abfd83c7a8235f5d65f07dc3ad1296b40ae0) Thanks [@nkrishang](https://github.com/nkrishang)! - Use IAccountFactoryCore
|
||||
|
||||
- [#1599](https://github.com/thirdweb-dev/js/pull/1599) [`3056c34c`](https://github.com/thirdweb-dev/js/commit/3056c34c646e1a8c80f1323899c163e0fa867fd1) Thanks [@MananTank](https://github.com/MananTank)! - Update chains
|
||||
|
||||
## 0.1.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1558](https://github.com/thirdweb-dev/js/pull/1558) [`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005) Thanks [@Marfuen](https://github.com/Marfuen)! - Updating chains list
|
||||
|
||||
## 0.1.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1540](https://github.com/thirdweb-dev/js/pull/1540) [`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - updated chains
|
||||
|
||||
- [#1422](https://github.com/thirdweb-dev/js/pull/1422) [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3) Thanks [@Marfuen](https://github.com/Marfuen)! - CLI will now use an OAuth like login flow to authenticate the device with the wallet on the dashboard.
|
||||
Any actions performed by the CLI will be linked to your account / wallet on the dashboard, including but not limited to tracking your usage, and billing as needed.
|
||||
|
||||
- [#1551](https://github.com/thirdweb-dev/js/pull/1551) [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update chains
|
||||
|
||||
## 0.1.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1530](https://github.com/thirdweb-dev/js/pull/1530) [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Add Chiliz Spicy testnet
|
||||
|
||||
## 0.1.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1518](https://github.com/thirdweb-dev/js/pull/1518) [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8) Thanks [@nkrishang](https://github.com/nkrishang)! - Update contracts package
|
||||
|
||||
## 0.1.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1508](https://github.com/thirdweb-dev/js/pull/1508) [`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f) Thanks [@jnsdls](https://github.com/jnsdls)! - update xpla chain icons
|
||||
|
||||
- [#1513](https://github.com/thirdweb-dev/js/pull/1513) [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34) Thanks [@jnsdls](https://github.com/jnsdls)! - add additonal 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
|
||||
|
||||
+66
-36
@@ -1,41 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Ethereum Mainnet",
|
||||
"chain": "ETH",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcxZHpyJa8T4i63xqjPYrZ6tKrt55tZJpbXcjSDKuKaf9/ethereum/512.png",
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_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"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
},
|
||||
{
|
||||
"name": "EIP155"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://ethereum.org",
|
||||
"shortName": "eth",
|
||||
"chainId": 1,
|
||||
"networkId": 1,
|
||||
"slip44": 60,
|
||||
"ens": {
|
||||
"registry": "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
|
||||
},
|
||||
@@ -44,8 +10,72 @@ export default {
|
||||
"name": "etherscan",
|
||||
"url": "https://etherscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://eth.blockscout.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dexguru",
|
||||
"url": "https://ethereum.dex.guru",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRaASKRSjQ5btoUQ2rNTJNxKtx2a2RoewgA7DMQkLVEne",
|
||||
"width": 83,
|
||||
"height": 82,
|
||||
"format": "svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "ethereum"
|
||||
"faucets": [],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://QmcxZHpyJa8T4i63xqjPYrZ6tKrt55tZJpbXcjSDKuKaf9/ethereum/512.png",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://ethereum.org",
|
||||
"name": "Ethereum Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1,
|
||||
"redFlags": [],
|
||||
"rpc": [
|
||||
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1.rpc.thirdweb.com/${THIRDWEB_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",
|
||||
"wss://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
"wss://mainnet.gateway.tenderly.co",
|
||||
"https://rpc.blocknative.com/boost",
|
||||
"https://rpc.flashbots.net/fast",
|
||||
"https://rpc.mevblocker.io/fullprivacy"
|
||||
],
|
||||
"shortName": "eth",
|
||||
"slip44": 60,
|
||||
"slug": "ethereum",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,36 +1,65 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "OP Mainnet",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.optimism.io/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://optimism.io",
|
||||
"shortName": "oeth",
|
||||
"chainId": 10,
|
||||
"networkId": 10,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "etherscan",
|
||||
"url": "https://optimistic.etherscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://optimism.blockscout.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dexguru",
|
||||
"url": "https://optimism.dex.guru",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRaASKRSjQ5btoUQ2rNTJNxKtx2a2RoewgA7DMQkLVEne",
|
||||
"width": 83,
|
||||
"height": 82,
|
||||
"format": "svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"features": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmcxZHpyJa8T4i63xqjPYrZ6tKrt55tZJpbXcjSDKuKaf9/optimism/512.png",
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"testnet": false,
|
||||
"slug": "optimism"
|
||||
"infoURL": "https://optimism.io",
|
||||
"name": "OP Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10,
|
||||
"redFlags": [],
|
||||
"rpc": [
|
||||
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.optimism.io",
|
||||
"https://optimism.publicnode.com",
|
||||
"wss://optimism.publicnode.com",
|
||||
"https://optimism.gateway.tenderly.co",
|
||||
"wss://optimism.gateway.tenderly.co"
|
||||
],
|
||||
"shortName": "oeth",
|
||||
"slug": "optimism",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,15 +1,58 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Gnosis",
|
||||
"chain": "GNO",
|
||||
"chainId": 100,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://gnosis.blockscout.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gnosisscan",
|
||||
"url": "https://gnosisscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "dexguru",
|
||||
"url": "https://gnosis.dex.guru",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRaASKRSjQ5btoUQ2rNTJNxKtx2a2RoewgA7DMQkLVEne",
|
||||
"width": 83,
|
||||
"height": 82,
|
||||
"format": "svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com",
|
||||
"https://stakely.io/faucet/gnosis-chain-xdai",
|
||||
"https://faucet.prussia.dev/xdai"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeidk4swpgdyqmpz6shd5onvpaujvwiwthrhypufnwr6xh3dausz2dm",
|
||||
"width": 1800,
|
||||
"height": 1800,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
"name": "Gnosis",
|
||||
"nativeCurrency": {
|
||||
"name": "xDAI",
|
||||
"symbol": "XDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100,
|
||||
"rpc": [
|
||||
"https://gnosis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.gnosischain.com",
|
||||
"https://rpc.gnosis.gateway.fm",
|
||||
"https://rpc.ankr.com/gnosis",
|
||||
@@ -18,41 +61,13 @@ export default {
|
||||
"https://gnosis.api.onfinality.io/public",
|
||||
"https://gnosis.blockpi.network/v1/rpc/public",
|
||||
"https://web3endpoints.com/gnosischain-mainnet",
|
||||
"wss://rpc.gnosischain.com/wss"
|
||||
"https://gnosis.oat.farm",
|
||||
"wss://rpc.gnosischain.com/wss",
|
||||
"https://gnosis.publicnode.com",
|
||||
"wss://gnosis.publicnode.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com",
|
||||
"https://stakely.io/faucet/gnosis-chain-xdai",
|
||||
"https://faucet.prussia.dev/xdai"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "xDAI",
|
||||
"symbol": "XDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
"shortName": "gno",
|
||||
"chainId": 100,
|
||||
"networkId": 100,
|
||||
"slip44": 700,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "gnosisscan",
|
||||
"url": "https://gnosisscan.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.com/xdai/mainnet",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "gnosis"
|
||||
"slug": "gnosis",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "GTON Mainnet",
|
||||
"chain": "GTON",
|
||||
"rpc": [
|
||||
"https://gton.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.gton.network/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "GCD",
|
||||
"symbol": "GCD",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://gton.capital",
|
||||
"shortName": "gton",
|
||||
"chainId": 1000,
|
||||
"networkId": 1000,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "GTON Network Explorer",
|
||||
@@ -23,10 +9,25 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"infoURL": "https://gton.capital",
|
||||
"name": "GTON Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "GCD",
|
||||
"symbol": "GCD",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1000,
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-1"
|
||||
},
|
||||
"testnet": false,
|
||||
"slug": "gton"
|
||||
"rpc": [
|
||||
"https://gton.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1000.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.gton.network/"
|
||||
],
|
||||
"shortName": "gton",
|
||||
"slug": "gton",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,24 +1,26 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Smart Bitcoin Cash",
|
||||
"chain": "smartBCH",
|
||||
"rpc": [
|
||||
"https://smart-bitcoin-cash.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://smartbch.greyh.at",
|
||||
"https://rpc-mainnet.smartbch.org",
|
||||
"https://smartbch.fountainhead.cash/mainnet",
|
||||
"https://smartbch.devops.cash/mainnet"
|
||||
],
|
||||
"chainId": 10000,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://smartbch.org/",
|
||||
"name": "Smart Bitcoin Cash",
|
||||
"nativeCurrency": {
|
||||
"name": "Bitcoin Cash",
|
||||
"symbol": "BCH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://smartbch.org/",
|
||||
"shortName": "smartbch",
|
||||
"chainId": 10000,
|
||||
"networkId": 10000,
|
||||
"testnet": false,
|
||||
"slug": "smart-bitcoin-cash"
|
||||
"rpc": [
|
||||
"https://smart-bitcoin-cash.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10000.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://smartbch.greyh.at",
|
||||
"https://rpc-mainnet.smartbch.org",
|
||||
"https://smartbch.fountainhead.cash/mainnet",
|
||||
"https://smartbch.devops.cash/mainnet"
|
||||
],
|
||||
"shortName": "smartbch",
|
||||
"slug": "smart-bitcoin-cash",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Root",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-root.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://jrpc.mainnet.quarkchain.io:38391"
|
||||
],
|
||||
"chainId": 100000,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Root",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-r",
|
||||
"chainId": 100000,
|
||||
"networkId": 100000,
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-root"
|
||||
"rpc": [
|
||||
"https://quarkchain-root.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100000.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://jrpc.mainnet.quarkchain.io:38391"
|
||||
],
|
||||
"shortName": "qkc-r",
|
||||
"slug": "quarkchain-root",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 0",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s0-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39000"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s0",
|
||||
"chainId": 100001,
|
||||
"networkId": 100001,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-0"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 0",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100001,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100001.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s0-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39000"
|
||||
],
|
||||
"shortName": "qkc-s0",
|
||||
"slug": "quarkchain-shard-0",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 1",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s1-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39001"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s1",
|
||||
"chainId": 100002,
|
||||
"networkId": 100002,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-1"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 1",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100002,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100002.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s1-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39001"
|
||||
],
|
||||
"shortName": "qkc-s1",
|
||||
"slug": "quarkchain-shard-1",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 2",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s2-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39002"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s2",
|
||||
"chainId": 100003,
|
||||
"networkId": 100003,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-2"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 2",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100003,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100003.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s2-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39002"
|
||||
],
|
||||
"shortName": "qkc-s2",
|
||||
"slug": "quarkchain-shard-2",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 3",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-3.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s3-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39003"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s3",
|
||||
"chainId": 100004,
|
||||
"networkId": 100004,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-3"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 3",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100004,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-3.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100004.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s3-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39003"
|
||||
],
|
||||
"shortName": "qkc-s3",
|
||||
"slug": "quarkchain-shard-3",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 4",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-4.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s4-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39004"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s4",
|
||||
"chainId": 100005,
|
||||
"networkId": 100005,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-4"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 4",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100005,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-4.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100005.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s4-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39004"
|
||||
],
|
||||
"shortName": "qkc-s4",
|
||||
"slug": "quarkchain-shard-4",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 5",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-5.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s5-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39005"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s5",
|
||||
"chainId": 100006,
|
||||
"networkId": 100006,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-5"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 5",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100006,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-5.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100006.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s5-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39005"
|
||||
],
|
||||
"shortName": "qkc-s5",
|
||||
"slug": "quarkchain-shard-5",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 6",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-6.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s6-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39006"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s6",
|
||||
"chainId": 100007,
|
||||
"networkId": 100007,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-6"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 6",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100007,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-6.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100007.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s6-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39006"
|
||||
],
|
||||
"shortName": "qkc-s6",
|
||||
"slug": "quarkchain-shard-6",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,26 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "QuarkChain Mainnet Shard 7",
|
||||
"chain": "QuarkChain",
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-7.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s7-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39007"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"shortName": "qkc-s7",
|
||||
"chainId": 100008,
|
||||
"networkId": 100008,
|
||||
"parent": {
|
||||
"chain": "eip155-100000",
|
||||
"type": "shard"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "quarkchain-mainnet",
|
||||
@@ -28,6 +9,26 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "quarkchain-shard-7"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.quarkchain.io",
|
||||
"name": "QuarkChain Mainnet Shard 7",
|
||||
"nativeCurrency": {
|
||||
"name": "QKC",
|
||||
"symbol": "QKC",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100008,
|
||||
"parent": {
|
||||
"type": "shard",
|
||||
"chain": "eip155-100000"
|
||||
},
|
||||
"rpc": [
|
||||
"https://quarkchain-shard-7.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://100008.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-s7-ethapi.quarkchain.io",
|
||||
"http://eth-jrpc.mainnet.quarkchain.io:39007"
|
||||
],
|
||||
"shortName": "qkc-s7",
|
||||
"slug": "quarkchain-shard-7",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,18 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "VeChain",
|
||||
"chain": "VeChain",
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "VeChain",
|
||||
"symbol": "VET",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://vechain.org",
|
||||
"shortName": "vechain",
|
||||
"chainId": 100009,
|
||||
"networkId": 100009,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "VeChain Stats",
|
||||
@@ -25,6 +14,17 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "vechain"
|
||||
"faucets": [],
|
||||
"infoURL": "https://vechain.org",
|
||||
"name": "VeChain",
|
||||
"nativeCurrency": {
|
||||
"name": "VeChain",
|
||||
"symbol": "VET",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100009,
|
||||
"rpc": [],
|
||||
"shortName": "vechain",
|
||||
"slug": "vechain",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,22 +1,24 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Smart Bitcoin Cash Testnet",
|
||||
"chain": "smartBCHTest",
|
||||
"rpc": [
|
||||
"https://smart-bitcoin-cash-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.smartbch.org",
|
||||
"https://smartbch.devops.cash/testnet"
|
||||
],
|
||||
"chainId": 10001,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "http://smartbch.org/",
|
||||
"name": "Smart Bitcoin Cash Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Bitcoin Cash Test Token",
|
||||
"symbol": "BCHT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "http://smartbch.org/",
|
||||
"shortName": "smartbchtest",
|
||||
"chainId": 10001,
|
||||
"networkId": 10001,
|
||||
"testnet": true,
|
||||
"slug": "smart-bitcoin-cash-testnet"
|
||||
"rpc": [
|
||||
"https://smart-bitcoin-cash-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10001.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.smartbch.org",
|
||||
"https://smartbch.devops.cash/testnet"
|
||||
],
|
||||
"shortName": "smartbchtest",
|
||||
"slug": "smart-bitcoin-cash-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,20 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "VeChain Testnet",
|
||||
"chain": "VeChain",
|
||||
"rpc": [],
|
||||
"faucets": [
|
||||
"https://faucet.vecha.in"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "VeChain",
|
||||
"symbol": "VET",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://vechain.org",
|
||||
"shortName": "vechain-testnet",
|
||||
"chainId": 100010,
|
||||
"networkId": 100010,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "VeChain Explorer",
|
||||
@@ -22,6 +9,19 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "vechain-testnet"
|
||||
"faucets": [
|
||||
"https://faucet.vecha.in"
|
||||
],
|
||||
"infoURL": "https://vechain.org",
|
||||
"name": "VeChain Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "VeChain",
|
||||
"symbol": "VET",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100010,
|
||||
"rpc": [],
|
||||
"shortName": "vechain-testnet",
|
||||
"slug": "vechain-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,23 +1,31 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Klaytn Testnet Baobab",
|
||||
"chain": "KLAY",
|
||||
"rpc": [
|
||||
"https://klaytn-testnet-baobab.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.baobab.klaytn.net:8651"
|
||||
"chainId": 1001,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "klaytnscope",
|
||||
"url": "https://scope.klaytn.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://baobab.wallet.klaytn.com/access?next=faucet"
|
||||
],
|
||||
"infoURL": "https://www.klaytn.com/",
|
||||
"name": "Klaytn Testnet Baobab",
|
||||
"nativeCurrency": {
|
||||
"name": "KLAY",
|
||||
"symbol": "KLAY",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.klaytn.com/",
|
||||
"shortName": "Baobab",
|
||||
"chainId": 1001,
|
||||
"networkId": 1001,
|
||||
"testnet": true,
|
||||
"slug": "klaytn-testnet-baobab"
|
||||
"rpc": [
|
||||
"https://klaytn-testnet-baobab.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1001.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.baobab.klaytn.net:8651"
|
||||
],
|
||||
"shortName": "Baobab",
|
||||
"slug": "klaytn-testnet-baobab",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "CHI1",
|
||||
"chainId": 100100,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeidk4swpgdyqmpz6shd5onvpaujvwiwthrhypufnwr6xh3dausz2dm",
|
||||
"width": 1800,
|
||||
"height": 1800,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
"name": "Deprecated CHI",
|
||||
"nativeCurrency": {
|
||||
"name": "Chiado xDAI",
|
||||
"symbol": "xDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 100100,
|
||||
"rpc": [],
|
||||
"shortName": "chi1",
|
||||
"slug": "deprecated-chi",
|
||||
"status": "deprecated",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,28 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Gon Chain",
|
||||
"chain": "GonChain",
|
||||
"icon": {
|
||||
"url": "ipfs://QmPtiJGaApbW3ATZhPW3pKJpw3iGVrRGsZLWhrDKF9ZK18",
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://gon-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://node1.testnet.gaiaopen.network",
|
||||
"http://database1.gaiaopen.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Gon Token",
|
||||
"symbol": "GT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "",
|
||||
"shortName": "gon",
|
||||
"chainId": 10024,
|
||||
"networkId": 10024,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Gon Explorer",
|
||||
@@ -30,6 +9,30 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "gon-chain"
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmPtiJGaApbW3ATZhPW3pKJpw3iGVrRGsZLWhrDKF9ZK18",
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"format": "png"
|
||||
},
|
||||
"name": "Gon Chain",
|
||||
"nativeCurrency": {
|
||||
"name": "Gon Token",
|
||||
"symbol": "GT",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10024,
|
||||
"rpc": [
|
||||
"https://gon-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10024.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://node1.testnet.gaiaopen.network",
|
||||
"https://node1.mainnet.gon.network",
|
||||
"https://node2.mainnet.gon.network",
|
||||
"https://node3.mainnet.gon.network",
|
||||
"https://node4.mainnet.gon.network"
|
||||
],
|
||||
"shortName": "gon",
|
||||
"slug": "gon-chain",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "TET",
|
||||
"chainId": 1003,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Tectum explorer",
|
||||
"url": "https://explorer.tectum.io",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYvFVprVdAGJH4iHUCXGEmy7pq8MMfxEjM64SuXutz9qx",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"infoURL": "https://softnote.com",
|
||||
"name": "Tectum Emission Token",
|
||||
"nativeCurrency": {
|
||||
"name": "Tectum",
|
||||
"symbol": "TET",
|
||||
"decimals": 8
|
||||
},
|
||||
"networkId": 1003,
|
||||
"rpc": [
|
||||
"https://tectum-emission-token.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1003.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.softnote.com/"
|
||||
],
|
||||
"shortName": "tet",
|
||||
"slug": "tectum-emission-token",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,41 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "T-EKTA",
|
||||
"title": "EKTA Testnet T-EKTA",
|
||||
"chain": "T-EKTA",
|
||||
"rpc": [
|
||||
"https://t-ekta.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://test.ekta.io:8545"
|
||||
"chainId": 1004,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "test-ektascan",
|
||||
"url": "https://test.ektascan.io",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmfMd564KUPK8eKZDwGCT71ZC2jMnUZqP6LCtLpup3rHH1",
|
||||
"width": 2100,
|
||||
"height": 2100,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "T-EKTA",
|
||||
"symbol": "T-EKTA",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.ekta.io",
|
||||
"shortName": "t-ekta",
|
||||
"chainId": 1004,
|
||||
"networkId": 1004,
|
||||
"icon": {
|
||||
"url": "ipfs://QmfMd564KUPK8eKZDwGCT71ZC2jMnUZqP6LCtLpup3rHH1",
|
||||
"width": 2100,
|
||||
"height": 2100,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "test-ektascan",
|
||||
"url": "https://test.ektascan.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmfMd564KUPK8eKZDwGCT71ZC2jMnUZqP6LCtLpup3rHH1",
|
||||
"width": 2100,
|
||||
"height": 2100,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
"infoURL": "https://www.ekta.io",
|
||||
"name": "T-EKTA",
|
||||
"nativeCurrency": {
|
||||
"name": "T-EKTA",
|
||||
"symbol": "T-EKTA",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1004,
|
||||
"rpc": [
|
||||
"https://t-ekta.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1004.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://test.ekta.io:8545"
|
||||
],
|
||||
"shortName": "t-ekta",
|
||||
"slug": "t-ekta",
|
||||
"testnet": true,
|
||||
"slug": "t-ekta"
|
||||
"title": "EKTA Testnet T-EKTA"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Plian Testnet Subchain 1",
|
||||
"chain": "Plian",
|
||||
"rpc": [
|
||||
"https://plian-testnet-subchain-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.plian.io/child_test"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Plian Token",
|
||||
"symbol": "TPI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://plian.org/",
|
||||
"shortName": "plian-testnet-l2",
|
||||
"chainId": 10067275,
|
||||
"networkId": 10067275,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "piscan",
|
||||
@@ -23,10 +9,25 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"parent": {
|
||||
"chain": "eip155-16658437",
|
||||
"type": "L2"
|
||||
"faucets": [],
|
||||
"infoURL": "https://plian.org/",
|
||||
"name": "Plian Testnet Subchain 1",
|
||||
"nativeCurrency": {
|
||||
"name": "Plian Token",
|
||||
"symbol": "TPI",
|
||||
"decimals": 18
|
||||
},
|
||||
"testnet": true,
|
||||
"slug": "plian-testnet-subchain-1"
|
||||
"networkId": 10067275,
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-16658437"
|
||||
},
|
||||
"rpc": [
|
||||
"https://plian-testnet-subchain-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10067275.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.plian.io/child_test"
|
||||
],
|
||||
"shortName": "plian-testnet-l2",
|
||||
"slug": "plian-testnet-subchain-1",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Newton Testnet",
|
||||
"chain": "NEW",
|
||||
"rpc": [
|
||||
"https://newton-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc1.newchain.newtonproject.org"
|
||||
],
|
||||
"chainId": 1007,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.newtonproject.org/",
|
||||
"name": "Newton Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Newton",
|
||||
"symbol": "NEW",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.newtonproject.org/",
|
||||
"shortName": "tnew",
|
||||
"chainId": 1007,
|
||||
"networkId": 1007,
|
||||
"testnet": true,
|
||||
"slug": "newton-testnet"
|
||||
"rpc": [
|
||||
"https://newton-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1007.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc1.newchain.newtonproject.org"
|
||||
],
|
||||
"shortName": "tnew",
|
||||
"slug": "newton-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,40 +1,41 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Eurus Mainnet",
|
||||
"chain": "EUN",
|
||||
"rpc": [
|
||||
"https://eurus.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.eurus.network/"
|
||||
"chainId": 1008,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "eurusexplorer",
|
||||
"url": "https://explorer.eurus.network",
|
||||
"standard": "none",
|
||||
"icon": {
|
||||
"url": "ipfs://QmaGd5L9jGPbfyGXBFhu9gjinWJ66YtNrXq8x6Q98Eep9e",
|
||||
"width": 471,
|
||||
"height": 471,
|
||||
"format": "svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Eurus",
|
||||
"symbol": "EUN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://eurus.network",
|
||||
"shortName": "eun",
|
||||
"chainId": 1008,
|
||||
"networkId": 1008,
|
||||
"icon": {
|
||||
"url": "ipfs://QmaGd5L9jGPbfyGXBFhu9gjinWJ66YtNrXq8x6Q98Eep9e",
|
||||
"width": 471,
|
||||
"height": 471,
|
||||
"format": "svg"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "eurusexplorer",
|
||||
"url": "https://explorer.eurus.network",
|
||||
"icon": {
|
||||
"url": "ipfs://QmaGd5L9jGPbfyGXBFhu9gjinWJ66YtNrXq8x6Q98Eep9e",
|
||||
"width": 471,
|
||||
"height": 471,
|
||||
"format": "svg"
|
||||
},
|
||||
"standard": "none"
|
||||
}
|
||||
"infoURL": "https://eurus.network",
|
||||
"name": "Eurus Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Eurus",
|
||||
"symbol": "EUN",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1008,
|
||||
"rpc": [
|
||||
"https://eurus.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1008.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.eurus.network/"
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "eurus"
|
||||
"shortName": "eun",
|
||||
"slug": "eurus",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "JOCT",
|
||||
"chainId": 10081,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Testnet Block Explorer",
|
||||
"url": "https://explorer.testnet.japanopenchain.org",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.japanopenchain.org/",
|
||||
"name": "Japan Open Chain Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Japan Open Chain Testnet Token",
|
||||
"symbol": "JOCT",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10081,
|
||||
"rpc": [
|
||||
"https://japan-open-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10081.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-1.testnet.japanopenchain.org:8545",
|
||||
"https://rpc-2.testnet.japanopenchain.org:8545"
|
||||
],
|
||||
"shortName": "joct",
|
||||
"slug": "japan-open-chain-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "SJATSH",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://sjatsh.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://geth.free.idcfengye.com"
|
||||
],
|
||||
"chainId": 10086,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://sjis.me",
|
||||
"name": "SJATSH",
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://sjis.me",
|
||||
"shortName": "SJ",
|
||||
"chainId": 10086,
|
||||
"networkId": 10086,
|
||||
"testnet": false,
|
||||
"slug": "sjatsh"
|
||||
"rpc": [
|
||||
"https://sjatsh.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10086.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://geth.free.idcfengye.com"
|
||||
],
|
||||
"shortName": "SJ",
|
||||
"slug": "sjatsh",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,22 +1,24 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "EtherInc",
|
||||
"chain": "ETI",
|
||||
"rpc": [
|
||||
"https://etherinc.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.einc.io/jsonrpc/mainnet"
|
||||
],
|
||||
"chainId": 101,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://einc.io",
|
||||
"name": "EtherInc",
|
||||
"nativeCurrency": {
|
||||
"name": "EtherInc Ether",
|
||||
"symbol": "ETI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://einc.io",
|
||||
"shortName": "eti",
|
||||
"chainId": 101,
|
||||
"networkId": 1,
|
||||
"rpc": [
|
||||
"https://etherinc.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://101.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.einc.io/jsonrpc/mainnet"
|
||||
],
|
||||
"shortName": "eti",
|
||||
"slip44": 464,
|
||||
"testnet": false,
|
||||
"slug": "etherinc"
|
||||
"slug": "etherinc",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,22 +1,24 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Evrice Network",
|
||||
"chain": "EVC",
|
||||
"rpc": [
|
||||
"https://evrice-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://meta.evrice.com"
|
||||
],
|
||||
"chainId": 1010,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://evrice.com",
|
||||
"name": "Evrice Network",
|
||||
"nativeCurrency": {
|
||||
"name": "Evrice",
|
||||
"symbol": "EVC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://evrice.com",
|
||||
"shortName": "EVC",
|
||||
"chainId": 1010,
|
||||
"networkId": 1010,
|
||||
"rpc": [
|
||||
"https://evrice-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1010.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://meta.evrice.com"
|
||||
],
|
||||
"shortName": "EVC",
|
||||
"slip44": 1020,
|
||||
"testnet": false,
|
||||
"slug": "evrice-network"
|
||||
"slug": "evrice-network",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,23 +1,25 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Blockchain Genesis Mainnet",
|
||||
"chain": "GEN",
|
||||
"rpc": [
|
||||
"https://blockchain-genesis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eu.mainnet.xixoio.com",
|
||||
"https://us.mainnet.xixoio.com",
|
||||
"https://asia.mainnet.xixoio.com"
|
||||
],
|
||||
"chainId": 10101,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.xixoio.com/",
|
||||
"name": "Blockchain Genesis Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "GEN",
|
||||
"symbol": "GEN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.xixoio.com/",
|
||||
"shortName": "GEN",
|
||||
"chainId": 10101,
|
||||
"networkId": 10101,
|
||||
"testnet": false,
|
||||
"slug": "blockchain-genesis"
|
||||
"rpc": [
|
||||
"https://blockchain-genesis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10101.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eu.mainnet.xixoio.com",
|
||||
"https://us.mainnet.xixoio.com",
|
||||
"https://asia.mainnet.xixoio.com"
|
||||
],
|
||||
"shortName": "GEN",
|
||||
"slug": "blockchain-genesis",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,29 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Soverun Testnet",
|
||||
"chain": "SVRN",
|
||||
"icon": {
|
||||
"url": "ipfs://QmTYazUzgY9Nn2mCjWwFUSLy3dG6i2PvALpwCNQvx1zXyi",
|
||||
"width": 1154,
|
||||
"height": 1154,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://soverun-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-rpc.soverun.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.soverun.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Soverun",
|
||||
"symbol": "SVRN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://soverun.com",
|
||||
"shortName": "SVRNt",
|
||||
"chainId": 101010,
|
||||
"networkId": 101010,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Soverun",
|
||||
@@ -31,6 +9,29 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "soverun-testnet"
|
||||
"faucets": [
|
||||
"https://faucet.soverun.com"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://QmTYazUzgY9Nn2mCjWwFUSLy3dG6i2PvALpwCNQvx1zXyi",
|
||||
"width": 1154,
|
||||
"height": 1154,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://soverun.com",
|
||||
"name": "Soverun Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Soverun",
|
||||
"symbol": "SVRN",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 101010,
|
||||
"rpc": [
|
||||
"https://soverun-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://101010.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-rpc.soverun.com"
|
||||
],
|
||||
"shortName": "SVRNt",
|
||||
"slug": "soverun-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,29 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Soverun Mainnet",
|
||||
"chain": "SVRN",
|
||||
"icon": {
|
||||
"url": "ipfs://QmTYazUzgY9Nn2mCjWwFUSLy3dG6i2PvALpwCNQvx1zXyi",
|
||||
"width": 1154,
|
||||
"height": 1154,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://soverun.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-rpc.soverun.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.soverun.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Soverun",
|
||||
"symbol": "SVRN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://soverun.com",
|
||||
"shortName": "SVRNm",
|
||||
"chainId": 10101010,
|
||||
"networkId": 10101010,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Soverun",
|
||||
@@ -31,6 +9,29 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "soverun"
|
||||
"faucets": [
|
||||
"https://faucet.soverun.com"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://QmTYazUzgY9Nn2mCjWwFUSLy3dG6i2PvALpwCNQvx1zXyi",
|
||||
"width": 1154,
|
||||
"height": 1154,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://soverun.com",
|
||||
"name": "Soverun Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Soverun",
|
||||
"symbol": "SVRN",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10101010,
|
||||
"rpc": [
|
||||
"https://soverun.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10101010.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-rpc.soverun.com"
|
||||
],
|
||||
"shortName": "SVRNm",
|
||||
"slug": "soverun",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Newton",
|
||||
"chain": "NEW",
|
||||
"rpc": [
|
||||
"https://newton.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://global.rpc.mainnet.newtonproject.org"
|
||||
],
|
||||
"chainId": 1012,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.newtonproject.org/",
|
||||
"name": "Newton",
|
||||
"nativeCurrency": {
|
||||
"name": "Newton",
|
||||
"symbol": "NEW",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.newtonproject.org/",
|
||||
"shortName": "new",
|
||||
"chainId": 1012,
|
||||
"networkId": 1012,
|
||||
"testnet": false,
|
||||
"slug": "newton"
|
||||
"rpc": [
|
||||
"https://newton.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1012.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://global.rpc.mainnet.newtonproject.org"
|
||||
],
|
||||
"shortName": "new",
|
||||
"slug": "newton",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,29 +1,31 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Web3Games Testnet",
|
||||
"chain": "Web3Games",
|
||||
"chainId": 102,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmUc57w3UTHiWapNW9oQb1dP57ymtdemTTbpvGkjVHBRCo",
|
||||
"width": 192,
|
||||
"height": 192,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://web3games-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-rpc-0.web3games.org/evm",
|
||||
"https://testnet-rpc-1.web3games.org/evm",
|
||||
"https://testnet-rpc-2.web3games.org/evm"
|
||||
],
|
||||
"faucets": [],
|
||||
"infoURL": "https://web3games.org/",
|
||||
"name": "Web3Games Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Web3Games",
|
||||
"symbol": "W3G",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://web3games.org/",
|
||||
"shortName": "tw3g",
|
||||
"chainId": 102,
|
||||
"networkId": 102,
|
||||
"testnet": true,
|
||||
"slug": "web3games-testnet"
|
||||
"rpc": [
|
||||
"https://web3games-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://102.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-rpc-0.web3games.org/evm",
|
||||
"https://testnet-rpc-1.web3games.org/evm",
|
||||
"https://testnet-rpc-2.web3games.org/evm"
|
||||
],
|
||||
"shortName": "tw3g",
|
||||
"slug": "web3games-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,44 +1,47 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Gnosis Chiado Testnet",
|
||||
"chain": "GNO",
|
||||
"chainId": 10200,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://gnosis-chiado.blockscout.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeidk4swpgdyqmpz6shd5onvpaujvwiwthrhypufnwr6xh3dausz2dm",
|
||||
"width": 1800,
|
||||
"height": 1800,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://gnosis-chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.chiadochain.net",
|
||||
"https://rpc.chiado.gnosis.gateway.fm",
|
||||
"wss://rpc.chiadochain.net/wss"
|
||||
],
|
||||
"faucets": [
|
||||
"https://gnosisfaucet.com"
|
||||
],
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
"name": "Gnosis Chiado Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Chiado xDAI",
|
||||
"symbol": "XDAI",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.gnosischain.com",
|
||||
"shortName": "chi",
|
||||
"chainId": 10200,
|
||||
"networkId": 10200,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.chiadochain.net",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
"rpc": [
|
||||
"https://gnosis-chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10200.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.chiadochain.net",
|
||||
"https://rpc.chiado.gnosis.gateway.fm",
|
||||
"wss://rpc.chiadochain.net/wss",
|
||||
"https://gnosis-chiado.publicnode.com",
|
||||
"wss://gnosis-chiado.publicnode.com"
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "gnosis-chiado-testnet"
|
||||
"shortName": "chi",
|
||||
"slug": "gnosis-chiado-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "MaxxChain",
|
||||
"chainId": 10201,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "MaxxChain Block Explorer",
|
||||
"url": "https://explorer.maxxchain.org",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.maxxchain.org"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://QmRhQG9TZrXDdbQeTzBmjg3pqgwaD5TKVZj8k4kaz8AoZx",
|
||||
"width": 1021,
|
||||
"height": 1021,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://www.maxxchain.org/",
|
||||
"name": "MaxxChain Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Power",
|
||||
"symbol": "PWR",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10201,
|
||||
"rpc": [
|
||||
"https://maxxchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10201.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.maxxchain.org",
|
||||
"https://rpc1.maxxchain.org",
|
||||
"https://rpc2.maxxchain.org"
|
||||
],
|
||||
"shortName": "PWR",
|
||||
"slug": "maxxchain",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,18 +1,19 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Sakura",
|
||||
"chain": "Sakura",
|
||||
"rpc": [],
|
||||
"chainId": 1022,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://clover.finance/sakura",
|
||||
"name": "Sakura",
|
||||
"nativeCurrency": {
|
||||
"name": "Sakura",
|
||||
"symbol": "SKU",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://clover.finance/sakura",
|
||||
"shortName": "sku",
|
||||
"chainId": 1022,
|
||||
"networkId": 1022,
|
||||
"testnet": false,
|
||||
"slug": "sakura"
|
||||
"rpc": [],
|
||||
"shortName": "sku",
|
||||
"slug": "sakura",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,18 +1,19 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Clover Testnet",
|
||||
"chain": "Clover",
|
||||
"rpc": [],
|
||||
"chainId": 1023,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://clover.finance",
|
||||
"name": "Clover Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Clover",
|
||||
"symbol": "CLV",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://clover.finance",
|
||||
"shortName": "tclv",
|
||||
"chainId": 1023,
|
||||
"networkId": 1023,
|
||||
"testnet": true,
|
||||
"slug": "clover-testnet"
|
||||
"rpc": [],
|
||||
"shortName": "tclv",
|
||||
"slug": "clover-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "CLV Parachain",
|
||||
"chain": "CLV",
|
||||
"rpc": [
|
||||
"https://clv-parachain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api-para.clover.finance"
|
||||
],
|
||||
"chainId": 1024,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://clv.org",
|
||||
"name": "CLV Parachain",
|
||||
"nativeCurrency": {
|
||||
"name": "CLV",
|
||||
"symbol": "CLV",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://clv.org",
|
||||
"shortName": "clv",
|
||||
"chainId": 1024,
|
||||
"networkId": 1024,
|
||||
"testnet": false,
|
||||
"slug": "clv-parachain"
|
||||
"rpc": [
|
||||
"https://clv-parachain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1024.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api-para.clover.finance"
|
||||
],
|
||||
"shortName": "clv",
|
||||
"slug": "clv-parachain",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "AA",
|
||||
"chainId": 10243,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://explorer-test.arthera.net",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.arthera.net"
|
||||
],
|
||||
"icon": {
|
||||
"url": "ipfs://QmYQp3e52KjkT4bYdAvB6ACEEpXs2D8DozsDitaADRY2Ak",
|
||||
"width": 1024,
|
||||
"height": 998,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://docs.arthera.net",
|
||||
"name": "Arthera Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Arthera",
|
||||
"symbol": "AA",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10243,
|
||||
"rpc": [
|
||||
"https://arthera-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10243.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-test.arthera.net"
|
||||
],
|
||||
"shortName": "aa",
|
||||
"slug": "arthera-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "0XTade",
|
||||
"chain": "0XTade Chain",
|
||||
"rpc": [
|
||||
"https://0xtade.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://node.0xtchain.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "0XT",
|
||||
"symbol": "0XT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.0xtrade.finance/",
|
||||
"shortName": "0xt",
|
||||
"chainId": 10248,
|
||||
"networkId": 10248,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "0xtrade Scan",
|
||||
@@ -23,6 +9,21 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "0xtade"
|
||||
"faucets": [],
|
||||
"infoURL": "https://www.0xtrade.finance/",
|
||||
"name": "0XTade",
|
||||
"nativeCurrency": {
|
||||
"name": "0XT",
|
||||
"symbol": "0XT",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 10248,
|
||||
"rpc": [
|
||||
"https://0xtade.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://10248.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://node.0xtchain.com"
|
||||
],
|
||||
"shortName": "0xt",
|
||||
"slug": "0xtade",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "BitTorrent Chain Testnet",
|
||||
"chain": "BTTC",
|
||||
"rpc": [
|
||||
"https://bittorrent-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testrpc.bittorrentchain.io/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "BitTorrent",
|
||||
"symbol": "BTT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://bittorrentchain.io/",
|
||||
"shortName": "tbtt",
|
||||
"chainId": 1028,
|
||||
"networkId": 1028,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "testbttcscan",
|
||||
@@ -23,6 +9,21 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "bittorrent-chain-testnet"
|
||||
"faucets": [],
|
||||
"infoURL": "https://bittorrentchain.io/",
|
||||
"name": "BitTorrent Chain Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "BitTorrent",
|
||||
"symbol": "BTT",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1028,
|
||||
"rpc": [
|
||||
"https://bittorrent-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1028.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testrpc.bittorrentchain.io/"
|
||||
],
|
||||
"shortName": "tbtt",
|
||||
"slug": "bittorrent-chain-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Worldland",
|
||||
"chainId": 103,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Worldland Explorer",
|
||||
"url": "https://scan.worldland.foundation",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmYZNTfK3byhgLsTjXP8vPubVHRz2CWsBrTJxZrQmKq6JZ",
|
||||
"width": 3509,
|
||||
"height": 2482,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://worldland.foundation",
|
||||
"name": "Worldland Mainnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Worldland",
|
||||
"symbol": "WL",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 103,
|
||||
"rpc": [
|
||||
"https://worldland.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://103.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://seoul.worldland.foundation"
|
||||
],
|
||||
"shortName": "WLC",
|
||||
"slug": "worldland",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
@@ -1,27 +1,7 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Conflux eSpace",
|
||||
"chain": "Conflux",
|
||||
"rpc": [
|
||||
"https://conflux-espace.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://evm.confluxrpc.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "CFX",
|
||||
"symbol": "CFX",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://confluxnetwork.org",
|
||||
"shortName": "cfx",
|
||||
"chainId": 1030,
|
||||
"networkId": 1030,
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifj7n24u2dslfijfihwqvpdeigt5aj3k3sxv6s35lv75sxsfr3ojy",
|
||||
"width": 460,
|
||||
"height": 576,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Conflux Scan",
|
||||
@@ -29,6 +9,27 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "conflux-espace"
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifj7n24u2dslfijfihwqvpdeigt5aj3k3sxv6s35lv75sxsfr3ojy",
|
||||
"width": 460,
|
||||
"height": 576,
|
||||
"format": "png"
|
||||
},
|
||||
"infoURL": "https://confluxnetwork.org",
|
||||
"name": "Conflux eSpace",
|
||||
"nativeCurrency": {
|
||||
"name": "CFX",
|
||||
"symbol": "CFX",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1030,
|
||||
"rpc": [
|
||||
"https://conflux-espace.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://1030.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://evm.confluxrpc.com"
|
||||
],
|
||||
"shortName": "cfx",
|
||||
"slug": "conflux-espace",
|
||||
"testnet": false
|
||||
} as const satisfies Chain;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user