Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
318b274aae Version Packages (#924)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-03 21:24:18 -07:00
77f0474b88 [ReactNative] update copy for smart wallet (#963)
Co-authored-by: Manan Tank <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-03 19:15:33 +00:00
5ffb1cba03 [REACT] Add onLogout function to ConnectWallet authOptions prop (#960)
Co-authored-by: frog <[email protected]>
2023-05-03 16:07:31 +00:00
YashandGitHub 0bf29745b0 [SDK] GSNv2 Forwarder addresses (#961) 2023-05-03 15:55:30 +00:00
Joaquim VergesandGitHub 00d0d01e61 [SDK] Feature detection for Account and AccountFactory (#959) 2023-05-03 05:51:13 +00:00
Adam MajmudarandGitHub 72b8b9829e [Auth] Add all fields to cookie on logout (#958) 2023-05-03 00:14:29 +00:00
Joaquim VergesandGitHub 26cd91ffe1 [Wallets] update to latest account factory (#953) 2023-05-02 23:24:30 +00:00
1c3a846045 [ReactNative] Update guest mode icon and update learn more link (#957)
Co-authored-by: Manan Tank <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-02 22:40:44 +00:00
4a69f8c85d [ReactNative] Allow switching between personal wallet and smart wallet (#956)
Co-authored-by: Manan Tank <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-02 19:44:32 +00:00
Manan TankandGitHub c7c2530c7f [react] Local Wallet UI refactor, various fixes and cleanup (#955) 2023-05-02 17:58:14 +00:00
7012513bc2 [ReactNative] Introducing Smart Wallet (#937)
Co-authored-by: Manan Tank <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-01 22:58:06 +00:00
YashandGitHub 28b5d1eb6d [SDK] Custom gas-price for Theta testnet and mainnet (#951) 2023-05-01 21:37:15 +00:00
1e9fad779f safe, device wallet, smartWallet autoconnect (#927)
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-01 20:07:25 +00:00
Joaquim VergesandGitHub 7e7a507f03 [Unity] fix unity wallet connect (#950) 2023-05-01 18:48:09 +00:00
Joaquim VergesandGitHub 5a67d5d894 [Wallets] Batch transactions functionality for Smart Wallets (#948) 2023-04-30 21:42:41 +00:00
Joaquim VergesandGitHub fc96e14750 [Wallets] Expose execute functions directly from smart wallet (#947) 2023-04-29 02:05:16 +00:00
YashandGitHub 8f962bc15c [SDK] Add default domain in gasless options (#944) 2023-04-29 01:19:15 +00:00
Joaquim VergesandGitHub f12a80a475 [Wallets] fix default RPC for local wallet providers (#931) 2023-04-29 01:11:57 +00:00
Joaquim VergesandGitHub 0186721bc4 [Wallets] New utils functions for smart wallets (#945) 2023-04-28 23:25:27 +00:00
Manan TankandGitHub 5d67b2807f add magic link wallet and UI (#941) 2023-04-28 21:11:52 +00:00
Joaquim VergesandGitHub 1e4ac67272 [SmartWallet] remove accountIds and allow passing custom factory/account contract definitions (#942) 2023-04-28 17:41:44 +00:00
iketwandGitHub 465d8e2c3d [ReactNative] Make web3button action return a promise (#943) 2023-04-28 15:03:05 +00:00
0xHendrixandGitHub a8b790652c [REACT] Add onLogin callback to ConnectWallet authOptions props (#940) 2023-04-28 03:41:38 +00:00
iketwandGitHub 4828c87691 [ReactNative] Enable copying the address by pressing on it (#936) 2023-04-26 17:46:52 +00:00
iketwandGitHub 45d2ffcf89 [ReactNative] continue as guest (#935) 2023-04-26 15:37:03 +00:00
YashandGitHub bf6df26711 [SDK] Add support for Skale chaos testnet (#932) 2023-04-25 19:56:15 +00:00
Manan TankandGitHub e22e4a47d7 [react] suggest first supportedWallet for getting started (#930) 2023-04-24 12:29:13 +00:00
iketwandGitHub d2c7f6d758 [ReactNativeSDK] Adds Local Wallet (#787) 2023-04-22 04:14:55 +00:00
Joaquim VergesandGitHub 7af99d9a6d [Wallets] Switch to entrypoint v0.6 for Smart Wallet (#929) 2023-04-21 23:01:33 +00:00
YashandGitHub f0279c2288 [SDK] Contract verification utils (#905) 2023-04-21 17:17:10 +00:00
iketwandGitHub 07194b06e5 [RN] Remove select wallet step with one supported wallet (#925) 2023-04-21 14:43:51 +00:00
255c5dcae8 [Wallets] Add accountId handling for SmartWallet (#923)
Co-authored-by: Manan Tank <[email protected]>
2023-04-21 14:15:39 +00:00
8cfb4f38ed [Wallets] Introducing Smart Wallet (#904)
Co-authored-by: Manan Tank <[email protected]>
2023-04-21 05:10:56 +00:00
253 changed files with 11950 additions and 3550 deletions
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/auth
## 3.0.16
### Patch Changes
- [#958](https://github.com/thirdweb-dev/js/pull/958) [`72b8b982`](https://github.com/thirdweb-dev/js/commit/72b8b9829eb11d51a63530af62e5634f182c0d03) Thanks [@adam-maj](https://github.com/adam-maj)! - Add extra options to cookie on logout
- Updated dependencies [[`7012513b`](https://github.com/thirdweb-dev/js/commit/7012513bc20f283b2cde46c0b938af33fe3a1a20), [`5d67b280`](https://github.com/thirdweb-dev/js/commit/5d67b2807f2504add4c202d2eb18897415662fb6), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`5a67d5d8`](https://github.com/thirdweb-dev/js/commit/5a67d5d89474eac9a638ffaddba139b62965deff), [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f), [`c7c2530c`](https://github.com/thirdweb-dev/js/commit/c7c2530c7f2ef412f1e40428391e85decf504392), [`e22e4a47`](https://github.com/thirdweb-dev/js/commit/e22e4a47d73e1bbc6e3f0ae7ed56717b44e5ffcd), [`1e4ac672`](https://github.com/thirdweb-dev/js/commit/1e4ac672720c2fb01046bec195877a074ffbda06), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a), [`4a69f8c8`](https://github.com/thirdweb-dev/js/commit/4a69f8c85dec420615e9eda8d1ad5b5ef0b87713), [`26cd91ff`](https://github.com/thirdweb-dev/js/commit/26cd91ffe18dad37133a18988f21185c13d64cfb), [`0186721b`](https://github.com/thirdweb-dev/js/commit/0186721bc455aa1f8454839a1a25fa4062b45102), [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa), [`7af99d9a`](https://github.com/thirdweb-dev/js/commit/7af99d9a6d54492a29a90288a25b30773a8a10a7), [`8cfb4f38`](https://github.com/thirdweb-dev/js/commit/8cfb4f38ed89c26ad04f19d27c65c24cefa976b6)]:
- @thirdweb-dev/wallets@0.2.17
## 3.0.15
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.0.15",
"version": "3.0.16",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
@@ -27,7 +27,10 @@ export default async function handler(
serialize("thirdweb_auth_token", "", {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(Date.now() + 5 * 1000),
httpOnly: true,
secure: true,
}),
);
+3
View File
@@ -27,7 +27,10 @@ export default async function handler(
serialize("thirdweb_auth_token", "", {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(Date.now() + 5 * 1000),
httpOnly: true,
secure: true,
}),
);
+8
View File
@@ -1,5 +1,13 @@
# @thirdweb-dev/chains
## 0.1.13
### Patch Changes
- [#787](https://github.com/thirdweb-dev/js/pull/787) [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adds Device Wallet
- [#931](https://github.com/thirdweb-dev/js/pull/931) [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Updated chains
## 0.1.12
### Patch Changes
+1 -1
View File
@@ -10,7 +10,7 @@ export default {
},
"rpc": [
"https://nebula-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.rpc.novanetwork.io:9070"
"https://testnet.rpc.novanetwork.io"
],
"faucets": [
"https://faucet.novanetwork.io"
+37
View File
@@ -0,0 +1,37 @@
import type { Chain } from "../src/types";
export default {
"name": "Alphabet Mainnet",
"chain": "Alphabet Network",
"icon": {
"url": "ipfs://QmfTeudwVJcu7jzySBcpD9H5ZVK66nPJKRnicxend1bxfq",
"width": 500,
"height": 500,
"format": "svg"
},
"rpc": [
"https://alphabet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://londonpublic.alphabetnetwork.org",
"wss://londonpublic.alphabetnetwork.org/ws/",
"https://main-rpc.com",
"wss://main-rpc.com/ws/"
],
"faucets": [],
"nativeCurrency": {
"name": "ALT",
"symbol": "ALT",
"decimals": 18
},
"infoURL": "https://alphabetnetwork.org",
"shortName": "alphabet",
"chainId": 111222333444,
"networkId": 111222333444,
"explorers": [
{
"name": "Alphabet Explorer",
"url": "https://scan.alphabetnetwork.org",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "alphabet"
} as const satisfies Chain;
+6
View File
@@ -2,6 +2,12 @@ import type { Chain } from "../src/types";
export default {
"name": "Palm Testnet",
"chain": "Palm",
"icon": {
"url": "ipfs://bafkreihifvvbq6xzviygveivayogqiotdtpjvilu27bgqobduqemzeq7o4",
"width": 72,
"height": 72,
"format": "svg"
},
"rpc": [
"https://palm-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://palm-testnet.infura.io/v3/${INFURA_API_KEY}"
+6
View File
@@ -2,6 +2,12 @@ import type { Chain } from "../src/types";
export default {
"name": "Palm",
"chain": "Palm",
"icon": {
"url": "ipfs://bafkreihifvvbq6xzviygveivayogqiotdtpjvilu27bgqobduqemzeq7o4",
"width": 72,
"height": 72,
"format": "svg"
},
"rpc": [
"https://palm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://palm-mainnet.infura.io/v3/${INFURA_API_KEY}"
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Symplexia Smart Chain",
"chain": "Plexchain",
"rpc": [
"https://symplexia-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://plex-rpc.plexfinance.us"
],
"faucets": [],
"nativeCurrency": {
"name": "Plex Native Token",
"symbol": "PLEX",
"decimals": 18
},
"infoURL": "https://plexfinance.us/",
"shortName": "Plexchain",
"chainId": 1149,
"networkId": 1149,
"icon": {
"url": "ipfs://QmcXzfMNSQ7SZzKemNquVoXyG5ergdqCGeLWjRYETGBTUM",
"width": 256,
"height": 256,
"format": "png"
},
"explorers": [
{
"name": "Plexchain Explorer",
"url": "https://explorer.plexfinance.us",
"icon": {
"url": "ipfs://QmcXzfMNSQ7SZzKemNquVoXyG5ergdqCGeLWjRYETGBTUM",
"width": 256,
"height": 256,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "symplexia-smart-chain"
} as const satisfies Chain;
+6
View File
@@ -3,6 +3,12 @@ export default {
"name": "Rikeza Network Testnet",
"title": "Rikeza Network Testnet",
"chain": "Rikeza",
"icon": {
"url": "ipfs://QmfJ1Qxpzi6CSLeFeWY1Bwe435CpT5za5WfrLUE7vNzZfy",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://rikeza-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-rpc.rikscan.com"
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Deamchain Mainnet",
"chain": "Deamchain",
"icon": {
"url": "ipfs://QmXvHWmjfXKdZMSz7x82NR4SjEqigKdJELVHbnzUPkj17F",
"width": 512,
"height": 512,
"format": "svg"
},
"rpc": [
"https://deamchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet.deamchain.com"
],
"faucets": [],
"nativeCurrency": {
"name": "Deamchain Native Token",
"symbol": "DEAM",
"decimals": 18
},
"infoURL": "https://deamchain.com",
"shortName": "deam",
"chainId": 136,
"networkId": 136,
"explorers": [
{
"name": "Deamchain Block Explorer",
"url": "https://scan.deamchain.com",
"standard": "EIP3091",
"icon": {
"url": "ipfs://QmXvHWmjfXKdZMSz7x82NR4SjEqigKdJELVHbnzUPkj17F",
"width": 512,
"height": 512,
"format": "svg"
}
}
],
"testnet": false,
"slug": "deamchain"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "ICPlaza Mainnet",
"chain": "ICPlaza",
"icon": {
"url": "ipfs://QmQpKKwpqrx77VA4SJLEWhuv9eLFMcVV9uvxRCLb6gdgCX",
"width": 847,
"height": 906,
"format": "png"
},
"rpc": [
"https://icplaza.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpcmainnet.ic-plaza.org/"
],
"faucets": [],
"nativeCurrency": {
"name": "ict",
"symbol": "ict",
"decimals": 18
},
"infoURL": "https://docs.ic-plaza.org/",
"shortName": "ICPlaza",
"chainId": 142857,
"networkId": 142857,
"explorers": [
{
"name": "ICPlaza",
"url": "https://browsemainnet.ic-plaza.org/index",
"standard": "none"
}
],
"testnet": false,
"slug": "icplaza"
} as const satisfies Chain;
+6
View File
@@ -3,6 +3,12 @@ export default {
"name": "Rikeza Network Mainnet",
"title": "Rikeza Network Mainnet",
"chain": "Rikeza",
"icon": {
"url": "ipfs://QmfJ1Qxpzi6CSLeFeWY1Bwe435CpT5za5WfrLUE7vNzZfy",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://rikeza-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.rikscan.com"
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "Six Protocol Testnet",
"chain": "FIVENET",
"icon": {
"url": "ipfs://QmP93z696v8Hetu13peY2oEHDXq8Bj5CqaDRwpVkpnM15A",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://six-protocol-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-evm.fivenet.sixprotocol.net"
],
"faucets": [
"https://faucet.sixprotocol.net"
],
"nativeCurrency": {
"name": "SIX testnet evm token",
"symbol": "tSIX",
"decimals": 18
},
"infoURL": "https://six.network/",
"shortName": "sixt",
"chainId": 150,
"networkId": 150,
"explorers": [
{
"name": "SIX Scan fivenet",
"url": "https://sixscan.io/fivenet",
"standard": "none",
"icon": {
"url": "ipfs://QmP93z696v8Hetu13peY2oEHDXq8Bj5CqaDRwpVkpnM15A",
"width": 512,
"height": 512,
"format": "png"
}
}
],
"testnet": true,
"slug": "six-protocol-testnet"
} as const satisfies Chain;
+9 -1
View File
@@ -2,9 +2,17 @@ import type { Chain } from "../src/types";
export default {
"name": "OEBlock Testnet",
"chain": "OEBt",
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"rpc": [
"https://oeblock-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-rpc.oeblock.com/"
"https://testnet-rpc.oeblock.com"
],
"faucets": [],
"nativeCurrency": {
+1 -1
View File
@@ -14,7 +14,7 @@ export default {
},
"features": [],
"infoURL": "https://hashpalette.com/",
"shortName": "PaletteChain",
"shortName": "PCM",
"chainId": 1718,
"networkId": 1718,
"icon": {
+4 -4
View File
@@ -27,10 +27,10 @@ export default {
"name": "Blockscout",
"url": "https://explorer.gather.network",
"icon": {
"url": "ipfs://QmeoEHUVYKSJFkM9o5j62rhQqCDN5iQxPC7PtzmH77rSWR",
"width": 512,
"height": 512,
"format": "png"
"url": "ipfs://QmTYR8CeFiNbJ1zJHnE3DK2wEN18r2y2vqSKUcLweUT2Gz",
"width": 1080,
"height": 1080,
"format": "svg"
},
"standard": "none"
}
+1 -1
View File
@@ -28,7 +28,7 @@ export default {
"explorers": [
{
"name": "edexa-testnet",
"url": "https://explorer.edexa.com",
"url": "https://explorer.testnet.edexa.com",
"standard": "EIP3091"
}
],
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Metaplayerone Network",
"chain": "MP1 Dubai-Testnet",
"icon": {
"url": "ipfs://QmfJKxmubJrqYWDcR2PnPvmpukxPz4fYDu3hqTaSnpJDxC",
"width": 42,
"height": 23,
"format": "svg"
},
"rpc": [
"https://metaplayerone-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-dubai.mp1network.com/"
],
"faucets": [],
"nativeCurrency": {
"name": "Metaunit",
"symbol": "MEU",
"decimals": 18
},
"infoURL": "https://docs.metaplayer.one/",
"shortName": "MEU",
"chainId": 2124,
"networkId": 2124,
"explorers": [
{
"name": "MP1Scan",
"url": "https://dubai.mp1scan.io",
"icon": {
"url": "ipfs://QmfJKxmubJrqYWDcR2PnPvmpukxPz4fYDu3hqTaSnpJDxC",
"width": 42,
"height": 23,
"format": "svg"
},
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "metaplayerone-network"
} as const satisfies Chain;
+8 -2
View File
@@ -2,7 +2,7 @@ import type { Chain } from "../src/types";
export default {
"name": "Kanazawa",
"title": "Meld Testnet Kanazawa",
"chain": "MELD",
"chain": "Kanazawa",
"rpc": [
"https://kanazawa.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-kanazawa.meldlabs.dev/ext/bc/2Ci7VYrUd4fTBqGA5D2HA6UPHzQ4LQyr8rZQww9MGSv9rNkRzn/rpc"
@@ -14,8 +14,14 @@ export default {
"symbol": "gMELD",
"decimals": 18
},
"icon": {
"url": "ipfs://QmRhB4AbjDrhvwfSAQi2JvKirFiDWxzJvKEvG8S8AdDdED",
"width": 4000,
"height": 4000,
"format": "png"
},
"infoURL": "https://meld.com",
"shortName": "meld",
"shortName": "kanazawa",
"chainId": 222000222,
"networkId": 222000222,
"explorers": [],
+29
View File
@@ -0,0 +1,29 @@
import type { Chain } from "../src/types";
export default {
"name": "SwapDEX",
"chain": "SDX",
"rpc": [
"https://swapdex.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.swapdex.network",
"wss://ss.swapdex.network"
],
"faucets": [],
"nativeCurrency": {
"name": "SwapDEX",
"symbol": "SDX",
"decimals": 18
},
"infoURL": "https://swapdex.network/",
"shortName": "SDX",
"chainId": 230,
"networkId": 230,
"explorers": [
{
"name": "SwapDEX",
"url": "https://evm.swapdex.network",
"standard": "none"
}
],
"testnet": false,
"slug": "swapdex"
} as const satisfies Chain;
+11 -11
View File
@@ -1,9 +1,9 @@
import type { Chain } from "../src/types";
export default {
"name": "WEMIX Kanvas Sepolia",
"title": "WEMIX Kanvas Testnet Sepolia",
"name": "Kroma Sepolia",
"title": "Kroma Testnet Sepolia",
"chainId": 2357,
"shortName": "kanvas-aqua",
"shortName": "kroma-sepolia",
"chain": "ETH",
"networkId": 2357,
"nativeCurrency": {
@@ -12,13 +12,13 @@ export default {
"decimals": 18
},
"rpc": [
"https://wemix-kanvas-sepolia.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.aqua.wemixkanvas.io"
"https://kroma-sepolia.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.sepolia.kroma.network"
],
"faucets": [],
"infoURL": "https://wemixkanvas.io",
"infoURL": "https://kroma.network",
"icon": {
"url": "ipfs://QmVcVxsHsVg5BMii3EJ1MUSnLBZkQicpjmXjSmW66bCEUF",
"url": "ipfs://QmcYafk2je5rMqgnFPDZJTaLi6dgFgq96vmX2Li6DX441B",
"width": 320,
"height": 320,
"format": "svg"
@@ -26,9 +26,9 @@ export default {
"explorers": [
{
"name": "blockscout",
"url": "https://blockscout.aqua.wemixkanvas.io",
"url": "https://blockscout.sepolia.kroma.network",
"icon": {
"url": "ipfs://QmVcVxsHsVg5BMii3EJ1MUSnLBZkQicpjmXjSmW66bCEUF",
"url": "ipfs://QmcYafk2je5rMqgnFPDZJTaLi6dgFgq96vmX2Li6DX441B",
"width": 320,
"height": 320,
"format": "svg"
@@ -41,10 +41,10 @@ export default {
"chain": "eip155-11155111",
"bridges": [
{
"url": "https://wemixkanvas.io/bridge"
"url": "https://kroma.network/bridge"
}
]
},
"testnet": true,
"slug": "wemix-kanvas-sepolia"
"slug": "kroma-sepolia"
} as const satisfies Chain;
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "Deamchain Testnet",
"chain": "Deamchain",
"icon": {
"url": "ipfs://QmXvHWmjfXKdZMSz7x82NR4SjEqigKdJELVHbnzUPkj17F",
"width": 512,
"height": 512,
"format": "svg"
},
"rpc": [
"https://deamchain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.deamchain.com"
],
"faucets": [
"https://faucet.deamchain.com"
],
"nativeCurrency": {
"name": "Deamchain Native Token",
"symbol": "DEAM",
"decimals": 18
},
"infoURL": "https://deamchain.com",
"shortName": "deamtest",
"chainId": 236,
"networkId": 236,
"explorers": [
{
"name": "Deamchain Testnet Explorer",
"url": "https://testnet-scan.deamchain.com",
"standard": "EIP3091",
"icon": {
"url": "ipfs://QmXvHWmjfXKdZMSz7x82NR4SjEqigKdJELVHbnzUPkj17F",
"width": 512,
"height": 512,
"format": "svg"
}
}
],
"testnet": true,
"slug": "deamchain-testnet"
} as const satisfies Chain;
+38
View File
@@ -0,0 +1,38 @@
import type { Chain } from "../src/types";
export default {
"name": "Ferrum Testnet",
"chain": "tFRM",
"rpc": [
"https://ferrum-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"http://testnet.dev.svcs.ferrumnetwork.io:9933"
],
"faucets": [
"https://testnet.faucet.ferrumnetwork.io"
],
"nativeCurrency": {
"name": "Ferrum",
"symbol": "tFRM",
"decimals": 18
},
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"infoURL": "https://ferrum.network",
"shortName": "frm",
"chainId": 26026,
"networkId": 26026,
"explorers": [
{
"name": "polkadotjs",
"url": "https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftestnet.dev.svcs.ferrumnetwork.io#/explorer",
"standard": "none"
}
],
"testnet": true,
"slug": "ferrum-testnet"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Zilliqa EVM",
"chain": "ZIL",
"rpc": [
"https://zilliqa-evm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.zilliqa.com"
],
"faucets": [],
"nativeCurrency": {
"name": "Zilliqa",
"symbol": "ZIL",
"decimals": 18
},
"infoURL": "https://www.zilliqa.com/",
"shortName": "zil",
"chainId": 32769,
"networkId": 32769,
"icon": {
"url": "ipfs://QmTREXNgGtUhSoxFsrkhTe5LUnDBTKL5byaX8kpET6UuKp",
"width": 2048,
"height": 2048,
"format": "png"
},
"explorers": [
{
"name": "Zilliqa EVM Explorer",
"url": "https://evmx.zilliqa.com",
"standard": "none"
}
],
"testnet": false,
"slug": "zilliqa-evm"
} as const satisfies Chain;
+30
View File
@@ -0,0 +1,30 @@
import type { Chain } from "../src/types";
export default {
"name": "Meld",
"title": "Meld Mainnet",
"chain": "MELD",
"rpc": [
"https://meld.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://network-rpc.meld.com"
],
"faucets": [],
"features": [],
"nativeCurrency": {
"name": "gMeld",
"symbol": "gMELD",
"decimals": 18
},
"icon": {
"url": "ipfs://QmRhB4AbjDrhvwfSAQi2JvKirFiDWxzJvKEvG8S8AdDdED",
"width": 4000,
"height": 4000,
"format": "png"
},
"infoURL": "https://meld.com",
"shortName": "meld",
"chainId": 333000333,
"networkId": 333000333,
"explorers": [],
"testnet": false,
"slug": "meld"
} as const satisfies Chain;
+4 -4
View File
@@ -29,10 +29,10 @@ export default {
"name": "Blockscout",
"url": "https://testnet-explorer.gather.network",
"icon": {
"url": "ipfs://QmeoEHUVYKSJFkM9o5j62rhQqCDN5iQxPC7PtzmH77rSWR",
"width": 512,
"height": 512,
"format": "png"
"url": "ipfs://QmTYR8CeFiNbJ1zJHnE3DK2wEN18r2y2vqSKUcLweUT2Gz",
"width": 1080,
"height": 1080,
"format": "svg"
},
"standard": "none"
}
+2 -1
View File
@@ -6,7 +6,8 @@ export default {
"https://xinfin-xdc-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://erpc.xinfin.network",
"https://rpc.xinfin.network",
"https://rpc1.xinfin.network"
"https://rpc1.xinfin.network",
"https://rpc-xdc.icecreamswap.com"
],
"faucets": [],
"nativeCurrency": {
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "SatoshiChain Testnet",
"chain": "SATS",
"icon": {
"url": "ipfs://QmRegpZQBW4o1imYNsW3d27MQjygBSU23Gf6JKje26nvs7",
"width": 1251,
"height": 1251,
"format": "png"
},
"rpc": [
"https://satoshichain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.satoshichain.io"
],
"faucets": [
"https://faucet.satoshichain.io"
],
"nativeCurrency": {
"name": "SatoshiChain Coin",
"symbol": "SATS",
"decimals": 18
},
"infoURL": "https://satoshichain.net",
"shortName": "sats",
"chainId": 5758,
"networkId": 5758,
"explorers": [
{
"name": "SatoshiChain Explorer",
"url": "https://satoshiscan.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "satoshichain-testnet"
} as const satisfies Chain;
-28
View File
@@ -1,28 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "EOS Mainnet",
"chain": "EOS",
"rpc": [
"https://eos.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.eosargentina.io"
],
"faucets": [],
"nativeCurrency": {
"name": "EOS",
"symbol": "EOS",
"decimals": 18
},
"infoURL": "https://eoscommunity.org/",
"shortName": "EOSMainnet",
"chainId": 59,
"networkId": 59,
"explorers": [
{
"name": "bloks",
"url": "https://bloks.eosargentina.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "eos"
} as const satisfies Chain;
+13 -10
View File
@@ -1,17 +1,20 @@
import type { Chain } from "../src/types";
export default {
"name": "Linea Testnet",
"title": "Linea Testnet",
"title": "Linea Goerli Testnet",
"chain": "ETH",
"rpc": [
"https://linea-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.goerli.linea.build"
"https://rpc.goerli.linea.build",
"wss://rpc.goerli.linea.build",
"https://consensys-zkevm-goerli-prealpha.infura.io/v3/${INFURA_API_KEY}",
"wss://consensys-zkevm-goerli-prealpha.infura.io/v3/${INFURA_API_KEY}"
],
"faucets": [
"https://faucetlink.to/goerli"
],
"nativeCurrency": {
"name": "Goerli Ether",
"name": "Linea Ether",
"symbol": "ETH",
"decimals": 18
},
@@ -20,9 +23,9 @@ export default {
"chainId": 59140,
"networkId": 59140,
"icon": {
"url": "ipfs://QmP6rcphqMTeByPxomeYeR5XRPZaFpwGbZxHkGQKyao4Le",
"width": 115,
"height": 115,
"url": "ipfs://QmURjritnHL7a8TwZgsFwp3f272DJmG5paaPtWDZ98QZwH",
"width": 97,
"height": 102,
"format": "svg"
},
"parent": {
@@ -36,13 +39,13 @@ export default {
},
"explorers": [
{
"name": "Linea Testnet Explorer",
"name": "blockscout",
"url": "https://explorer.goerli.linea.build",
"standard": "EIP3091",
"icon": {
"url": "ipfs://QmP6rcphqMTeByPxomeYeR5XRPZaFpwGbZxHkGQKyao4Le",
"width": 115,
"height": 115,
"url": "ipfs://QmURjritnHL7a8TwZgsFwp3f272DJmG5paaPtWDZ98QZwH",
"width": 97,
"height": 102,
"format": "svg"
}
}
+22
View File
@@ -0,0 +1,22 @@
import type { Chain } from "../src/types";
export default {
"name": "Peerpay",
"chain": "P2P",
"rpc": [
"https://peerpay.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://peerpay.su.gy/p2p"
],
"faucets": [],
"nativeCurrency": {
"name": "Peerpay",
"symbol": "P2P",
"decimals": 18
},
"infoURL": "https://peerpay.su.gy",
"shortName": "Peerpay",
"chainId": 6502,
"networkId": 6502,
"explorers": [],
"testnet": false,
"slug": "peerpay"
} as const satisfies Chain;
+5 -5
View File
@@ -1,6 +1,6 @@
import type { Chain } from "../src/types";
export default {
"name": "ADIL Mainnet",
"name": "Adil Chain V2 Mainnet",
"chain": "ADIL",
"icon": {
"url": "ipfs://QmeHNYUx6n8CjUFSLWNT17oAtDYrUq6r8buyvGCUBXCJw6",
@@ -9,8 +9,8 @@ export default {
"format": "png"
},
"rpc": [
"https://adil.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://s2.adilchain-rpc.io"
"https://adil-chain-v2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://adilchain-rpc.io"
],
"faucets": [],
"nativeCurrency": {
@@ -25,10 +25,10 @@ export default {
"explorers": [
{
"name": "ADIL Mainnet Explorer",
"url": "https://s2.adilchain-scan.io",
"url": "https://adilchain-scan.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "adil"
"slug": "adil-chain-v2"
} as const satisfies Chain;
+1 -1
View File
@@ -21,7 +21,7 @@ export default {
{
"name": "rootnet",
"url": "https://explorer.rootnet.live",
"standard": "none"
"standard": "EIP3091"
}
],
"testnet": false,
+1 -1
View File
@@ -21,7 +21,7 @@ export default {
{
"name": "rootnet",
"url": "https://explorer.rootnet.cloud",
"standard": "none"
"standard": "EIP3091"
}
],
"testnet": true,
-24
View File
@@ -1,24 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "PulseChain Testnet",
"shortName": "tpls",
"chain": "tPLS",
"chainId": 940,
"networkId": 940,
"infoURL": "https://pulsechain.com/",
"rpc": [
"https://pulsechain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.v2.testnet.pulsechain.com/",
"wss://rpc.v2.testnet.pulsechain.com/"
],
"faucets": [
"https://faucet.v2.testnet.pulsechain.com/"
],
"nativeCurrency": {
"name": "Test Pulse",
"symbol": "tPLS",
"decimals": 18
},
"testnet": true,
"slug": "pulsechain-testnet"
} as const satisfies Chain;
-24
View File
@@ -1,24 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "PulseChain Testnet v2b",
"shortName": "t2bpls",
"chain": "t2bPLS",
"chainId": 941,
"networkId": 941,
"infoURL": "https://pulsechain.com/",
"rpc": [
"https://pulsechain-testnet-v2b.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.v2b.testnet.pulsechain.com/",
"wss://rpc.v2b.testnet.pulsechain.com/"
],
"faucets": [
"https://faucet.v2b.testnet.pulsechain.com/"
],
"nativeCurrency": {
"name": "Test Pulse",
"symbol": "tPLS",
"decimals": 18
},
"testnet": true,
"slug": "pulsechain-testnet-v2b"
} as const satisfies Chain;
-28
View File
@@ -1,28 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "CryptoKylin Testnet",
"chain": "EOS",
"rpc": [
"https://cryptokylin-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://kylin.eosargentina.io"
],
"faucets": [],
"nativeCurrency": {
"name": "EOS",
"symbol": "EOS",
"decimals": 18
},
"infoURL": "https://www.cryptokylin.io/",
"shortName": "KylinTestnet",
"chainId": 95,
"networkId": 95,
"explorers": [
{
"name": "eosq",
"url": "https://kylin.eosargentina.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "cryptokylin-testnet"
} as const satisfies Chain;
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Six Protocol",
"chain": "SIXNET",
"icon": {
"url": "ipfs://QmP93z696v8Hetu13peY2oEHDXq8Bj5CqaDRwpVkpnM15A",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://six-protocol.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://sixnet-rpc-evm.sixprotocol.net"
],
"faucets": [],
"nativeCurrency": {
"name": "SIX evm token",
"symbol": "SIX",
"decimals": 18
},
"infoURL": "https://six.network/",
"shortName": "six",
"chainId": 98,
"networkId": 98,
"explorers": [
{
"name": "SIX Scan",
"url": "https://sixscan.io/sixnet",
"standard": "none",
"icon": {
"url": "ipfs://QmP93z696v8Hetu13peY2oEHDXq8Bj5CqaDRwpVkpnM15A",
"width": 512,
"height": 512,
"format": "png"
}
}
],
"testnet": false,
"slug": "six-protocol"
} as const satisfies Chain;
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "5ireChain Thunder",
"chain": "5ireChain",
"rpc": [
"https://5irechain-thunder.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-testnet.5ire.network"
],
"faucets": [
"https://explorer.5ire.network/faucet"
],
"nativeCurrency": {
"name": "5ire Token",
"symbol": "5ire",
"decimals": 18
},
"infoURL": "https://5ire.org",
"shortName": "5ire",
"chainId": 997,
"networkId": 997,
"icon": {
"url": "ipfs://QmaZDNDFLWESH4i3XqwEWfWBb1HPnQSNbDAr74nr2x8QAk",
"width": 800,
"height": 800,
"format": "svg"
},
"explorers": [
{
"name": "5ireChain Explorer",
"url": "https://explorer.5ire.network",
"standard": "none",
"icon": {
"url": "ipfs://QmaZDNDFLWESH4i3XqwEWfWBb1HPnQSNbDAr74nr2x8QAk",
"width": 800,
"height": 800,
"format": "svg"
}
}
],
"testnet": true,
"slug": "5irechain-thunder"
} as const satisfies Chain;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.12",
"version": "0.1.13",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
+2642 -1682
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -1,5 +1,14 @@
# thirdweb
## 0.10.13
### Patch Changes
- Updated dependencies [[`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`bf6df267`](https://github.com/thirdweb-dev/js/commit/bf6df2671131d7ed38650e2bed806081b32dc244), [`8f962bc1`](https://github.com/thirdweb-dev/js/commit/8f962bc15c35da52ed5bc4025bb4cd18b69079e3), [`28b5d1eb`](https://github.com/thirdweb-dev/js/commit/28b5d1eb6d0142d3ebefb8bd078c30949f77fe61), [`0bf29745`](https://github.com/thirdweb-dev/js/commit/0bf29745b0e842763c271ad8773312f0836ea00f), [`f0279c22`](https://github.com/thirdweb-dev/js/commit/f0279c228829b86ff1f828219bcef4fe16901f67), [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa), [`00d0d01e`](https://github.com/thirdweb-dev/js/commit/00d0d01e619ff5c60b9f31386f51a55b5e466efa), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a)]:
- @thirdweb-dev/chains@0.1.13
- @thirdweb-dev/sdk@3.10.12
- @thirdweb-dev/storage@1.1.2
## 0.10.12
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.10.12",
"version": "0.10.13",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/contracts-js
## 1.3.4
### Patch Changes
- [#959](https://github.com/thirdweb-dev/js/pull/959) [`00d0d01e`](https://github.com/thirdweb-dev/js/commit/00d0d01e619ff5c60b9f31386f51a55b5e466efa) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update contracts package to 3.4.6
## 1.3.3
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.3.3",
"version": "1.3.4",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"browser": {
@@ -10,7 +10,7 @@
"license": "Apache-2.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
"dependencies": {
"@thirdweb-dev/contracts": "3.4.6-1"
"@thirdweb-dev/contracts": "3.4.7-0"
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
+20
View File
@@ -1,5 +1,25 @@
# @thirdweb-dev/react-core
## 3.11.9
### Patch Changes
- [#937](https://github.com/thirdweb-dev/js/pull/937) [`7012513b`](https://github.com/thirdweb-dev/js/commit/7012513bc20f283b2cde46c0b938af33fe3a1a20) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adding Smart Wallet to React Native as an option in the ConnectWallet button
- [#941](https://github.com/thirdweb-dev/js/pull/941) [`5d67b280`](https://github.com/thirdweb-dev/js/commit/5d67b2807f2504add4c202d2eb18897415662fb6) Thanks [@MananTank](https://github.com/MananTank)! - Add Magic Link
- [#787](https://github.com/thirdweb-dev/js/pull/787) [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adds Device Wallet
- [#955](https://github.com/thirdweb-dev/js/pull/955) [`c7c2530c`](https://github.com/thirdweb-dev/js/commit/c7c2530c7f2ef412f1e40428391e85decf504392) Thanks [@MananTank](https://github.com/MananTank)! - Local wallet UI refactor and other fixes
- [#927](https://github.com/thirdweb-dev/js/pull/927) [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa) Thanks [@MananTank](https://github.com/MananTank)! - safe, deviceWallet and smartWallet autoconnect
- Updated dependencies [[`7012513b`](https://github.com/thirdweb-dev/js/commit/7012513bc20f283b2cde46c0b938af33fe3a1a20), [`5d67b280`](https://github.com/thirdweb-dev/js/commit/5d67b2807f2504add4c202d2eb18897415662fb6), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`5a67d5d8`](https://github.com/thirdweb-dev/js/commit/5a67d5d89474eac9a638ffaddba139b62965deff), [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f), [`c7c2530c`](https://github.com/thirdweb-dev/js/commit/c7c2530c7f2ef412f1e40428391e85decf504392), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`bf6df267`](https://github.com/thirdweb-dev/js/commit/bf6df2671131d7ed38650e2bed806081b32dc244), [`e22e4a47`](https://github.com/thirdweb-dev/js/commit/e22e4a47d73e1bbc6e3f0ae7ed56717b44e5ffcd), [`1e4ac672`](https://github.com/thirdweb-dev/js/commit/1e4ac672720c2fb01046bec195877a074ffbda06), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a), [`4a69f8c8`](https://github.com/thirdweb-dev/js/commit/4a69f8c85dec420615e9eda8d1ad5b5ef0b87713), [`26cd91ff`](https://github.com/thirdweb-dev/js/commit/26cd91ffe18dad37133a18988f21185c13d64cfb), [`8f962bc1`](https://github.com/thirdweb-dev/js/commit/8f962bc15c35da52ed5bc4025bb4cd18b69079e3), [`28b5d1eb`](https://github.com/thirdweb-dev/js/commit/28b5d1eb6d0142d3ebefb8bd078c30949f77fe61), [`0186721b`](https://github.com/thirdweb-dev/js/commit/0186721bc455aa1f8454839a1a25fa4062b45102), [`0bf29745`](https://github.com/thirdweb-dev/js/commit/0bf29745b0e842763c271ad8773312f0836ea00f), [`f0279c22`](https://github.com/thirdweb-dev/js/commit/f0279c228829b86ff1f828219bcef4fe16901f67), [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa), [`7af99d9a`](https://github.com/thirdweb-dev/js/commit/7af99d9a6d54492a29a90288a25b30773a8a10a7), [`00d0d01e`](https://github.com/thirdweb-dev/js/commit/00d0d01e619ff5c60b9f31386f51a55b5e466efa), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a), [`8cfb4f38`](https://github.com/thirdweb-dev/js/commit/8cfb4f38ed89c26ad04f19d27c65c24cefa976b6)]:
- @thirdweb-dev/wallets@0.2.17
- @thirdweb-dev/chains@0.1.13
- @thirdweb-dev/sdk@3.10.12
- @thirdweb-dev/storage@1.1.2
## 3.11.8
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.11.8",
"version": "3.11.9",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -3,7 +3,7 @@ import { useCallback, useState } from "react";
import { useActiveChain, useChainId } from "../../evm/hooks/wallet";
import { useSupportedChains } from "../../evm/hooks/useSupportedChains";
import { useSwitchChain, useWallet } from "./wallet-hooks";
import { assertWindowEthereum } from "@thirdweb-dev/wallets";
import { assertWindowEthereum, walletIds } from "@thirdweb-dev/wallets";
// this hook is only for backwards compatibility
@@ -72,10 +72,10 @@ export function useNetwork(): [NetworkMetadata, SwitchNetwork | undefined] {
// switch not supported if connected to a mobile wallet
const switchChainNotSupported =
!wallet ||
wallet.walletId === "walletConnectV1" ||
wallet.walletId === "walletConnect" ||
(wallet.walletId === "metamask" && !isMetamaskInstalled) ||
(wallet.walletId === "coinbaseWallet" && !isCoinbaseInstalled);
wallet.walletId === walletIds.walletConnectV1 ||
wallet.walletId === walletIds.walletConnect ||
(wallet.walletId === walletIds.metamask && !isMetamaskInstalled) ||
(wallet.walletId === walletIds.coinbase && !isCoinbaseInstalled);
// error when switching network
const [error, setError] = useState<Error | undefined>(undefined);
@@ -72,6 +72,23 @@ export function useConnectionStatus() {
return context.connectionStatus;
}
/**
*
* @returns if the wallet is currently connecting
*
*/
export function useIsConnecting() {
const context = useThirdwebWallet();
invariant(
context,
"useConnectionStatus() must be used within a <ThirdwebProvider/>",
);
return (
context.connectionStatus === "connecting" ||
context.connectionStatus === "unknown"
);
}
/**
*
* @returns a method to create an instance of given wallet class
@@ -69,7 +69,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
}: React.PropsWithChildren<ThirdwebProviderCoreProps<TChains>>) => {
const { activeChain } = props;
const supportedChainsNonNull = useMemo(() => {
const supportedChainsNonNull: Chain[] = useMemo(() => {
const isActiveChainObject =
typeof activeChain === "object" && activeChain !== null;
@@ -107,14 +107,27 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
const activeChainWithKey = useMemo(() => {
if (typeof activeChainIdOrObjWithKey === "number") {
return supportedChainsWithKey.find(
const resolveChain = supportedChainsWithKey.find(
(chain) => chain.chainId === activeChainIdOrObjWithKey,
);
if (!resolveChain) {
throw new Error(
`Invalid chainId: ${activeChainIdOrObjWithKey}. It is not one of supportedChains`,
);
}
return resolveChain;
}
if (typeof activeChainIdOrObjWithKey === "string") {
return supportedChainsWithKey.find(
const resolvedChain = supportedChainsWithKey.find(
(chain) => chain.slug === activeChainIdOrObjWithKey,
);
if (!resolvedChain) {
throw new Error(
`Invalid chain: "${activeChainIdOrObjWithKey}". It is not one of supportedChains`,
);
}
return resolvedChain;
}
return activeChainIdOrObjWithKey;
@@ -3,6 +3,7 @@ import type { Wallet, WalletInstance } from "../types/wallet";
import { ThirdwebThemeContext } from "./theme-context";
import { Chain } from "@thirdweb-dev/chains";
import {
AbstractClientWallet,
AsyncStorage,
ConnectParams,
CreateAsyncStorage,
@@ -20,7 +21,18 @@ import {
} from "react";
const LAST_CONNECTED_WALLET_STORAGE_KEY = "lastConnectedWallet";
let coordinatorStorage: AsyncStorage;
let lastConnectedWalletStorage: AsyncStorage;
type LastConnectedWalletInfo = {
walletId: string;
connectParams?: ConnectParams & {
personalWallet?: {
walletId: string;
connectParams?: ConnectParams;
};
};
};
type NonNullable<T> = T extends null | undefined ? never : T;
type WalletConnectParams<I extends WalletInstance> = Parameters<
@@ -50,7 +62,7 @@ type ThirdwebWalletContextData = {
createWalletStorage: CreateAsyncStorage;
switchChain: (chain: number) => Promise<void>;
chainToConnect?: Chain;
activeChain?: Chain;
activeChain: Chain;
handleWalletConnect: (
wallet: WalletInstance,
params?: ConnectParams<Record<string, any>>,
@@ -63,7 +75,7 @@ const ThirdwebWalletContext = createContext<
export function ThirdwebWalletProvider(
props: PropsWithChildren<{
activeChain?: Chain;
activeChain: Chain;
supportedWallets: Wallet[];
shouldAutoConnect?: boolean;
createWalletStorage: CreateAsyncStorage;
@@ -80,8 +92,9 @@ export function ThirdwebWalletProvider(
WalletInstance | undefined
>();
if (!coordinatorStorage) {
coordinatorStorage = props.createWalletStorage("coordinatorStorage");
if (!lastConnectedWalletStorage) {
lastConnectedWalletStorage =
props.createWalletStorage("coordinatorStorage");
}
// if autoSwitch is enabled - enforce connection to activeChain
@@ -120,33 +133,47 @@ export function ThirdwebWalletProvider(
const handleWalletConnect = useCallback(
async (
wallet: WalletInstance,
params?: ConnectParams<Record<string, any>>,
connectParams?: ConnectParams<Record<string, any>>,
isAutoConnect = false,
) => {
const connectParams = params || walletParams;
const lastConnectedWallet = {
walletId: wallet.walletId,
connectParams,
};
try {
await coordinatorStorage.setItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
JSON.stringify(lastConnectedWallet),
);
} catch (e) {
console.error(e);
}
const _signer = await wallet.getSigner();
setSigner(_signer);
setActiveWallet(wallet);
setConnectionStatus("connected");
// it autoconnected, then the details is already saved in storage, no need to store again
if (isAutoConnect) {
return;
}
// save to storage
const walletInfo: LastConnectedWalletInfo = {
walletId: wallet.walletId,
connectParams,
};
// if personal wallet exists, we need to replace the connectParams.personalWallet to a stringifiable version
const personalWallet = wallet.getPersonalWallet() as AbstractClientWallet;
if (personalWallet) {
walletInfo.connectParams = {
...walletInfo.connectParams,
personalWallet: {
walletId: personalWallet.walletId,
connectParams: personalWallet.getConnectParams(),
},
};
saveLastConnectedWalletInfo(walletInfo);
} else {
saveLastConnectedWalletInfo(walletInfo);
}
},
[walletParams],
[],
);
const storeLastActiveChainId = useCallback(async (chainId: number) => {
const lastConnectedWallet = await coordinatorStorage.getItem(
const lastConnectedWallet = await lastConnectedWalletStorage.getItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
);
@@ -157,7 +184,7 @@ export function ThirdwebWalletProvider(
try {
const parsedWallet = JSON.parse(lastConnectedWallet as string);
parsedWallet.connectParams.chainId = chainId;
await coordinatorStorage.setItem(
await lastConnectedWalletStorage.setItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
JSON.stringify(parsedWallet),
);
@@ -206,52 +233,83 @@ export function ThirdwebWalletProvider(
}
autoConnectTriggered.current = true;
(async () => {
const lastConnectedWalletInfo = await coordinatorStorage.getItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
async function autoconnect() {
const walletInfo = await getLastConnectedWalletInfo();
if (!walletInfo) {
setConnectionStatus("disconnected");
return;
}
const walletObj = props.supportedWallets.find(
(W) => W.id === walletInfo.walletId,
);
if (!lastConnectedWalletInfo) {
if (!walletObj) {
// last connected wallet is no longer present in the supported wallets
setConnectionStatus("disconnected");
return;
}
let parsedParams: ConnectParams<Record<string, any>> | undefined;
let lastConnectedWalletId: string | undefined;
const personalWalletInfo = walletInfo.connectParams?.personalWallet;
try {
const parsedWallet = JSON.parse(lastConnectedWalletInfo as string);
parsedParams = parsedWallet.connectParams;
lastConnectedWalletId = parsedWallet.walletId;
} catch (error) {
console.error(`Error parsing the last connected wallet: ${error}`);
if (personalWalletInfo) {
type Config = {
personalWallets: Wallet[];
};
const personalWallets =
"config" in walletObj
? (walletObj.config as Config).personalWallets
: [];
const personalWalleObj = personalWallets.find(
(W) => W.id === personalWalletInfo.walletId,
);
if (personalWalleObj) {
// create a personal wallet instance and auto connect it
const personalWalletInstance = createWalletInstance(personalWalleObj);
try {
await personalWalletInstance.autoConnect(
personalWalletInfo.connectParams,
);
} catch (e) {
console.error(e);
setConnectionStatus("disconnected");
return;
}
// set the personal wallet instance to the connectParams
walletInfo.connectParams = {
...walletInfo.connectParams,
personalWallet: personalWalletInstance,
};
} else {
// last used personal wallet is no longer present in the supported wallets
setConnectionStatus("disconnected");
return;
}
}
if (!lastConnectedWalletId) {
setConnectionStatus("disconnected");
return;
}
// create a wallet instance and auto connect it
const wallet = createWalletInstance(walletObj);
let lastConnectedWallet = props.supportedWallets.find(
(W) => W.id === lastConnectedWalletId,
);
if (!lastConnectedWallet) {
setConnectionStatus("disconnected");
return;
}
const wallet = createWalletInstance(lastConnectedWallet);
try {
setConnectionStatus("connecting");
await wallet.autoConnect(parsedParams);
handleWalletConnect(wallet, parsedParams);
await wallet.autoConnect(walletInfo.connectParams);
handleWalletConnect(wallet, walletInfo.connectParams, true);
} catch (e) {
coordinatorStorage.removeItem(LAST_CONNECTED_WALLET_STORAGE_KEY);
lastConnectedWalletStorage.removeItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
);
setConnectionStatus("disconnected");
throw e;
}
})();
}
autoconnect();
}, [
createWalletInstance,
props.supportedWallets,
@@ -285,7 +343,9 @@ export function ThirdwebWalletProvider(
);
const onWalletDisconnect = useCallback(async () => {
await coordinatorStorage.removeItem(LAST_CONNECTED_WALLET_STORAGE_KEY);
await lastConnectedWalletStorage.removeItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
);
setConnectionStatus("disconnected");
setSigner(undefined);
setActiveWallet(undefined);
@@ -299,6 +359,12 @@ export function ThirdwebWalletProvider(
}
await activeWallet.disconnect();
if (activeWallet.getPersonalWallet()) {
await (
activeWallet.getPersonalWallet() as AbstractClientWallet
)?.disconnect();
}
onWalletDisconnect();
}, [activeWallet, onWalletDisconnect]);
@@ -351,5 +417,35 @@ export function ThirdwebWalletProvider(
}
export function useThirdwebWallet() {
return useContext(ThirdwebWalletContext);
const ctx = useContext(ThirdwebWalletContext);
if (!ctx) {
throw new Error(
`useThirdwebWallet() can only be used inside <ThirdwebProvider />`,
);
}
return ctx;
}
async function getLastConnectedWalletInfo() {
const str = await lastConnectedWalletStorage.getItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
);
if (!str) {
return null;
}
return JSON.parse(str) as LastConnectedWalletInfo;
}
async function saveLastConnectedWalletInfo(
walletInfo: LastConnectedWalletInfo,
) {
try {
await lastConnectedWalletStorage.setItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
JSON.stringify(walletInfo),
);
} catch (e) {
console.error("Error saving the last connected wallet info", e);
}
}
+9 -2
View File
@@ -23,8 +23,15 @@ export type WalletClass<I extends WalletInstance = WalletInstance> = {
meta: (typeof AbstractClientWallet)["meta"];
};
export type Wallet<I extends WalletInstance = WalletInstance> = {
export type Wallet<
I extends WalletInstance = WalletInstance,
Config extends Record<string, any> | undefined = undefined,
> = {
id: string;
meta: (typeof AbstractClientWallet)["meta"];
create: (options: WalletOptions) => I;
};
} & (Config extends undefined
? {}
: {
config: Config;
});
@@ -1,4 +1,4 @@
import { useThirdwebWallet } from "@thirdweb-dev/react-core";
import { useThirdwebWallet } from "../../core/providers/thirdweb-wallet-provider";
export function useSupportedWallet(id: string) {
const context = useThirdwebWallet();
+2
View File
@@ -16,6 +16,7 @@ export {
useDisconnect,
useSwitchChain,
useWallets,
useIsConnecting,
} from "../core/hooks/wallet-hooks";
export { useNetwork } from "../core/hooks/useNetwork";
export { useThirdwebWallet } from "../core/providers/thirdweb-wallet-provider";
@@ -214,6 +215,7 @@ export { useNetworkMismatch } from "./hooks/useNetworkMismatch";
export { useReadonlySDK } from "./hooks/useReadonlySDK";
export { useSigner } from "./hooks/useSigner";
export { useSupportedChains } from "./hooks/useSupportedChains";
export { useSupportedWallet } from "./hooks/useSupportedWallet";
export { useAppURI, useSetAppURI } from "./hooks/async/app";
// sdk provider
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.2.9
## 0.2.8
## 0.2.7
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.8",
"version": "0.2.9",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+44
View File
@@ -1,5 +1,49 @@
# @thirdweb-dev/react-native
## 0.2.9
### Patch Changes
- [#935](https://github.com/thirdweb-dev/js/pull/935) [`45d2ffcf`](https://github.com/thirdweb-dev/js/commit/45d2ffcf8917ac42b9913844ad111b6a7cacff23) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Allow guest mode to be directly connected when no supported wallets are passed in
When passing an empty `supportedWallets` array and setting `guestMode` to true:
```
<ThirdwebProvider
activeChain={activeChain}
supportedChains={[activeChain]}
guestMode={true}
supportedWallets={[]}
```
Pressing on the ConnectWallet button will automatically create a `LocalWallet` for you and connect the user without any further prompts
- [#937](https://github.com/thirdweb-dev/js/pull/937) [`7012513b`](https://github.com/thirdweb-dev/js/commit/7012513bc20f283b2cde46c0b938af33fe3a1a20) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adding Smart Wallet to React Native as an option in the ConnectWallet button
- [#787](https://github.com/thirdweb-dev/js/pull/787) [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adds Device Wallet
- [#955](https://github.com/thirdweb-dev/js/pull/955) [`c7c2530c`](https://github.com/thirdweb-dev/js/commit/c7c2530c7f2ef412f1e40428391e85decf504392) Thanks [@MananTank](https://github.com/MananTank)! - Local wallet UI refactor and other fixes
- [#956](https://github.com/thirdweb-dev/js/pull/956) [`4a69f8c8`](https://github.com/thirdweb-dev/js/commit/4a69f8c85dec420615e9eda8d1ad5b5ef0b87713) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Allow switching between personal wallet and smart wallet
- Updates SmartWallet and LocalWallet icons
- Adds "Learn More" links to both new wallets
- [#936](https://github.com/thirdweb-dev/js/pull/936) [`4828c876`](https://github.com/thirdweb-dev/js/commit/4828c8769180f821b482d38a63870e7c8ae454e0) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Enable copying the address by pressing on it
- [#943](https://github.com/thirdweb-dev/js/pull/943) [`465d8e2c`](https://github.com/thirdweb-dev/js/commit/465d8e2c3d77984af9031d707bfafc3121d7bd15) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Enforce web3button action to return a promise to make sure onSuccess and onError are triggered correctly
- [#927](https://github.com/thirdweb-dev/js/pull/927) [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa) Thanks [@MananTank](https://github.com/MananTank)! - safe, deviceWallet and smartWallet autoconnect
- [#925](https://github.com/thirdweb-dev/js/pull/925) [`07194b06`](https://github.com/thirdweb-dev/js/commit/07194b06e542826334f404df3891c071966a4dfb) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Directly call connect when there's only one supported wallet defined in the provider
- Updated dependencies [[`7012513b`](https://github.com/thirdweb-dev/js/commit/7012513bc20f283b2cde46c0b938af33fe3a1a20), [`5d67b280`](https://github.com/thirdweb-dev/js/commit/5d67b2807f2504add4c202d2eb18897415662fb6), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`5a67d5d8`](https://github.com/thirdweb-dev/js/commit/5a67d5d89474eac9a638ffaddba139b62965deff), [`d2c7f6d7`](https://github.com/thirdweb-dev/js/commit/d2c7f6d758787fab102ecc0cec16ac74f3c87a1f), [`c7c2530c`](https://github.com/thirdweb-dev/js/commit/c7c2530c7f2ef412f1e40428391e85decf504392), [`f12a80a4`](https://github.com/thirdweb-dev/js/commit/f12a80a4758aa91c43084acedb212de9f36a7371), [`bf6df267`](https://github.com/thirdweb-dev/js/commit/bf6df2671131d7ed38650e2bed806081b32dc244), [`e22e4a47`](https://github.com/thirdweb-dev/js/commit/e22e4a47d73e1bbc6e3f0ae7ed56717b44e5ffcd), [`1e4ac672`](https://github.com/thirdweb-dev/js/commit/1e4ac672720c2fb01046bec195877a074ffbda06), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a), [`4a69f8c8`](https://github.com/thirdweb-dev/js/commit/4a69f8c85dec420615e9eda8d1ad5b5ef0b87713), [`26cd91ff`](https://github.com/thirdweb-dev/js/commit/26cd91ffe18dad37133a18988f21185c13d64cfb), [`8f962bc1`](https://github.com/thirdweb-dev/js/commit/8f962bc15c35da52ed5bc4025bb4cd18b69079e3), [`28b5d1eb`](https://github.com/thirdweb-dev/js/commit/28b5d1eb6d0142d3ebefb8bd078c30949f77fe61), [`0186721b`](https://github.com/thirdweb-dev/js/commit/0186721bc455aa1f8454839a1a25fa4062b45102), [`0bf29745`](https://github.com/thirdweb-dev/js/commit/0bf29745b0e842763c271ad8773312f0836ea00f), [`f0279c22`](https://github.com/thirdweb-dev/js/commit/f0279c228829b86ff1f828219bcef4fe16901f67), [`1e9fad77`](https://github.com/thirdweb-dev/js/commit/1e9fad779f3ebe535d32c0ce76905a3a8033f2fa), [`7af99d9a`](https://github.com/thirdweb-dev/js/commit/7af99d9a6d54492a29a90288a25b30773a8a10a7), [`00d0d01e`](https://github.com/thirdweb-dev/js/commit/00d0d01e619ff5c60b9f31386f51a55b5e466efa), [`fc96e147`](https://github.com/thirdweb-dev/js/commit/fc96e14750175b19cb66fa7d50cdbad65b42153a), [`8cfb4f38`](https://github.com/thirdweb-dev/js/commit/8cfb4f38ed89c26ad04f19d27c65c24cefa976b6)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.8
### Patch Changes
+6 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.8",
"version": "0.2.9",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -33,6 +33,9 @@
"@thirdweb-dev/storage": "workspace:*",
"@thirdweb-dev/wallets": "workspace:*",
"abitype": "^0.2.5",
"expo-clipboard": "^4.1.2",
"expo-document-picker": "^11.2.2",
"expo-file-system": "^15.2.2",
"expo-secure-store": "^12.1.1",
"react-native-mmkv": "2.5.1",
"react-native-modal": "^13.0.1",
@@ -51,8 +54,8 @@
"@types/jest": "^29.2.1",
"@types/react": "^18.0.5",
"@types/react-native": "^0.71.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"babel-jest": "^29.2.1",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.3.0",
-17
View File
@@ -1,17 +0,0 @@
const warnSet = new Set<`${string}:${string}`>();
export function showDeprecationWarning(
deprecated: string,
replacement: string,
) {
// deprecation warnings only in dev only in dev
if (__DEV__) {
if (warnSet.has(`${deprecated}:${replacement}`)) {
return;
}
warnSet.add(`${deprecated}:${replacement}`);
console.warn(
`\`${deprecated}\` is deprecated and will be removed in a future major version. Please use \`${replacement}\` instead.`,
);
}
}
@@ -1,9 +1,9 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const BackIcon = ({ size, color }: IconStyleProp) => {
const BackIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={size} height={size} viewBox="0 0 12 20" fill="none">
<Svg width={width} height={height} viewBox="0 0 12 20" fill="none">
<Path
d="M9.1248 19.1L0.699804 10.7C0.599804 10.6 0.529138 10.4917 0.487804 10.375C0.445804 10.2584 0.424805 10.1334 0.424805 10C0.424805 9.86669 0.445804 9.74169 0.487804 9.62502C0.529138 9.50836 0.599804 9.40002 0.699804 9.30002L9.1248 0.875024C9.35814 0.641691 9.6498 0.525024 9.9998 0.525024C10.3498 0.525024 10.6498 0.650024 10.8998 0.900024C11.1498 1.15002 11.2748 1.44169 11.2748 1.77502C11.2748 2.10836 11.1498 2.40002 10.8998 2.65002L3.5498 10L10.8998 17.35C11.1331 17.5834 11.2498 17.8707 11.2498 18.212C11.2498 18.554 11.1248 18.85 10.8748 19.1C10.6248 19.35 10.3331 19.475 9.9998 19.475C9.66647 19.475 9.3748 19.35 9.1248 19.1Z"
fill={color}
@@ -1,8 +1,9 @@
import Svg, { Path } from "react-native-svg";
import { IconStyleProp } from "./types";
const CloseIcon = ({ size }: { size: number }) => {
const CloseIcon = ({ width, height }: IconStyleProp) => {
return (
<Svg width={size} height={size} viewBox="0 0 14 14" fill="none">
<Svg width={width} height={height} viewBox="0 0 14 14" fill="none">
<Path
d="M13.3002 0.70998C13.2077 0.617276 13.0978 0.543728 12.9768 0.493547C12.8559 0.443366 12.7262 0.417535 12.5952 0.417535C12.4643 0.417535 12.3346 0.443366 12.2136 0.493547C12.0926 0.543728 11.9827 0.617276 11.8902 0.70998L7.00022 5.58998L2.11022 0.699979C2.01764 0.607397 1.90773 0.533957 1.78677 0.483852C1.6658 0.433747 1.53615 0.407959 1.40522 0.407959C1.27429 0.407959 1.14464 0.433747 1.02368 0.483852C0.902716 0.533957 0.792805 0.607397 0.700223 0.699979C0.607642 0.792561 0.534202 0.902472 0.484097 1.02344C0.433992 1.1444 0.408203 1.27405 0.408203 1.40498C0.408203 1.53591 0.433992 1.66556 0.484097 1.78652C0.534202 1.90749 0.607642 2.0174 0.700223 2.10998L5.59022 6.99998L0.700223 11.89C0.607642 11.9826 0.534202 12.0925 0.484097 12.2134C0.433992 12.3344 0.408203 12.464 0.408203 12.595C0.408203 12.7259 0.433992 12.8556 0.484097 12.9765C0.534202 13.0975 0.607642 13.2074 0.700223 13.3C0.792805 13.3926 0.902716 13.466 1.02368 13.5161C1.14464 13.5662 1.27429 13.592 1.40522 13.592C1.53615 13.592 1.6658 13.5662 1.78677 13.5161C1.90773 13.466 2.01764 13.3926 2.11022 13.3L7.00022 8.40998L11.8902 13.3C11.9828 13.3926 12.0927 13.466 12.2137 13.5161C12.3346 13.5662 12.4643 13.592 12.5952 13.592C12.7262 13.592 12.8558 13.5662 12.9768 13.5161C13.0977 13.466 13.2076 13.3926 13.3002 13.3C13.3928 13.2074 13.4662 13.0975 13.5163 12.9765C13.5665 12.8556 13.5922 12.7259 13.5922 12.595C13.5922 12.464 13.5665 12.3344 13.5163 12.2134C13.4662 12.0925 13.3928 11.9826 13.3002 11.89L8.41022 6.99998L13.3002 2.10998C13.6802 1.72998 13.6802 1.08998 13.3002 0.70998Z"
fill="#646D7A"
@@ -0,0 +1,22 @@
import { IconStyleProp } from "./types";
import Svg, { Path, Rect } from "react-native-svg";
const CopyIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg
width={width}
height={height}
viewBox="0 0 24 24"
fill="none"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<Rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
<Path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
</Svg>
);
};
export default CopyIcon;
@@ -1,9 +1,9 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const DisconnectIcon = ({ size, color }: IconStyleProp) => {
const DisconnectIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={size} height={size} viewBox="0 0 18 18" fill="none">
<Svg width={width} height={height} viewBox="0 0 18 18" fill="none">
<Path
d="M7.79 13.29C8.18 13.68 8.81 13.68 9.2 13.29L12.79 9.7C12.8827 9.60749 12.9563 9.4976 13.0064 9.37662C13.0566 9.25565 13.0824 9.12597 13.0824 8.995C13.0824 8.86403 13.0566 8.73435 13.0064 8.61338C12.9563 8.4924 12.8827 8.38251 12.79 8.29L9.2 4.7C9.01302 4.51302 8.75943 4.40798 8.495 4.40798C8.23057 4.40798 7.97698 4.51302 7.79 4.7C7.60302 4.88698 7.49798 5.14057 7.49798 5.405C7.49798 5.66943 7.60302 5.92302 7.79 6.11L9.67 8H1C0.45 8 0 8.45 0 9C0 9.55 0.45 10 1 10H9.67L7.79 11.88C7.4 12.27 7.41 12.91 7.79 13.29ZM16 0H2C1.46957 0 0.960859 0.210714 0.585786 0.585786C0.210714 0.960859 0 1.46957 0 2V5C0 5.55 0.45 6 1 6C1.55 6 2 5.55 2 5V3C2 2.45 2.45 2 3 2H15C15.55 2 16 2.45 16 3V15C16 15.55 15.55 16 15 16H3C2.45 16 2 15.55 2 15V13C2 12.45 1.55 12 1 12C0.45 12 0 12.45 0 13V16C0 17.1 0.9 18 2 18H16C17.1 18 18 17.1 18 16V2C18 0.9 17.1 0 16 0Z"
fill={color}
@@ -1,9 +1,9 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const DownArrowIcon = ({ size, color }: IconStyleProp) => {
const DownArrowIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={size} height={size} viewBox="0 0 12 7" fill="none">
<Svg width={width} height={height} viewBox="0 0 12 7" fill="none">
<Path
d="M6.00005 6.97505C5.86672 6.97505 5.73772 6.95005 5.61305 6.90005C5.48772 6.85005 5.38338 6.78338 5.30005 6.70005L0.700048 2.10005C0.516715 1.91672 0.425049 1.68338 0.425049 1.40005C0.425049 1.11671 0.516715 0.883382 0.700048 0.700048C0.883382 0.516715 1.11672 0.425049 1.40005 0.425049C1.68338 0.425049 1.91672 0.516715 2.10005 0.700048L6.00005 4.60005L9.90005 0.700048C10.0834 0.516715 10.3167 0.425049 10.6 0.425049C10.8834 0.425049 11.1167 0.516715 11.3 0.700048C11.4834 0.883382 11.575 1.11671 11.575 1.40005C11.575 1.68338 11.4834 1.91672 11.3 2.10005L6.70005 6.70005C6.60005 6.80005 6.49172 6.87072 6.37505 6.91205C6.25838 6.95405 6.13338 6.97505 6.00005 6.97505Z"
fill={color}
@@ -0,0 +1,15 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const EyeClosed = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 256 256" fill="none">
<Path
d="M234.42 162C235.208 163.369 235.719 164.879 235.923 166.445C236.127 168.01 236.021 169.601 235.611 171.126C235.2 172.651 234.494 174.08 233.531 175.331C232.568 176.583 231.368 177.632 230 178.42C228.632 179.208 227.121 179.719 225.556 179.923C223.99 180.128 222.399 180.022 220.875 179.611C219.35 179.201 217.921 178.494 216.669 177.531C215.418 176.569 214.368 175.369 213.58 174L196.72 144.5C187.312 150.419 177.169 155.078 166.55 158.36L171.84 190C172.36 193.139 171.613 196.356 169.762 198.944C167.911 201.532 165.108 203.279 161.97 203.8C161.31 203.917 160.64 203.974 159.97 203.97C157.136 203.968 154.395 202.962 152.232 201.132C150.068 199.301 148.622 196.765 148.15 193.97L143 163.17C133.011 164.277 122.929 164.277 112.94 163.17L107.84 194C107.367 196.798 105.918 199.337 103.751 201.168C101.583 202.999 98.8372 204.002 96 204C95.3296 204.004 94.6603 203.947 94 203.83C92.4457 203.569 90.9582 203.003 89.6224 202.167C88.2867 201.33 87.1288 200.238 86.2151 198.954C85.3013 197.67 84.6495 196.218 84.2969 194.682C83.9443 193.145 83.8978 191.555 84.16 190L89.45 158.28C78.8309 154.998 68.6879 150.339 59.28 144.42L42.42 174C41.6321 175.369 40.5823 176.569 39.3307 177.531C38.0791 178.494 36.6502 179.201 35.1254 179.611C33.6007 180.022 32.01 180.128 30.4443 179.923C28.8786 179.719 27.3684 179.208 26 178.42C24.6316 177.632 23.4319 176.583 22.4692 175.331C21.5065 174.08 20.7997 172.651 20.3893 171.126C19.9789 169.601 19.8728 168.01 20.0771 166.445C20.2814 164.879 20.7921 163.369 21.58 162L40 129.85C33.7569 124.212 27.9689 118.09 22.69 111.54C20.8264 109.055 19.9994 105.943 20.3828 102.861C20.7663 99.7779 22.3303 96.9639 24.746 95.0106C27.1617 93.0573 30.2408 92.117 33.3355 92.3874C36.4303 92.6578 39.2997 94.1178 41.34 96.4604C57.38 116.32 85.44 140 128 140C170.56 140 198.62 116.32 214.66 96.4604C216.667 94.0083 219.563 92.4497 222.715 92.1248C225.868 91.7999 229.021 92.7351 231.486 94.7264C233.951 96.7176 235.529 99.6031 235.874 102.753C236.22 105.903 235.305 109.062 233.33 111.54C228.045 118.091 222.25 124.213 216 129.85L234.42 162Z"
fill={color}
/>
</Svg>
);
};
export default EyeClosed;
@@ -0,0 +1,15 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const EyeOpened = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 22 16" fill="none">
<Path
d="M11 0.5C6 0.5 1.73 3.61 0 8C1.73 12.39 6 15.5 11 15.5C16 15.5 20.27 12.39 22 8C20.27 3.61 16 0.5 11 0.5ZM11 13C8.24 13 6 10.76 6 8C6 5.24 8.24 3 11 3C13.76 3 16 5.24 16 8C16 10.76 13.76 13 11 13ZM11 5C9.34 5 8 6.34 8 8C8 9.66 9.34 11 11 11C12.66 11 14 9.66 14 8C14 6.34 12.66 5 11 5Z"
fill={color}
/>
</Svg>
);
};
export default EyeOpened;
@@ -1,9 +1,9 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const RightArrowIcon = ({ size, color }: IconStyleProp) => {
const RightArrowIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={size} height={size} viewBox="0 0 5 8" fill="none">
<Svg width={width} height={height} viewBox="0 0 5 8" fill="none">
<Path
d="M4.98337 4.00001C4.98337 4.0889 4.9667 4.1749 4.93337 4.25801C4.90003 4.34156 4.85559 4.41112 4.80003 4.46667L1.73337 7.53334C1.61114 7.65556 1.45559 7.71667 1.2667 7.71667C1.07781 7.71667 0.922255 7.65556 0.800032 7.53334C0.67781 7.41112 0.616699 7.25556 0.616699 7.06667C0.616699 6.87779 0.67781 6.72223 0.800032 6.60001L3.40003 4.00001L0.800032 1.40001C0.67781 1.27779 0.616699 1.12223 0.616699 0.933341C0.616699 0.744452 0.67781 0.588897 0.800032 0.466675C0.922254 0.344453 1.07781 0.283341 1.2667 0.283341C1.45559 0.283341 1.61114 0.344453 1.73337 0.466675L4.80003 3.53334C4.8667 3.60001 4.91381 3.67223 4.94137 3.75001C4.96937 3.82779 4.98337 3.91112 4.98337 4.00001Z"
fill={color}
@@ -0,0 +1,19 @@
import { IconStyleProp } from "./types";
import Svg, { Circle, Path } from "react-native-svg";
const Step1Image = ({ width, height }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 189 24" fill="none">
<Path
d="M22 12C22 10.8954 22.8954 10 24 10H165C166.105 10 167 10.8954 167 12C167 13.1046 166.105 14 165 14H24C22.8954 14 22 13.1046 22 12Z"
fill="#2B3036"
/>
<Circle cx="177" cy="12" r="11" stroke="#2B3036" stroke-width="2" />
<Circle cx="177" cy="12" r="7" fill="#2B3036" />
<Circle cx="12" cy="12" r="11" stroke="#3385FF" stroke-width="2" />
<Circle cx="12" cy="12" r="7" fill="#3385FF" />
</Svg>
);
};
export default Step1Image;
@@ -0,0 +1,19 @@
import { IconStyleProp } from "./types";
import Svg, { Circle, Path } from "react-native-svg";
const Step2Image = ({ width, height }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 189 24" fill="none">
<Path
d="M22 12C22 10.8954 22.8954 10 24 10H165C166.105 10 167 10.8954 167 12C167 13.1046 166.105 14 165 14H24C22.8954 14 22 13.1046 22 12Z"
fill="#3385FF"
/>
<Circle cx="177" cy="12" r="11" stroke="#3385FF" stroke-width="2" />
<Circle cx="177" cy="12" r="7" fill="#3385FF" />
<Circle cx="12" cy="12" r="11" stroke="#3385FF" stroke-width="2" />
<Circle cx="12" cy="12" r="7" fill="#3385FF" />
</Svg>
);
};
export default Step2Image;
@@ -1,4 +1,5 @@
export type IconStyleProp = {
color: string;
size: number;
color?: string;
width: number;
height: number;
};
@@ -0,0 +1,31 @@
import Svg, { Path } from "react-native-svg";
const PocketWalletIcon = ({ size }: { size: number }) => {
return (
<Svg width={size} height={size} viewBox="0 0 16 16" fill="none">
<Path
d="M13.3337 7.99996V5.33329H4.00033C3.6467 5.33329 3.30756 5.19282 3.05752 4.94277C2.80747 4.69272 2.66699 4.35358 2.66699 3.99996C2.66699 3.26663 3.26699 2.66663 4.00033 2.66663H12.0003V5.33329"
stroke="#646D7A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M2.66699 4V12C2.66699 12.7333 3.26699 13.3333 4.00033 13.3333H13.3337V10.6667"
stroke="#646D7A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M12.0003 8C11.6467 8 11.3076 8.14048 11.0575 8.39052C10.8075 8.64057 10.667 8.97971 10.667 9.33333C10.667 10.0667 11.267 10.6667 12.0003 10.6667H14.667V8H12.0003Z"
stroke="#646D7A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
</Svg>
);
};
export default PocketWalletIcon;
@@ -2,6 +2,7 @@ import { NetworkSelectorModal } from "../NetworkSelector/NetworkSelectorModal";
import { Address } from "../base/Address";
import BaseButton from "../base/BaseButton";
import { ChainIcon } from "../base/ChainIcon";
import PocketWalletIcon from "../../assets/wallet";
import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import { TWModal } from "../base/modal/TWModal";
@@ -9,8 +10,15 @@ import { NetworkButton } from "./NetworkButton";
import { WalletDetailsModalHeader } from "./WalletDetailsModalHeader";
import { useWallet, useBalance, useDisconnect } from "@thirdweb-dev/react-core";
import { useActiveChain } from "@thirdweb-dev/react-core/evm";
import { useState } from "react";
import { StyleSheet, View } from "react-native";
import { useCallback, useEffect, useState } from "react";
import { Linking, StyleSheet, View } from "react-native";
import { ExportLocalWalletModal } from "./ExportLocalWalletModal";
import { Toast } from "../base/Toast";
import { SmartWallet, walletIds } from "@thirdweb-dev/wallets";
import { SmartWalletAdditionalActions } from "./SmartWalletAdditionalActions";
import { useSmartWallet } from "../../providers/context-provider";
import { Link } from "../base/Link";
import Box from "../base/Box";
export type ConnectWalletDetailsProps = {
address: string;
@@ -20,15 +28,27 @@ export const ConnectWalletDetails = ({
address,
}: ConnectWalletDetailsProps) => {
const [isDetailsModalVisible, setIsDetailsModalVisible] = useState(false);
const [isExportModalVisible, setIsExportModalVisible] = useState(false);
const [isNetworkSelectorModalVisible, setIsNetworkSelectorModalVisible] =
useState(false);
const [isDisconnecting, setIsDisconnecting] = useState(false);
const [addressCopied, setAddressCopied] = useState(false);
const activeWallet = useWallet();
const disconnect = useDisconnect();
const [smartWallet, setSmartWallet] = useSmartWallet();
const chain = useActiveChain();
const balanceQuery = useBalance();
useEffect(() => {
const timeout = setTimeout(() => {
if (addressCopied) {
setAddressCopied(false);
}
}, 2000);
return () => clearTimeout(timeout);
}, [addressCopied]);
const onPress = () => {
setIsDetailsModalVisible(true);
};
@@ -37,6 +57,7 @@ export const ConnectWalletDetails = ({
setIsDisconnecting(true);
disconnect().finally(() => {
setIsDisconnecting(false);
setSmartWallet?.(undefined);
});
};
@@ -52,17 +73,80 @@ export const ConnectWalletDetails = ({
const onBackdropPress = () => {
setIsDetailsModalVisible(false);
setIsExportModalVisible(false);
};
const onExportLocalWalletPress = useCallback(() => {
setIsExportModalVisible(true);
}, []);
const onExportModalClose = () => {
setIsExportModalVisible(false);
};
const onAddressCopied = () => {
setAddressCopied(true);
};
const getAdditionalActions = useCallback(() => {
if (activeWallet?.walletId === SmartWallet.id || smartWallet) {
return (
<SmartWalletAdditionalActions
onExportPress={onExportLocalWalletPress}
/>
);
}
if (activeWallet?.walletId === walletIds.localWallet) {
return (
<>
<View style={styles.currentNetwork}>
<Text variant="bodySmallSecondary">Additional Actions</Text>
</View>
<BaseButton
backgroundColor="background"
borderColor="border"
mb="sm"
style={styles.exportWallet}
onPress={onExportLocalWalletPress}
>
<PocketWalletIcon size={16} />
<View style={styles.exportWalletInfo}>
<Text variant="bodySmall">Export wallet</Text>
</View>
</BaseButton>
<Box flexDirection="row" alignItems="center" justifyContent="center">
<Link
text="Learn more"
onPress={() =>
Linking.openURL(
"https://portal.thirdweb.com/wallet/local-wallet",
)
}
/>
</Box>
</>
);
}
return null;
}, [activeWallet?.walletId, onExportLocalWalletPress, smartWallet]);
return (
<>
<TWModal
isVisible={isDetailsModalVisible}
onBackdropPress={onBackdropPress}
>
<ExportLocalWalletModal
isVisible={isExportModalVisible}
onClose={onExportModalClose}
/>
<WalletDetailsModalHeader
address={address}
onDisconnectPress={onDisconnectPress}
onAddressCopied={onAddressCopied}
loading={isDisconnecting}
/>
<View style={styles.currentNetwork}>
@@ -73,6 +157,10 @@ export const ConnectWalletDetails = ({
chainName={chain?.name || "Unknown Network"}
onPress={onChangeNetworkPress}
/>
{getAdditionalActions()}
{addressCopied === true ? (
<Toast text={"Address copied to clipboard"} />
) : null}
</TWModal>
<NetworkSelectorModal
@@ -108,6 +196,26 @@ const styles = StyleSheet.create({
flexDirection: "column",
marginLeft: 5,
},
exportWalletInfo: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
alignContent: "center",
flexDirection: "column",
marginLeft: 8,
},
exportWallet: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "flex-start",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
minWidth: 200,
},
walletDetails: {
display: "flex",
flexDirection: "row",
@@ -126,6 +234,7 @@ const styles = StyleSheet.create({
alignContent: "flex-start",
alignItems: "flex-start",
justifyContent: "flex-start",
marginTop: 36,
marginTop: 24,
marginBottom: 8,
},
});
@@ -0,0 +1,222 @@
import Text from "../base/Text";
import {
ActivityIndicator,
KeyboardAvoidingView,
Platform,
Share,
StyleSheet,
} from "react-native";
import Modal from "react-native-modal";
import { useState } from "react";
import BaseButton from "../base/BaseButton";
import Box from "../base/Box";
import { ModalHeaderTextClose } from "../base/modal/ModalHeaderTextClose";
import { useAddress, useWallet } from "@thirdweb-dev/react-core";
import { PasswordInput } from "../PasswordInput";
import * as FileSystem from "expo-file-system";
import { LocalWallet } from "../../wallets/wallets/local-wallet";
import { SmartWallet } from "@thirdweb-dev/wallets";
import { usePersonalWalletAddress } from "../../wallets/hooks/usePersonalWalletAddress";
export type ExportLocalWalletModalProps = {
isVisible: boolean;
onClose: () => void;
};
export const ExportLocalWalletModal = ({
isVisible,
onClose,
}: ExportLocalWalletModalProps) => {
const [password, setPassword] = useState<string | undefined>();
const [error, setError] = useState<string | undefined>();
const [isExporting, setIsExporting] = useState<boolean>(false);
const activeWallet = useWallet();
const address = useAddress();
const personalWalletAddress = usePersonalWalletAddress();
const onContinuePress = async () => {
if (!password) {
setError("Please enter a password");
return;
}
setIsExporting(true);
setError(undefined);
let data;
if (activeWallet?.walletId === SmartWallet.id) {
data = await (activeWallet.getPersonalWallet() as LocalWallet).export({
strategy: "encryptedJson",
password: password,
});
} else {
data = await (activeWallet as LocalWallet).export({
strategy: "encryptedJson",
password: password,
});
}
const fileName = "wallet.json";
if (Platform.OS === "android") {
// Requests permissions for external directory
const permissions =
await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
if (permissions.granted) {
// Gets SAF URI from response
const uri = permissions.directoryUri;
let fileURI;
try {
// Create file in external directory. If file already exists, it will be renamed.
fileURI = await FileSystem.StorageAccessFramework.createFileAsync(
uri,
fileName,
"application/json",
);
} catch (e) {
console.error("Error creating the file", e);
setError("Error creating the file. Please try again.");
setIsExporting(false);
return;
}
try {
await FileSystem.StorageAccessFramework.writeAsStringAsync(
fileURI,
data,
{
encoding: FileSystem.EncodingType.UTF8,
},
);
} catch (e) {
console.error("Error writing the file", e);
setError("Error writing the file. Please try again.");
setIsExporting(false);
return;
}
}
onCloseInternal();
} else {
let filePath;
try {
filePath = `${FileSystem.documentDirectory}${fileName}`;
await FileSystem.writeAsStringAsync(filePath, data, {
encoding: FileSystem.EncodingType.UTF8,
});
} catch (e) {
console.error("Error writing the file", e);
setError("Error writing the file. Please try again.");
}
if (!filePath) {
setIsExporting(false);
return;
}
await Share.share({ title: "Wallet JSON", url: filePath });
onCloseInternal();
}
setIsExporting(false);
};
const onCloseInternal = () => {
setError(undefined);
setPassword(undefined);
onClose();
};
const onChangeText = (text: string) => {
if (error) {
setError(undefined);
}
setPassword(text);
};
return (
<Modal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
<Box
flexDirection="column"
backgroundColor="background"
borderRadius="md"
p="lg"
>
<ModalHeaderTextClose headerText={""} onClose={onCloseInternal} />
<Text variant="header" textAlign="center">
Export your Wallet
</Text>
<Text variant="subHeader" mt="md" textAlign="center">
{
"This will download a JSON file containing your wallet information onto your device encrypted with the password."
}
</Text>
<Text variant="bodySmall" textAlign="left" mt="lg" mb="xxs">
Wallet Address
</Text>
<Text variant="bodySmallSecondary">
{personalWalletAddress ? personalWalletAddress : address}
</Text>
<Text variant="bodySmall" textAlign="left" mt="lg" mb="xxs">
Password
</Text>
<PasswordInput onChangeText={onChangeText} />
<Text variant="bodySmall" color="red" mt="xs" textAlign="left">
{error}
</Text>
<Box
flexDirection="row"
justifyContent="center"
paddingHorizontal="md"
mt="lg"
>
<BaseButton
backgroundColor="white"
style={styles.modalButton}
onPress={onContinuePress}
>
{isExporting ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : (
<Text variant="bodySmall" color="black">
Export
</Text>
)}
</BaseButton>
</Box>
</Box>
</KeyboardAvoidingView>
</Modal>
);
};
const styles = StyleSheet.create({
modalButton: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
minWidth: 100,
},
pkButton: {
display: "flex",
flexDirection: "column",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
},
});
@@ -1,3 +1,4 @@
import { Theme } from "../../styles/theme";
import BaseButton from "../base/BaseButton";
import { ChainIcon } from "../base/ChainIcon";
import Text from "../base/Text";
@@ -6,6 +7,7 @@ import { StyleSheet } from "react-native";
interface NetworkButtonProps {
chainIconUrl?: string;
chainName: string;
padding?: keyof Theme["spacing"];
onPress: () => void;
}
@@ -13,17 +15,19 @@ export const NetworkButton = ({
onPress,
chainName,
chainIconUrl,
padding,
}: NetworkButtonProps) => {
return (
<BaseButton
mt="md"
p="md"
p={padding || "md"}
backgroundColor="background"
style={styles.networkContainer}
onPress={onPress}
borderColor="border"
>
<ChainIcon chainIconUrl={chainIconUrl} size={32} active={false} />
{chainIconUrl ? (
<ChainIcon chainIconUrl={chainIconUrl} size={32} active={false} />
) : null}
<Text variant="bodyLarge" style={styles.networkText}>
{chainName}
</Text>
@@ -0,0 +1,168 @@
import { StyleSheet, View } from "react-native";
import PocketWalletIcon from "../../assets/wallet";
import BaseButton from "../base/BaseButton";
import { WalletIcon } from "../base/WalletIcon";
import { AbstractClientWallet, SmartWallet } from "@thirdweb-dev/wallets";
import { Address } from "../base/Address";
import Text from "../base/Text";
import { usePersonalWalletAddress } from "../../wallets/hooks/usePersonalWalletAddress";
import { LocalWallet } from "../../wallets/wallets/local-wallet";
import { useThirdwebWallet, useWallet } from "@thirdweb-dev/react-core";
import { useEffect, useState } from "react";
import { useSmartWallet } from "../../providers/context-provider";
import RightArrowIcon from "../../assets/right-arrow";
import { useTheme } from "@shopify/restyle";
export const SmartWalletAdditionalActions = ({
onExportPress,
}: {
onExportPress: () => void;
}) => {
const personalWalletAddress = usePersonalWalletAddress();
const handleWalletConnect = useThirdwebWallet().handleWalletConnect;
const [smartWallet, setSmartWallet] = useSmartWallet();
const [smartWalletAddress, setSmartWalletAddress] = useState<string>("");
const [showSmartWallet, setShowSmartWallet] = useState(false);
const activeWallet = useWallet();
const theme = useTheme();
const wallet = showSmartWallet
? smartWallet
: (activeWallet?.getPersonalWallet() as AbstractClientWallet);
useEffect(() => {
if (activeWallet?.walletId === SmartWallet.id) {
setSmartWallet?.(activeWallet as SmartWallet);
setShowSmartWallet(false);
} else {
setShowSmartWallet(true);
}
}, [activeWallet, activeWallet?.walletId, setSmartWallet]);
useEffect(() => {
(async () => {
if (smartWallet) {
const addr = await smartWallet.getAddress();
setSmartWalletAddress(addr);
}
})();
}, [smartWallet]);
const onWalletPress = () => {
if (!wallet) {
return;
}
handleWalletConnect(wallet);
};
return (
<>
<View style={styles.currentNetwork}>
<Text variant="bodySmallSecondary">
{showSmartWallet ? "Smart Wallet" : "Personal Wallet"}
</Text>
</View>
<BaseButton
backgroundColor="background"
borderColor="border"
justifyContent="space-between"
mb="md"
style={styles.walletDetails}
onPress={onWalletPress}
>
<>
{wallet?.getMeta().iconURL ? (
<WalletIcon size={32} iconUri={wallet?.getMeta().iconURL || ""} />
) : null}
<View style={styles.walletInfo}>
{personalWalletAddress ? (
<Address
variant="bodyLarge"
address={
showSmartWallet ? smartWalletAddress : personalWalletAddress
}
/>
) : null}
</View>
</>
<RightArrowIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
</BaseButton>
{wallet?.walletId === LocalWallet.id ||
activeWallet?.walletId === LocalWallet.id ? (
<BaseButton
backgroundColor="background"
borderColor="border"
mb="sm"
style={styles.exportWallet}
onPress={onExportPress}
>
<PocketWalletIcon size={16} />
<View style={styles.exportWalletInfo}>
<Text variant="bodySmall">
{wallet?.walletId === LocalWallet.id
? "Export personal wallet"
: "Export wallet"}
</Text>
</View>
</BaseButton>
) : null}
</>
);
};
const styles = StyleSheet.create({
walletInfo: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
alignContent: "center",
flexDirection: "column",
marginLeft: 15,
},
exportWalletInfo: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
alignContent: "center",
flexDirection: "column",
marginLeft: 8,
},
exportWallet: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "flex-start",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
minWidth: 200,
},
walletDetails: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "flex-start",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
minWidth: 200,
},
currentNetwork: {
display: "flex",
flexDirection: "column",
alignContent: "flex-start",
alignItems: "flex-start",
justifyContent: "flex-start",
marginTop: 24,
marginBottom: 8,
},
});
@@ -1,43 +1,74 @@
import { Icon } from "../../assets/icon";
import { useAppTheme } from "../../styles/hooks";
import { Address } from "../base/Address";
import BaseButton from "../base/BaseButton";
import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import { useWallet, useBalance } from "@thirdweb-dev/react-core";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import * as Clipboard from "expo-clipboard";
import Box from "../base/Box";
import CopyIcon from "../../assets/copy";
interface WalletDetailsModalHeaderProps {
address: string;
onDisconnectPress: () => void;
onAddressCopied?: () => void;
loading?: boolean;
}
export const WalletDetailsModalHeader = ({
address,
onDisconnectPress,
onAddressCopied,
loading,
}: WalletDetailsModalHeaderProps) => {
const theme = useAppTheme();
const balanceQuery = useBalance();
const activeWallet = useWallet();
const onAddressPress = async () => {
await Clipboard.setStringAsync(address);
onAddressCopied?.();
};
return (
<>
<View style={styles.header}>
<WalletIcon size={40} iconUri={activeWallet?.getMeta().iconURL || ""} />
<View style={styles.walletInfo}>
<Address address={address} />
<BaseButton
flex={1}
justifyContent="flex-start"
alignItems="flex-start"
ml="md"
onPress={onAddressPress}
>
<Box
flexDirection="row"
mr="sm"
gap="xs"
justifyContent="center"
alignItems="center"
>
<Address address={address} />
<CopyIcon
width={14}
height={14}
color={theme.colors.textSecondary}
/>
</Box>
<Text variant="bodySmallSecondary">
{balanceQuery.data?.displayValue.slice(0, 5)}{" "}
{balanceQuery.data?.symbol}
</Text>
</View>
</BaseButton>
{loading ? (
<ActivityIndicator size={18} color={theme.colors.iconHighlight} />
) : (
<Icon
type="disconnect"
size={18}
width={18}
height={18}
onPress={onDisconnectPress}
color={theme.colors.iconHighlight}
/>
@@ -55,11 +86,4 @@ const styles = StyleSheet.create({
alignItems: "center",
justifyContent: "flex-start",
},
walletInfo: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
flexDirection: "column",
marginLeft: 16,
},
});
@@ -1,27 +1,42 @@
import {
LocalWallet,
localWallet,
} from "../../../wallets/wallets/local-wallet";
import { ModalFooter } from "../../base/modal/ModalFooter";
import { ModalHeaderTextClose } from "../../base/modal/ModalHeaderTextClose";
import { ChooseWalletContent } from "./ChooseWalletContent";
import type { Wallet } from "@thirdweb-dev/react-core";
import { ReactNode } from "react";
import { Wallet } from "@thirdweb-dev/react-core";
import { ReactNode, useState } from "react";
import { View } from "react-native";
export type ChooseWalletProps = {
headerText?: ReactNode | string;
subHeaderText?: ReactNode | string;
footer?: ReactNode;
onChooseWallet: (wallet: Wallet) => void;
onClose: () => void;
wallets: Wallet[];
excludeWalletIds?: string[];
showGuestWalletAsButton?: boolean;
};
export function ChooseWallet({
headerText = "Choose your Wallet",
subHeaderText,
wallets,
footer,
onChooseWallet,
onClose,
excludeWalletIds = [],
showGuestWalletAsButton = false,
}: ChooseWalletProps) {
const [isConnecting, setIsConnecting] = useState(false);
const guestWallet = wallets.find((w) => w.id === LocalWallet.id);
const onContinueAsGuestPress = () => {
setIsConnecting(true);
onChooseWallet(localWallet());
};
return (
<View>
<ModalHeaderTextClose
@@ -29,8 +44,22 @@ export function ChooseWallet({
headerText={headerText}
subHeaderText={subHeaderText}
/>
<ChooseWalletContent wallets={wallets} onChooseWallet={onChooseWallet} />
{footer ? footer : <ModalFooter footer={"Need help getting started?"} />}
<ChooseWalletContent
wallets={wallets}
excludeWalletIds={
showGuestWalletAsButton
? excludeWalletIds
: [...excludeWalletIds, LocalWallet.id]
}
onChooseWallet={onChooseWallet}
/>
{guestWallet && !showGuestWalletAsButton ? (
<ModalFooter
footer={"Continue as Guest"}
isLoading={isConnecting}
onPress={onContinueAsGuestPress}
/>
) : null}
</View>
);
}
@@ -1,41 +1,40 @@
import BaseButton from "../../base/BaseButton";
import ImageSvgUri from "../../base/ImageSvgUri";
import Text from "../../base/Text";
import { useMemo } from "react";
import type { Wallet } from "@thirdweb-dev/react-core";
import { StyleSheet, View, FlatList } from "react-native";
import { WalletButton } from "../../base/WalletButton";
interface InitialExplorerContentProps {
wallets: Wallet[];
excludeWalletIds?: string[];
onChooseWallet: (wallet: Wallet) => void;
}
export const ChooseWalletContent = ({
wallets,
excludeWalletIds,
onChooseWallet,
}: InitialExplorerContentProps) => {
const walletsToDisplay = useMemo(() => {
return wallets.filter(
(w) => !!!excludeWalletIds?.find((ewId) => ewId === w.id),
);
}, [wallets, excludeWalletIds]);
return (
<View style={styles.explorerContainer}>
<FlatList
keyExtractor={(item) => item.meta.name}
data={wallets}
data={walletsToDisplay}
renderItem={({ item, index }) => {
const marginBottom = index === wallets.length - 1 ? "none" : "xxs";
const marginBottom =
index === walletsToDisplay.length - 1 ? "none" : "xxs";
return (
<BaseButton
mb={marginBottom}
style={styles.row}
backgroundColor="backgroundHighlight"
<WalletButton
walletIconUrl={item.meta.iconURL}
name={item.meta.name}
onPress={() => onChooseWallet(item)}
>
<View style={styles.imageView}>
<ImageSvgUri
imageUrl={item.meta.iconURL}
width={32}
height={32}
/>
</View>
<Text variant="bodyLarge">{item.meta.name}</Text>
</BaseButton>
mb={marginBottom}
/>
);
}}
/>
@@ -44,18 +43,6 @@ export const ChooseWalletContent = ({
};
const styles = StyleSheet.create({
row: {
display: "flex",
flexDirection: "row",
justifyContent: "flex-start",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 12,
borderRadius: 12,
},
imageView: {
marginRight: 16,
},
explorerContainer: {
display: "flex",
flexDirection: "row",
@@ -3,53 +3,141 @@ import Text from "../base/Text";
import { TWModal } from "../base/modal/TWModal";
import { ChooseWallet } from "./ChooseWallet/ChooseWallet";
import { ConnectingWallet } from "./ConnectingWallet/ConnectingWallet";
import { Wallet, useConnect, useWallets } from "@thirdweb-dev/react-core";
import { useState } from "react";
import { StyleSheet } from "react-native";
import {
Wallet,
useConnect,
useIsConnecting,
useThirdwebWallet,
useWallets,
} from "@thirdweb-dev/react-core";
import { useEffect, useState } from "react";
import { ActivityIndicator, StyleSheet } from "react-native";
import { SmartWallet } from "@thirdweb-dev/wallets";
import { SmartWalletFlow } from "./SmartWallet/SmartWalletFlow";
import { LocalWalletFlow } from "./LocalWalletFlow";
import { LocalWallet } from "../../wallets/wallets/local-wallet";
export const ConnectWalletFlow = () => {
const [modalVisible, setModalVisible] = useState(false);
const [activeWallet, setActiveWallet] = useState<Wallet | undefined>();
const [isConnecting, setIsConnecting] = useState(false);
const supportedWallets = useWallets();
const isWalletConnecting = useIsConnecting();
const [showButtonSpinner, setShowButtonSpinner] = useState(false);
const twWalletContext = useThirdwebWallet();
useEffect(() => {
setShowButtonSpinner(isWalletConnecting);
if (!isWalletConnecting) {
return;
}
const timeout = setTimeout(() => {
if (isWalletConnecting) {
setShowButtonSpinner(false);
}
}, 3000);
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, [isWalletConnecting]);
const connect = useConnect();
const supportedWallets = useWallets();
const onConnectPress = () => {
if (supportedWallets.length === 1) {
onChooseWallet(supportedWallets[0]);
}
setModalVisible(true);
};
const onClose = () => {
setModalVisible(false);
setActiveWallet(undefined);
reset();
};
const onChooseWallet = async (wallet: Wallet) => {
setActiveWallet(() => wallet);
const onLocalWalletImported = async (localWallet: LocalWallet) => {
await localWallet.connect();
twWalletContext?.handleWalletConnect(localWallet);
};
await connect(wallet, {}).catch((error) => {
console.log("error", error);
const connectActiveWallet = async (wallet: Wallet) => {
setIsConnecting(true);
connect(wallet, {}).catch((error) => {
console.error("Error connecting to the wallet", error);
onBackPress();
});
};
const onBackPress = () => {
setActiveWallet(undefined);
const onChooseWallet = (wallet: Wallet) => {
setActiveWallet(() => wallet);
if (wallet.id !== SmartWallet.id) {
connectActiveWallet(wallet);
}
};
const onBackPress = () => {
reset();
};
const reset = () => {
setActiveWallet(undefined);
setIsConnecting(false);
};
function getComponentForWallet(activeWalletP: Wallet) {
switch (activeWalletP.id) {
case LocalWallet.id:
return (
<LocalWalletFlow
onClose={onClose}
onBackPress={supportedWallets.length > 1 ? onBackPress : undefined}
onWalletImported={onLocalWalletImported}
onConnectPress={() => connectActiveWallet(activeWalletP)}
/>
);
case SmartWallet.id:
return (
<SmartWalletFlow
onClose={() => {
onClose();
}}
onConnect={onBackPress}
/>
);
}
}
return (
<>
<TWModal isVisible={modalVisible}>
{activeWallet ? (
<ConnectingWallet
wallet={activeWallet}
onClose={onClose}
onBackPress={onBackPress}
/>
isConnecting ? (
<ConnectingWallet
content={
activeWallet.id === LocalWallet.id ? (
<Text variant="bodySmallSecondary" mt="md">
Creating, encrypting and securing your device wallet.
</Text>
) : undefined
}
wallet={activeWallet}
onClose={onClose}
onBackPress={onBackPress}
/>
) : (
getComponentForWallet(activeWallet)
)
) : (
<ChooseWallet
wallets={supportedWallets}
onChooseWallet={onChooseWallet}
footer={<></>}
onClose={onClose}
/>
)}
@@ -60,9 +148,17 @@ export const ConnectWalletFlow = () => {
onPress={onConnectPress}
style={styles.connectWalletButton}
>
{/* {showButtonSpinner ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : ( */}
<Text variant="bodyLarge" color="buttonTextColor">
Connect Wallet
{showButtonSpinner ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : (
"Connect Wallet"
)}
</Text>
{/* )} */}
</BaseButton>
</>
);
@@ -72,10 +168,12 @@ const styles = StyleSheet.create({
connectWalletButton: {
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 8,
paddingHorizontal: 10,
paddingVertical: 10,
minWidth: 150,
},
});
@@ -7,9 +7,9 @@ import { ReactNode } from "react";
import { ActivityIndicator, Linking, StyleSheet, View } from "react-native";
export type ConnectingWalletProps = {
headerText?: ReactNode | string;
subHeaderText?: ReactNode | string;
subHeaderText?: string;
footer?: ReactNode;
content?: ReactNode;
onClose: () => void;
onBackPress: () => void;
wallet: Wallet;
@@ -17,6 +17,7 @@ export type ConnectingWalletProps = {
export function ConnectingWallet({
subHeaderText,
content,
wallet,
footer,
onClose,
@@ -34,13 +35,17 @@ export function ConnectingWallet({
onBackPress={onBackPress}
walletLogoUrl={wallet.meta.iconURL}
subHeaderText={subHeaderText}
close={onClose}
onClose={onClose}
/>
<View style={styles.connectingContainer}>
<ActivityIndicator size="small" color={theme.colors.linkPrimary} />
<Text variant="bodySmallSecondary" mt="md">
Connect your wallet through the {wallet.meta.name} application.
</Text>
{content ? (
content
) : (
<Text variant="bodySmallSecondary" mt="md">
Connect your wallet through the {wallet.meta.name} application.
</Text>
)}
</View>
{footer ? (
footer
@@ -2,46 +2,62 @@ import { Icon } from "../../../assets/icon";
import { useAppTheme } from "../../../styles/hooks";
import ImageSvgUri from "../../base/ImageSvgUri";
import Text from "../../base/Text";
import { ReactNode } from "react";
import { StyleSheet, View } from "react-native";
import { FlexAlignType, StyleSheet, View } from "react-native";
interface ConnectWalletHeaderProps {
close: () => void;
onBackPress: () => void;
walletLogoUrl: string;
subHeaderText?: ReactNode | string;
onClose: () => void;
onBackPress?: () => void;
walletLogoUrl?: string;
headerText?: string;
subHeaderText?: string;
alignHeader?: FlexAlignType;
}
export const ConnectWalletHeader = ({
headerText,
subHeaderText = "Connecting your wallet",
alignHeader = "center",
walletLogoUrl,
close,
onClose,
onBackPress,
}: ConnectWalletHeaderProps) => {
const theme = useAppTheme();
return (
<>
<View style={styles.header}>
<Icon
type="back"
size={14}
onPress={onBackPress}
color={theme.colors.iconPrimary}
/>
<ImageSvgUri width={56} height={56} imageUrl={walletLogoUrl} />
{onBackPress ? (
<Icon
type="back"
width={14}
height={14}
onPress={onBackPress}
color={theme.colors.iconPrimary}
/>
) : (
<View />
)}
{walletLogoUrl ? (
<ImageSvgUri width={56} height={56} imageUrl={walletLogoUrl} />
) : null}
<Icon
type="close"
size={14}
onPress={close}
width={14}
height={14}
onPress={onClose}
color={theme.colors.iconPrimary}
/>
</View>
<View style={styles.subHeader}>
{typeof subHeaderText === "string" ? (
<Text variant="subHeader">{subHeaderText}</Text>
) : (
subHeaderText
)}
<View style={{ ...styles.headerContainer, alignItems: alignHeader }}>
{headerText ? (
<Text variant="header" mt="md">
{headerText}
</Text>
) : null}
{subHeaderText ? (
<Text variant="subHeader" mt="md">
{subHeaderText}
</Text>
) : null}
</View>
</>
);
@@ -53,10 +69,9 @@ const styles = StyleSheet.create({
flexDirection: "row",
justifyContent: "space-between",
},
subHeader: {
headerContainer: {
display: "flex",
flexDirection: "row",
flexDirection: "column",
justifyContent: "center",
marginTop: 24,
},
});
@@ -0,0 +1,98 @@
import BaseButton from "../base/BaseButton";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import { ConnectWalletHeader } from "./ConnectingWallet/ConnectingWalletHeader";
import Text from "../base/Text";
import { ModalFooter } from "../base/modal/ModalFooter";
import { LocalWallet } from "../../wallets/wallets/local-wallet";
import { LocalWalletImportModal } from "./LocalWalletImportModal";
import { useState } from "react";
export type LocalWalletFlowProps = {
onClose: () => void;
onBackPress?: () => void;
onConnectPress: () => void;
onWalletImported: (localWallet: LocalWallet) => void;
};
export function LocalWalletFlow({
onClose,
onBackPress,
onConnectPress,
onWalletImported,
}: LocalWalletFlowProps) {
const [isImportModalVisible, setIsImportModalVisible] = useState(false);
const [isCreatingWallet, setIsCreatingWallet] = useState(false);
const onImportPress = async () => {
setIsImportModalVisible(true);
};
const onImportModalClose = () => {
setIsImportModalVisible(false);
};
const onConnectPressInternal = () => {
setIsCreatingWallet(true);
onConnectPress();
};
return (
<>
<ConnectWalletHeader
onBackPress={onBackPress}
headerText="Guest Wallet"
alignHeader="flex-start"
subHeaderText={""}
onClose={onClose}
/>
<View style={styles.connectingContainer}>
<BaseButton
backgroundColor="white"
minWidth={130}
onPress={onConnectPressInternal}
style={styles.connectWalletButton}
>
{isCreatingWallet ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : (
<Text variant="bodyLarge" color="black">
Create new wallet
</Text>
)}
</BaseButton>
<Text variant="subHeader" mt="lg">
-------- OR --------
</Text>
<ModalFooter footer={"Import a wallet"} onPress={onImportPress} />
</View>
<LocalWalletImportModal
isVisible={isImportModalVisible}
onWalletImported={onWalletImported}
onClose={onImportModalClose}
/>
</>
);
}
const styles = StyleSheet.create({
connectingContainer: {
display: "flex",
flexDirection: "column",
flexWrap: "wrap",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
paddingHorizontal: 4,
marginTop: 18,
},
connectWalletButton: {
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
borderRadius: 8,
paddingHorizontal: 10,
paddingVertical: 10,
},
});
@@ -0,0 +1,199 @@
import Text from "../base/Text";
import {
ActivityIndicator,
KeyboardAvoidingView,
StyleSheet,
} from "react-native";
import Modal from "react-native-modal";
import { useState } from "react";
import BaseButton from "../base/BaseButton";
import Box from "../base/Box";
import { ModalHeaderTextClose } from "../base/modal/ModalHeaderTextClose";
import { useCreateWalletInstance } from "@thirdweb-dev/react-core";
import { PasswordInput } from "../PasswordInput";
import { LocalWallet, localWallet } from "../../wallets/wallets/local-wallet";
import * as DocumentPicker from "expo-document-picker";
import * as FileSystem from "expo-file-system";
export type LocalWalletImportModalProps = {
isVisible: boolean;
onClose: () => void;
onWalletImported: (wallet: LocalWallet) => void;
};
export const LocalWalletImportModal = ({
isVisible,
onClose,
onWalletImported,
}: LocalWalletImportModalProps) => {
const [password, setPassword] = useState<string | undefined>();
const [jsonFile, setJsonFile] = useState<string | undefined>();
const [error, setError] = useState<string | undefined>();
const [isImporting, setIsImporting] = useState<boolean>(false);
const createWalletInstance = useCreateWalletInstance();
const onImportPress = async () => {
setError(undefined);
if (!password || !jsonFile) {
setError("Please enter a password and select a file.");
return;
}
setIsImporting(true);
let json;
try {
json = await FileSystem.readAsStringAsync(jsonFile, {
encoding: FileSystem.EncodingType.UTF8,
});
} catch (err) {
setError("Error reading the file. Please try again.");
setIsImporting(false);
return;
}
const localWalletInstance = createWalletInstance(
localWallet(),
) as LocalWallet;
try {
await localWalletInstance.import({
encryptedJson: json,
password: password,
});
} catch (err) {
console.error("Error importing the wallet", err);
setError("Invalid password");
setIsImporting(false);
return;
}
localWalletInstance.save({
strategy: "privateKey",
encryption: false,
});
onWalletImported(localWalletInstance);
setIsImporting(false);
onCloseInternal();
};
const onCloseInternal = () => {
setPassword(undefined);
onClose();
};
const onChangeText = (text: string) => {
setPassword(text);
if (text.length === 0) {
setError(undefined);
}
};
const onPickFilePress = async () => {
const result = await DocumentPicker.getDocumentAsync({
copyToCacheDirectory: true,
type: "application/json",
});
if (result.type === "success") {
setJsonFile(result.uri);
setError(undefined);
} else {
setError("Error accessing the file. Please try again.");
}
};
return (
<Modal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
<Box
flexDirection="column"
backgroundColor="background"
borderRadius="md"
p="lg"
>
<ModalHeaderTextClose headerText={""} onClose={onCloseInternal} />
<Text variant="header" textAlign="center">
Import JSON Wallet
</Text>
<Text variant="subHeader" mt="md" textAlign="center">
{
"The application can authorize any transactions on behalf of the wallet without any approvals. We recommend only connecting to trusted applications."
}
</Text>
<BaseButton
backgroundColor="background"
borderColor="border"
mt="lg"
onPress={onPickFilePress}
style={styles.pkButton}
>
<Text variant="bodySmallSecondary" textAlign="left">
{jsonFile ||
"Select the JSON file you exported from your wallet."}
</Text>
</BaseButton>
<Text variant="bodySmall" textAlign="left" mt="lg" mb="xxs">
Password
</Text>
<PasswordInput onChangeText={onChangeText} />
<Text variant="bodySmall" color="red" mt="xs" textAlign="left">
{error}
</Text>
<Box
flexDirection="row"
justifyContent="center"
paddingHorizontal="md"
mt="lg"
>
<BaseButton
backgroundColor="white"
style={styles.modalButton}
onPress={onImportPress}
>
{isImporting ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : (
<Text variant="bodySmall" color="black">
Import
</Text>
)}
</BaseButton>
</Box>
</Box>
</KeyboardAvoidingView>
</Modal>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
modalButton: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
minWidth: 100,
},
pkButton: {
display: "flex",
flexDirection: "column",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 12,
borderWidth: 0.5,
paddingHorizontal: 10,
paddingVertical: 12,
},
});
@@ -0,0 +1,201 @@
import { useCallback, useEffect, useState } from "react";
import {
Wallet,
WalletInstance,
useConnect,
useCreateWalletInstance,
useSupportedWallet,
useThirdwebWallet,
} from "@thirdweb-dev/react-core";
import { SmartWalletObj } from "../../../wallets/wallets/smart-wallet";
import {
LocalWallet,
localWallet,
} from "../../../wallets/wallets/local-wallet";
import { ChooseWallet } from "../ChooseWallet/ChooseWallet";
import { LocalWalletFlow } from "../LocalWalletFlow";
import { ModalHeaderTextClose } from "../../base/modal/ModalHeaderTextClose";
import { ActivityIndicator, Linking } from "react-native";
import { useTheme } from "@shopify/restyle";
import BaseButton from "../../base/BaseButton";
import Text from "../../base/Text";
import { walletIds } from "@thirdweb-dev/wallets";
export const SmartWalletFlow = ({
onClose,
onConnect,
}: {
onClose: () => void;
onConnect: () => void;
}) => {
const [showLocalWalletFlow, setShowLocalWalletFlow] = useState<boolean>();
const [connectedPersonalWallet, setConnectedPersonalWallet] =
useState<WalletInstance>();
const [isConnecting, setIsConnecting] = useState(false);
const [personalWalletChainId, setPersonalWalletChaindId] = useState<
number | undefined
>();
const theme = useTheme();
const createWalletInstance = useCreateWalletInstance();
const walletObj = useSupportedWallet(walletIds.smartWallet) as SmartWalletObj;
const connect = useConnect();
const targetChain = useThirdwebWallet().activeChain;
const mismatch = personalWalletChainId
? personalWalletChainId !== targetChain.chainId
: false;
useEffect(() => {
(async () => {
if (connectedPersonalWallet) {
const chainId = await connectedPersonalWallet.getChainId();
setPersonalWalletChaindId(chainId);
}
})();
}, [connectedPersonalWallet]);
const connectSmartWallet = useCallback(
async (personalWallet: WalletInstance) => {
if (!mismatch && personalWalletChainId) {
await connect(walletObj, {
personalWallet: personalWallet,
});
onConnect();
}
},
[connect, mismatch, onConnect, personalWalletChainId, walletObj],
);
useEffect(() => {
if (connectedPersonalWallet) {
if (!mismatch) {
connectSmartWallet(connectedPersonalWallet);
}
}
}, [connectSmartWallet, connectedPersonalWallet, mismatch]);
const connectPersonalWallet = useCallback(
async (wallet: Wallet) => {
setIsConnecting(true);
const walletInstance = createWalletInstance(wallet);
await walletInstance.connect();
setConnectedPersonalWallet(walletInstance);
},
[createWalletInstance],
);
const onLocalWalletImported = async (localWalletImported: LocalWallet) => {
setIsConnecting(true);
await localWalletImported.connect();
connectSmartWallet(localWalletImported);
};
const onChoosePersonalWallet = useCallback(
async (wallet: Wallet) => {
// if (wallet.id === LocalWallet.id) {
// setShowLocalWalletFlow(true);
// } else {
connectPersonalWallet(wallet);
// }
},
[connectPersonalWallet],
);
const onLocalWalletBackPress = () => {
setShowLocalWalletFlow(false);
reset();
};
const onConnectingClosePress = () => {
connectedPersonalWallet?.disconnect();
reset();
};
const onSwitchNetworkPress = async () => {
await connectedPersonalWallet?.switchChain(targetChain.chainId);
setPersonalWalletChaindId(targetChain.chainId);
};
const reset = () => {
setIsConnecting(false);
setConnectedPersonalWallet(undefined);
setPersonalWalletChaindId(undefined);
};
const onLearnMorePress = () => {
Linking.openURL("https://portal.thirdweb.com/wallet/smart-wallet");
};
if (isConnecting) {
return (
<>
<ModalHeaderTextClose
onClose={onConnectingClosePress}
headerText={mismatch ? "Network Mismatch" : "Connecting smart wallet"}
subHeaderText={
mismatch
? "There's a network mismatch between your contract and your wallet"
: ""
}
/>
{mismatch ? null : (
<ActivityIndicator size="large" color={theme.colors.linkPrimary} />
)}
{mismatch === true ? (
<BaseButton
marginVertical="sm"
flexDirection="row"
justifyContent="flex-start"
alignItems="center"
paddingHorizontal="md"
paddingVertical="sm"
gap="md"
borderRadius="sm"
backgroundColor="backgroundHighlight"
onPress={onSwitchNetworkPress}
>
<Text variant="bodyLarge">Switch Network</Text>
</BaseButton>
) : null}
</>
);
}
if (showLocalWalletFlow) {
return (
<LocalWalletFlow
onClose={onClose}
onBackPress={onLocalWalletBackPress}
onWalletImported={onLocalWalletImported}
onConnectPress={() => connectPersonalWallet(localWallet())}
/>
);
}
return (
<ChooseWallet
headerText={"Link key"}
subHeaderText={
<Text variant="subHeader">
{
"Choose a personal wallet that acts as your account's key. This controls access to your account. "
}
<Text
variant="subHeader"
color="linkPrimary"
onPress={onLearnMorePress}
>
Learn more.
</Text>
</Text>
}
wallets={walletObj.config.personalWallets}
onChooseWallet={onChoosePersonalWallet}
onClose={onClose}
/>
);
};
@@ -0,0 +1,46 @@
import { StyleSheet, TextInput } from "react-native";
import { useTheme } from "@shopify/restyle";
import Box from "../../base/Box";
import Text from "../../base/Text";
export const UsernameInput = ({
onChangeText,
}: {
onChangeText: TextInput["props"]["onChangeText"];
}) => {
const theme = useTheme();
return (
<>
<Text variant="bodySmall" textAlign="left" mt="lg" mb="xxs">
Username
</Text>
<Box
flexDirection="row"
alignItems="center"
borderColor="border"
borderWidth={1}
borderRadius="md"
pr="xs"
>
<TextInput
style={{ ...styles.textInput, color: theme.colors.textPrimary }}
returnKeyType={"done"}
clearTextOnFocus={false}
autoCapitalize="none"
autoCorrect={false}
onChangeText={onChangeText}
/>
</Box>
</>
);
};
const styles = StyleSheet.create({
textInput: {
textAlign: "left",
flex: 1,
height: 40,
paddingLeft: 5,
},
});
@@ -0,0 +1,65 @@
import { StyleSheet, TextInput, TouchableOpacity } from "react-native";
import Box from "./base/Box";
import { useState } from "react";
import EyeClosed from "../assets/eye-closed";
import { useTheme } from "@shopify/restyle";
import EyeOpened from "../assets/eye-opened";
export const PasswordInput = ({
onChangeText,
}: {
onChangeText: TextInput["props"]["onChangeText"];
}) => {
const theme = useTheme();
const [showPassword, setShowPassword] = useState(false);
const onPressEyeIcon = () => {
setShowPassword(!showPassword);
};
return (
<Box
flexDirection="row"
alignItems="center"
borderColor="border"
borderWidth={1}
borderRadius="md"
pr="xs"
>
<TextInput
style={{ ...styles.textInput, color: theme.colors.textPrimary }}
secureTextEntry={!showPassword}
textContentType="none"
returnKeyType={"done"}
clearTextOnFocus={false}
autoCapitalize="none"
autoCorrect={false}
onChangeText={onChangeText}
/>
<TouchableOpacity onPress={onPressEyeIcon}>
{showPassword ? (
<EyeClosed
width={18}
height={18}
color={theme.colors.iconSecondary}
/>
) : (
<EyeOpened
width={18}
height={18}
color={theme.colors.iconSecondary}
/>
)}
</TouchableOpacity>
</Box>
);
};
const styles = StyleSheet.create({
textInput: {
textAlign: "left",
flex: 1,
height: 40,
paddingLeft: 5,
},
});
@@ -19,7 +19,7 @@ import { PropsWithChildren, useEffect } from "react";
import { ActivityIndicator, StyleSheet } from "react-native";
import invariant from "tiny-invariant";
type ActionFn = (contract: SmartContract) => any;
type ActionFn = (contract: SmartContract) => Promise<any>;
interface Web3ButtonProps<TActionFn extends ActionFn> {
contractAddress: `0x${string}` | `${string}.eth` | string;
@@ -0,0 +1,21 @@
import Box from "./Box";
import Text from "./Text";
type LabelProps = {
text: string;
};
export const Label = ({ text }: LabelProps) => {
return (
<Box
justifyContent="center"
flexDirection="row"
alignItems="center"
paddingVertical="xxs"
paddingHorizontal="xs"
borderRadius="lg"
backgroundColor="labelBackground"
>
<Text variant="bodyLarge">{text}</Text>
</Box>
);
};
@@ -0,0 +1,24 @@
import { TouchableOpacity } from "react-native";
import Text from "./Text";
import { Theme } from "../../styles/theme";
type LinkProps = {
text: string;
variant?: keyof Theme["textVariants"];
onPress?: () => void;
} & (typeof Text)["arguments"];
export const Link = ({
text,
variant = "link",
onPress,
...props
}: LinkProps) => {
return (
<TouchableOpacity onPress={onPress}>
<Text variant={variant} {...props}>
{text}
</Text>
</TouchableOpacity>
);
};
@@ -0,0 +1,71 @@
import { ReactElement, useEffect, useRef } from "react";
import { Theme } from "../../styles/theme";
import Text from "./Text";
import { Animated, StyleSheet } from "react-native";
import { useTheme } from "@shopify/restyle";
export const TOAST_HEIGHT = 45;
export type ToastProps = {
text: string;
icon?: ReactElement;
backgroundColor?: keyof Theme["colors"];
translateY?: number;
};
export function Toast({
text,
icon,
backgroundColor,
translateY = TOAST_HEIGHT,
}: ToastProps) {
const theme = useTheme();
const translateYRef = useRef(new Animated.Value(translateY)).current;
useEffect(() => {
Animated.timing(translateYRef, {
toValue: 0,
duration: 100,
useNativeDriver: true,
}).start();
}, [translateYRef]);
return (
<Animated.View
style={{
...styles.toast,
transform: [
{
translateY: translateYRef,
},
],
backgroundColor: backgroundColor
? backgroundColor
: theme.colors.backgroundHighlight,
}}
>
{icon}
<Text variant="bodySmall">{text}</Text>
</Animated.View>
);
}
const styles = StyleSheet.create({
toast: {
position: "absolute",
flexDirection: "row",
bottom: 0,
left: 0,
right: 0,
zIndex: 1060,
alignContent: "center",
alignItems: "center",
justifyContent: "center",
alignSelf: "stretch",
height: TOAST_HEIGHT,
marginHorizontal: 10,
padding: 10,
borderRadius: 12,
},
});
@@ -0,0 +1,46 @@
import { View } from "react-native";
import BaseButton from "./BaseButton";
import ImageSvgUri from "./ImageSvgUri";
import { Label } from "./Label";
import Text from "./Text";
import Box from "./Box";
type WalletButtonProps = {
onPress: () => void;
walletIconUrl: string;
name: string;
labelText?: string;
} & (typeof BaseButton)["arguments"];
export const WalletButton = ({
mb,
onPress,
walletIconUrl,
name,
labelText,
}: WalletButtonProps) => {
return (
<BaseButton
mb={mb}
flexDirection="row"
justifyContent="space-between"
alignItems="center"
paddingHorizontal="md"
paddingVertical="sm"
borderRadius="sm"
backgroundColor="backgroundHighlight"
onPress={onPress}
>
<Box
flexDirection="row"
justifyContent="flex-start"
alignItems="center"
gap="md"
>
<ImageSvgUri imageUrl={walletIconUrl} width={32} height={32} />
<Text variant="bodyLarge">{name}</Text>
</Box>
{labelText ? <Label text={labelText} /> : <View />}
</BaseButton>
);
};
@@ -1,16 +1,25 @@
import { useTheme } from "@shopify/restyle";
import Text from "../Text";
import { TouchableOpacity, StyleSheet } from "react-native";
import { TouchableOpacity, StyleSheet, ActivityIndicator } from "react-native";
export const ModalFooter = ({
footer,
isLoading,
onPress,
}: {
footer: string;
isLoading?: boolean;
onPress?: () => void;
}) => {
const theme = useTheme();
return (
<TouchableOpacity style={styles.footer} onPress={onPress}>
<Text variant="link">{footer}</Text>
{isLoading ? (
<ActivityIndicator size="small" color={theme.colors.linkPrimary} />
) : (
<Text variant="link">{footer}</Text>
)}
</TouchableOpacity>
);
};
@@ -18,6 +27,8 @@ export const ModalFooter = ({
const styles = StyleSheet.create({
footer: {
marginTop: 24,
marginBottom: 14,
minHeight: 30,
display: "flex",
flexDirection: "row",
justifyContent: "center",
@@ -27,7 +27,8 @@ export const ModalHeaderTextClose = ({
)}
<Icon
type="close"
size={14}
width={14}
height={14}
color={theme.colors.iconSecondary}
onPress={onClose}
/>
@@ -0,0 +1,9 @@
import { metamaskWallet } from "../wallets/wallets/metamask-wallet";
import { rainbowWallet } from "../wallets/wallets/rainbow-wallet";
import { trustWallet } from "../wallets/wallets/trust-wallet";
export const DEFAULT_WALLETS = [
metamaskWallet(),
rainbowWallet(),
trustWallet(),
];
+2
View File
@@ -5,6 +5,8 @@ export { coinbaseWallet } from "./wallets/wallets/coinbase-wallet";
export { metamaskWallet } from "./wallets/wallets/metamask-wallet";
export { rainbowWallet } from "./wallets/wallets/rainbow-wallet";
export { trustWallet } from "./wallets/wallets/trust-wallet";
export { smartWallet } from "./wallets/wallets/smart-wallet";
export { localWallet } from "./wallets/wallets/local-wallet";
export { useCoinbaseWallet } from "./wallets/hooks/useCoinbaseWallet";
export { useMetaMaskWallet } from "./wallets/hooks/useMetaMaskWallet";
@@ -0,0 +1,29 @@
import { SmartWallet } from "@thirdweb-dev/wallets";
import { createContext, useContext, useState } from "react";
type DappContextType = {
smartWallet?: SmartWallet;
setSmartWallet?: (value?: SmartWallet) => void;
};
const DappContext = createContext<DappContextType>({});
export const DappContextProvider = (props: React.PropsWithChildren<{}>) => {
const [smartWallet, setSmartWallet] = useState<SmartWallet | undefined>();
return (
<DappContext.Provider value={{ smartWallet, setSmartWallet }}>
{props.children}
</DappContext.Provider>
);
};
export const useDappContext = () => {
return useContext(DappContext);
};
export const useSmartWallet = () => {
const context = useContext(DappContext);
return [context.smartWallet, context.setSmartWallet] as const;
};
@@ -7,12 +7,10 @@ import {
} from "@thirdweb-dev/react-core";
import { PropsWithChildren } from "react";
import type { Chain, defaultChains } from "@thirdweb-dev/chains";
import { metamaskWallet } from "../wallets/wallets/metamask-wallet";
import { rainbowWallet } from "../wallets/wallets/rainbow-wallet";
import { SecureStorage } from "../../core/SecureStorage";
import { useCoinbaseWalletListener } from "../wallets/hooks/useCoinbaseWalletListener";
const DEFAULT_WALLETS = [metamaskWallet(), rainbowWallet()];
import { DEFAULT_WALLETS } from "../constants/wallets";
import { DappContextProvider } from "./context-provider";
interface ThirdwebProviderProps<TChains extends Chain[]>
extends Omit<ThirdwebProviderCoreProps<TChains>, "supportedWallets"> {
@@ -64,14 +62,22 @@ export const ThirdwebProvider = <
useCoinbaseWalletListener();
return (
<ThirdwebProviderCore
thirdwebApiKey={thirdwebApiKey}
supportedWallets={supportedWallets}
authConfig={authConfig ? (authConfig.secureStorage ? authConfig : {...authConfig, secureStorage: new SecureStorage('auth')}) : undefined}
createWalletStorage={createWalletStorage}
{...restProps}
>
{children}
</ThirdwebProviderCore>
<DappContextProvider>
<ThirdwebProviderCore
thirdwebApiKey={thirdwebApiKey}
supportedWallets={supportedWallets}
authConfig={
authConfig
? authConfig.secureStorage
? authConfig
: { ...authConfig, secureStorage: new SecureStorage("auth") }
: undefined
}
createWalletStorage={createWalletStorage}
{...restProps}
>
{children}
</ThirdwebProviderCore>
</DappContextProvider>
);
};
@@ -12,17 +12,24 @@ export type Palette = {
iconSecondary: string;
iconHighlight: string;
warning: string;
linkPrimary: string;
labelBackground: string;
border: string;
black: string;
white: string;
red: string;
};
export const paletteBase = {
black: "black",
white: "white",
red: "red",
warning: "#F46565",
};
export const paletteLight: Palette = {
@@ -41,6 +48,8 @@ export const paletteLight: Palette = {
linkPrimary: "#3385FF",
labelBackground: "#3E3F43",
border: "#CBD2DB",
...paletteBase,
};
@@ -61,6 +70,8 @@ export const paletteDark: Palette = {
linkPrimary: "#3385FF",
labelBackground: "#3E3F43",
border: "#2E3339",
...paletteBase,
};

Some files were not shown because too many files have changed in this diff Show More