Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -23,6 +23,7 @@
|
||||
| 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> |
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.37",
|
||||
"version": "3.2.40",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @thirdweb-dev/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
|
||||
|
||||
@@ -15,7 +15,9 @@ export default {
|
||||
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com"
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
"wss://mainnet.gateway.tenderly.co"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
|
||||
@@ -7,7 +7,9 @@ export default {
|
||||
"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"
|
||||
"https://optimism.publicnode.com",
|
||||
"https://optimism.gateway.tenderly.co",
|
||||
"wss://optimism.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Worldland Mainnet",
|
||||
"chain": "Worldland",
|
||||
"rpc": [
|
||||
"https://worldland.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://seoul.worldland.foundation"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Worldland",
|
||||
"symbol": "WL",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://worldland.foundation",
|
||||
"shortName": "WLC",
|
||||
"chainId": 103,
|
||||
"networkId": 103,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Worldland Explorer",
|
||||
"url": "https://scan.worldland.foundation",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "worldland"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Worldland Testnet",
|
||||
"chain": "Worldland",
|
||||
"rpc": [
|
||||
"https://worldland-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://gwangju.worldland.foundation"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Worldland",
|
||||
"symbol": "WL",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://worldland.foundation",
|
||||
"shortName": "TWLC",
|
||||
"chainId": 10395,
|
||||
"networkId": 10395,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Worldland Explorer",
|
||||
"url": "https://testscan.worldland.foundation",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "worldland-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -10,7 +10,9 @@ export default {
|
||||
"https://rpc.sepolia.org",
|
||||
"https://rpc2.sepolia.org",
|
||||
"https://rpc-sepolia.rockx.com",
|
||||
"https://rpc.sepolia.ethpandaops.io"
|
||||
"https://rpc.sepolia.ethpandaops.io",
|
||||
"https://sepolia.gateway.tenderly.co",
|
||||
"wss://sepolia.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [
|
||||
"http://fauceth.komputing.org?chain=11155111&address=${ADDRESS}"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "DeBank Testnet",
|
||||
"chain": "DeBank",
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmW9pBps8WHRRWmyXhjLZrjZJUe8F48hUu7z98bu2RVsjN",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://debank.com",
|
||||
"shortName": "debank-testnet",
|
||||
"chainId": 115,
|
||||
"networkId": 115,
|
||||
"explorers": [],
|
||||
"testnet": true,
|
||||
"slug": "debank-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "DeBank Mainnet",
|
||||
"chain": "DeBank",
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmW9pBps8WHRRWmyXhjLZrjZJUe8F48hUu7z98bu2RVsjN",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://debank.com",
|
||||
"shortName": "debank-mainnet",
|
||||
"chainId": 116,
|
||||
"networkId": 116,
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "debank"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Polygon Supernet Arianee",
|
||||
"chain": "Arianee",
|
||||
"rpc": [
|
||||
"https://polygon-supernet-arianee.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.polygonsupernet.public.arianee.net"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Arianee",
|
||||
"symbol": "ARIA20",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://arianee.org",
|
||||
"shortName": "Arianee",
|
||||
"chainId": 11891,
|
||||
"networkId": 11891,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Polygon Supernet Arianee Explorer",
|
||||
"url": "https://polygonsupernet.explorer.arianee.net",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"parent": {
|
||||
"chain": "eip155-1",
|
||||
"type": "L2"
|
||||
},
|
||||
"testnet": false,
|
||||
"slug": "polygon-supernet-arianee"
|
||||
} as const satisfies Chain;
|
||||
@@ -17,8 +17,14 @@ export default {
|
||||
"symbol": "MC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://gaming.meritcircle.io",
|
||||
"shortName": "BEAM",
|
||||
"infoURL": "https://www.onbeam.com",
|
||||
"shortName": "beam-testnet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmQJ21NWyGGDraicVEzS1Uqq1yXahM9NCuNZgnfYvtspdt",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"chainId": 13337,
|
||||
"networkId": 13337,
|
||||
"explorers": [
|
||||
|
||||
@@ -18,7 +18,9 @@ export default {
|
||||
"https://rpc-mainnet.maticvigil.com",
|
||||
"https://rpc-mainnet.matic.quiknode.pro",
|
||||
"https://matic-mainnet-full-rpc.bwarelabs.com",
|
||||
"https://polygon-bor.publicnode.com"
|
||||
"https://polygon-bor.publicnode.com",
|
||||
"https://polygon.gateway.tenderly.co",
|
||||
"wss://polygon.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Redbelly Network Mainnet",
|
||||
"shortName": "rbn",
|
||||
"chain": "RBN",
|
||||
"chainId": 151,
|
||||
"networkId": 151,
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://redbelly.network",
|
||||
"nativeCurrency": {
|
||||
"name": "Redbelly Network Coin",
|
||||
"symbol": "RBNT",
|
||||
"decimals": 18
|
||||
},
|
||||
"status": "incubating",
|
||||
"testnet": false,
|
||||
"slug": "redbelly-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Redbelly Network Devnet",
|
||||
"shortName": "rbn-devnet",
|
||||
"chain": "RBN",
|
||||
"chainId": 152,
|
||||
"networkId": 152,
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://redbelly.network",
|
||||
"nativeCurrency": {
|
||||
"name": "Redbelly Network Coin",
|
||||
"symbol": "RBNT",
|
||||
"decimals": 18
|
||||
},
|
||||
"status": "incubating",
|
||||
"testnet": false,
|
||||
"slug": "redbelly-network-devnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Redbelly Network Testnet",
|
||||
"shortName": "rbn-testnet",
|
||||
"chain": "RBN",
|
||||
"chainId": 153,
|
||||
"networkId": 153,
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://redbelly.network",
|
||||
"nativeCurrency": {
|
||||
"name": "Redbelly Network Coin",
|
||||
"symbol": "RBNT",
|
||||
"decimals": 18
|
||||
},
|
||||
"status": "incubating",
|
||||
"testnet": true,
|
||||
"slug": "redbelly-network-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Redbelly Network TGE",
|
||||
"shortName": "rbn-tge",
|
||||
"chain": "RBN",
|
||||
"chainId": 154,
|
||||
"networkId": 154,
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"infoURL": "https://redbelly.network",
|
||||
"nativeCurrency": {
|
||||
"name": "Redbelly Network Coin",
|
||||
"symbol": "RBNT",
|
||||
"decimals": 18
|
||||
},
|
||||
"testnet": false,
|
||||
"slug": "redbelly-network-tge"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Bitchain Mainnet",
|
||||
"chain": "Bit",
|
||||
"rpc": [
|
||||
"https://bitchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.bitchain.biz/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Bitcoin",
|
||||
"symbol": "BTC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.bitchain.biz/",
|
||||
"shortName": "bit",
|
||||
"chainId": 198,
|
||||
"networkId": 198,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Bitchain Scan",
|
||||
"url": "https://explorer.bitchain.biz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "bitchain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Shrapnel Testnet",
|
||||
"chain": "SHRAPNEL",
|
||||
"rpc": [
|
||||
"https://shrapnel-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/shrapnel/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "SHRAPG",
|
||||
"symbol": "SHRAPG",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.shrapnel.com/",
|
||||
"shortName": "shraptest",
|
||||
"chainId": 2038,
|
||||
"networkId": 2038,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "SHRAPNEL Explorer",
|
||||
"url": "https://subnets-test.avax.network/shrapnel",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "shrapnel-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "BigShortBets",
|
||||
"chain": "BIGSB",
|
||||
"rpc": [
|
||||
"https://bigshortbets.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://market.bigsb.io",
|
||||
"wss://market.bigsb.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "USD Coin",
|
||||
"symbol": "USDC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://bigshortbets.com/",
|
||||
"shortName": "bigsb",
|
||||
"chainId": 2137,
|
||||
"networkId": 2137,
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "bigshortbets"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Nautilus Mainnet",
|
||||
"chain": "ETH",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNutSgM7n6aJPPDiofe9Dm1epy1RcYTMvugukLUK2vmPM",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://nautilus.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.nautilus.nautchain.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Zebec",
|
||||
"symbol": "ZBC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.nautchain.xyz",
|
||||
"shortName": "NAUTCHAIN",
|
||||
"chainId": 22222,
|
||||
"networkId": 22222,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Nautscan",
|
||||
"url": "https://nautscan.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNutSgM7n6aJPPDiofe9Dm1epy1RcYTMvugukLUK2vmPM",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "nautilus"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Morphism Testnet",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://morphism-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.morphism.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://morphism.xyz",
|
||||
"shortName": "tmorph",
|
||||
"chainId": 2710,
|
||||
"networkId": 2710,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Morphism Testnet Explorer",
|
||||
"url": "https://explorer-testnet.morphism.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-1",
|
||||
"bridges": [
|
||||
{
|
||||
"url": "https://bridge-testnet.morphism.xyz"
|
||||
}
|
||||
]
|
||||
},
|
||||
"testnet": true,
|
||||
"slug": "morphism-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -6,8 +6,8 @@ export default {
|
||||
"https://boba-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.boba.network",
|
||||
"https://replica.boba.network",
|
||||
"http://boba-ethereum.gateway.tenderly.co",
|
||||
"http://gateway.tenderly.co/public/boba-ethereum",
|
||||
"https://boba-ethereum.gateway.tenderly.co",
|
||||
"https://gateway.tenderly.co/public/boba-ethereum",
|
||||
"wss://boba-ethereum.gateway.tenderly.co/",
|
||||
"wss://gateway.tenderly.co/public/boba-ethereum"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Dubxcoin network",
|
||||
"chain": "DUBX",
|
||||
"rpc": [
|
||||
"https://dubxcoin-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpcmain.arabianchain.org"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Dubxcoin mainnet",
|
||||
"symbol": "DUBX",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://arabianchain.org",
|
||||
"shortName": "dubx",
|
||||
"chainId": 3269,
|
||||
"networkId": 3269,
|
||||
"testnet": false,
|
||||
"slug": "dubxcoin-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Dubxcoin testnet",
|
||||
"chain": "TESTDUBX",
|
||||
"rpc": [
|
||||
"https://dubxcoin-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpctestnet.arabianchain.org"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.arabianchain.org/"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Dubxcoin testnet",
|
||||
"symbol": "TDUBX",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://arabianchain.org",
|
||||
"shortName": "testdubx",
|
||||
"chainId": 3270,
|
||||
"networkId": 3270,
|
||||
"testnet": true,
|
||||
"slug": "dubxcoin-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Xpla Mainnet",
|
||||
"chain": "XPLA",
|
||||
"rpc": [
|
||||
"https://xpla-xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://dimension-evm-rpc.xpla.dev"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
@@ -31,5 +31,5 @@ export default {
|
||||
"redFlags": [
|
||||
"reusedChainId"
|
||||
],
|
||||
"slug": "xpla-xpla"
|
||||
"slug": "xpla"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Xpla Mainnet",
|
||||
"chain": "XPLA",
|
||||
"name": "Xpla Testnet",
|
||||
"chain": "XPLATest",
|
||||
"rpc": [
|
||||
"https://xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://xpla-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://dimension-rpc.xpla.dev"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.xpla.io/"
|
||||
"https://faucet.xpla.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "XPLA",
|
||||
"symbol": "XPLA",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://xpla.io/",
|
||||
"shortName": "xpla",
|
||||
"infoURL": "https://xpla.io",
|
||||
"shortName": "xplatest",
|
||||
"chainId": 3701,
|
||||
"networkId": 3701,
|
||||
"icon": {
|
||||
@@ -31,6 +31,9 @@ export default {
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "xpla"
|
||||
"redFlags": [
|
||||
"reusedChainId"
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "xpla-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "ConnectorManager Robin",
|
||||
"chain": "Rangers",
|
||||
"icon": {
|
||||
"url": "ipfs://QmXR5e5SDABWfQn6XT9uMsVYAo5Bv7vUv4jVs8DFqatZWG",
|
||||
"width": 2000,
|
||||
"height": 2000,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://connectormanager-robin.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://robin-cm.rangersprotocol.com/api/jsonrpc"
|
||||
],
|
||||
"faucets": [
|
||||
"https://robin-faucet.rangersprotocol.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Rangers Protocol Gas",
|
||||
"symbol": "ttRPG",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://rangersprotocol.com",
|
||||
"shortName": "ttrpg",
|
||||
"chainId": 38401,
|
||||
"networkId": 38401,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "rangersscan-robin",
|
||||
"url": "https://robin-rangersscan.rangersprotocol.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "connectormanager-robin"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,14 +1,12 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Unicorn Ultra Testnet",
|
||||
"name": "U2U Solaris Mainnet",
|
||||
"chain": "u2u",
|
||||
"rpc": [
|
||||
"https://unicorn-ultra-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.uniultra.xyz"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.uniultra.xyz"
|
||||
"https://u2u-solaris.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-mainnet.uniultra.xyz"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Unicorn Ultra",
|
||||
"symbol": "U2U",
|
||||
@@ -33,10 +31,10 @@ export default {
|
||||
"format": "png"
|
||||
},
|
||||
"name": "U2U Explorer",
|
||||
"url": "https://testnet.uniultra.xyz",
|
||||
"url": "https://u2uscan.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "unicorn-ultra-testnet"
|
||||
"testnet": false,
|
||||
"slug": "u2u-solaris"
|
||||
} as const satisfies Chain;
|
||||
@@ -7,7 +7,9 @@ export default {
|
||||
"https://optimism-goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://goerli.optimism.io",
|
||||
"https://optimism-goerli.publicnode.com"
|
||||
"https://optimism-goerli.publicnode.com",
|
||||
"https://optimism-goerli.gateway.tenderly.co",
|
||||
"wss://optimism-goerli.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [
|
||||
"https://coinbase.com/faucets/optimism-goerli-faucet"
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Xpla Testnet",
|
||||
"chain": "XPLA",
|
||||
"rpc": [
|
||||
"https://xpla-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://xpla-testnet-xpla-test.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://cube-evm-rpc.xpla.dev"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
@@ -34,5 +34,5 @@ export default {
|
||||
"redFlags": [
|
||||
"reusedChainId"
|
||||
],
|
||||
"slug": "xpla-testnet"
|
||||
"slug": "xpla-testnet-xpla-test"
|
||||
} as const satisfies Chain;
|
||||
@@ -9,7 +9,9 @@ export default {
|
||||
"wss://goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://rpc.goerli.mudit.blog/",
|
||||
"https://ethereum-goerli.publicnode.com"
|
||||
"https://ethereum-goerli.publicnode.com",
|
||||
"https://goerli.gateway.tenderly.co",
|
||||
"wss://goerli.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.paradigm.xyz/",
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Tritanium Testnet",
|
||||
"chain": "TRITANIUM",
|
||||
"rpc": [
|
||||
"https://tritanium-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://nodetestnet-station-one.tritanium.network/",
|
||||
"https://nodetestnet-station-two.tritanium.network/"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.tritanium.network"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Tritanium Native Token",
|
||||
"symbol": "tTRN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://tritanium.network",
|
||||
"shortName": "ttrn",
|
||||
"chainId": 5353,
|
||||
"networkId": 5353,
|
||||
"icon": {
|
||||
"url": "ipfs://QmRm6gcEPJmU9a86zrmyP7FALTN4Toz9HrnrL2Kwg6FPeh",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "TRITANIUM Testnet Explorer",
|
||||
"icon": {
|
||||
"url": "ipfs://QmRm6gcEPJmU9a86zrmyP7FALTN4Toz9HrnrL2Kwg6FPeh",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://testnet.tritanium.network",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "tritanium-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "opBNB",
|
||||
"name": "Opbnb Testnet",
|
||||
"chain": "opBNB",
|
||||
"shortName": "opBNB",
|
||||
"chainId": 5611,
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"rpc": [
|
||||
"https://opbnb.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://opbnb-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://opbnb-testnet-rpc.bnbchain.org"
|
||||
],
|
||||
"explorers": [
|
||||
@@ -31,5 +31,5 @@ export default {
|
||||
"width": 512,
|
||||
"format": "svg"
|
||||
},
|
||||
"slug": "opbnb"
|
||||
"slug": "opbnb-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -5,8 +5,8 @@ export default {
|
||||
"rpc": [
|
||||
"https://boba-bnb.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://bnb.boba.network",
|
||||
"http://boba-bnb.gateway.tenderly.co/",
|
||||
"http://gateway.tenderly.co/public/boba-bnb",
|
||||
"https://boba-bnb.gateway.tenderly.co/",
|
||||
"https://gateway.tenderly.co/public/boba-bnb",
|
||||
"https://replica.bnb.boba.network",
|
||||
"wss://boba-bnb.gateway.tenderly.co/",
|
||||
"wss://gateway.tenderly.co/public/boba-bnb"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Rethereum Mainnet",
|
||||
"chain": "RTH",
|
||||
"rpc": [
|
||||
"https://rethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.rethereum.org",
|
||||
"https://rethereum.rpc.restratagem.com",
|
||||
"https://rpc.rthcentral.org"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Rethereum",
|
||||
"symbol": "RTH",
|
||||
"decimals": 18
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"infoURL": "https://www.rethereum.org",
|
||||
"shortName": "rth",
|
||||
"chainId": 622277,
|
||||
"networkId": 622277,
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreiawlhc2trzyxgnz24vowdymxme2m446uk4vmrplgxsdd74ecpfloq",
|
||||
"width": 830,
|
||||
"height": 830,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "rethereum",
|
||||
"url": "https://explorer.rethereum.org",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "rethereum"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "JuncaChain",
|
||||
"chain": "JuncaChain",
|
||||
"rpc": [
|
||||
"https://juncachain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.juncachain.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "JuncaChain Native Token",
|
||||
"symbol": "JGC",
|
||||
"decimals": 18
|
||||
},
|
||||
"faucets": [],
|
||||
"infoURL": "https://junca-cash.world",
|
||||
"shortName": "junca",
|
||||
"chainId": 668,
|
||||
"networkId": 668,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "JuncaScan",
|
||||
"url": "https://scan.juncachain.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "juncachain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "JuncaGlobal Chain Testnet",
|
||||
"chain": "JuncaGlobal Test Chain",
|
||||
"rpc": [
|
||||
"https://juncaglobal-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.juncachain.com",
|
||||
"wss://ws-testnet.juncachain.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet-testnet.juncachain.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "JuncaGlobal Chain Testnet Native Token",
|
||||
"symbol": "JGCT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://junca-cash.world",
|
||||
"shortName": "junca",
|
||||
"chainId": 669,
|
||||
"networkId": 669,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://scan-testnet.juncachain.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
|
||||
"width": 551,
|
||||
"height": 540,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "juncaglobal-chain-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Horizen EON",
|
||||
"name": "Horizen EON Mainnet",
|
||||
"shortName": "EON",
|
||||
"chain": "EON",
|
||||
"icon": {
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://horizen-eon.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eon-rpc.horizenlabs.io/ethv1"
|
||||
"https://eon-rpc.horizenlabs.io/ethv1",
|
||||
"https://rpc.ankr.com/horizen_eon"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Amplify Subnet",
|
||||
"chain": "AMPLIFY",
|
||||
"rpc": [
|
||||
"https://amplify-subnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/amplify/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "AMP",
|
||||
"symbol": "AMP",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.avax.network",
|
||||
"shortName": "amplify",
|
||||
"chainId": 78430,
|
||||
"networkId": 78430,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "AMPLIFY Explorer",
|
||||
"url": "https://subnets-test.avax.network/amplify",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "amplify-subnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Bulletin Subnet",
|
||||
"chain": "BULLETIN",
|
||||
"rpc": [
|
||||
"https://bulletin-subnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/bulletin/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "BLT",
|
||||
"symbol": "BLT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.avax.network",
|
||||
"shortName": "bulletin",
|
||||
"chainId": 78431,
|
||||
"networkId": 78431,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "BULLETIN Explorer",
|
||||
"url": "https://subnets-test.avax.network/bulletin",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "bulletin-subnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Conduit Subnet",
|
||||
"chain": "CONDUIT",
|
||||
"rpc": [
|
||||
"https://conduit-subnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/conduit/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "CON",
|
||||
"symbol": "CON",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.avax.network",
|
||||
"shortName": "conduit",
|
||||
"chainId": 78432,
|
||||
"networkId": 78432,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "CONDUIT Explorer",
|
||||
"url": "https://subnets-test.avax.network/conduit",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "conduit-subnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -16,7 +16,9 @@ export default {
|
||||
"https://matic-mumbai.chainstacklabs.com",
|
||||
"https://rpc-mumbai.maticvigil.com",
|
||||
"https://matic-testnet-archive-rpc.bwarelabs.com",
|
||||
"https://polygon-mumbai-bor.publicnode.com"
|
||||
"https://polygon-mumbai-bor.publicnode.com",
|
||||
"https://polygon-mumbai.gateway.tenderly.co",
|
||||
"wss://polygon-mumbai.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.polygon.technology/"
|
||||
|
||||
@@ -5,7 +5,10 @@ export default {
|
||||
"rpc": [
|
||||
"https://base.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.base.org/",
|
||||
"https://developer-access-mainnet.base.org/"
|
||||
"https://developer-access-mainnet.base.org/",
|
||||
"https://base.gateway.tenderly.co",
|
||||
"wss://base.gateway.tenderly.co",
|
||||
"https://base.publicnode.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -4,6 +4,9 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://base-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://base-goerli.publicnode.com",
|
||||
"wss://base-goerli.gateway.tenderly.co",
|
||||
"https://base-goerli.gateway.tenderly.co",
|
||||
"https://goerli.base.org"
|
||||
],
|
||||
"faucets": [
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Nautilus Proteus Testnet",
|
||||
"chain": "ETH",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNutSgM7n6aJPPDiofe9Dm1epy1RcYTMvugukLUK2vmPM",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://nautilus-proteus-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.proteus.nautchain.xyz/solana"
|
||||
],
|
||||
"faucets": [
|
||||
"https://proteusfaucet.nautchain.xyz"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Zebec Test Token",
|
||||
"symbol": "tZBC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://docs.nautchain.xyz",
|
||||
"shortName": "NAUTTest",
|
||||
"chainId": 88002,
|
||||
"networkId": 88002,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Nautscan",
|
||||
"url": "https://proteus.nautscan.com",
|
||||
"standard": "EIP3091",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNutSgM7n6aJPPDiofe9Dm1epy1RcYTMvugukLUK2vmPM",
|
||||
"width": 500,
|
||||
"height": 500,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "nautilus-proteus-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -7,7 +7,9 @@ export default {
|
||||
"https://testnet.bnb.boba.network",
|
||||
"wss://wss.testnet.bnb.boba.network",
|
||||
"https://replica.testnet.bnb.boba.network",
|
||||
"wss://replica-wss.testnet.bnb.boba.network"
|
||||
"wss://replica-wss.testnet.bnb.boba.network",
|
||||
"https://boba-bnb-testnet.gateway.tenderly.co",
|
||||
"wss://boba-bnb-testnet.gateway.tenderly.co"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// @ts-check
|
||||
/** @typedef { import("../../src/types").Chain } Chain */
|
||||
|
||||
/** @type {Partial<Chain>} */
|
||||
export default {
|
||||
name: "Opbnb Testnet",
|
||||
slug: "opbnb-testnet",
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.48",
|
||||
"version": "0.1.50",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -75,7 +75,6 @@ export function getChainRPCs(
|
||||
*
|
||||
* @param chain - The chain config to assemble RPC URLs from
|
||||
* @param clientId - The client id to use for the RPC URL
|
||||
* @param secretKey - The secret key to use for the RPC URL
|
||||
* @returns The first valid RPC URL for the chain
|
||||
*/
|
||||
export function getValidChainRPCs(
|
||||
|
||||
@@ -18,6 +18,7 @@ const CHAIN_RPC_TEST_CASES: [ChainRPCOptions, string[]][] = [
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -27,6 +28,7 @@ const CHAIN_RPC_TEST_CASES: [ChainRPCOptions, string[]][] = [
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -36,12 +38,16 @@ const CHAIN_RPC_TEST_CASES: [ChainRPCOptions, string[]][] = [
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
// infura is supported for both http and ws
|
||||
[
|
||||
{ mode: "ws", infuraApiKey: "SAMPLE_KEY" },
|
||||
["wss://mainnet.infura.io/ws/v3/SAMPLE_KEY"],
|
||||
[
|
||||
"wss://mainnet.infura.io/ws/v3/SAMPLE_KEY",
|
||||
"wss://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -53,12 +59,6 @@ describe("chains/utils", () => {
|
||||
},
|
||||
);
|
||||
|
||||
test("Should throw error if no processedRPCs (getChainRPCs(%p))", () => {
|
||||
expect(() => {
|
||||
getChainRPCs(Ethereum, { mode: "ws" });
|
||||
}).toThrowError('No RPC available for chainId "1" with mode ws');
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
undefined,
|
||||
@@ -68,6 +68,7 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -78,6 +79,7 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -88,6 +90,7 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -98,24 +101,13 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
])("getValidChainRPCs(Ethereum, %s, %s) = %p", (clientId, mode, expected) => {
|
||||
expect(getValidChainRPCs(Ethereum, clientId, mode)).toEqual(expected);
|
||||
});
|
||||
|
||||
test.each([
|
||||
[undefined, "ws"],
|
||||
["SAMPLE_CLIENT_KEY", "ws"],
|
||||
])(
|
||||
"Should throw error if no processedRPCs (getValidChainRPCs(Ethereum, %s, %s))",
|
||||
(clientId, mode) => {
|
||||
expect(() => {
|
||||
getValidChainRPCs(Ethereum, clientId, mode);
|
||||
}).toThrowError('No RPC available for chainId "1" with mode ws');
|
||||
},
|
||||
);
|
||||
|
||||
test.each(CHAIN_RPC_TEST_CASES)(
|
||||
"getChainRPC(%p) = %p",
|
||||
(options, expected) => {
|
||||
@@ -174,6 +166,7 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -187,6 +180,7 @@ describe("chains/utils", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -210,6 +204,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -220,6 +215,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -230,6 +226,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -240,6 +237,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
],
|
||||
])("getValidChainRPCs(Ethereum, %s, %s) = %p", (clientId, mode, expected) => {
|
||||
@@ -257,6 +255,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -270,6 +269,7 @@ describe("chains/utils with APP_BUNDLE_ID", () => {
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://mainnet.gateway.tenderly.co",
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.12.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1562](https://github.com/thirdweb-dev/js/pull/1562) [`04b6ef73`](https://github.com/thirdweb-dev/js/commit/04b6ef73e4641c5284353bffc43dbc5c597405de) Thanks [@Marfuen](https://github.com/Marfuen)! - Logout underlying wallet on logout
|
||||
|
||||
- [#1569](https://github.com/thirdweb-dev/js/pull/1569) [`1e6f9dcc`](https://github.com/thirdweb-dev/js/commit/1e6f9dcc04022c6a8a39d490123a3e22e52b5e0b) Thanks [@Marfuen](https://github.com/Marfuen)! - Use a different globalThis for CLI related flow.
|
||||
|
||||
- Updated dependencies [[`3eb9592e`](https://github.com/thirdweb-dev/js/commit/3eb9592e10154e06d2fa5effbc0c1a483f62498f), [`066b9cfa`](https://github.com/thirdweb-dev/js/commit/066b9cfa09df2531c9e5440477a24edc1374e0e0), [`a00cbaf7`](https://github.com/thirdweb-dev/js/commit/a00cbaf78c05ea43d3814ba9f9ec8e667f0ddb25), [`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/storage@1.2.10
|
||||
- @thirdweb-dev/sdk@3.10.59
|
||||
- @thirdweb-dev/wallets@1.1.23
|
||||
- @thirdweb-dev/auth@3.2.40
|
||||
|
||||
## 0.12.1
|
||||
|
||||
### 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)! - Updated descriptions for publish and deploy. Print out the login url for users without browsers. Remove the Release command (Use "Publish" instead).
|
||||
|
||||
- Updated dependencies [[`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005), [`e00dd123`](https://github.com/thirdweb-dev/js/commit/e00dd123579f75752b6fe4fcf613d2cae5419e19)]:
|
||||
- @thirdweb-dev/chains@0.1.50
|
||||
- @thirdweb-dev/sdk@3.10.58
|
||||
- @thirdweb-dev/wallets@1.1.22
|
||||
- @thirdweb-dev/auth@3.2.39
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#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.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b), [`adec589e`](https://github.com/thirdweb-dev/js/commit/adec589ead8ceff1b57169e05a3e6733b4652cc7), [`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3), [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5)]:
|
||||
- @thirdweb-dev/wallets@1.1.21
|
||||
- @thirdweb-dev/sdk@3.10.57
|
||||
- @thirdweb-dev/chains@0.1.49
|
||||
- @thirdweb-dev/storage@1.2.9
|
||||
- @thirdweb-dev/auth@3.2.38
|
||||
|
||||
## 0.11.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.11.20",
|
||||
"version": "0.12.2",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -37,9 +37,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@thirdweb-dev/auth": "workspace:*",
|
||||
"@thirdweb-dev/chains": "workspace:*",
|
||||
"@thirdweb-dev/sdk": "workspace:*",
|
||||
"@thirdweb-dev/storage": "workspace:*",
|
||||
"@thirdweb-dev/wallets": "workspace:*",
|
||||
"async-retry": "^1.3.3",
|
||||
"commander": "^9.1.0",
|
||||
"detect-package-manager": "^2.0.1",
|
||||
@@ -53,10 +55,10 @@
|
||||
"prompts": "^2.4.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"solc": "0.8.17",
|
||||
"sync-disk-cache": "^2.1.0",
|
||||
"tar": "^6.1.15",
|
||||
"update-notifier": "^6.0.2",
|
||||
"validate-npm-package-name": "^4.0.0",
|
||||
"xdg-app-paths": "^8.3.0",
|
||||
"yaml": "^2.3.1"
|
||||
},
|
||||
"bin": {
|
||||
|
||||
+253
-65
@@ -1,105 +1,293 @@
|
||||
import { LocalWallet } from "@thirdweb-dev/wallets";
|
||||
import assert from "assert";
|
||||
import chalk from "chalk";
|
||||
import prompts from "prompts";
|
||||
import Cache, { CacheEntry } from "sync-disk-cache";
|
||||
import { ApiResponse } from "../lib/types";
|
||||
import os from "os";
|
||||
import fs from "fs";
|
||||
import http from "http";
|
||||
import open from "open";
|
||||
import ora from "ora";
|
||||
import url from "url";
|
||||
import { logger, spinner } from "../core/helpers/logger";
|
||||
import { ThirdwebAuth } from "@thirdweb-dev/auth";
|
||||
import { ICredsConfig } from "../lib/types";
|
||||
import { generateStateParameter } from "../lib/utils";
|
||||
import crypto from "node:crypto";
|
||||
|
||||
type LoginProps = {
|
||||
browser: boolean;
|
||||
configPaths: ConfigPaths;
|
||||
};
|
||||
|
||||
const defaultLoginProps = {
|
||||
browser: true,
|
||||
configPaths: {
|
||||
credsConfigPath: "",
|
||||
cliWalletPath: "",
|
||||
tokenPath: "",
|
||||
},
|
||||
};
|
||||
|
||||
type ConfigPaths = {
|
||||
credsConfigPath: string;
|
||||
cliWalletPath: string;
|
||||
tokenPath: string;
|
||||
}
|
||||
|
||||
export async function loginUser(
|
||||
cache: Cache,
|
||||
configPaths: ConfigPaths,
|
||||
options?: { new: boolean },
|
||||
showLogs?: boolean,
|
||||
) {
|
||||
const keyFound = getSession(cache);
|
||||
if (keyFound && !options?.new) {
|
||||
const { credsConfigPath, tokenPath } = configPaths;
|
||||
const authToken = await getSession(tokenPath, credsConfigPath);
|
||||
if (authToken && !options?.new) {
|
||||
if (showLogs) {
|
||||
console.log(chalk.green("You are already logged in"));
|
||||
}
|
||||
return keyFound;
|
||||
globalThis["TW_CLI_AUTH_TOKEN"] = authToken;
|
||||
return authToken;
|
||||
} else {
|
||||
const apiKey = await createSession(cache);
|
||||
return apiKey;
|
||||
const token = await authenticateUser({ browser: true, configPaths });
|
||||
if (!token) {
|
||||
throw new Error("Failed to login");
|
||||
}
|
||||
|
||||
globalThis["TW_CLI_AUTH_TOKEN"] = token;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
export async function logoutUser(cache: Cache) {
|
||||
export async function logoutUser(credsConfigPath: string, tokenPath: string, cliWalletPath: string) {
|
||||
try {
|
||||
cache.remove("api-secret-key");
|
||||
console.log(chalk.green("You have been logged out"));
|
||||
ora("Logging out...").start();
|
||||
const dirExists = fs.existsSync(credsConfigPath) && fs.existsSync(tokenPath) && fs.existsSync(cliWalletPath);
|
||||
if (!dirExists) {
|
||||
ora().warn(chalk.yellow("You are already logged out, did you mean to login?"));
|
||||
return;
|
||||
}
|
||||
fs.unlinkSync(credsConfigPath);
|
||||
fs.unlinkSync(tokenPath);
|
||||
// TODO: We can consider not removing this on logout later, once we want to implement teams. For now this wallet will be ephemeral.
|
||||
fs.unlinkSync(cliWalletPath);
|
||||
ora().succeed(chalk.green("You have been logged out"));
|
||||
} catch (error) {
|
||||
console.log(chalk.red("Something went wrong", error));
|
||||
}
|
||||
}
|
||||
|
||||
export function getSession(cache: Cache) {
|
||||
export async function getSession(tokenPath: string, configCredsPath: string) {
|
||||
if (!fs.existsSync(tokenPath) || !fs.existsSync(configCredsPath)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const apiKey: CacheEntry = cache.get("api-secret-key");
|
||||
return apiKey.value;
|
||||
return fs.readFileSync(tokenPath, "utf8");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSession(cache: Cache) {
|
||||
try {
|
||||
const isWindows = os.type() === "Windows_NT";
|
||||
if (isWindows) {
|
||||
console.log(chalk.yellow("Windows detected: if you are using powershell, there are some known issues with it that we are actively working on, please use git bash or the command prompt. Thank you for your understanding."));
|
||||
}
|
||||
const response = await prompts({
|
||||
type: "invisible",
|
||||
name: "apiSecretKey",
|
||||
message: `Please enter your API secret key, you can find or create it on ${chalk.blue(
|
||||
"https://thirdweb.com/create-api-key",
|
||||
)}`,
|
||||
export const authenticateUser = async (
|
||||
props: LoginProps = defaultLoginProps,
|
||||
) => {
|
||||
const { credsConfigPath, cliWalletPath, tokenPath } = props.configPaths;
|
||||
const waitForDashboard = spinner("Waiting for a response from the dashboard").clear();
|
||||
|
||||
// Get or generate a localwallet.
|
||||
const wallet = await getOrGenerateLocalWallet(credsConfigPath, cliWalletPath);
|
||||
const walletAddress = await wallet.getAddress();
|
||||
const domain = "thirdweb.com";
|
||||
const auth = new ThirdwebAuth(wallet, domain);
|
||||
|
||||
// Generate the login payload to pass to the dashboard.
|
||||
const loggedIn = await auth.login({
|
||||
domain: domain,
|
||||
address: walletAddress,
|
||||
});
|
||||
|
||||
// In this case the state is the loggedIn object.
|
||||
const ourState = generateStateParameter(32);
|
||||
const payload = encodeURIComponent(JSON.stringify(loggedIn));
|
||||
const urlToOpen = `https://thirdweb.com/cli/login?payload=${payload}&#${ourState}`;
|
||||
|
||||
let server: http.Server;
|
||||
let loginTimeoutHandle: NodeJS.Timeout;
|
||||
const timerPromise = new Promise<void>((resolve, reject) => {
|
||||
loginTimeoutHandle = setTimeout(() => {
|
||||
logger.error("Login session timed out, server didn't receive a response in 5 minutes. Please try again.");
|
||||
server.close();
|
||||
clearTimeout(loginTimeoutHandle);
|
||||
reject(new Error("Login session timed out, server didn't receive a response in 5 minutes. Please try again."));
|
||||
}, 300000);
|
||||
});
|
||||
|
||||
const loginPromise = new Promise<string>((resolve, reject) => {
|
||||
server = http.createServer(async (req, res) => {
|
||||
function finish(error?: Error) {
|
||||
clearTimeout(loginTimeoutHandle);
|
||||
server.close((closeErr?: Error) => {
|
||||
if (error || closeErr) {
|
||||
reject(error || closeErr);
|
||||
}
|
||||
});
|
||||
}
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
res.setHeader('Access-Control-Allow-Origin', "https://thirdweb.com");
|
||||
res.setHeader('Access-Control-Allow-Methods', 'POST');
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.setHeader('Access-Control-Allow-Headers', 'content-type, baggage, sentry-trace');
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(req.url, "This request doesn't have a URL");
|
||||
const { pathname, query } = url.parse(req.url, true);
|
||||
switch (pathname) {
|
||||
case "/auth/callback": {
|
||||
if (query.failed) {
|
||||
res.writeHead(500, "Unable to authenticate with the dashboard!");
|
||||
res.end("Unable to authenticate with the dashboard!", () => {
|
||||
finish(new Error("Unable to authenticate with the dashboard!"));
|
||||
})
|
||||
reject(chalk.red("Something went wrong! Unable to authenticate with the dashboard."));
|
||||
waitForDashboard.stop();
|
||||
}
|
||||
if (query.token) {
|
||||
const token = Array.isArray(query.token) ? query.token[0] : query.token;
|
||||
const theirState = Array.isArray(query.state)
|
||||
? query.state[0]
|
||||
: query.state;
|
||||
|
||||
// Check if the state sent back is the same as the one we sent.
|
||||
if (theirState !== ourState) {
|
||||
res.writeHead(400, { "Content-Type": "text/plain" }); // send a 400 response
|
||||
res.end("Unauthorized request, state mismatch", () => {
|
||||
finish(new Error("Unauthorized request, state mismatch"));
|
||||
});
|
||||
reject(
|
||||
new Error(chalk.red("\nUnauthorized request, state mismatch")),
|
||||
);
|
||||
waitForDashboard.stop();
|
||||
} else {
|
||||
// Save the token to the config file.
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
fs.writeFileSync(tokenPath, token), {
|
||||
encoding: "utf8",
|
||||
mode: 0o600,
|
||||
};
|
||||
res.end(() => {
|
||||
waitForDashboard.clear();
|
||||
console.log(chalk.green(`Successfully linked your account to this device`));
|
||||
finish();
|
||||
});
|
||||
logger.info(chalk.green(`\nSuccessfully logged in.`));
|
||||
resolve(token); // resolve promise with secretKey
|
||||
}
|
||||
} else {
|
||||
res.writeHead(400, { "Content-Type": "text/plain" });
|
||||
res.end("No authToken received", () => {
|
||||
finish(new Error("No authToken received"));
|
||||
});
|
||||
reject(new Error(chalk.red("\nNo authToken received")));
|
||||
waitForDashboard.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const keyPassed = response.apiSecretKey;
|
||||
if (!keyPassed) {
|
||||
console.log(chalk.red("You need to pass an API secret key"));
|
||||
process.exit(1);
|
||||
}
|
||||
server.listen(8976);
|
||||
});
|
||||
console.log(`Automatically attempting to open a link to authenticate with our dashboard...\n`);
|
||||
waitForDashboard.start();
|
||||
// Adding this timeout since it feels weird for the browser to open before the spinner.
|
||||
setTimeout(async () => {
|
||||
await open(urlToOpen);
|
||||
}, 2000);
|
||||
|
||||
if (keyPassed.length === 32) {
|
||||
console.log(chalk.red(`This is not a valid secret key. To get your secret key
|
||||
1. Create an API key at https://thirdweb.com/create-api-key
|
||||
2. Store and copy your Secret Key. This will be shown only once.
|
||||
3. Paste it in the CLI when prompted`));
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(chalk.yellow(`If the browser doesn't open, please use this link to authenticate:\n`));
|
||||
console.log(chalk.yellow(urlToOpen + '\n'));
|
||||
|
||||
return Promise.race([timerPromise, loginPromise]);
|
||||
};
|
||||
|
||||
async function getOrCreatePassword(configCredsPath: string): Promise<string> {
|
||||
const passwordFileExists = fs.existsSync(configCredsPath);
|
||||
if (!passwordFileExists) {
|
||||
// Generate a random password for the CLI to be able to import / export the wallet.
|
||||
return crypto.randomUUID();
|
||||
} else {
|
||||
const file = fs.readFileSync(configCredsPath, "utf8");
|
||||
try {
|
||||
await validateKey(response.apiSecretKey);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
process.exit(1);
|
||||
JSON.parse(file);
|
||||
} catch (e) {
|
||||
// If it fails to parse the password we should just delete the file and generate a new password, since this password is not shown to the user.
|
||||
fs.unlinkSync(configCredsPath);
|
||||
return getOrCreatePassword(configCredsPath);
|
||||
}
|
||||
cache.set("api-secret-key", response.apiSecretKey);
|
||||
return response.apiSecretKey;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
const { password } = JSON.parse(file) as ICredsConfig;
|
||||
return password;
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateKey(apiSecretKey: string) {
|
||||
const fetch = (await import("node-fetch")).default;
|
||||
// TODO: CHANGE THIS TO PROD BEFORE MERGING!!!
|
||||
const response = await fetch(
|
||||
`https://api.thirdweb.com/v1/keys/use?scope=storage`,
|
||||
{
|
||||
async function getOrGenerateLocalWallet(configCredsPath: string, cliWalletPath: string) {
|
||||
// Get or prompt for password.
|
||||
const password = await getOrCreatePassword(configCredsPath);
|
||||
const wallet = new LocalWallet();
|
||||
const foundWallet = fs.existsSync(cliWalletPath);
|
||||
|
||||
if (foundWallet) {
|
||||
const walletJson = fs.readFileSync(cliWalletPath, "utf8");
|
||||
try {
|
||||
// See if file is valid before proceeding.
|
||||
JSON.parse(walletJson);
|
||||
|
||||
await wallet.import({
|
||||
encryptedJson: walletJson,
|
||||
password,
|
||||
});
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
// Wallet file is not valid json, create a new one.
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, generate a new wallet.
|
||||
wallet.generate();
|
||||
const walletExported = await wallet.export({
|
||||
strategy: "encryptedJson",
|
||||
password,
|
||||
});
|
||||
|
||||
// write wallet
|
||||
fs.writeFileSync(cliWalletPath, walletExported, {
|
||||
encoding: "utf8",
|
||||
mode: 0o600,
|
||||
});
|
||||
|
||||
// write password
|
||||
fs.writeFileSync(configCredsPath, JSON.stringify({
|
||||
password: password,
|
||||
}), "utf8");
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
export const validateKey = async (apiSecretKey: string) => {
|
||||
const apiUrl = "https://api.thirdweb.com/v1/keys/use";
|
||||
try {
|
||||
const response = await fetch(`${apiUrl}?scope=storage`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-secret-key": apiSecretKey,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
const apiResponse = (await response.json()) as ApiResponse;
|
||||
if (response.status !== 200) {
|
||||
throw new Error("Unauthorized key");
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const { error } = apiResponse;
|
||||
throw new Error(chalk.red(error.message));
|
||||
} else {
|
||||
return apiSecretKey;
|
||||
} catch (error) {
|
||||
throw new Error(chalk.red("Unauthorized key"));
|
||||
}
|
||||
}
|
||||
};
|
||||
+100
-81
@@ -3,11 +3,11 @@ import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { exec, spawn } from "child_process";
|
||||
import { Command } from "commander";
|
||||
import fs from "fs";
|
||||
import open from "open";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import prompts from "prompts";
|
||||
import Cache, { CacheEntry } from "sync-disk-cache";
|
||||
import xdgAppPaths from "xdg-app-paths";
|
||||
import { loginUser, logoutUser, validateKey } from "../auth";
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
@@ -24,11 +24,17 @@ import { upload } from "../storage/command";
|
||||
const main = async () => {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
|
||||
const configDir = xdgAppPaths(".thirdweb").config();
|
||||
const cacheDir = xdgAppPaths(".thirdweb").cache();
|
||||
const lastVersionCheckCachePath = path.join(
|
||||
cacheDir,
|
||||
"last-version-check.txt",
|
||||
);
|
||||
const credsConfigPath = path.join(configDir, "creds.json");
|
||||
const cliWalletPath = path.join(configDir, "wallet.json");
|
||||
const tokenPath = path.join(configDir, "auth-token.txt");
|
||||
|
||||
const program = new Command();
|
||||
const cache = new Cache("thirdweb-cli", {
|
||||
location: path.join(os.homedir(), ".thirdweb", "creds"),
|
||||
});
|
||||
|
||||
// yes this has to look like this, eliminates whitespace
|
||||
if (!skipIntro) {
|
||||
@@ -41,25 +47,41 @@ const main = async () => {
|
||||
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
||||
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
||||
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
|
||||
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
|
||||
console.info(`\n 💎 thirdweb v${cliVersion} 💎\n`);
|
||||
}
|
||||
|
||||
program
|
||||
.name("thirdweb-cli")
|
||||
.name("thirdweb")
|
||||
.description("Official thirdweb command line interface")
|
||||
.version(cliVersion, "-v, --version")
|
||||
.option("--skip-update-check", "Skip check for auto updates")
|
||||
.hook("preAction", async () => {
|
||||
const regenerateConfig = !fs.existsSync(configDir);
|
||||
const regenerateCache = !fs.existsSync(cacheDir);
|
||||
|
||||
// Create config directory if it doesn't exist
|
||||
if (regenerateConfig) {
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Create cache directory if it doesn't exist
|
||||
if (regenerateCache) {
|
||||
fs.mkdirSync(cacheDir, { recursive: true });
|
||||
}
|
||||
|
||||
if (skipIntro || program.opts().skipUpdateCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldCheckVersion = true;
|
||||
try {
|
||||
const lastCheckCache: CacheEntry = cache.get("last-version-check");
|
||||
const lastVersionCheckCache = fs.readFileSync(
|
||||
lastVersionCheckCachePath,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
if (lastCheckCache.isCached) {
|
||||
const lastVersionCheck = new Date(lastCheckCache.value);
|
||||
if (lastVersionCheckCache) {
|
||||
const lastVersionCheck = new Date(lastVersionCheckCache);
|
||||
// Don't check for updates if already checked within past 24 hours
|
||||
if (Date.now() - lastVersionCheck.getTime() < 1000 * 60 * 60 * 24) {
|
||||
shouldCheckVersion = false;
|
||||
@@ -88,7 +110,14 @@ const main = async () => {
|
||||
|
||||
try {
|
||||
// Set cache to prevent checking for updates again for 24 hours
|
||||
cache.set("last-version-check", new Date().toISOString());
|
||||
fs.writeFileSync(
|
||||
lastVersionCheckCachePath,
|
||||
new Date().toISOString(),
|
||||
{
|
||||
encoding: "utf-8",
|
||||
mode: 0o600,
|
||||
},
|
||||
);
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
@@ -267,7 +296,7 @@ const main = async () => {
|
||||
|
||||
program
|
||||
.command("deploy")
|
||||
.description("Deploy your (or team) contracts securely to blockchains")
|
||||
.description("Securely deploy your contract to any EVM network without having to deal with scripts, private keys, or ABIs")
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--clean", "clear the cache before building")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
@@ -300,66 +329,31 @@ const main = async () => {
|
||||
"Deploy a dynamic smart contract made up of extensions to blockchains",
|
||||
)
|
||||
.option("--zksync", "Deploy on ZKSync")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.option("-k, --key <key>", "API secret key to authorize usage")
|
||||
.action(async (options) => {
|
||||
let apiSecretKey = "";
|
||||
let secretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
await loginUser({
|
||||
credsConfigPath,
|
||||
cliWalletPath,
|
||||
tokenPath,
|
||||
});
|
||||
} else {
|
||||
// Don't need to validate anymore? Also, should probably rely on the underlying service to throw that error.
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
secretKey = options.key;
|
||||
}
|
||||
const url = await deploy(options, apiSecretKey);
|
||||
const url = await deploy(options, secretKey);
|
||||
if (url && !options.ci) {
|
||||
await open(url);
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command("release")
|
||||
.description("[Deprecated] use 'publish' instead.")
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option(
|
||||
"-f, --file [name]",
|
||||
"Filter for contract files that contain the file name",
|
||||
)
|
||||
.option(
|
||||
"-cn, --contract-name [name]",
|
||||
"Filter for contracts that contain this contract name",
|
||||
)
|
||||
.option("--clean", "clear the cache before building")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (options) => {
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
logger.warn(
|
||||
"'release' is deprecated and will be removed in a future update. Please use 'publish' instead.",
|
||||
);
|
||||
const url = await processProject(options, "publish", apiSecretKey);
|
||||
info(
|
||||
`Open this link to publish your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
if (url && !options.ci) {
|
||||
await open(url.toString());
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command("publish")
|
||||
.description(
|
||||
"Publish your protocol so other devs can deploy them and unlock SDKs, Dashboards and Analytics",
|
||||
"Get a shareable page for your contract with a README, changelog, and version control. Enable one-click deploys to any EVM network",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option(
|
||||
@@ -374,17 +368,22 @@ const main = async () => {
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.option("-k, --key <key>", "API secret key to authorize usage")
|
||||
.action(async (options) => {
|
||||
let apiSecretKey = "";
|
||||
let secretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
await loginUser({
|
||||
credsConfigPath,
|
||||
cliWalletPath,
|
||||
tokenPath,
|
||||
});
|
||||
} else {
|
||||
// Don't need to validate anymore? Also, should probably rely on the underlying service to throw that error.
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
secretKey = options.key;
|
||||
}
|
||||
const url = await processProject(options, "publish", apiSecretKey);
|
||||
const url = await processProject(options, "publish", secretKey);
|
||||
info(
|
||||
`Open this link to publish your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
@@ -399,19 +398,31 @@ const main = async () => {
|
||||
.command("upload")
|
||||
.description("Upload any file or directory to decentralized storage (IPFS)")
|
||||
.argument("[upload]", "path to file or directory to upload")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.option("-k, --key <key>", "API secret key to authorize usage")
|
||||
.action(async (_path, options) => {
|
||||
let apiSecretKey = "";
|
||||
let secretKey = "";
|
||||
let storage: ThirdwebStorage;
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
await loginUser({
|
||||
credsConfigPath,
|
||||
cliWalletPath,
|
||||
tokenPath,
|
||||
});
|
||||
} else {
|
||||
// Don't need to validate anymore? Also, should probably rely on the underlying service to throw that error.
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
secretKey = options.key;
|
||||
}
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
|
||||
if (secretKey) {
|
||||
storage = new ThirdwebStorage({
|
||||
secretKey,
|
||||
});
|
||||
} else {
|
||||
storage = new ThirdwebStorage();
|
||||
}
|
||||
|
||||
try {
|
||||
const uri = await upload(storage, _path);
|
||||
info(
|
||||
@@ -438,7 +449,7 @@ const main = async () => {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
logger.error(chalk.redBright("Failed to upload files"), err);
|
||||
logger.error(chalk.redBright(err.message ? err.message : err));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -460,36 +471,44 @@ const main = async () => {
|
||||
"Preload ABIs and generate types for your smart contract to strongly type the thirdweb SDK",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.option("-k, --key <key>", "API secret key to authorize usage")
|
||||
.action(async (options) => {
|
||||
let apiSecretKey = "";
|
||||
let secretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
await loginUser({
|
||||
credsConfigPath,
|
||||
cliWalletPath,
|
||||
tokenPath,
|
||||
});
|
||||
} else {
|
||||
// Don't need to validate anymore? Also, should probably rely on the underlying service to throw that error.
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
secretKey = options.key;
|
||||
}
|
||||
await generate(options, apiSecretKey);
|
||||
await generate(options, secretKey);
|
||||
});
|
||||
|
||||
program
|
||||
.command("login")
|
||||
.description(
|
||||
"Authenticate with the thirdweb CLI using your API secret key or replace an existing API secret key",
|
||||
"Authorize your device to use the thirdweb CLI by authenticating with your wallet from our dashboard",
|
||||
)
|
||||
.option("-n, --new", "Login with a new API secret key", false)
|
||||
.action(async (options) => {
|
||||
await loginUser(cache, options, true);
|
||||
await loginUser({
|
||||
credsConfigPath,
|
||||
cliWalletPath,
|
||||
tokenPath,
|
||||
}, options, true);
|
||||
});
|
||||
|
||||
program
|
||||
.command("logout")
|
||||
.description(
|
||||
"Logout of the thirdweb CLI, effectively removing your API secret key from your machine",
|
||||
"Logout of the thirdweb CLI",
|
||||
)
|
||||
.action(async () => {
|
||||
await logoutUser(cache);
|
||||
await logoutUser(credsConfigPath, tokenPath, cliWalletPath);
|
||||
});
|
||||
|
||||
await program.parseAsync();
|
||||
|
||||
@@ -32,12 +32,18 @@ import {
|
||||
export async function processProject(
|
||||
options: any,
|
||||
command: "deploy" | "publish",
|
||||
apiSecretKey: string,
|
||||
secretKey: string,
|
||||
) {
|
||||
// TODO: allow overriding the default storage
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
let storage: ThirdwebStorage;
|
||||
if (secretKey) {
|
||||
storage = new ThirdwebStorage({
|
||||
secretKey,
|
||||
});
|
||||
} else {
|
||||
// Since the auth key is being set in the global context, we don't need to pass anything here.
|
||||
storage = new ThirdwebStorage();
|
||||
}
|
||||
|
||||
logger.setSettings({
|
||||
minLevel: options.debug ? "debug" : "info",
|
||||
@@ -240,7 +246,7 @@ export async function processProject(
|
||||
} else {
|
||||
const deployArgs: RouterParams = await formatToExtensions(
|
||||
selectedContracts,
|
||||
apiSecretKey,
|
||||
secretKey,
|
||||
);
|
||||
|
||||
const outputDeployArgs = JSON.stringify(deployArgs, undefined, 2);
|
||||
@@ -345,9 +351,9 @@ export async function processProject(
|
||||
loader.succeed("Upload successful");
|
||||
|
||||
return getUrl(combinedURIs, command);
|
||||
} catch (e) {
|
||||
} catch (err: any) {
|
||||
loader.fail("Error uploading metadata");
|
||||
throw e;
|
||||
throw new Error(err.message ? err.message : err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,8 +362,8 @@ export function getUrl(hashes: string[], command: string) {
|
||||
if (hashes.length === 1) {
|
||||
url = new URL(
|
||||
THIRDWEB_URL +
|
||||
`/contracts/${command}/` +
|
||||
encodeURIComponent(hashes[0].replace("ipfs://", "")),
|
||||
`/contracts/${command}/` +
|
||||
encodeURIComponent(hashes[0].replace("ipfs://", "")),
|
||||
);
|
||||
} else {
|
||||
url = new URL(THIRDWEB_URL + "/contracts/" + command);
|
||||
@@ -370,14 +376,20 @@ export function getUrl(hashes: string[], command: string) {
|
||||
|
||||
async function formatToExtensions(
|
||||
contracts: ContractPayload[],
|
||||
apiSecretKey: string,
|
||||
secretKey: string,
|
||||
): Promise<{
|
||||
extensions: Extension[];
|
||||
extensionDeployArgs: ExtensionDeployArgs[];
|
||||
}> {
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
let storage: ThirdwebStorage;
|
||||
if (secretKey) {
|
||||
storage = new ThirdwebStorage({
|
||||
secretKey,
|
||||
});
|
||||
} else {
|
||||
// Since the auth key is being set in the global context, we don't need to pass anything here.
|
||||
storage = new ThirdwebStorage();
|
||||
}
|
||||
const extensions: Extension[] = [];
|
||||
const extensionDeployArgs: ExtensionDeployArgs[] = [];
|
||||
|
||||
|
||||
@@ -8,11 +8,17 @@ import { upload } from "../storage/command";
|
||||
export async function deployApp(
|
||||
distPath = "dist",
|
||||
projectPath = ".",
|
||||
apiSecretKey: string,
|
||||
secretKey: string,
|
||||
) {
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
let storage: ThirdwebStorage;
|
||||
if (secretKey) {
|
||||
storage = new ThirdwebStorage({
|
||||
secretKey,
|
||||
});
|
||||
} else {
|
||||
// Since the auth key is being set in the global context, we don't need to pass anything here.
|
||||
storage = new ThirdwebStorage();
|
||||
}
|
||||
const detectedPackageManager = await detectPackageManager(projectPath, {});
|
||||
const detectedFramework = await detectFramework(
|
||||
projectPath,
|
||||
@@ -74,8 +80,8 @@ export async function deployApp(
|
||||
"ipfs://",
|
||||
"https://cf-ipfs.com/ipfs/",
|
||||
)}`;
|
||||
} catch (err) {
|
||||
console.error("Can't upload project", err);
|
||||
} catch (err: any) {
|
||||
console.error(err.message ? err.message : err);
|
||||
return Promise.reject("Can't upload project");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type DeployOptions = {
|
||||
distPath?: string;
|
||||
};
|
||||
|
||||
export async function deploy(options: DeployOptions, apiSecretKey: string) {
|
||||
export async function deploy(options: DeployOptions, secretKey: string) {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
@@ -33,7 +33,7 @@ export async function deploy(options: DeployOptions, apiSecretKey: string) {
|
||||
|
||||
if (options.app) {
|
||||
try {
|
||||
const url = await deployApp(options.distPath, options.path, apiSecretKey);
|
||||
const url = await deployApp(options.distPath, options.path, secretKey);
|
||||
info(`Here is the link to your app: ${chalk.blueBright(url.toString())}`);
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
@@ -44,7 +44,7 @@ export async function deploy(options: DeployOptions, apiSecretKey: string) {
|
||||
}
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy", apiSecretKey);
|
||||
const url = await processProject(options, "deploy", secretKey);
|
||||
info(
|
||||
`Open this link to deploy your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
|
||||
@@ -14,7 +14,7 @@ import { info } from "../core/helpers/logger";
|
||||
import { GenerateOptions, ThirdwebConfig } from "./types";
|
||||
import { CHAIN_OPTIONS, getContractsForAddresses } from "./utils";
|
||||
|
||||
export async function generate(options: GenerateOptions, apiSecretKey: string) {
|
||||
export async function generate(options: GenerateOptions, secretKey: string) {
|
||||
const projectPath: string = options.path?.replace(/\/$/, "") || ".";
|
||||
let contracts: DeployedContract[] = [];
|
||||
|
||||
@@ -55,8 +55,7 @@ export async function generate(options: GenerateOptions, apiSecretKey: string) {
|
||||
const numberOfNewContracts =
|
||||
contracts.length - thirdwebConfig.contracts.length;
|
||||
info(
|
||||
`Updated thirdweb.json with ${numberOfNewContracts} new contract${
|
||||
numberOfNewContracts === 1 ? "" : "s"
|
||||
`Updated thirdweb.json with ${numberOfNewContracts} new contract${numberOfNewContracts === 1 ? "" : "s"
|
||||
}`,
|
||||
);
|
||||
}
|
||||
@@ -86,19 +85,22 @@ export async function generate(options: GenerateOptions, apiSecretKey: string) {
|
||||
);
|
||||
|
||||
info(
|
||||
`Created a thirdweb.json file with configuration for ${
|
||||
contracts.length
|
||||
} contract${
|
||||
contracts.length === 1 ? "" : "s"
|
||||
`Created a thirdweb.json file with configuration for ${contracts.length
|
||||
} contract${contracts.length === 1 ? "" : "s"
|
||||
} detected in your project.\n\n - You can also update this configuration manually by editing the file.\n`,
|
||||
);
|
||||
}
|
||||
|
||||
// Attempt to download the ABI for each contract
|
||||
ora(`Downloading ABIs for contracts configured in 'thirdweb.json'`).info();
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
let storage: ThirdwebStorage;
|
||||
if (secretKey) {
|
||||
storage = new ThirdwebStorage({
|
||||
secretKey,
|
||||
});
|
||||
} else {
|
||||
storage = new ThirdwebStorage();
|
||||
}
|
||||
const metadata: {
|
||||
address: string;
|
||||
metadata: Awaited<ReturnType<typeof fetchContractMetadataFromAddress>>;
|
||||
@@ -187,8 +189,7 @@ export async function generate(options: GenerateOptions, apiSecretKey: string) {
|
||||
}
|
||||
|
||||
ora(
|
||||
`Downloaded and cached ABIs for ${metadata.length} smart contract${
|
||||
metadata.length === 1 ? "" : "s"
|
||||
`Downloaded and cached ABIs for ${metadata.length} smart contract${metadata.length === 1 ? "" : "s"
|
||||
}`,
|
||||
).succeed();
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { DeployedContract } from "@thirdweb-dev/sdk";
|
||||
|
||||
export type AuthConfig = {
|
||||
secretKey?: string;
|
||||
authToken?: string;
|
||||
}
|
||||
|
||||
export type ThirdwebConfig = {
|
||||
chainIds: number[];
|
||||
contracts: DeployedContract[];
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/* eslint-disable no-var */
|
||||
declare module globalThis {
|
||||
var TW_AUTH_TOKEN: string;
|
||||
var TW_CLI_AUTH_TOKEN: string;
|
||||
}
|
||||
@@ -4,6 +4,11 @@ import {
|
||||
PackageManagerType,
|
||||
} from "../core/types/ProjectType";
|
||||
|
||||
export type ICredsConfig = {
|
||||
password: string;
|
||||
expiration: number;
|
||||
}
|
||||
|
||||
export type IProcessContractAppTypeArgs = {
|
||||
detectedPackageManager: PackageManagerType;
|
||||
thirdwebDepsToUpdate: Set<string>;
|
||||
@@ -43,4 +48,4 @@ export type ApiResponse = {
|
||||
statusCode: number;
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -4,6 +4,11 @@ import path from "path";
|
||||
import { PackageManagerType } from "../core/types/ProjectType";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { IProcessAppTypeArgs, IProcessContractAppTypeArgs } from "./types";
|
||||
import crypto from "crypto";
|
||||
|
||||
export function generateStateParameter(length: number) {
|
||||
return crypto.randomBytes(length).toString("hex");
|
||||
}
|
||||
|
||||
export function convertDependenciesToStringFormat(dependenciesObject: object) {
|
||||
return Object.entries(dependenciesObject).map(([pkg, versionDetails]) => {
|
||||
|
||||
@@ -69,9 +69,9 @@ export async function upload(
|
||||
);
|
||||
try {
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
spin.fail("Failed to upload file to IPFS.");
|
||||
return Promise.reject(err);
|
||||
return Promise.reject(err.message ? err.message : err);
|
||||
}
|
||||
spin.succeed("Successfully uploaded file to IPFS.");
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 3.14.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3eb9592e`](https://github.com/thirdweb-dev/js/commit/3eb9592e10154e06d2fa5effbc0c1a483f62498f), [`066b9cfa`](https://github.com/thirdweb-dev/js/commit/066b9cfa09df2531c9e5440477a24edc1374e0e0), [`a00cbaf7`](https://github.com/thirdweb-dev/js/commit/a00cbaf78c05ea43d3814ba9f9ec8e667f0ddb25), [`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/storage@1.2.10
|
||||
- @thirdweb-dev/sdk@3.10.59
|
||||
- @thirdweb-dev/wallets@1.1.23
|
||||
- @thirdweb-dev/auth@3.2.40
|
||||
|
||||
## 3.14.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005), [`e00dd123`](https://github.com/thirdweb-dev/js/commit/e00dd123579f75752b6fe4fcf613d2cae5419e19)]:
|
||||
- @thirdweb-dev/chains@0.1.50
|
||||
- @thirdweb-dev/sdk@3.10.58
|
||||
- @thirdweb-dev/wallets@1.1.22
|
||||
- @thirdweb-dev/auth@3.2.39
|
||||
|
||||
## 3.14.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b), [`adec589e`](https://github.com/thirdweb-dev/js/commit/adec589ead8ceff1b57169e05a3e6733b4652cc7), [`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3), [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5)]:
|
||||
- @thirdweb-dev/wallets@1.1.21
|
||||
- @thirdweb-dev/sdk@3.10.57
|
||||
- @thirdweb-dev/chains@0.1.49
|
||||
- @thirdweb-dev/storage@1.2.9
|
||||
- @thirdweb-dev/auth@3.2.38
|
||||
|
||||
## 3.14.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.37",
|
||||
"version": "3.14.40",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.59
|
||||
|
||||
## 0.2.58
|
||||
|
||||
## 0.2.57
|
||||
|
||||
## 0.2.56
|
||||
|
||||
## 0.2.55
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.56",
|
||||
"version": "0.2.59",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.2.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3eb9592e`](https://github.com/thirdweb-dev/js/commit/3eb9592e10154e06d2fa5effbc0c1a483f62498f), [`066b9cfa`](https://github.com/thirdweb-dev/js/commit/066b9cfa09df2531c9e5440477a24edc1374e0e0), [`a00cbaf7`](https://github.com/thirdweb-dev/js/commit/a00cbaf78c05ea43d3814ba9f9ec8e667f0ddb25), [`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/storage@1.2.10
|
||||
- @thirdweb-dev/sdk@3.10.59
|
||||
- @thirdweb-dev/wallets@1.1.23
|
||||
- @thirdweb-dev/react-core@3.14.40
|
||||
|
||||
## 0.2.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1546](https://github.com/thirdweb-dev/js/pull/1546) [`cdc08c55`](https://github.com/thirdweb-dev/js/commit/cdc08c55282d5873972b85217c42ba2f97a1ffed) Thanks [@iketw](https://github.com/iketw)! - Use regular import for coinbase connector in React Native
|
||||
|
||||
- Updated dependencies [[`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005), [`e00dd123`](https://github.com/thirdweb-dev/js/commit/e00dd123579f75752b6fe4fcf613d2cae5419e19)]:
|
||||
- @thirdweb-dev/chains@0.1.50
|
||||
- @thirdweb-dev/sdk@3.10.58
|
||||
- @thirdweb-dev/react-core@3.14.39
|
||||
- @thirdweb-dev/wallets@1.1.22
|
||||
|
||||
## 0.2.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b), [`adec589e`](https://github.com/thirdweb-dev/js/commit/adec589ead8ceff1b57169e05a3e6733b4652cc7), [`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3), [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5)]:
|
||||
- @thirdweb-dev/wallets@1.1.21
|
||||
- @thirdweb-dev/sdk@3.10.57
|
||||
- @thirdweb-dev/chains@0.1.49
|
||||
- @thirdweb-dev/storage@1.2.9
|
||||
- @thirdweb-dev/react-core@3.14.38
|
||||
|
||||
## 0.2.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.56",
|
||||
"version": "0.2.59",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { noopStorage } from "../../../core/AsyncStorage";
|
||||
import type {
|
||||
CoinbaseWalletConnector,
|
||||
CoinbaseWalletConnector as CoinbaseWalletConnectorType,
|
||||
CoinbaseWalletConnectorOptions,
|
||||
} from "../connectors/coinbase-wallet";
|
||||
import { CoinbaseWalletConnector } from "../connectors/coinbase-wallet";
|
||||
import {
|
||||
AbstractClientWallet,
|
||||
Connector,
|
||||
@@ -28,8 +29,8 @@ export class CoinbaseWallet extends AbstractClientWallet<CoinbaseWalletConnector
|
||||
};
|
||||
|
||||
connector?: Connector;
|
||||
coinbaseConnector?: CoinbaseWalletConnector;
|
||||
provider?: CoinbaseWalletConnector["provider"];
|
||||
coinbaseConnector?: CoinbaseWalletConnectorType;
|
||||
provider?: CoinbaseWalletConnectorType["provider"];
|
||||
|
||||
static id = walletIds.coinbase;
|
||||
public get walletName() {
|
||||
@@ -50,11 +51,6 @@ export class CoinbaseWallet extends AbstractClientWallet<CoinbaseWalletConnector
|
||||
|
||||
protected async getConnector(): Promise<Connector> {
|
||||
if (!this.connector) {
|
||||
// import the connector dynamically
|
||||
const { CoinbaseWalletConnector: CoinbaseWalletConnector } = await import(
|
||||
"../connectors/coinbase-wallet"
|
||||
);
|
||||
|
||||
const cbConnector = new CoinbaseWalletConnector({
|
||||
chains: this.chains,
|
||||
options: {
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.14.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a00cbaf7`](https://github.com/thirdweb-dev/js/commit/a00cbaf78c05ea43d3814ba9f9ec8e667f0ddb25), [`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/sdk@3.10.59
|
||||
- @thirdweb-dev/wallets@1.1.23
|
||||
- @thirdweb-dev/react-core@3.14.40
|
||||
|
||||
## 3.14.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005), [`e00dd123`](https://github.com/thirdweb-dev/js/commit/e00dd123579f75752b6fe4fcf613d2cae5419e19)]:
|
||||
- @thirdweb-dev/chains@0.1.50
|
||||
- @thirdweb-dev/sdk@3.10.58
|
||||
- @thirdweb-dev/react-core@3.14.39
|
||||
- @thirdweb-dev/wallets@1.1.22
|
||||
|
||||
## 3.14.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1532](https://github.com/thirdweb-dev/js/pull/1532) [`b29ec675`](https://github.com/thirdweb-dev/js/commit/b29ec675f9c41c49c015af2427d5402367c06c73) Thanks [@MananTank](https://github.com/MananTank)! - Export ConnectModalInline component
|
||||
|
||||
- [#1544](https://github.com/thirdweb-dev/js/pull/1544) [`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b) Thanks [@iketw](https://github.com/iketw)! - Adds support for Rainbow's new browser extension
|
||||
|
||||
- Updated dependencies [[`eb463735`](https://github.com/thirdweb-dev/js/commit/eb463735e2f784cd1d212a982835af95cf60766b), [`adec589e`](https://github.com/thirdweb-dev/js/commit/adec589ead8ceff1b57169e05a3e6733b4652cc7), [`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3), [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5)]:
|
||||
- @thirdweb-dev/wallets@1.1.21
|
||||
- @thirdweb-dev/sdk@3.10.57
|
||||
- @thirdweb-dev/chains@0.1.49
|
||||
- @thirdweb-dev/react-core@3.14.38
|
||||
|
||||
## 3.14.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.14.37",
|
||||
"version": "3.14.40",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -152,7 +152,7 @@ const DialogContent = styled.div<{ theme?: Theme }>`
|
||||
}
|
||||
`;
|
||||
|
||||
const DialogTitle = /* @__PURE__ */ styled(/* @__PURE__ */ Dialog.Title)<{
|
||||
const DialogTitle = /* @__PURE__ */ styled.h2<{
|
||||
theme?: Theme;
|
||||
}>`
|
||||
margin: 0;
|
||||
|
||||
@@ -2,10 +2,9 @@ import { type Theme, fontSize, media } from "../design-system";
|
||||
import { iconSize } from "../design-system";
|
||||
import { IconButton } from "./buttons";
|
||||
import styled from "@emotion/styled";
|
||||
import { Title } from "@radix-ui/react-dialog";
|
||||
import { ChevronLeftIcon } from "@radix-ui/react-icons";
|
||||
|
||||
export const ModalTitle = /* @__PURE__ */ styled(Title)<{
|
||||
export const ModalTitle = /* @__PURE__ */ styled.h2<{
|
||||
theme?: Theme;
|
||||
centerOnMobile?: boolean;
|
||||
}>`
|
||||
|
||||
@@ -7,6 +7,8 @@ export { useSafe } from "./connectors/gnosis";
|
||||
export { useMagic } from "./connectors/magic";
|
||||
|
||||
export { ConnectWallet } from "../wallet/ConnectWallet/ConnectWallet";
|
||||
export { ConnectModalInline } from "../wallet/ConnectWallet/ConnectModal";
|
||||
|
||||
export { NetworkSelector } from "../wallet/ConnectWallet/NetworkSelector";
|
||||
export type { NetworkSelectorProps } from "../wallet/ConnectWallet/NetworkSelector";
|
||||
|
||||
|
||||
@@ -10,25 +10,41 @@ import {
|
||||
import {
|
||||
ModalConfigCtx,
|
||||
SetModalConfigCtx,
|
||||
WalletUIStatesProvider,
|
||||
useIsWalletModalOpen,
|
||||
useSetIsWalletModalOpen,
|
||||
} from "../../evm/providers/wallet-ui-states-provider";
|
||||
import { ThemeProvider } from "@emotion/react";
|
||||
import { darkTheme, lightTheme } from "../../design-system";
|
||||
import {
|
||||
Theme,
|
||||
darkTheme,
|
||||
lightTheme,
|
||||
radius,
|
||||
spacing,
|
||||
} from "../../design-system";
|
||||
import { useState, useCallback, useEffect, useRef, useContext } from "react";
|
||||
import { GetStartedWithWallets } from "./screens/GetStartedWithWallets";
|
||||
import { reservedScreens } from "./constants";
|
||||
import { HeadlessConnectUI } from "../wallets/headlessConnectUI";
|
||||
import styled from "@emotion/styled";
|
||||
import { scrollbar } from "../../design-system/styles";
|
||||
|
||||
export const ConnectModal = () => {
|
||||
const { theme, title } = useContext(ModalConfigCtx);
|
||||
export const ConnectModalContent = (props: {
|
||||
screen: string | WalletConfig;
|
||||
setScreen: (screen: string | WalletConfig) => void;
|
||||
theme?: "light" | "dark";
|
||||
title?: string;
|
||||
}) => {
|
||||
const { screen, setScreen } = props;
|
||||
const modalConfig = useContext(ModalConfigCtx);
|
||||
const title = props.title || modalConfig.title;
|
||||
const theme = props.theme || modalConfig.theme;
|
||||
const walletConfigs = useWallets();
|
||||
const initialScreen =
|
||||
walletConfigs.length === 1 && !walletConfigs[0].selectUI
|
||||
? walletConfigs[0]
|
||||
: reservedScreens.main;
|
||||
|
||||
const [screen, setScreen] = useState<string | WalletConfig>(initialScreen);
|
||||
const isWalletModalOpen = useIsWalletModalOpen();
|
||||
const setIsWalletModalOpen = useSetIsWalletModalOpen();
|
||||
const connectionStatus = useConnectionStatus();
|
||||
@@ -47,7 +63,13 @@ export const ConnectModal = () => {
|
||||
}
|
||||
setIsWalletModalOpen(false);
|
||||
},
|
||||
[setIsWalletModalOpen, initialScreen, connectionStatus, disconnect],
|
||||
[
|
||||
connectionStatus,
|
||||
setIsWalletModalOpen,
|
||||
setScreen,
|
||||
initialScreen,
|
||||
disconnect,
|
||||
],
|
||||
);
|
||||
|
||||
const handleBack = useCallback(() => {
|
||||
@@ -95,6 +117,55 @@ export const ConnectModal = () => {
|
||||
: darkTheme
|
||||
}
|
||||
>
|
||||
{screen === reservedScreens.main && (
|
||||
<WalletSelector
|
||||
title={title}
|
||||
walletConfigs={walletConfigs}
|
||||
onGetStarted={() => {
|
||||
setScreen(reservedScreens.getStarted);
|
||||
}}
|
||||
selectWallet={setScreen}
|
||||
/>
|
||||
)}
|
||||
|
||||
{screen === reservedScreens.getStarted && (
|
||||
<GetStartedWithWallets onBack={handleBack} />
|
||||
)}
|
||||
|
||||
{WalletConnectUI && (
|
||||
<WalletConnectUI
|
||||
supportedWallets={walletConfigs}
|
||||
theme={theme}
|
||||
goBack={handleBack}
|
||||
close={handleClose}
|
||||
isOpen={isWalletModalOpen}
|
||||
open={() => {
|
||||
setIsWalletModalOpen(true);
|
||||
}}
|
||||
walletConfig={screen}
|
||||
selectionData={walletModalConfig.data}
|
||||
setSelectionData={(data) => {
|
||||
setWalletModalConfig((config) => ({
|
||||
...config,
|
||||
data,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectModal = () => {
|
||||
const { theme } = useContext(ModalConfigCtx);
|
||||
const { screen, setScreen, initialScreen } = useScreen();
|
||||
const isWalletModalOpen = useIsWalletModalOpen();
|
||||
const setIsWalletModalOpen = useSetIsWalletModalOpen();
|
||||
const connectionStatus = useConnectionStatus();
|
||||
const disconnect = useDisconnect();
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
|
||||
<Modal
|
||||
style={{
|
||||
maxWidth: "450px",
|
||||
@@ -111,42 +182,62 @@ export const ConnectModal = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{screen === reservedScreens.main && (
|
||||
<WalletSelector
|
||||
title={title}
|
||||
walletConfigs={walletConfigs}
|
||||
onGetStarted={() => {
|
||||
setScreen(reservedScreens.getStarted);
|
||||
}}
|
||||
selectWallet={setScreen}
|
||||
/>
|
||||
)}
|
||||
|
||||
{screen === reservedScreens.getStarted && (
|
||||
<GetStartedWithWallets onBack={handleBack} />
|
||||
)}
|
||||
|
||||
{WalletConnectUI && (
|
||||
<WalletConnectUI
|
||||
supportedWallets={walletConfigs}
|
||||
theme={theme}
|
||||
goBack={handleBack}
|
||||
close={handleClose}
|
||||
isOpen={isWalletModalOpen}
|
||||
open={() => {
|
||||
setIsWalletModalOpen(true);
|
||||
}}
|
||||
walletConfig={screen}
|
||||
selectionData={walletModalConfig.data}
|
||||
setSelectionData={(data) => {
|
||||
setWalletModalConfig((config) => ({
|
||||
...config,
|
||||
data,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<ConnectModalContent screen={screen} setScreen={setScreen} />
|
||||
</Modal>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectModalInline = (props: {
|
||||
theme?: "light" | "dark";
|
||||
title?: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
const { screen, setScreen } = useScreen();
|
||||
return (
|
||||
<WalletUIStatesProvider theme={props.theme}>
|
||||
<ThemeProvider theme={props.theme === "light" ? lightTheme : darkTheme}>
|
||||
<ConnectModalInlineContainer className={props.className}>
|
||||
<ConnectModalContent
|
||||
screen={screen}
|
||||
setScreen={setScreen}
|
||||
theme={props.theme}
|
||||
title={props.title}
|
||||
/>
|
||||
</ConnectModalInlineContainer>
|
||||
</ThemeProvider>
|
||||
</WalletUIStatesProvider>
|
||||
);
|
||||
};
|
||||
|
||||
function useScreen() {
|
||||
const walletConfigs = useWallets();
|
||||
const initialScreen =
|
||||
walletConfigs.length === 1 && !walletConfigs[0].selectUI
|
||||
? walletConfigs[0]
|
||||
: reservedScreens.main;
|
||||
|
||||
const [screen, setScreen] = useState<string | WalletConfig>(initialScreen);
|
||||
return {
|
||||
screen,
|
||||
setScreen,
|
||||
initialScreen,
|
||||
};
|
||||
}
|
||||
|
||||
const ConnectModalInlineContainer = styled.div<{ theme?: Theme }>`
|
||||
background: ${(p) => p.theme.bg.base};
|
||||
padding: ${spacing.lg};
|
||||
border-radius: ${radius.xl};
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
${(p) =>
|
||||
scrollbar({
|
||||
track: "transparent",
|
||||
thumb: p.theme.bg.elevated,
|
||||
hover: p.theme.bg.highlighted,
|
||||
})}
|
||||
`;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { ConnectUIProps, useConnect } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { isMobile } from "../../../evm/utils/isMobile";
|
||||
import { ConnectingScreen } from "../../ConnectWallet/screens/ConnectingScreen";
|
||||
import { GetStartedScreen } from "../../ConnectWallet/screens/GetStartedScreen";
|
||||
import { isMobile } from "../../../evm/utils/isMobile";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { RainbowScan } from "./RainbowScan";
|
||||
import { WCOpenURI } from "../../ConnectWallet/screens/WCOpenUri";
|
||||
import { GetStartedScreen } from "../../ConnectWallet/screens/GetStartedScreen";
|
||||
import { RainbowWallet } from "@thirdweb-dev/wallets";
|
||||
|
||||
export const RainbowConnectUI = (props: ConnectUIProps<WalletConnect>) => {
|
||||
export const RainbowConnectUI = (props: ConnectUIProps<RainbowWallet>) => {
|
||||
const [screen, setScreen] = useState<
|
||||
"connecting" | "scanning" | "get-started" | "open-wc-uri"
|
||||
"connecting" | "scanning" | "get-started"
|
||||
>("connecting");
|
||||
const { walletConfig, close } = props;
|
||||
const connect = useConnect();
|
||||
@@ -24,14 +23,34 @@ export const RainbowConnectUI = (props: ConnectUIProps<WalletConnect>) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const isInstalled = walletConfig.isInstalled
|
||||
? walletConfig.isInstalled()
|
||||
: false;
|
||||
|
||||
// if loading
|
||||
(async () => {
|
||||
// on mobile, open rainbow app link
|
||||
if (isMobile()) {
|
||||
setScreen("open-wc-uri");
|
||||
} else {
|
||||
// on desktop, show the rainbow scan qr code
|
||||
setScreen("scanning");
|
||||
if (isInstalled) {
|
||||
try {
|
||||
connectPrompted.current = true;
|
||||
setScreen("connecting");
|
||||
await connect(walletConfig);
|
||||
close();
|
||||
} catch (e) {
|
||||
goBack();
|
||||
}
|
||||
}
|
||||
|
||||
// if rainbow is not injected
|
||||
else {
|
||||
// on mobile, open rainbow app link
|
||||
if (isMobile()) {
|
||||
window.open(
|
||||
`https://rainbow.app.link/dapp/${window.location.toString()}`,
|
||||
);
|
||||
} else {
|
||||
// on desktop, show the rainbow scan qr code
|
||||
setScreen("scanning");
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [walletConfig, close, connect, goBack]);
|
||||
@@ -43,24 +62,7 @@ export const RainbowConnectUI = (props: ConnectUIProps<WalletConnect>) => {
|
||||
onBack={props.goBack}
|
||||
walletName={walletConfig.meta.name}
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
supportLink="https://rainbow.me/"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "open-wc-uri") {
|
||||
return (
|
||||
<WCOpenURI
|
||||
hideBackButton={hideBackButton}
|
||||
onBack={props.goBack}
|
||||
onConnected={close}
|
||||
walletConfig={walletConfig}
|
||||
supportLink="https://rainbow.me/"
|
||||
appUriPrefix={{
|
||||
ios: "rainbow://",
|
||||
android: "https://rnbwapp.com/",
|
||||
other: "https://rnbwapp.com/",
|
||||
}}
|
||||
supportLink="https://support.rainbow.io/hc/en-us/articles/4406430256539-User-Guide-Troubleshooting"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -83,7 +85,7 @@ export const RainbowConnectUI = (props: ConnectUIProps<WalletConnect>) => {
|
||||
if (screen === "scanning") {
|
||||
return (
|
||||
<RainbowScan
|
||||
onBack={props.goBack}
|
||||
onBack={goBack}
|
||||
onConnected={close}
|
||||
onGetStarted={() => {
|
||||
setScreen("get-started");
|
||||
|
||||
@@ -4,14 +4,14 @@ import {
|
||||
useWalletContext,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import type { RainbowWallet } from "@thirdweb-dev/wallets";
|
||||
import type { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
|
||||
export const RainbowScan: React.FC<{
|
||||
onBack: () => void;
|
||||
onGetStarted: () => void;
|
||||
onConnected: () => void;
|
||||
walletConfig: WalletConfig<WalletConnect>;
|
||||
walletConfig: WalletConfig<RainbowWallet>;
|
||||
hideBackButton: boolean;
|
||||
}> = ({ onBack, onConnected, onGetStarted, walletConfig, hideBackButton }) => {
|
||||
const createInstance = useCreateWalletInstance();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import {
|
||||
RainbowWallet,
|
||||
getInjectedRainbowProvider,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { RainbowConnectUI } from "./RainbowConnectUI";
|
||||
import { rainbowWalletUris } from "./rainbowWalletUris";
|
||||
import { handelWCSessionRequest } from "../handleWCSessionRequest";
|
||||
|
||||
type RainbowWalletOptions = {
|
||||
/**
|
||||
@@ -16,33 +17,22 @@ type RainbowWalletOptions = {
|
||||
|
||||
export const rainbowWallet = (
|
||||
options?: RainbowWalletOptions,
|
||||
): WalletConfig<WalletConnect> => {
|
||||
): WalletConfig<RainbowWallet> => {
|
||||
return {
|
||||
id: "rainbow",
|
||||
meta: {
|
||||
name: "Rainbow Wallet",
|
||||
iconURL:
|
||||
"ipfs://QmSZn47p4DVVBfzvg9BAX2EqwnPxkT1YAE7rUnrtd9CybQ/rainbow-logo.png",
|
||||
urls: {
|
||||
android: "https://rnbwapp.com/e/Va41HWS6Oxb",
|
||||
ios: "https://rnbwapp.com/e/OeMdmkJ6Oxb",
|
||||
},
|
||||
},
|
||||
id: RainbowWallet.id,
|
||||
meta: RainbowWallet.meta,
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
const wallet = new WalletConnect({
|
||||
const wallet = new RainbowWallet({
|
||||
...walletOptions,
|
||||
walletId: "rainbow",
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
|
||||
handelWCSessionRequest(wallet, rainbowWalletUris);
|
||||
|
||||
return wallet;
|
||||
},
|
||||
connectUI: RainbowConnectUI,
|
||||
isInstalled() {
|
||||
return false;
|
||||
return !!getInjectedRainbowProvider();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,6 +14,12 @@ module.exports = {
|
||||
message:
|
||||
"Do not import entire ethers object, Use named imports instead.",
|
||||
},
|
||||
{
|
||||
name: "eventemitter3",
|
||||
importNames: ["EventEmitter"],
|
||||
message:
|
||||
"Do not use named import for importing EventEmitter, Use default import instead.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.10.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1567](https://github.com/thirdweb-dev/js/pull/1567) [`a00cbaf7`](https://github.com/thirdweb-dev/js/commit/a00cbaf78c05ea43d3814ba9f9ec8e667f0ddb25) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Fix constructor param encoding for deterministic deployments
|
||||
|
||||
- [#1568](https://github.com/thirdweb-dev/js/pull/1568) [`a023cb8c`](https://github.com/thirdweb-dev/js/commit/a023cb8cf1e4f08be56a2e33c146c8d307c80f40) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Better fee calculations for OP stack
|
||||
|
||||
- [#1572](https://github.com/thirdweb-dev/js/pull/1572) [`2088de1c`](https://github.com/thirdweb-dev/js/commit/2088de1cacbc903d4f18a84c21a8f27af8d06b29) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Dynamic gas fee estimations
|
||||
|
||||
- [#1569](https://github.com/thirdweb-dev/js/pull/1569) [`1e6f9dcc`](https://github.com/thirdweb-dev/js/commit/1e6f9dcc04022c6a8a39d490123a3e22e52b5e0b) Thanks [@Marfuen](https://github.com/Marfuen)! - Use a different globalThis for CLI related flow.
|
||||
|
||||
- Updated dependencies [[`3eb9592e`](https://github.com/thirdweb-dev/js/commit/3eb9592e10154e06d2fa5effbc0c1a483f62498f), [`066b9cfa`](https://github.com/thirdweb-dev/js/commit/066b9cfa09df2531c9e5440477a24edc1374e0e0), [`1e6f9dcc`](https://github.com/thirdweb-dev/js/commit/1e6f9dcc04022c6a8a39d490123a3e22e52b5e0b)]:
|
||||
- @thirdweb-dev/storage@1.2.10
|
||||
|
||||
## 3.10.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1557](https://github.com/thirdweb-dev/js/pull/1557) [`e00dd123`](https://github.com/thirdweb-dev/js/commit/e00dd123579f75752b6fe4fcf613d2cae5419e19) Thanks [@MananTank](https://github.com/MananTank)! - Use default export for EventEmitter to fix issue with Nuxt/Vite + Yarn to fix the "Named export 'EventEmitter' not found" error
|
||||
|
||||
- Updated dependencies [[`926dd7b0`](https://github.com/thirdweb-dev/js/commit/926dd7b03f38ed25ca303dc23d3323d5edd28005)]:
|
||||
- @thirdweb-dev/chains@0.1.50
|
||||
|
||||
## 3.10.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1545](https://github.com/thirdweb-dev/js/pull/1545) [`adec589e`](https://github.com/thirdweb-dev/js/commit/adec589ead8ceff1b57169e05a3e6733b4652cc7) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose joinAbis() utility function
|
||||
|
||||
- [#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.
|
||||
- Updated dependencies [[`b30566c6`](https://github.com/thirdweb-dev/js/commit/b30566c68436ad94ddc938a380eccc13a8a7147d), [`0f027069`](https://github.com/thirdweb-dev/js/commit/0f027069064bebe647f9235fa86ef7f165ffc7b3), [`f5aed34d`](https://github.com/thirdweb-dev/js/commit/f5aed34d3c71065c3f45df2c1eb84ba9c36162d5)]:
|
||||
- @thirdweb-dev/chains@0.1.49
|
||||
- @thirdweb-dev/storage@1.2.9
|
||||
|
||||
## 3.10.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.10.56",
|
||||
"version": "3.10.59",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -48,17 +48,24 @@ export async function directDeployDeterministic(
|
||||
const create2Factory = await deployCreate2Factory(signer);
|
||||
|
||||
// 2. Encode constructor params
|
||||
const constructorParamTypes = extractConstructorParamsFromAbi(abi).map(
|
||||
(p) => {
|
||||
return p.type;
|
||||
},
|
||||
);
|
||||
const constructorParams = extractConstructorParamsFromAbi(abi);
|
||||
const constructorParamTypes = constructorParams.map((p) => {
|
||||
return p.type;
|
||||
});
|
||||
const paramValues = convertParamValues(
|
||||
constructorParamTypes,
|
||||
constructorArgs,
|
||||
);
|
||||
|
||||
const paramTypesForEncoder = constructorParams.map((p) => {
|
||||
if (p.type === "tuple[]") {
|
||||
return utils.ParamType.from(p);
|
||||
} else {
|
||||
return p.type;
|
||||
}
|
||||
});
|
||||
const encodedArgs = utils.defaultAbiCoder.encode(
|
||||
constructorParamTypes,
|
||||
paramTypesForEncoder,
|
||||
paramValues,
|
||||
);
|
||||
|
||||
@@ -212,18 +219,24 @@ export async function predictAddressDeterministic(
|
||||
const create2Factory = await getCreate2FactoryAddress(provider);
|
||||
|
||||
// 2. Encode constructor params
|
||||
const constructorParamTypes = extractConstructorParamsFromAbi(abi).map(
|
||||
(p) => {
|
||||
return p.type;
|
||||
},
|
||||
);
|
||||
|
||||
const constructorParams = extractConstructorParamsFromAbi(abi);
|
||||
const constructorParamTypes = constructorParams.map((p) => {
|
||||
return p.type;
|
||||
});
|
||||
const paramValues = convertParamValues(
|
||||
constructorParamTypes,
|
||||
constructorArgs,
|
||||
);
|
||||
|
||||
const paramTypesForEncoder = constructorParams.map((p) => {
|
||||
if (p.type === "tuple[]") {
|
||||
return utils.ParamType.from(p);
|
||||
} else {
|
||||
return p.type;
|
||||
}
|
||||
});
|
||||
const encodedArgs = utils.defaultAbiCoder.encode(
|
||||
constructorParamTypes,
|
||||
paramTypesForEncoder,
|
||||
paramValues,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,108 @@
|
||||
import { ChainId } from "../constants/chains/ChainId";
|
||||
import fetch from "cross-fetch";
|
||||
import { BigNumber, utils } from "ethers";
|
||||
import { BigNumber, utils, providers } from "ethers";
|
||||
import { Mumbai, Polygon } from "@thirdweb-dev/chains";
|
||||
import { isBrowser } from "./utils";
|
||||
|
||||
type FeeData = {
|
||||
maxFeePerGas: null | BigNumber;
|
||||
maxPriorityFeePerGas: null | BigNumber;
|
||||
};
|
||||
|
||||
export async function getDefaultGasOverrides(provider: providers.Provider) {
|
||||
// If we're running in the browser, let users configure gas price in their wallet UI
|
||||
if (isBrowser()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// handle smart wallet provider
|
||||
if ((provider as any).originalProvider) {
|
||||
provider = (provider as any).originalProvider;
|
||||
}
|
||||
|
||||
const feeData = await getDynamicFeeData(
|
||||
provider as providers.JsonRpcProvider,
|
||||
);
|
||||
if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
|
||||
return {
|
||||
maxFeePerGas: feeData.maxPriorityFeePerGas,
|
||||
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
gasPrice: await getGasPrice(provider),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDynamicFeeData(
|
||||
provider: providers.JsonRpcProvider,
|
||||
): Promise<FeeData> {
|
||||
let maxFeePerGas: null | BigNumber = null;
|
||||
let maxPriorityFeePerGas: null | BigNumber = null;
|
||||
|
||||
const [chainId, block, eth_maxPriorityFeePerGas] = await Promise.all([
|
||||
(await provider.getNetwork()).chainId,
|
||||
await provider.getBlock("latest"),
|
||||
await provider.send("eth_maxPriorityFeePerGas", []).catch(() => null),
|
||||
]);
|
||||
|
||||
const baseBlockFee =
|
||||
block && block.baseFeePerGas
|
||||
? block.baseFeePerGas
|
||||
: utils.parseUnits("100", "wei");
|
||||
|
||||
if (chainId === Mumbai.chainId || chainId === Polygon.chainId) {
|
||||
// for polygon, get fee data from gas station
|
||||
maxPriorityFeePerGas = await getPolygonGasPriorityFee(chainId);
|
||||
console.log(
|
||||
"DYNAMIC: polygon fee",
|
||||
utils.formatUnits(maxPriorityFeePerGas, "gwei"),
|
||||
);
|
||||
} else if (eth_maxPriorityFeePerGas) {
|
||||
// prioritize fee from eth_maxPriorityFeePerGas
|
||||
maxPriorityFeePerGas = BigNumber.from(eth_maxPriorityFeePerGas);
|
||||
} else {
|
||||
// if eth_maxPriorityFeePerGas is not available, use 1.5 gwei default
|
||||
const feeData = await provider.getFeeData();
|
||||
maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
|
||||
if (!maxPriorityFeePerGas) {
|
||||
// chain does not support eip-1559, return null for both
|
||||
return { maxFeePerGas: null, maxPriorityFeePerGas: null };
|
||||
}
|
||||
}
|
||||
|
||||
// eip-1559 formula, with an extra 10% tip to account for gas volatility
|
||||
maxFeePerGas = baseBlockFee
|
||||
.mul(2)
|
||||
.add(getPreferredPriorityFee(maxPriorityFeePerGas));
|
||||
|
||||
return { maxFeePerGas, maxPriorityFeePerGas };
|
||||
}
|
||||
|
||||
function getPreferredPriorityFee(
|
||||
defaultPriorityFeePerGas: BigNumber,
|
||||
percentMultiplier: number = 10,
|
||||
): BigNumber {
|
||||
const extraTip = defaultPriorityFeePerGas.div(100).mul(percentMultiplier); // + 10%
|
||||
const txGasPrice = defaultPriorityFeePerGas.add(extraTip);
|
||||
return txGasPrice;
|
||||
}
|
||||
|
||||
export async function getGasPrice(
|
||||
provider: providers.Provider,
|
||||
): Promise<BigNumber> {
|
||||
const gasPrice = await provider.getGasPrice();
|
||||
const maxGasPrice = utils.parseUnits("300", "gwei"); // 300 gwei
|
||||
const extraTip = gasPrice.div(100).mul(10); // + 10%
|
||||
const txGasPrice = gasPrice.add(extraTip);
|
||||
|
||||
if (txGasPrice.gt(maxGasPrice)) {
|
||||
return maxGasPrice;
|
||||
}
|
||||
|
||||
return txGasPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -28,6 +28,7 @@ export * from "./feature-detection/isFeatureEnabled";
|
||||
export * from "./feature-detection/assertEnabled";
|
||||
export * from "./feature-detection/detectContractFeature";
|
||||
export * from "./feature-detection/hasFunction";
|
||||
export * from "./plugin/joinABIs";
|
||||
|
||||
export * from "./version-checker";
|
||||
export * from "./fetchSourceFilesFromMetadata";
|
||||
|
||||
@@ -12,10 +12,7 @@ export * from "./addresses/getDefaultTrustedForwarders";
|
||||
export * from "./chains/ChainId";
|
||||
export * from "./chains/SUPPORTED_CHAIN_ID";
|
||||
export * from "./chains/SUPPORTED_CHAIN_IDS";
|
||||
export {
|
||||
setSupportedChains,
|
||||
getSupportedChains,
|
||||
} from "./chains/supportedChains";
|
||||
export * from "./chains/supportedChains";
|
||||
|
||||
export * from "./contract";
|
||||
export * from "./currency";
|
||||
|
||||
@@ -64,9 +64,8 @@ export function getChainProvider(
|
||||
|
||||
// if we still don't have an url fall back to just using the chainId or slug in the rpc and try that
|
||||
if (!rpcUrl) {
|
||||
rpcUrl = `https://${chainId || network}.rpc.thirdweb.com/${
|
||||
options.clientId || ""
|
||||
}`;
|
||||
rpcUrl = `https://${chainId || network}.rpc.thirdweb.com/${options.clientId || ""
|
||||
}`;
|
||||
}
|
||||
|
||||
if (!rpcUrl) {
|
||||
@@ -244,6 +243,14 @@ export function getProviderFromRpcUrl(
|
||||
authStrategy = "twAuthToken";
|
||||
}
|
||||
|
||||
if (
|
||||
typeof globalThis !== "undefined" &&
|
||||
"TW_CLI_AUTH_TOKEN" in globalThis &&
|
||||
typeof (globalThis as any).TW_CLI_AUTH_TOKEN === "string"
|
||||
) {
|
||||
headers["x-authorize-wallet"] = "true";
|
||||
}
|
||||
|
||||
const bundleId =
|
||||
typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
|
||||
? ((globalThis as any).APP_BUNDLE_ID as string)
|
||||
@@ -278,18 +285,18 @@ export function getProviderFromRpcUrl(
|
||||
// Otherwise, create a new provider on the specific network
|
||||
const newProvider = chainId
|
||||
? // If we know the chainId we should use the StaticJsonRpcBatchProvider
|
||||
new StaticJsonRpcBatchProvider(
|
||||
{
|
||||
url: rpcUrl,
|
||||
headers,
|
||||
},
|
||||
chainId,
|
||||
)
|
||||
: // Otherwise fall back to the built in json rpc batch provider
|
||||
new providers.JsonRpcBatchProvider({
|
||||
new StaticJsonRpcBatchProvider(
|
||||
{
|
||||
url: rpcUrl,
|
||||
headers,
|
||||
});
|
||||
},
|
||||
chainId,
|
||||
)
|
||||
: // Otherwise fall back to the built in json rpc batch provider
|
||||
new providers.JsonRpcBatchProvider({
|
||||
url: rpcUrl,
|
||||
headers,
|
||||
});
|
||||
|
||||
// Save the provider in our cache
|
||||
RPC_PROVIDER_MAP.set(seralizedOpts, newProvider);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { EventType } from "../../constants/events";
|
||||
import type { ContractEvent, EventQueryOptions } from "../../types/events";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import type { BaseContract, Event, providers, utils } from "ethers";
|
||||
import type { EventEmitter } from "eventemitter3";
|
||||
import type EventEmitter from "eventemitter3";
|
||||
|
||||
/**
|
||||
* Listen to Contract events in real time
|
||||
|
||||
@@ -27,14 +27,12 @@ import {
|
||||
ForwardRequest,
|
||||
getAndIncrementNonce,
|
||||
} from "../../common/forwarder";
|
||||
import { getPolygonGasPriorityFee } from "../../common/gas-price";
|
||||
import { getDefaultGasOverrides } from "../../common/gas-price";
|
||||
import { fetchContractMetadataFromAddress } from "../../common/metadata-resolver";
|
||||
import { signEIP2612Permit } from "../../common/permit";
|
||||
import { signTypedDataInternal } from "../../common/sign";
|
||||
import { isBrowser } from "../../common/utils";
|
||||
import { CONTRACT_ADDRESSES } from "../../constants/addresses/CONTRACT_ADDRESSES";
|
||||
import { getContractAddressByChainId } from "../../constants/addresses/getContractAddressByChainId";
|
||||
import { ChainId } from "../../constants/chains/ChainId";
|
||||
import { EventType } from "../../constants/events";
|
||||
import { AbiSchema, ContractSource } from "../../schema/contracts/custom";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
@@ -133,105 +131,7 @@ export class ContractWrapper<
|
||||
* @internal
|
||||
*/
|
||||
public async getCallOverrides(): Promise<CallOverrides> {
|
||||
if (isBrowser()) {
|
||||
// When running in the browser, let the wallet suggest gas estimates
|
||||
// this means that the gas speed preferences set in the SDK options are ignored in a browser context
|
||||
// but it also allows users to select their own gas speed prefs per tx from their wallet directly
|
||||
return {};
|
||||
}
|
||||
const feeData = await this.getProvider().getFeeData();
|
||||
const supports1559 = feeData.maxFeePerGas && feeData.maxPriorityFeePerGas;
|
||||
if (supports1559) {
|
||||
const chainId = await this.getChainID();
|
||||
const block = await this.getProvider().getBlock("latest");
|
||||
const baseBlockFee =
|
||||
block && block.baseFeePerGas
|
||||
? block.baseFeePerGas
|
||||
: utils.parseUnits("1", "gwei");
|
||||
let defaultPriorityFee: BigNumber;
|
||||
if (chainId === ChainId.Mumbai || chainId === ChainId.Polygon) {
|
||||
// for polygon, get fee data from gas station
|
||||
defaultPriorityFee = await getPolygonGasPriorityFee(chainId);
|
||||
} else {
|
||||
// otherwise get it from ethers
|
||||
defaultPriorityFee = BigNumber.from(feeData.maxPriorityFeePerGas);
|
||||
}
|
||||
// then add additional fee based on user preferences
|
||||
const maxPriorityFeePerGas =
|
||||
this.getPreferredPriorityFee(defaultPriorityFee);
|
||||
// See: https://eips.ethereum.org/EIPS/eip-1559 for formula
|
||||
const baseMaxFeePerGas = baseBlockFee.mul(2);
|
||||
const maxFeePerGas = baseMaxFeePerGas.add(maxPriorityFeePerGas);
|
||||
return {
|
||||
maxFeePerGas,
|
||||
maxPriorityFeePerGas,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
gasPrice: await this.getPreferredGasPrice(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the priority fee per gas according to user preferences
|
||||
* @param defaultPriorityFeePerGas - the base priority fee
|
||||
*/
|
||||
private getPreferredPriorityFee(
|
||||
defaultPriorityFeePerGas: BigNumber,
|
||||
): BigNumber {
|
||||
const speed = this.options.gasSettings.speed;
|
||||
const maxGasPrice = this.options.gasSettings.maxPriceInGwei;
|
||||
let extraTip;
|
||||
switch (speed) {
|
||||
case "standard":
|
||||
extraTip = BigNumber.from(0); // default is 2.5 gwei for ETH, 31 gwei for polygon
|
||||
break;
|
||||
case "fast":
|
||||
extraTip = defaultPriorityFeePerGas.div(100).mul(5); // + 5% - 2.625 gwei / 32.5 gwei
|
||||
break;
|
||||
case "fastest":
|
||||
extraTip = defaultPriorityFeePerGas.div(100).mul(10); // + 10% - 2.75 gwei / 34.1 gwei
|
||||
break;
|
||||
}
|
||||
let txGasPrice = defaultPriorityFeePerGas.add(extraTip);
|
||||
const max = utils.parseUnits(maxGasPrice.toString(), "gwei"); // no more than max gas setting
|
||||
const min = utils.parseUnits("2.5", "gwei"); // no less than 2.5 gwei
|
||||
if (txGasPrice.gt(max)) {
|
||||
txGasPrice = max;
|
||||
}
|
||||
if (txGasPrice.lt(min)) {
|
||||
txGasPrice = min;
|
||||
}
|
||||
return txGasPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the gas price for transactions according to user preferences
|
||||
*/
|
||||
public async getPreferredGasPrice(): Promise<BigNumber> {
|
||||
const gasPrice = await this.getProvider().getGasPrice();
|
||||
const speed = this.options.gasSettings.speed;
|
||||
const maxGasPrice = this.options.gasSettings.maxPriceInGwei;
|
||||
let txGasPrice = gasPrice;
|
||||
let extraTip;
|
||||
switch (speed) {
|
||||
case "standard":
|
||||
extraTip = BigNumber.from(1); // min 1 wei
|
||||
break;
|
||||
case "fast":
|
||||
extraTip = gasPrice.div(100).mul(5); // + 5%
|
||||
break;
|
||||
case "fastest":
|
||||
extraTip = gasPrice.div(100).mul(10); // + 10%
|
||||
break;
|
||||
}
|
||||
txGasPrice = txGasPrice.add(extraTip);
|
||||
const max = utils.parseUnits(maxGasPrice.toString(), "gwei");
|
||||
if (txGasPrice.gt(max)) {
|
||||
txGasPrice = max;
|
||||
}
|
||||
return txGasPrice;
|
||||
return getDefaultGasOverrides(this.getProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,7 +38,7 @@ import {
|
||||
type ContractInterface,
|
||||
utils,
|
||||
} from "ethers";
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
import { z } from "zod";
|
||||
import { getApprovedImplementation } from "../../constants/addresses/getApprovedImplementation";
|
||||
|
||||
@@ -35,7 +35,7 @@ export class GasCostEstimator<TContract extends BaseContract> {
|
||||
fn: keyof TContract["functions"] | (string & {}),
|
||||
args: Parameters<TContract["functions"][typeof fn]> | any[],
|
||||
): Promise<string> {
|
||||
const price = await this.contractWrapper.getPreferredGasPrice();
|
||||
const price = await this.contractWrapper.getProvider().getGasPrice();
|
||||
const gasUnits = await this.contractWrapper.estimateGas(fn, args);
|
||||
return utils.formatEther(gasUnits.mul(price));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { TransactionError, parseRevertReason } from "../../common/error";
|
||||
import { getPolygonGasPriorityFee } from "../../common/gas-price";
|
||||
import { getDefaultGasOverrides, getGasPrice } from "../../common/gas-price";
|
||||
import { fetchContractMetadataFromAddress } from "../../common/metadata-resolver";
|
||||
import { fetchSourceFilesFromMetadata } from "../../common/fetchSourceFilesFromMetadata";
|
||||
import { isRouterContract } from "../../common/plugin/isRouterContract";
|
||||
import { isBrowser } from "../../common/utils";
|
||||
import { ChainId } from "../../constants/chains/ChainId";
|
||||
import { ContractSource } from "../../schema/contracts/custom";
|
||||
import { SDKOptionsOutput } from "../../schema/sdk-options";
|
||||
import type {
|
||||
@@ -205,16 +203,7 @@ abstract class TransactionContext {
|
||||
* Calculates the gas price for transactions (adding a 10% tip buffer)
|
||||
*/
|
||||
public async getGasPrice(): Promise<BigNumber> {
|
||||
const gasPrice = await this.provider.getGasPrice();
|
||||
const maxGasPrice = utils.parseUnits("300", "gwei"); // 300 gwei
|
||||
const extraTip = gasPrice.div(100).mul(10); // + 10%
|
||||
const txGasPrice = gasPrice.add(extraTip);
|
||||
|
||||
if (txGasPrice.gt(maxGasPrice)) {
|
||||
return maxGasPrice;
|
||||
}
|
||||
|
||||
return txGasPrice;
|
||||
return getGasPrice(this.provider);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,43 +217,7 @@ abstract class TransactionContext {
|
||||
* Get gas overrides for the transaction
|
||||
*/
|
||||
protected async getGasOverrides() {
|
||||
// If we're running in the browser, let users configure gas price in their wallet UI
|
||||
if (isBrowser()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const feeData = await this.provider.getFeeData();
|
||||
const supports1559 = feeData.maxFeePerGas && feeData.maxPriorityFeePerGas;
|
||||
if (supports1559) {
|
||||
const chainId = (await this.provider.getNetwork()).chainId;
|
||||
const block = await this.provider.getBlock("latest");
|
||||
const baseBlockFee =
|
||||
block && block.baseFeePerGas
|
||||
? block.baseFeePerGas
|
||||
: utils.parseUnits("1", "gwei");
|
||||
let defaultPriorityFee: BigNumber;
|
||||
if (chainId === ChainId.Mumbai || chainId === ChainId.Polygon) {
|
||||
// for polygon, get fee data from gas station
|
||||
defaultPriorityFee = await getPolygonGasPriorityFee(chainId);
|
||||
} else {
|
||||
// otherwise get it from ethers
|
||||
defaultPriorityFee = BigNumber.from(feeData.maxPriorityFeePerGas);
|
||||
}
|
||||
// then add additional fee based on user preferences
|
||||
const maxPriorityFeePerGas =
|
||||
this.getPreferredPriorityFee(defaultPriorityFee);
|
||||
// See: https://eips.ethereum.org/EIPS/eip-1559 for formula
|
||||
const baseMaxFeePerGas = baseBlockFee.mul(2);
|
||||
const maxFeePerGas = baseMaxFeePerGas.add(maxPriorityFeePerGas);
|
||||
return {
|
||||
maxFeePerGas,
|
||||
maxPriorityFeePerGas,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
gasPrice: await this.getGasPrice(),
|
||||
};
|
||||
}
|
||||
return getDefaultGasOverrides(this.provider);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,16 +228,6 @@ abstract class TransactionContext {
|
||||
): BigNumber {
|
||||
const extraTip = defaultPriorityFeePerGas.div(100).mul(10); // + 10%
|
||||
const txGasPrice = defaultPriorityFeePerGas.add(extraTip);
|
||||
const maxGasPrice = utils.parseUnits("300", "gwei"); // no more than 300 gwei
|
||||
const minGasPrice = utils.parseUnits("2.5", "gwei"); // no less than 2.5 gwei
|
||||
|
||||
if (txGasPrice.gt(maxGasPrice)) {
|
||||
return maxGasPrice;
|
||||
}
|
||||
if (txGasPrice.lt(minGasPrice)) {
|
||||
return minGasPrice;
|
||||
}
|
||||
|
||||
return txGasPrice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ import {
|
||||
utils,
|
||||
ContractFactory as ethersContractFactory,
|
||||
} from "ethers";
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/* eslint-disable no-var */
|
||||
declare module globalThis {
|
||||
var TW_AUTH_TOKEN: string;
|
||||
var TW_CLI_AUTH_TOKEN: string;
|
||||
}
|
||||
@@ -1,5 +1,22 @@
|
||||
# @thirdweb-dev/service-utils
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1566](https://github.com/thirdweb-dev/js/pull/1566) [`d378106a`](https://github.com/thirdweb-dev/js/commit/d378106a852f941779bb72ac1841bddf34fc15a6) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - docs(service-utils): Add documentation for authorizeNode for node auth function
|
||||
|
||||
- [#1569](https://github.com/thirdweb-dev/js/pull/1569) [`1e6f9dcc`](https://github.com/thirdweb-dev/js/commit/1e6f9dcc04022c6a8a39d490123a3e22e52b5e0b) Thanks [@Marfuen](https://github.com/Marfuen)! - Use a different globalThis for CLI related flow.
|
||||
|
||||
- [#1559](https://github.com/thirdweb-dev/js/pull/1559) [`13ef6a50`](https://github.com/thirdweb-dev/js/commit/13ef6a50cf10b442b2b54b780e42210cab2db762) Thanks [@assimovt](https://github.com/assimovt)! - expose account status in api key metadata
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#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.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/service-utils",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.4",
|
||||
"main": "dist/thirdweb-dev-service-utils.cjs.js",
|
||||
"module": "dist/thirdweb-dev-service-utils.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import type { ServiceName } from "./services";
|
||||
|
||||
|
||||
export type CoreServiceConfig = {
|
||||
enforceAuth: boolean;
|
||||
apiUrl: string;
|
||||
serviceScope: ServiceName;
|
||||
serviceApiKey: string;
|
||||
serviceAction?: string;
|
||||
useWalletAuth?: boolean;
|
||||
};
|
||||
|
||||
export type ApiKeyMetadata = {
|
||||
id: string;
|
||||
key: string;
|
||||
accountId: string;
|
||||
accountStatus: "noCustomer" | "noPayment" | "validPayment" | "invalidPayment";
|
||||
accountPlan: "free" | "enterprise";
|
||||
creatorWalletAddress: string;
|
||||
secretHash: string;
|
||||
walletAddresses: string[];
|
||||
@@ -61,11 +65,15 @@ export async function fetchKeyMetadataFromApi(
|
||||
"content-type": "application/json",
|
||||
},
|
||||
});
|
||||
let json: ApiResponse
|
||||
let json: ApiResponse;
|
||||
try {
|
||||
json = await response.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Error fetching key metadata from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
|
||||
throw new Error(
|
||||
`Error fetching key metadata from API: ${response.status} - ${
|
||||
response.statusText
|
||||
} - ${await response.text()}`,
|
||||
);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
@@ -73,9 +81,12 @@ export async function fetchKeyMetadataFromApi(
|
||||
export async function fetchAccountFromApi(
|
||||
jwt: string,
|
||||
config: CoreServiceConfig,
|
||||
useWalletAuth: boolean,
|
||||
): Promise<ApiAccountResponse> {
|
||||
const { apiUrl, serviceApiKey } = config;
|
||||
const url = `${apiUrl}/v1/account/me`;
|
||||
const url = useWalletAuth
|
||||
? `${apiUrl}/v1/wallet/me`
|
||||
: `${apiUrl}/v1/account/me`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -84,11 +95,15 @@ export async function fetchAccountFromApi(
|
||||
authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
});
|
||||
let json: ApiAccountResponse
|
||||
let json: ApiAccountResponse;
|
||||
try {
|
||||
json = await response.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Error fetching account from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
|
||||
throw new Error(
|
||||
`Error fetching account from API: ${response.status} - ${
|
||||
response.statusText
|
||||
} - ${await response.text()}`,
|
||||
);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user