Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
df5f016d31 Version Packages (#1099)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-31 16:52:33 -07:00
iketwandGitHub 89102b0c89 [RN] fix bug after scanning wc uri (#1103) 2023-05-31 23:44:10 +00:00
Adam MajmudarandGitHub e1846c4469 [Auth] Default invalid before state to 5 minutes ago (#1101) 2023-05-31 22:05:16 +00:00
Manan TankandGitHub cc56037e64 [sdk] Reduce circular dependencies (#1102) 2023-05-31 21:23:03 +00:00
Manan TankandGitHub 23d90b3e77 [sdk] Reduce circular dependencies (#1100) 2023-05-31 19:58:48 +00:00
Manan TankandGitHub 6745078947 add sideEffects: false on auth, storage, unity-js-bridge (#1098) 2023-05-31 18:52:05 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
55d1f5c550 Version Packages (#1045)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-05-31 11:43:16 -07:00
iketwandGitHub b694f3c300 [Readme] fix react native title (#1097) 2023-05-31 17:58:09 +00:00
iketwandGitHub 217879ace1 [ReactNative] Make magic deps and camera deps optional (#1096) 2023-05-31 17:52:20 +00:00
Adam MajmudarandGitHub 35984362b0 [Wallets] Update gnosis safe signMessage function (#1087) 2023-05-31 00:47:23 +00:00
YashandGitHub bdabbef71a Fix create2 factory deployment (#1094) 2023-05-30 23:30:33 +00:00
Manan TankandGitHub 2f1df0b535 [sdk] reduce circular deps (#1093) 2023-05-30 22:16:06 +00:00
Joaquim VergesandGitHub da57610802 [SDK] return data from DeployTransaction.simulate() (#1091) 2023-05-30 21:51:46 +00:00
iketwandGitHub 119e785461 [RN] fix supportedWallets type (#1092) 2023-05-30 21:27:41 +00:00
Joaquim VergesandGitHub 5f1e6abb39 [Chains] add base-goerli as default chain (#1090) 2023-05-30 21:11:09 +00:00
Manan TankandGitHub 59206233e1 [sdk] reduce circular deps (#1089) 2023-05-30 20:52:34 +00:00
iketwandGitHub 4f99ccb49c [ReactNative/Wallets] Add sendTransaction for WCV1 handler (#1088) 2023-05-30 18:43:33 +00:00
Manan TankandGitHub 292a321a95 [wallets] Fix disconnect on switchChain in MetaMask (#1085) 2023-05-30 16:30:03 +00:00
Manan TankandGitHub 74f898ac28 [react] Fix Local wallet backup (#1084) 2023-05-30 15:20:32 +00:00
iketwandGitHub 431445e3c6 [Wallets] Fix bug getting account address (#1083) 2023-05-30 12:36:04 +00:00
fd7111d544 [react, react-core] add theme in WalletConfig.selectUI (#1068)
Co-authored-by: ikethirdweb <[email protected]>
2023-05-30 12:05:56 +00:00
ciaranightingaleandGitHub f3b2ae3f6d [SDK] add data to getAddress for Smart Wallet (#1073) 2023-05-27 01:17:39 +00:00
Manan TankandGitHub f5ae61aeba useSwitchChain instead of wallet.switchChain (#1078) 2023-05-26 21:50:37 +00:00
iketwandGitHub 37e0af5753 [ReactNative] Auto-connect sw with one EOA (#1077) 2023-05-26 20:56:37 +00:00
Manan TankandGitHub a034b0321f [sdk] reduce circular deps (#1075) 2023-05-26 18:48:28 +00:00
iketwandGitHub 8ffc597c06 [ReactNative] implement send_transaction for wcv2 (#1076) 2023-05-26 18:38:03 +00:00
Manan TankandGitHub 8eecf4c2d5 [sdk] reduce circular deps (#1072) 2023-05-26 10:54:33 +00:00
32cc54423e [CLI] De-duplicate addresses on generate (#1066)
Co-authored-by: Joaquim Verges <[email protected]>
2023-05-26 00:12:14 +00:00
iketwandGitHub bd86661f54 [ReactNative] Sign in with email/phone number (#1065) 2023-05-25 23:10:55 +00:00
Manan TankandGitHub ee4c7de25c [sdk] reduce circular deps (#1071) 2023-05-25 22:05:33 +00:00
Manan TankandGitHub c68a4bdd1f [sdk] reduce cyclic deps (#1069) 2023-05-25 20:24:39 +00:00
Joaquim VergesandGitHub 68fa1896f7 [Wallets] Expose smartWallet.deploy() and smartWallet.isDeployed() (#1070) 2023-05-25 19:17:23 +00:00
Manan TankandGitHub e21bdd0328 [react-core] return wallet instance from useConnect (#1067) 2023-05-25 16:37:31 +00:00
Manan TankandGitHub c85810eee3 [wallets] don't cache signer (#1064) 2023-05-24 23:17:20 +00:00
YashandGitHub d24a6146d8 [CLI] Add support for ZKSync (#1003) 2023-05-24 23:07:51 +00:00
FirekeeperandGitHub e94b7fdfed [thirdweb-unity-bridge] smart wallet webgl (#1063) 2023-05-24 22:39:44 +00:00
Joaquim VergesandGitHub 98efd090f6 [SDK] add transferFrom for 1155 contracts (#1062) 2023-05-24 21:24:21 +00:00
Joaquim VergesandGitHub 189daf0280 [SDK] add transferFrom for erc721 (#1061) 2023-05-24 19:54:29 +00:00
Joaquim VergesandGitHub f7b352a585 [SDK] Expose getSignerAddress on tx object (#1060) 2023-05-24 17:57:58 +00:00
iketwandGitHub 56ad0867bd [RN] Use walletConfig's selectUI to render Choose your Wallet item (#1059) 2023-05-24 14:16:00 +00:00
Manan TankandGitHub d565100614 [sdk] reduce cyclic deps (#1055) 2023-05-23 16:34:33 +00:00
Manan TankandGitHub edaa5b2e6c [sdk] reduce cyclic deps (#1054) 2023-05-23 14:08:45 +00:00
iketwandGitHub 77123a9a5a [ReactNative] Adds WC qrcode support for Connect an App (#1052) 2023-05-23 00:26:39 +00:00
Manan TankandGitHub 6fd10f94b4 [chains] Fix tree shaking in thirdweb-dev/chains package (#1047) 2023-05-22 22:42:05 +00:00
Nacho IacovinoandGitHub afae0873b0 [JS] Fix check for erc1155 claim conditions (#1051) 2023-05-22 21:55:20 +00:00
Nacho IacovinoandGitHub 4a1d758110 [JS] Fix creator phase check (#1049) 2023-05-22 21:09:21 +00:00
YashandGitHub c6e74ef0b0 [SDK] Allow overrides for read actions (#1043) 2023-05-22 19:43:30 +00:00
iketwandGitHub bba9767adf [ReactNative-Wallets] Enables SmartWallet to connect to an app, with implementation in React Native (#1010) 2023-05-22 17:58:12 +00:00
Manan TankandGitHub a5e509438d [react-core] do not re-throw auto-connect error (#1044) 2023-05-22 16:14:35 +00:00
Manan TankandGitHub f461290216 [react] Fix smart wallet config type (#1042) 2023-05-22 16:01:24 +00:00
387 changed files with 14088 additions and 7893 deletions
+8 -8
View File
@@ -20,14 +20,14 @@
## Packages
| Package | Description | Latest Version |
| --------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react](./packages/react-native) | Ultimate collection of React hooks for your native web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| Package | Description | Latest Version |
| ---------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react-native](./packages/react-native) | Ultimate collection of React hooks for your native mobile web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
## Documentation
+18
View File
@@ -1,5 +1,23 @@
# @thirdweb-dev/auth
## 3.0.23
### Patch Changes
- [#1101](https://github.com/thirdweb-dev/js/pull/1101) [`e1846c44`](https://github.com/thirdweb-dev/js/commit/e1846c44696bcb25a6a137d63e117e7d2ce9d979) Thanks [@adam-maj](https://github.com/adam-maj)! - Bump invalid before with 5 minute window
- [#1098](https://github.com/thirdweb-dev/js/pull/1098) [`67450789`](https://github.com/thirdweb-dev/js/commit/67450789473b6008b86453ee4f4c7b99461223a6) Thanks [@MananTank](https://github.com/MananTank)! - add sideEffects: false in package.json
- Updated dependencies []:
- @thirdweb-dev/wallets@0.2.24
## 3.0.22
### Patch Changes
- Updated dependencies [[`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`68fa1896`](https://github.com/thirdweb-dev/js/commit/68fa1896f75d3514e00cc380924fd8bc623064f0), [`292a321a`](https://github.com/thirdweb-dev/js/commit/292a321a95ed2d847097eed205353dd69eeb8d54), [`f3b2ae3f`](https://github.com/thirdweb-dev/js/commit/f3b2ae3f6d9c66356c521d3b9c2a6c096dbb4b57), [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`35984362`](https://github.com/thirdweb-dev/js/commit/35984362b0a60e5b9c3d3c9731450a8f47deb1c4)]:
- @thirdweb-dev/wallets@0.2.23
## 3.0.21
### Patch Changes
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.0.21",
"version": "3.0.23",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
@@ -54,6 +54,7 @@
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/auth",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
"sideEffects": false,
"scripts": {
"build": "preconstruct build",
"format": "prettier --write 'src/**/*'",
+2 -1
View File
@@ -54,7 +54,8 @@ export class ThirdwebAuth {
nonce: parsedOptions?.nonce,
expiration_time:
parsedOptions?.expirationTime || new Date(Date.now() + 1000 * 60 * 5),
invalid_before: parsedOptions?.invalidBefore,
invalid_before:
parsedOptions?.invalidBefore || new Date(Date.now() - 1000 * 60 * 5),
resources: parsedOptions?.resources,
});
+12
View File
@@ -1,5 +1,17 @@
# @thirdweb-dev/chains
## 0.1.19
### Patch Changes
- [#1065](https://github.com/thirdweb-dev/js/pull/1065) [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a) Thanks [@iketw](https://github.com/iketw)! - [Chains] update chains
- [#1064](https://github.com/thirdweb-dev/js/pull/1064) [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c) Thanks [@MananTank](https://github.com/MananTank)! - Do not cache signer in wallets
- [#1047](https://github.com/thirdweb-dev/js/pull/1047) [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d) Thanks [@MananTank](https://github.com/MananTank)! - Fix tree-shaking issue in `@thirdweb-dev/chains`
- [#1090](https://github.com/thirdweb-dev/js/pull/1090) [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add base-goerli to default chains
## 0.1.18
### Patch Changes
+5 -2
View File
@@ -11,20 +11,23 @@ export default {
"rpc": [
"https://gnosis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.gnosischain.com",
"https://rpc.gnosis.gateway.fm",
"https://rpc.ankr.com/gnosis",
"https://gnosischain-rpc.gateway.pokt.network",
"https://gnosis-mainnet.public.blastapi.io",
"https://gnosis.api.onfinality.io/public",
"https://gnosis.blockpi.network/v1/rpc/public",
"https://web3endpoints.com/gnosischain-mainnet",
"wss://rpc.gnosischain.com/wss"
],
"faucets": [
"https://gnosisfaucet.com",
"https://faucet.gimlu.com/gnosis",
"https://stakely.io/faucet/gnosis-chain-xdai",
"https://faucet.prussia.dev/xdai"
],
"nativeCurrency": {
"name": "xDAI",
"symbol": "xDAI",
"symbol": "XDAI",
"decimals": 18
},
"infoURL": "https://docs.gnosischain.com",
+7 -6
View File
@@ -1,7 +1,7 @@
import type { Chain } from "../src/types";
export default {
"name": "Chiado Testnet",
"chain": "CHI",
"name": "Gnosis Chiado Testnet",
"chain": "GNO",
"icon": {
"url": "ipfs://bafybeidk4swpgdyqmpz6shd5onvpaujvwiwthrhypufnwr6xh3dausz2dm",
"width": 1800,
@@ -9,16 +9,17 @@ export default {
"format": "png"
},
"rpc": [
"https://chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://gnosis-chiado-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.chiadochain.net",
"https://rpc.eu-central-2.gateway.fm/v3/gnosis/archival/chiado"
"https://rpc.chiado.gnosis.gateway.fm",
"wss://rpc.chiadochain.net/wss"
],
"faucets": [
"https://gnosisfaucet.com"
],
"nativeCurrency": {
"name": "Chiado xDAI",
"symbol": "xDAI",
"symbol": "XDAI",
"decimals": 18
},
"infoURL": "https://docs.gnosischain.com",
@@ -39,5 +40,5 @@ export default {
}
],
"testnet": true,
"slug": "chiado-testnet"
"slug": "gnosis-chiado-testnet"
} as const satisfies Chain;
+10 -10
View File
@@ -10,7 +10,7 @@ export default {
"faucets": [],
"nativeCurrency": {
"name": "Siberium",
"symbol": "SBR",
"symbol": "SIBR",
"decimals": 18
},
"infoURL": "https://siberium.net",
@@ -18,9 +18,9 @@ export default {
"chainId": 111111,
"networkId": 111111,
"icon": {
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
"width": 1920,
"height": 1920,
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
"width": 512,
"height": 512,
"format": "svg"
},
"explorers": [
@@ -28,9 +28,9 @@ export default {
"name": "Siberium Mainnet Explorer - blockscout - 1",
"url": "https://explorer.main.siberium.net",
"icon": {
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
"width": 1920,
"height": 1920,
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
"width": 512,
"height": 512,
"format": "svg"
},
"standard": "EIP3091"
@@ -39,9 +39,9 @@ export default {
"name": "Siberium Mainnet Explorer - blockscout - 2",
"url": "https://explorer.main.siberium.net.ru",
"icon": {
"url": "ipfs://QmVDeoGo2TZPDWiaNDdPCnH2tz2BCQ7viw8ugdDWnU5LFq",
"width": 1920,
"height": 1920,
"url": "ipfs://QmYeMdWDZ1iaBFeSPorRyPi7RuSXTdDKTgW3rfnUf3W5ne",
"width": 512,
"height": 512,
"format": "svg"
},
"standard": "EIP3091"
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Origin Testnet",
"chain": "Origin",
"rpc": [
"https://origin-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://json-rpc.origin.uptick.network"
],
"faucets": [],
"nativeCurrency": {
"name": "Origin",
"symbol": "UOC",
"decimals": 18
},
"infoURL": "https://www.uptick.network",
"shortName": "auoc",
"chainId": 1170,
"networkId": 1170,
"icon": {
"url": "ipfs://QmRGJ6PqYHDTWuUQ6xfnK8S82NzRXiMjTnSGat9qtLuaLP",
"width": 400,
"height": 400,
"format": "png"
},
"explorers": [
{
"name": "Origin Explorer",
"url": "https://evm-explorer.origin.uptick.network",
"icon": {
"url": "ipfs://QmRGJ6PqYHDTWuUQ6xfnK8S82NzRXiMjTnSGat9qtLuaLP",
"width": 400,
"height": 400,
"format": "png"
},
"standard": "none"
}
],
"testnet": true,
"slug": "origin-testnet"
} as const satisfies Chain;
+4 -4
View File
@@ -4,17 +4,17 @@ export default {
"chain": "TSCS",
"rpc": [
"https://super-smart-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.superexchain.com:8544"
"https://testnetrpc.scschain.com"
],
"faucets": [
"https://testnet.superexchain.com"
"https://testnet.scschain.com"
],
"nativeCurrency": {
"name": "Super Chain Native Token",
"symbol": "TSCS",
"decimals": 18
},
"infoURL": "https://testnet.superexchain.com",
"infoURL": "https://testnet.scschain.com",
"shortName": "tscs",
"chainId": 1969,
"networkId": 1969,
@@ -27,7 +27,7 @@ export default {
"explorers": [
{
"name": "blockscout",
"url": "https://testnetscan.superexchain.com",
"url": "https://testnetscan.scschain.com",
"standard": "EIP3091"
}
],
+3 -3
View File
@@ -4,7 +4,7 @@ export default {
"chain": "SCS",
"rpc": [
"https://super-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://superexchain.com:8545"
"https://rpc.scschain.com"
],
"faucets": [],
"nativeCurrency": {
@@ -12,7 +12,7 @@ export default {
"symbol": "SCS",
"decimals": 18
},
"infoURL": "https://superexchain.com",
"infoURL": "https://scschain.com",
"shortName": "scs",
"chainId": 1970,
"networkId": 1970,
@@ -25,7 +25,7 @@ export default {
"explorers": [
{
"name": "blockscout",
"url": "https://scan.superexchain.com",
"url": "https://scan.scschain.com",
"standard": "EIP3091"
}
],
+4 -4
View File
@@ -12,15 +12,15 @@ export default {
"symbol": "BTT",
"decimals": 18
},
"infoURL": "https://bittorrentchain.io/",
"infoURL": "https:/bt.io",
"shortName": "BTT",
"chainId": 199,
"networkId": 199,
"explorers": [
{
"name": "bttcscan",
"url": "https://scan.bittorrentchain.io",
"standard": "none"
"name": "BitTorrent Chain Explorer",
"url": "https://bttcscan.com",
"standard": "EIP3091"
}
],
"testnet": false,
+3 -3
View File
@@ -4,7 +4,7 @@ export default {
"chain": "SHIB",
"rpc": [
"https://shibachain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.shibachain.net"
"https://rpc.shibchain.org"
],
"faucets": [],
"nativeCurrency": {
@@ -12,14 +12,14 @@ export default {
"symbol": "SHIB",
"decimals": 18
},
"infoURL": "https://www.shibachain.net",
"infoURL": "https://shibchain.org",
"shortName": "shib",
"chainId": 27,
"networkId": 27,
"explorers": [
{
"name": "Shiba Explorer",
"url": "https://exp.shibachain.net",
"url": "https://exp.shibchain.org",
"standard": "none"
}
],
+3 -3
View File
@@ -3,9 +3,9 @@ export default {
"name": "LaChain",
"chain": "LaChain",
"icon": {
"url": "ipfs://bafkreiecoqvit2mikpbpbtzy2zrn6e7fvqdegm72sdcathdwmgiyuzey7u",
"width": 104,
"height": 114,
"url": "ipfs://QmQxGA6rhuCQDXUueVcNvFRhMEWisyTmnF57TqL7h6k6cZ",
"width": 1280,
"height": 1280,
"format": "png"
},
"rpc": [
-37
View File
@@ -1,37 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "Optimism on Gnosis",
"chain": "OGC",
"rpc": [
"https://optimism-on-gnosis.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://optimism.gnosischain.com",
"wss://optimism.gnosischain.com/wss"
],
"faucets": [
"https://faucet.gimlu.com/gnosis"
],
"nativeCurrency": {
"name": "xDAI",
"symbol": "xDAI",
"decimals": 18
},
"infoURL": "https://www.xdaichain.com/for-developers/optimism-optimistic-rollups-on-gc",
"shortName": "ogc",
"chainId": 300,
"networkId": 300,
"explorers": [
{
"name": "blockscout",
"url": "https://blockscout.com/xdai/optimism",
"icon": {
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
"width": 512,
"height": 512,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "optimism-on-gnosis"
} as const satisfies Chain;
+28
View File
@@ -0,0 +1,28 @@
import type { Chain } from "../src/types";
export default {
"name": "Canxium Mainnet",
"chain": "CAU",
"rpc": [
"https://canxium.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.canxium.org"
],
"faucets": [],
"nativeCurrency": {
"name": "Canxium",
"symbol": "CAU",
"decimals": 18
},
"infoURL": "https://canxium.org",
"shortName": "cau",
"chainId": 3003,
"networkId": 3003,
"explorers": [
{
"name": "canxium explorer",
"url": "https://explorer.canxium.org",
"standard": "none"
}
],
"testnet": false,
"slug": "canxium"
} as const satisfies Chain;
+45
View File
@@ -0,0 +1,45 @@
import type { Chain } from "../src/types";
export default {
"name": "PLAYA3ULL GAMES",
"chain": "3ULL",
"rpc": [
"https://playa3ull-games.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.mainnet.playa3ull.games"
],
"faucets": [],
"nativeCurrency": {
"name": "3ULL",
"symbol": "3ULL",
"decimals": 18
},
"features": [
{
"name": "EIP1559"
}
],
"infoURL": "https://playa3ull.games",
"shortName": "3ULL",
"chainId": 3011,
"networkId": 3011,
"icon": {
"url": "ipfs://bafkreib62bv2d65d7nidojgpkgatrt7smee2l4ov6i6ozqhpfaqsonxku4",
"width": 512,
"height": 443,
"format": "png"
},
"explorers": [
{
"name": "PLAYA3ULL GAMES Explorer",
"url": "https://3011.routescan.io",
"icon": {
"url": "ipfs://bafkreib62bv2d65d7nidojgpkgatrt7smee2l4ov6i6ozqhpfaqsonxku4",
"width": 512,
"height": 443,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "playa3ull-games"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "SecureChain Testnet",
"chain": "SCAI",
"icon": {
"url": "ipfs://Qme2Z8VFYjhHGfLQPBnfseNpEdRfmTDy7VXqrdH4AHETJf",
"width": 150,
"height": 150,
"format": "png"
},
"rpc": [
"https://securechain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-rpc.securechain.ai"
],
"faucets": [
"https://faucet.securechain.ai"
],
"nativeCurrency": {
"name": "SCAI",
"symbol": "SCAI",
"decimals": 18
},
"infoURL": "https://securechain.ai",
"shortName": "SCAIt",
"chainId": 3434,
"networkId": 3434,
"explorers": [
{
"name": "SecureChain",
"url": "https://testnet.securechain.ai",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "securechain-testnet"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Bitfinity Network Testnet",
"chain": "BFT",
"rpc": [
"https://bitfinity-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.bitfinity.network"
],
"faucets": [
"https://bitfinity.network/faucet"
],
"nativeCurrency": {
"name": "BITFINITY",
"symbol": "BFT",
"decimals": 18
},
"infoURL": "https://bitfinity.network",
"shortName": "Bitfinity",
"chainId": 355113,
"networkId": 355113,
"explorers": [
{
"name": "Bitfinity Block Explorer",
"url": "https://explorer.bitfinity.network",
"icon": {
"url": "ipfs://bafkreiczbhnoc5wpjikskmehexmg3xmqr4fchrny64db4wmk3lrygqik5e",
"width": 796,
"height": 129,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "bitfinity-network-testnet"
} as const satisfies Chain;
+3 -3
View File
@@ -3,9 +3,9 @@ export default {
"name": "LaTestnet",
"chain": "LaTestnet",
"icon": {
"url": "ipfs://bafkreiecoqvit2mikpbpbtzy2zrn6e7fvqdegm72sdcathdwmgiyuzey7u",
"width": 104,
"height": 114,
"url": "ipfs://QmQxGA6rhuCQDXUueVcNvFRhMEWisyTmnF57TqL7h6k6cZ",
"width": 1280,
"height": 1280,
"format": "png"
},
"rpc": [
+12 -5
View File
@@ -1,11 +1,18 @@
import type { Chain } from "../src/types";
export default {
"name": "Floripa",
"title": "Wireshape Testnet Floripa",
"name": "Wireshape Floripa Testnet",
"title": "Wireshape Floripa Testnet",
"chain": "Wireshape",
"icon": {
"url": "ipfs://QmTAyT3YrW2654CBRqRkec2cCznv6EBsbsRc2y6WQPbvXx",
"width": 1280,
"height": 1280,
"format": "png"
},
"rpc": [
"https://floripa.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-floripa.wireshape.org"
"https://wireshape-floripa-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-floripa.wireshape.org",
"https://floripa.rpc.thirdweb.com"
],
"faucets": [],
"nativeCurrency": {
@@ -25,5 +32,5 @@ export default {
}
],
"testnet": true,
"slug": "floripa"
"slug": "wireshape-floripa-testnet"
} as const satisfies Chain;
+25
View File
@@ -0,0 +1,25 @@
import type { Chain } from "../src/types";
export default {
"name": "Scroll Sepolia Testnet",
"chain": "ETH",
"status": "incubating",
"rpc": [],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://scroll.io",
"shortName": "scr-sepolia",
"chainId": 534351,
"networkId": 534351,
"explorers": [],
"parent": {
"type": "L2",
"chain": "eip155-11155111",
"bridges": []
},
"testnet": true,
"slug": "scroll-sepolia-testnet"
} as const satisfies Chain;
+1
View File
@@ -2,6 +2,7 @@ import type { Chain } from "../src/types";
export default {
"name": "Scroll",
"chain": "ETH",
"status": "incubating",
"rpc": [],
"faucets": [],
"nativeCurrency": {
+2 -2
View File
@@ -2,7 +2,7 @@ import type { Chain } from "../src/types";
export default {
"name": "Scroll Alpha Testnet",
"chain": "ETH",
"status": "incubating",
"status": "active",
"rpc": [
"https://scroll-alpha-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://alpha-rpc.scroll.io/l2"
@@ -25,7 +25,7 @@ export default {
},
{
"name": "Scroll Alpha Testnet Block Explorer",
"url": "https://scrollexplorer.unifra.io",
"url": "https://scrollscan.co",
"standard": "EIP3091"
}
],
-30
View File
@@ -1,30 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "Scroll Pre-Alpha Testnet",
"chain": "ETH",
"rpc": [
"https://scroll-pre-alpha-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://prealpha-rpc.scroll.io/l2"
],
"faucets": [
"https://prealpha.scroll.io/faucet"
],
"nativeCurrency": {
"name": "Ether",
"symbol": "TSETH",
"decimals": 18
},
"infoURL": "https://scroll.io",
"shortName": "scr-prealpha",
"chainId": 534354,
"networkId": 534354,
"explorers": [
{
"name": "Scroll L2 Block Explorer",
"url": "https://l2scan.scroll.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "scroll-pre-alpha-testnet"
} as const satisfies Chain;
+2 -2
View File
@@ -7,8 +7,8 @@ export default {
"https://linea-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"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}"
"https://linea-goerli.infura.io/v3/${INFURA_API_KEY}",
"wss://linea-goerli.infura.io/v3/${INFURA_API_KEY}"
],
"faucets": [
"https://faucetlink.to/goerli"
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "AxelChain Dev-Net",
"chain": "AXEL",
"rpc": [
"https://axelchain-dev-net.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://aium-rpc-dev.viacube.com"
],
"faucets": [],
"nativeCurrency": {
"name": "Axelium",
"symbol": "AIUM",
"decimals": 18
},
"infoURL": "https://www.axel.org",
"shortName": "aium-dev",
"chainId": 61800,
"networkId": 61800,
"icon": {
"url": "ipfs://QmNx8FRacfNeawhkjk5p57EKzDHkLGMaBBmK2VRL5CB2P2",
"width": 40,
"height": 40,
"format": "svg"
},
"explorers": [
{
"name": "AxelChain Dev-Net Explorer",
"url": "https://devexplorer2.viacube.com",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "axelchain-dev-net"
} as const satisfies Chain;
+44
View File
@@ -0,0 +1,44 @@
import type { Chain } from "../src/types";
export default {
"name": "Fox Testnet Network",
"chain": "FOX",
"rpc": [
"https://fox-testnet-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-testnet-v1.foxchain.app/",
"https://rpc2-testnet-v1.foxchain.app/",
"https://rpc3-testnet-v1.foxchain.app"
],
"faucets": [
"https://faucet.foxchain.app"
],
"nativeCurrency": {
"name": "FOX Native Token",
"symbol": "tFOX",
"decimals": 18
},
"infoURL": "https://foxchain.app",
"shortName": "fox",
"chainId": 6565,
"networkId": 6565,
"icon": {
"url": "ipfs://Qmbp1rwhtRr6JQRyYqyfLqkbmzXr1T17zbmChsi2ouvg3M",
"width": 100,
"height": 100,
"format": "png"
},
"explorers": [
{
"name": "FOX Testnet Explorer",
"icon": {
"url": "ipfs://Qmbp1rwhtRr6JQRyYqyfLqkbmzXr1T17zbmChsi2ouvg3M",
"width": 100,
"height": 100,
"format": "png"
},
"url": "https://testnet.foxscan.app",
"standard": "none"
}
],
"testnet": true,
"slug": "fox-testnet-network"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Shibarium Beta",
"chain": "Shibarium",
"icon": {
"url": "ipfs://QmYNVkoZgRjDBQzJz6kog9mA2yPzQFW2oSKvhnkwuBhLQE",
"width": 2000,
"height": 2000,
"format": "png"
},
"rpc": [
"https://shibarium-beta.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://puppynet.shibrpc.com"
],
"faucets": [],
"nativeCurrency": {
"name": "BONE",
"symbol": "BONE",
"decimals": 18
},
"infoURL": "https://beta.shibariumtech.com",
"shortName": "shibarium",
"chainId": 719,
"networkId": 719,
"explorers": [
{
"name": "shibscan",
"url": "https://puppyscan.shib.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "shibarium-beta"
} as const satisfies Chain;
+43
View File
@@ -0,0 +1,43 @@
import type { Chain } from "../src/types";
export default {
"name": "Dragonfly Mainnet (Hexapod)",
"chain": "Dragonfly",
"icon": {
"url": "ipfs://QmPXhdPGufjcPzZ9Y6nY6QyW8MgA6793L88iPMRh1Q3gjJ",
"width": 512,
"height": 366,
"format": "png"
},
"rpc": [
"https://dragonfly-hexapod.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://dragonfly-rpc.switch.ch",
"https://dragonfly-rpc.kore-technologies.ch",
"https://dragonfly-rpc.phoenix-systems.io",
"https://dragonfly-rpc.block-spirit.ch"
],
"faucets": [],
"nativeCurrency": {
"name": "Dragonfly",
"symbol": "DFLY",
"decimals": 18
},
"infoURL": "https://hexapod.network",
"shortName": "dfly",
"chainId": 78281,
"networkId": 78281,
"explorers": [
{
"name": "Dragonfly Blockscout",
"url": "https://blockscout.dragonfly.hexapod.network",
"icon": {
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
"width": 512,
"height": 512,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "dragonfly-hexapod"
} as const satisfies Chain;
+47
View File
@@ -0,0 +1,47 @@
import type { Chain } from "../src/types";
export default {
"name": "Mantis Testnet (Hexapod)",
"chain": "Mantis",
"icon": {
"url": "ipfs://Qma8dDhxSSVUyzV8Pu5bo252WaZEEikYFndRh7LVktvQEy",
"width": 512,
"height": 330,
"format": "png"
},
"rpc": [
"https://mantis-testnet-hexapod.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mantis-rpc.switch.ch",
"https://mantis-rpc.kore-technologies.ch",
"https://mantis-rpc.phoenix-systems.io"
],
"faucets": [
"https://mantis.switch.ch/faucet",
"https://mantis.kore-technologies.ch/faucet",
"https://mantis.phoenix-systems.io/faucet",
"https://mantis.block-spirit.ch/faucet"
],
"nativeCurrency": {
"name": "Mantis",
"symbol": "MANTIS",
"decimals": 18
},
"infoURL": "https://hexapod.network",
"shortName": "mantis",
"chainId": 96970,
"networkId": 96970,
"explorers": [
{
"name": "Mantis Blockscout",
"url": "https://blockscout.mantis.hexapod.network",
"icon": {
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
"width": 512,
"height": 512,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "mantis-testnet-hexapod"
} as const satisfies Chain;
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "PepeNetwork Mainnet",
"chain": "PepeNetwork",
"rpc": [
"https://pepenetwork.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-mainnet.pepenetwork.io"
],
"faucets": [],
"nativeCurrency": {
"name": "Pepe",
"symbol": "WPEPE",
"decimals": 18
},
"infoURL": "https://pepenetwork.io",
"shortName": "pn",
"chainId": 9779,
"networkId": 9779,
"icon": {
"url": "ipfs://QmPX3uipdwd195z1MJff7uj8hpZdSuVvM5z47eiz2o7Gz5",
"width": 960,
"height": 944,
"format": "png"
},
"explorers": [
{
"name": "Pepe Explorer",
"url": "https://explorer.pepenetwork.io",
"icon": {
"url": "ipfs://QmPX3uipdwd195z1MJff7uj8hpZdSuVvM5z47eiz2o7Gz5",
"width": 960,
"height": 944,
"format": "png"
},
"standard": "none"
}
],
"testnet": false,
"slug": "pepenetwork"
} as const satisfies Chain;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.18",
"version": "0.1.19",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
+59 -17
View File
@@ -81,6 +81,7 @@ chains = chains
const imports = [];
const exports = [];
const exportNames = [];
const exportNameToChain = {};
const takenSlugs = {};
@@ -216,9 +217,13 @@ export default ${JSON.stringify(chain, null, 2)} as const satisfies Chain;`,
imports.push(`import c${chain.chainId} from "../chains/${chain.chainId}";`);
exports.push(`export const ${exportName} = c${chain.chainId};`);
exports.push(
`export { default as ${exportName} } from "../chains/${chain.chainId}"`,
);
exportNames.push(exportName);
const key = `c${chain.chainId}`;
exportNames.push(key);
exportNameToChain[key] = chain;
}
fs.writeFileSync(
@@ -229,22 +234,58 @@ import type { Chain } from "./types";
${exports.join("\n")}
export * from "./types";
export * from "./utils";
export const defaultChains = [Ethereum, Goerli, Polygon, Mumbai, Arbitrum, ArbitrumGoerli, Optimism, OptimismGoerli, Binance, BinanceTestnet, Fantom, FantomTestnet, Avalanche, AvalancheFuji, Localhost];
export const allChains = [${exportNames.join(", ")}];
export const defaultChains = [c1, c5, c84531, c137, c80001, c42161, c421613, c10, c420, c56, c97, c250, c4002, c43114, c43113, c1337];
export const allChains: Chain[] = [${exportNames.join(", ")}];
const chainsById = {
${exportNames.map((n) => `[${n}.chainId]: ${n}`).join(",\n")}
} as const;
type ChainsById = {
${exportNames
.map((n) => `${exportNameToChain[n].chainId}: typeof ${n}`)
.join(",\n")}
};
const chainIdsBySlug = {
${exportNames.map((n) => `[${n}.slug]: ${n}.chainId`).join(",\n")}
} as const;
type ChainIdsBySlug = {
${exportNames
.map(
(n) => `"${exportNameToChain[n].slug}": ${exportNameToChain[n].chainId}`,
)
.join(",\n")}
};
let _chainsById: Record<number, Chain>;
let _chainIdsBySlug: Record<string, number>;
function getChainsById() {
if (_chainsById) {
return _chainsById;
}
_chainsById = {};
allChains.forEach((chain) => {
_chainsById[chain.chainId] = chain;
});
return _chainsById;
}
export function getChainIdsBySlug() {
if (_chainIdsBySlug) {
return _chainIdsBySlug;
}
_chainIdsBySlug = {};
allChains.forEach((chain) => {
_chainIdsBySlug[chain.slug] = chain.chainId;
});
return _chainIdsBySlug;
}
export type ChainSlug = keyof ChainIdsBySlug;
export type ChainId = keyof ChainsById;
function isValidChainId(chainId: number): chainId is ChainId {
const chainsById = getChainsById();
return chainId in chainsById;
}
function isValidChainSlug(slug: string): slug is ChainSlug {
const chainIdsBySlug = getChainIdsBySlug();
return slug in chainIdsBySlug;
}
@@ -252,7 +293,8 @@ export function getChainByChainId<TChainId extends ChainId>(
chainId: TChainId | (number & {}),
) {
if (isValidChainId(chainId)) {
return chainsById[chainId] as (typeof chainsById)[TChainId];
const chainsById = getChainsById();
return chainsById[chainId] as ChainsById[TChainId];
}
throw new Error(\`Chain with chainId "\${chainId}" not found\`);
}
@@ -261,13 +303,13 @@ export function getChainBySlug<TSlug extends ChainSlug>(
slug: TSlug | (string & {}),
) {
if (isValidChainSlug(slug)) {
return chainsById[chainIdsBySlug[slug]] as (typeof chainsById)[
(typeof chainIdsBySlug)[TSlug]
];
const chainIdsBySlug = getChainIdsBySlug();
const chainsById = getChainsById();
return chainsById[
chainIdsBySlug[slug]
] as ChainsById[ChainIdsBySlug[TSlug]];
}
throw new Error(\`Chain with slug "\${slug}" not found\`);
}
export type ChainSlug = keyof typeof chainIdsBySlug;
export type ChainId = keyof typeof chainsById;`,
`,
);
+2758 -2688
View File
File diff suppressed because one or more lines are too long
+20
View File
@@ -1,5 +1,25 @@
# thirdweb
## 0.10.20
### Patch Changes
- Updated dependencies [[`23d90b3e`](https://github.com/thirdweb-dev/js/commit/23d90b3e779a5bfdb7058b8c51349d9c278fcbce), [`cc56037e`](https://github.com/thirdweb-dev/js/commit/cc56037e64560b9e0fc16eb0ac7cc2e47e2c9fdf), [`67450789`](https://github.com/thirdweb-dev/js/commit/67450789473b6008b86453ee4f4c7b99461223a6)]:
- @thirdweb-dev/sdk@3.10.19
- @thirdweb-dev/storage@1.1.4
## 0.10.19
### Patch Changes
- [#1003](https://github.com/thirdweb-dev/js/pull/1003) [`d24a6146`](https://github.com/thirdweb-dev/js/commit/d24a6146d8a1c623c39687baf6f579e721ef99c6) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Add support for ZKSync
- [#1066](https://github.com/thirdweb-dev/js/pull/1066) [`32cc5442`](https://github.com/thirdweb-dev/js/commit/32cc54423e51b22cb665bf6106c484dfb45206b3) Thanks [@adam-maj](https://github.com/adam-maj)! - Deduplicate addresses when running thirdweb generate
- Updated dependencies [[`2f1df0b5`](https://github.com/thirdweb-dev/js/commit/2f1df0b5354a8ee55089b2c1e61c058788d890f1), [`189daf02`](https://github.com/thirdweb-dev/js/commit/189daf0280a90ed730200088948526a594da3408), [`afae0873`](https://github.com/thirdweb-dev/js/commit/afae0873b0e3f9741f5a9c44c5d255f38c6a9111), [`c6e74ef0`](https://github.com/thirdweb-dev/js/commit/c6e74ef0b00210f52e6778c548061376d3ba7001), [`ee4c7de2`](https://github.com/thirdweb-dev/js/commit/ee4c7de25cb63f99f33b90da8e26293bbfbe6f3e), [`f7b352a5`](https://github.com/thirdweb-dev/js/commit/f7b352a585a23726eaa3be116f65db56b005f4d8), [`4a1d7581`](https://github.com/thirdweb-dev/js/commit/4a1d75811058d6974616bdc12a6040cea5444e40), [`bdabbef7`](https://github.com/thirdweb-dev/js/commit/bdabbef71a2421a2dceb384f93bb6a59a3ddf007), [`59206233`](https://github.com/thirdweb-dev/js/commit/59206233e15ccfe3dc32047060055219d35938f2), [`98efd090`](https://github.com/thirdweb-dev/js/commit/98efd090f63cfd9dfed7b89b20b6e43db88cf75c), [`8eecf4c2`](https://github.com/thirdweb-dev/js/commit/8eecf4c2d5b0d6447ad5b9cdbf0269818bbb3498), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`d5651006`](https://github.com/thirdweb-dev/js/commit/d565100614d7d4e256554f998b8ce978a566051c), [`da576108`](https://github.com/thirdweb-dev/js/commit/da5761080288c3b325f54fb56c80f96405a1cb5d), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d), [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c), [`a034b032`](https://github.com/thirdweb-dev/js/commit/a034b0321fd0113ed51d95d538b5c3020615c227)]:
- @thirdweb-dev/sdk@3.10.18
- @thirdweb-dev/chains@0.1.19
## 0.10.18
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.10.18",
"version": "0.10.20",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+1
View File
@@ -294,6 +294,7 @@ const main = async () => {
"--dynamic",
"Deploy a dynamic smart contract made up of extensions to blockchains",
)
.option("--zksync", "Deploy on ZKSync")
.action(async (options) => {
const url = await deploy(options);
if (url) {
+6 -4
View File
@@ -52,7 +52,9 @@ export async function processProject(
logger.debug("Processing project at path " + projectPath);
const projectType = await detect(projectPath, options);
const projectType = options.zksync
? "hardhat"
: await detect(projectPath, options);
if (projectType === "none") {
if (command === "deploy") {
@@ -220,13 +222,13 @@ export async function processProject(
const soliditySDKPackage = "@thirdweb-dev/contracts";
let usesSoliditySDK = false;
if(options.dynamic) {
if (options.dynamic) {
if (selectedRouter.name === "thirdweb-router") {
const deployArgs: TWRouterParams = {
extensionRegistry: EXTENSION_REGISTRY_ADDRESS,
extensionNames: selectedContracts.map((c) => c.name),
};
const outputDeployArgs = JSON.stringify(deployArgs, undefined, 2);
writeFileSync("./deployArgs.json", outputDeployArgs, "utf-8");
info(
@@ -236,7 +238,7 @@ export async function processProject(
const deployArgs: RouterParams = await formatToExtensions(
selectedContracts,
);
const outputDeployArgs = JSON.stringify(deployArgs, undefined, 2);
writeFileSync("./deployArgs.json", outputDeployArgs, "utf-8");
info(
+2 -1
View File
@@ -9,7 +9,7 @@ import { TruffleBuilder } from "./truffle";
export default async function build(
path: string,
projectType: ProjectType,
options: { clean: boolean },
options: any,
): Promise<{
contracts: ContractPayload[];
}> {
@@ -40,5 +40,6 @@ export default async function build(
name: "",
projectPath: path,
clean: options.clean,
zksync: options.zksync,
});
}
+15 -12
View File
@@ -12,6 +12,7 @@ export abstract class BaseBuilder implements IBuilder {
abi: any[],
bytecode: string,
name: string,
ignoreIpfsHash?: boolean,
): boolean {
if (
!bytecode ||
@@ -31,19 +32,21 @@ export abstract class BaseBuilder implements IBuilder {
logger.debug(`Skipping '${name}'.`);
return false;
}
// ensure that we can extract IPFS hashes from the bytecode
let ipfsHash;
try {
ipfsHash = extractIPFSHashFromBytecode(bytecode);
} catch (e) {
logger.debug(`Error extracting IPFS hash from '${name}': ${e}`);
}
if (!ignoreIpfsHash) {
// ensure that we can extract IPFS hashes from the bytecode
let ipfsHash;
try {
ipfsHash = extractIPFSHashFromBytecode(bytecode);
} catch (e) {
logger.debug(`Error extracting IPFS hash from '${name}': ${e}`);
}
if (!ipfsHash) {
logger.debug(
`Cannot resolve build metadata IPFS hash for contract '${name}'. Skipping.`,
);
return false;
if (!ipfsHash) {
logger.debug(
`Cannot resolve build metadata IPFS hash for contract '${name}'. Skipping.`,
);
return false;
}
}
return true;
}
+33 -11
View File
@@ -1,7 +1,6 @@
import { findFiles } from "../../common/file-helper";
import { execute } from "../helpers/exec";
import { logger } from "../helpers/logger";
import { CompileOptions } from "../interfaces/Builder";
import { ContractPayload } from "../interfaces/ContractPayload";
import { BaseBuilder } from "./builder-base";
import { existsSync, readFileSync } from "fs";
@@ -9,13 +8,9 @@ import { HardhatConfig } from "hardhat/types";
import { join, resolve } from "path";
export class HardhatBuilder extends BaseBuilder {
public async compile(options: CompileOptions): Promise<{
public async compile(options: any): Promise<{
contracts: ContractPayload[];
}> {
if (options.clean) {
await execute("npx hardhat clean", options.projectPath);
}
await execute("npx hardhat compile", options.projectPath);
//we get our very own extractor script from the dir that we're in during execution
// this is `./dist/cli` (for all purposes of the CLI)
// then we look up the hardhat config extractor file path from there
@@ -39,6 +34,24 @@ export class HardhatBuilder extends BaseBuilder {
logger.debug("successfully extracted hardhat config", actualHardhatConfig);
await execute("npx hardhat clean", options.projectPath);
let ignoreIpfsHash = false;
if (options.zksync) {
const zkNetwork = Object.entries(actualHardhatConfig.networks).find(
(network) => {
return (network[1] as any).zksync;
},
);
ignoreIpfsHash = (zkNetwork?.[1] as any).zksync; // IPFS hash can't be recovered from ZKSync bytecode
await execute(
`npx hardhat compile --network ${zkNetwork?.[0]}`,
options.projectPath,
);
} else {
await execute(`npx hardhat compile`, options.projectPath);
}
const solcConfigs = actualHardhatConfig.solidity.compilers;
if (solcConfigs) {
for (const solcConfig of solcConfigs) {
@@ -80,7 +93,6 @@ export class HardhatBuilder extends BaseBuilder {
logger.debug("Skipping", contractPath, "(not a source target)");
continue;
}
for (const [contractName, contractInfo] of Object.entries(
contractInfos as any,
)) {
@@ -98,10 +110,13 @@ export class HardhatBuilder extends BaseBuilder {
}
const bytecode = info.evm.bytecode.object;
const deployedBytecode = info.evm.deployedBytecode.object;
const deployedBytecode =
info.evm.deployedBytecode?.object || bytecode;
const { metadata, abi } = info;
const meta = JSON.parse(metadata);
const meta = metadata.solc_metadata
? JSON.parse(metadata.solc_metadata)
: JSON.parse(metadata);
const sources = Object.keys(meta.sources)
.map((path) => {
const directPath = join(options.projectPath, path);
@@ -129,9 +144,16 @@ export class HardhatBuilder extends BaseBuilder {
);
const fileName = fileNames.length > 0 ? fileNames[0] : "";
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
if (
this.shouldProcessContract(
abi,
deployedBytecode,
contractName,
ignoreIpfsHash,
)
) {
contracts.push({
metadata,
metadata: JSON.stringify(meta),
bytecode,
name: contractName,
fileName,
+1
View File
@@ -8,6 +8,7 @@ import { basename, join } from "path";
import solc from "solc";
export class SolcBuilder extends BaseBuilder {
/* eslint-disable @typescript-eslint/no-unused-vars */
public async compile(options: CompileOptions): Promise<{
contracts: ContractPayload[];
}> {
@@ -4,6 +4,7 @@ export type CompileOptions = {
clean: boolean;
projectPath: string;
name: string;
zksync?: boolean;
};
export interface IBuilder {
+1 -1
View File
@@ -33,7 +33,7 @@ export async function generate(options: GenerateOptions) {
const configAddresses = thirdwebConfig.contracts.map((contract) =>
contract.address.toLowerCase(),
);
const newAddresses = addresses.filter(
const newAddresses = Array.from(new Set(addresses)).filter(
(address) => !configAddresses.includes(address.toLowerCase()),
);
+46
View File
@@ -1,5 +1,51 @@
# @thirdweb-dev/react-core
## 3.12.4
### Patch Changes
- Updated dependencies [[`23d90b3e`](https://github.com/thirdweb-dev/js/commit/23d90b3e779a5bfdb7058b8c51349d9c278fcbce), [`cc56037e`](https://github.com/thirdweb-dev/js/commit/cc56037e64560b9e0fc16eb0ac7cc2e47e2c9fdf), [`67450789`](https://github.com/thirdweb-dev/js/commit/67450789473b6008b86453ee4f4c7b99461223a6)]:
- @thirdweb-dev/sdk@3.10.19
- @thirdweb-dev/storage@1.1.4
- @thirdweb-dev/wallets@0.2.24
## 3.12.3
### Patch Changes
- [#1068](https://github.com/thirdweb-dev/js/pull/1068) [`fd7111d5`](https://github.com/thirdweb-dev/js/commit/fd7111d5449b8315d326c308a021eed335446e19) Thanks [@MananTank](https://github.com/MananTank)! - add `theme` in `WalletConfig.selectUI` to allow creating selection UI that follows the theme of the wallet Modal
- [#1065](https://github.com/thirdweb-dev/js/pull/1065) [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Add support for signing in with email/phone using magic sdk
Devs can now add a new supportedWallet:
```javascript
import { Goerli } from '@thirdweb-dev/chains';
import { ThirdwebProvider, magicWallet } from '@thirdweb-dev/react-native';
<ThirdwebProvider
activeChain={Goerli}
supportedWallets={[
magicWallet({
apiKey: 'magic_api_key',
}),
]}>
```
- [#1067](https://github.com/thirdweb-dev/js/pull/1067) [`e21bdd03`](https://github.com/thirdweb-dev/js/commit/e21bdd0328d9c52d58295aa4012fc11cde83b60a) Thanks [@MananTank](https://github.com/MananTank)! - Return wallet instance from `useConnect` hook instead of returning nothing
```diff
const connect = useConnect();
- await connect(walletConfig)
+ const walletInstance = await connect(walletConfig)
```
- Updated dependencies [[`2f1df0b5`](https://github.com/thirdweb-dev/js/commit/2f1df0b5354a8ee55089b2c1e61c058788d890f1), [`189daf02`](https://github.com/thirdweb-dev/js/commit/189daf0280a90ed730200088948526a594da3408), [`afae0873`](https://github.com/thirdweb-dev/js/commit/afae0873b0e3f9741f5a9c44c5d255f38c6a9111), [`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855), [`c6e74ef0`](https://github.com/thirdweb-dev/js/commit/c6e74ef0b00210f52e6778c548061376d3ba7001), [`ee4c7de2`](https://github.com/thirdweb-dev/js/commit/ee4c7de25cb63f99f33b90da8e26293bbfbe6f3e), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`68fa1896`](https://github.com/thirdweb-dev/js/commit/68fa1896f75d3514e00cc380924fd8bc623064f0), [`f7b352a5`](https://github.com/thirdweb-dev/js/commit/f7b352a585a23726eaa3be116f65db56b005f4d8), [`4a1d7581`](https://github.com/thirdweb-dev/js/commit/4a1d75811058d6974616bdc12a6040cea5444e40), [`bdabbef7`](https://github.com/thirdweb-dev/js/commit/bdabbef71a2421a2dceb384f93bb6a59a3ddf007), [`59206233`](https://github.com/thirdweb-dev/js/commit/59206233e15ccfe3dc32047060055219d35938f2), [`292a321a`](https://github.com/thirdweb-dev/js/commit/292a321a95ed2d847097eed205353dd69eeb8d54), [`98efd090`](https://github.com/thirdweb-dev/js/commit/98efd090f63cfd9dfed7b89b20b6e43db88cf75c), [`8eecf4c2`](https://github.com/thirdweb-dev/js/commit/8eecf4c2d5b0d6447ad5b9cdbf0269818bbb3498), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`f3b2ae3f`](https://github.com/thirdweb-dev/js/commit/f3b2ae3f6d9c66356c521d3b9c2a6c096dbb4b57), [`d5651006`](https://github.com/thirdweb-dev/js/commit/d565100614d7d4e256554f998b8ce978a566051c), [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76), [`da576108`](https://github.com/thirdweb-dev/js/commit/da5761080288c3b325f54fb56c80f96405a1cb5d), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d), [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c), [`a034b032`](https://github.com/thirdweb-dev/js/commit/a034b0321fd0113ed51d95d538b5c3020615c227), [`35984362`](https://github.com/thirdweb-dev/js/commit/35984362b0a60e5b9c3d3c9731450a8f47deb1c4)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 3.12.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.12.2",
"version": "3.12.4",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -7,6 +7,7 @@ import {
AsyncStorage,
ConnectParams,
CreateAsyncStorage,
walletIds,
} from "@thirdweb-dev/wallets";
import { Signer } from "ethers";
import {
@@ -73,7 +74,7 @@ type ThirdwebWalletContextData = {
Config extends Record<string, any> | undefined = undefined,
>(
...args: ConnectFnArgs<I, Config>
) => Promise<void>;
) => Promise<I>;
disconnect: () => Promise<void>;
connectionStatus: ConnectionStatus;
setConnectionStatus: (status: ConnectionStatus) => void;
@@ -83,6 +84,7 @@ type ThirdwebWalletContextData = {
>(
Wallet: WalletConfig<I, Config>,
) => I;
createdWalletInstance?: WalletInstance;
createWalletStorage: CreateAsyncStorage;
switchChain: (chain: number) => Promise<void>;
chainToConnect?: Chain;
@@ -120,6 +122,10 @@ export function ThirdwebWalletProvider(
WalletInstance | undefined
>();
const [createdWalletInstance, setCreatedWalletInstance] = useState<
WalletInstance | undefined
>();
const [activeWalletConfig, setActiveWalletConfig] = useState<
WalletConfig | undefined
>();
@@ -153,6 +159,14 @@ export function ThirdwebWalletProvider(
walletConfig: WalletConfig<I, Config>,
): I => {
const walletInstance = walletConfig.create(walletParams);
if (walletInstance.walletId === walletIds.magicLink) {
// NOTE: removing this if statement causes the component to re-render
// Patch for magic link wallet in react native
// needed because we need to add a component to the view tree
// from the instance, right before calling connect.
// Check it out in RN's DappContextProvider.
setCreatedWalletInstance(walletInstance);
}
walletInstanceToConfig.set(walletInstance, walletConfig);
return walletInstance;
},
@@ -346,11 +360,11 @@ export function ThirdwebWalletProvider(
await wallet.autoConnect(walletInfo.connectParams);
setConnectedWallet(wallet, walletInfo.connectParams, true);
} catch (e) {
console.error(e);
lastConnectedWalletStorage.removeItem(
LAST_CONNECTED_WALLET_STORAGE_KEY,
);
setConnectionStatus("disconnected");
throw e;
}
}
@@ -370,7 +384,7 @@ export function ThirdwebWalletProvider(
Config extends Record<string, any> | undefined = undefined,
>(
...args: ConnectFnArgs<I, Config>
) => {
): Promise<I> => {
const [WalletObj, connectParams] = args;
const _connectedParams = {
@@ -388,6 +402,8 @@ export function ThirdwebWalletProvider(
setConnectionStatus("disconnected");
throw e;
}
return wallet;
},
[createWalletInstance, setConnectedWallet, chainToConnect],
);
@@ -456,6 +472,7 @@ export function ThirdwebWalletProvider(
connectionStatus,
setConnectionStatus,
createWalletInstance: createWalletInstance,
createdWalletInstance: createdWalletInstance,
createWalletStorage: props.createWalletStorage,
switchChain,
setConnectedWallet: setConnectedWallet,
@@ -161,4 +161,9 @@ export type SelectUIProps<
* For example: You can render a larger UI if only one wallet (your wallet) is supported.
*/
supportedWallets: WalletConfig[];
/**
* theme of the connect wallet modal
*/
theme: "dark" | "light";
};
@@ -64,6 +64,7 @@ export const ThirdwebConnectedWalletProvider: React.FC<
});
} catch (e) {
// failed to get a viable rpc url, nothing we can do
console.error(e);
}
}
@@ -1,5 +1,9 @@
# @thirdweb-dev/react-native-compat
## 0.2.16
## 0.2.15
## 0.2.14
## 0.2.13
+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.14",
"version": "0.2.16",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+76
View File
@@ -1,5 +1,81 @@
# @thirdweb-dev/react-native
## 0.2.16
### Patch Changes
- [#1103](https://github.com/thirdweb-dev/js/pull/1103) [`89102b0c`](https://github.com/thirdweb-dev/js/commit/89102b0c895011bb6528d2b9bc4289173b351c8d) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Fix bug where the wc uri is not being copied in the textinput after scanning it
- Updated dependencies [[`23d90b3e`](https://github.com/thirdweb-dev/js/commit/23d90b3e779a5bfdb7058b8c51349d9c278fcbce), [`cc56037e`](https://github.com/thirdweb-dev/js/commit/cc56037e64560b9e0fc16eb0ac7cc2e47e2c9fdf), [`67450789`](https://github.com/thirdweb-dev/js/commit/67450789473b6008b86453ee4f4c7b99461223a6)]:
- @thirdweb-dev/sdk@3.10.19
- @thirdweb-dev/storage@1.1.4
- @thirdweb-dev/react-core@3.12.4
- @thirdweb-dev/wallets@0.2.24
## 0.2.15
### Patch Changes
- [#1059](https://github.com/thirdweb-dev/js/pull/1059) [`56ad0867`](https://github.com/thirdweb-dev/js/commit/56ad0867bd28da2c8ddaaca5ed5a26599c4e0ed6) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Use walletConfig's selectUI to render the wallet item in the Choose your Wallet dialog
- [#1010](https://github.com/thirdweb-dev/js/pull/1010) [`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855) Thanks [@iketw](https://github.com/iketw)! - [ReactNative-Wallets] Enables SmartWallet to connect to an app, with implementation in React Native
- Wallets package
1. Smart Wallet now supports connecting an external app to it. It acts as an actual wallet implementing the WC protocol
2. There are two WalletConnect handlers to manage V1 and V2 WC connections
3. Creates a synchronous storage interface used in WCV1
4. To have your connector support WC, you need to implement the interface: IWalletConnectReceiver.
5. You can now pass the flag enableConnectApp to the smart wallet config to enable a new field in our modal to connect an app to your smart wallet
```
smartWallet({
factoryAddress: "..."
thirdwebApiKey: "apiKey"
gasless: true,
personalWallets: [localWallet()],
enableConnectApp: true,
}),
```
- React Native
1. Creates new modals for WC SessionRequests and SessionApprovals
2. Implements SyncStorage using MMKV
- [#1068](https://github.com/thirdweb-dev/js/pull/1068) [`fd7111d5`](https://github.com/thirdweb-dev/js/commit/fd7111d5449b8315d326c308a021eed335446e19) Thanks [@MananTank](https://github.com/MananTank)! - add `theme` in `WalletConfig.selectUI` to allow creating selection UI that follows the theme of the wallet Modal
- [#1065](https://github.com/thirdweb-dev/js/pull/1065) [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Add support for signing in with email/phone using magic sdk
Devs can now add a new supportedWallet:
```javascript
import { Goerli } from '@thirdweb-dev/chains';
import { ThirdwebProvider, magicWallet } from '@thirdweb-dev/react-native';
<ThirdwebProvider
activeChain={Goerli}
supportedWallets={[
magicWallet({
apiKey: 'magic_api_key',
}),
]}>
```
- [#1088](https://github.com/thirdweb-dev/js/pull/1088) [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76) Thanks [@iketw](https://github.com/iketw)! - [RN/Wallets] Adds send_transaction support for wcv1 Connect to App feature
- [#1052](https://github.com/thirdweb-dev/js/pull/1052) [`77123a9a`](https://github.com/thirdweb-dev/js/commit/77123a9a5a29d8a1d7c6bf4be40f463e721a0412) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Adds support for WC QRCode scanning
Breaking change:
- Users will need to add the dependency `react-native-camera` to be able to use this version of the SDK.
- Updated dependencies [[`2f1df0b5`](https://github.com/thirdweb-dev/js/commit/2f1df0b5354a8ee55089b2c1e61c058788d890f1), [`189daf02`](https://github.com/thirdweb-dev/js/commit/189daf0280a90ed730200088948526a594da3408), [`afae0873`](https://github.com/thirdweb-dev/js/commit/afae0873b0e3f9741f5a9c44c5d255f38c6a9111), [`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855), [`c6e74ef0`](https://github.com/thirdweb-dev/js/commit/c6e74ef0b00210f52e6778c548061376d3ba7001), [`fd7111d5`](https://github.com/thirdweb-dev/js/commit/fd7111d5449b8315d326c308a021eed335446e19), [`ee4c7de2`](https://github.com/thirdweb-dev/js/commit/ee4c7de25cb63f99f33b90da8e26293bbfbe6f3e), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`68fa1896`](https://github.com/thirdweb-dev/js/commit/68fa1896f75d3514e00cc380924fd8bc623064f0), [`e21bdd03`](https://github.com/thirdweb-dev/js/commit/e21bdd0328d9c52d58295aa4012fc11cde83b60a), [`f7b352a5`](https://github.com/thirdweb-dev/js/commit/f7b352a585a23726eaa3be116f65db56b005f4d8), [`4a1d7581`](https://github.com/thirdweb-dev/js/commit/4a1d75811058d6974616bdc12a6040cea5444e40), [`bdabbef7`](https://github.com/thirdweb-dev/js/commit/bdabbef71a2421a2dceb384f93bb6a59a3ddf007), [`59206233`](https://github.com/thirdweb-dev/js/commit/59206233e15ccfe3dc32047060055219d35938f2), [`292a321a`](https://github.com/thirdweb-dev/js/commit/292a321a95ed2d847097eed205353dd69eeb8d54), [`98efd090`](https://github.com/thirdweb-dev/js/commit/98efd090f63cfd9dfed7b89b20b6e43db88cf75c), [`8eecf4c2`](https://github.com/thirdweb-dev/js/commit/8eecf4c2d5b0d6447ad5b9cdbf0269818bbb3498), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`f3b2ae3f`](https://github.com/thirdweb-dev/js/commit/f3b2ae3f6d9c66356c521d3b9c2a6c096dbb4b57), [`d5651006`](https://github.com/thirdweb-dev/js/commit/d565100614d7d4e256554f998b8ce978a566051c), [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76), [`da576108`](https://github.com/thirdweb-dev/js/commit/da5761080288c3b325f54fb56c80f96405a1cb5d), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d), [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c), [`a034b032`](https://github.com/thirdweb-dev/js/commit/a034b0321fd0113ed51d95d538b5c3020615c227), [`35984362`](https://github.com/thirdweb-dev/js/commit/35984362b0a60e5b9c3d3c9731450a8f47deb1c4)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.14
### Patch Changes
+15 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.14",
"version": "0.2.16",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -25,6 +25,8 @@
],
"dependencies": {
"@coinbase/wallet-mobile-sdk": "^1.0.4",
"@magic-sdk/provider": "17.2.0",
"@magic-sdk/react-native-bare": "^18.3.0",
"@shopify/restyle": "^2.4.1",
"@tanstack/react-query": "^4.0.10",
"@thirdweb-dev/chains": "workspace:*",
@@ -43,7 +45,8 @@
"tiny-invariant": "^1.2.0"
},
"resolutions": {
"react-native-mmkv": "2.5.1"
"react-native-mmkv": "2.5.1",
"@magic-sdk/provider": "17.2.0"
},
"devDependencies": {
"@babel/core": "^7.19.3",
@@ -69,8 +72,18 @@
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-native": "^0.71.0",
"react-native-camera": "^4.2.1",
"react-native-device-info": "10.6.0",
"react-native-safe-area-context": "4.5.3",
"react-native-webview": "12.1.0",
"typescript": "^4.7.4"
},
"optionalDependencies": {
"react-native-camera": "^4.2.1",
"react-native-device-info": "10.6.0",
"react-native-safe-area-context": "4.5.3",
"react-native-webview": "12.1.0"
},
"peerDependencies": {
"ethers": ">=5.5.1 <6",
"expo": "^47.0.0",
+36 -1
View File
@@ -1,4 +1,7 @@
import { AsyncStorage as IAsyncStorage } from "@thirdweb-dev/wallets";
import {
AsyncStorage as IAsyncStorage,
SyncStorage,
} from "@thirdweb-dev/wallets";
import { MMKV } from "react-native-mmkv";
const PREFIX = "__TW__";
@@ -31,6 +34,28 @@ export class AsyncLocalStorage implements IAsyncStorage {
}
}
export class LocalStorage implements SyncStorage {
name: string;
asyncStorage: MMKV;
constructor(name: string) {
this.name = name;
this.asyncStorage = new MMKV();
}
getItem(key: string) {
return this.asyncStorage.getString(`${PREFIX}/${this.name}/${key}`) || null;
}
setItem(key: string, value: string) {
return this.asyncStorage.set(`${PREFIX}/${this.name}/${key}`, value);
}
removeItem(key: string) {
return this.asyncStorage.delete(`${PREFIX}/${this.name}/${key}`);
}
}
export class noopStorage implements IAsyncStorage {
getItem(key: string): Promise<string | null> {
return Promise.resolve(key);
@@ -54,3 +79,13 @@ export class noopStorage implements IAsyncStorage {
export function createAsyncLocalStorage(name: string) {
return new AsyncLocalStorage(name);
}
/**
* Returns a new instance of LocalStorage
*
* @param name Name to namespace the storage with
* @returns A new instance of LocalStorage
*/
export function createSyncStorage(name: string) {
return new LocalStorage(name);
}
@@ -0,0 +1,60 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const QrCodeIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 24 24" fill="none">
<Path
d="M9 2H3C2.44772 2 2 2.44772 2 3V9C2 9.55228 2.44772 10 3 10H9C9.55228 10 10 9.55228 10 9V3C10 2.44772 9.55228 2 9 2Z"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M9 13.9999H3C2.44772 13.9999 2 14.4476 2 14.9999V20.9999C2 21.5522 2.44772 21.9999 3 21.9999H9C9.55228 21.9999 10 21.5522 10 20.9999V14.9999C10 14.4476 9.55228 13.9999 9 13.9999Z"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M21 2H15C14.4477 2 14 2.44772 14 3V9C14 9.55228 14.4477 10 15 10H21C21.5523 10 22 9.55228 22 9V3C22 2.44772 21.5523 2 21 2Z"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M14 13.9999V17.9999"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M14 21.9999H18V13.9999"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M18 16H22"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M22 20.0001V22.0001"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</Svg>
);
};
export default QrCodeIcon;
@@ -0,0 +1,25 @@
import { IconStyleProp } from "./types";
import Svg, { G, Path } from "react-native-svg";
const WalletConnectIcon = ({ width, height }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 300 185">
<G
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<G id="walletconnect-logo-alt" fill="#3B99FC" fill-rule="nonzero">
<Path
d="M61.4385429,36.2562612 C110.349767,-11.6319051 189.65053,-11.6319051 238.561752,36.2562612 L244.448297,42.0196786 C246.893858,44.4140867 246.893858,48.2961898 244.448297,50.690599 L224.311602,70.406102 C223.088821,71.6033071 221.106302,71.6033071 219.883521,70.406102 L211.782937,62.4749541 C177.661245,29.0669724 122.339051,29.0669724 88.2173582,62.4749541 L79.542302,70.9685592 C78.3195204,72.1657633 76.337001,72.1657633 75.1142214,70.9685592 L54.9775265,51.2530561 C52.5319653,48.8586469 52.5319653,44.9765439 54.9775265,42.5821357 L61.4385429,36.2562612 Z M280.206339,77.0300061 L298.128036,94.5769031 C300.573585,96.9713 300.573599,100.85338 298.128067,103.247793 L217.317896,182.368927 C214.872352,184.763353 210.907314,184.76338 208.461736,182.368989 C208.461726,182.368979 208.461714,182.368967 208.461704,182.368957 L151.107561,126.214385 C150.496171,125.615783 149.504911,125.615783 148.893521,126.214385 C148.893517,126.214389 148.893514,126.214393 148.89351,126.214396 L91.5405888,182.368927 C89.095052,184.763359 85.1300133,184.763399 82.6844276,182.369014 C82.6844133,182.369 82.684398,182.368986 82.6843827,182.36897 L1.87196327,103.246785 C-0.573596939,100.852377 -0.573596939,96.9702735 1.87196327,94.5758653 L19.7936929,77.028998 C22.2392531,74.6345898 26.2042918,74.6345898 28.6498531,77.028998 L86.0048306,133.184355 C86.6162214,133.782957 87.6074796,133.782957 88.2188704,133.184355 C88.2188796,133.184346 88.2188878,133.184338 88.2188969,133.184331 L145.571,77.028998 C148.016505,74.6345347 151.981544,74.6344449 154.427161,77.028798 C154.427195,77.0288316 154.427229,77.0288653 154.427262,77.028899 L211.782164,133.184331 C212.393554,133.782932 213.384814,133.782932 213.996204,133.184331 L271.350179,77.0300061 C273.79574,74.6355969 277.760778,74.6355969 280.206339,77.0300061 Z"
id="WalletConnect"
></Path>
</G>
</G>
</Svg>
);
};
export default WalletConnectIcon;
@@ -47,6 +47,7 @@ export const ConnectWallet = ({
setShowButtonSpinner(isWalletConnecting);
if (!isWalletConnecting) {
setShowButtonSpinner(false);
return;
}
@@ -54,7 +55,7 @@ export const ConnectWallet = ({
if (isWalletConnecting) {
setShowButtonSpinner(false);
}
}, 3000);
}, 5000);
return () => {
if (timeout) {
@@ -0,0 +1,250 @@
import { useWallet } from "@thirdweb-dev/react-core";
import { IWalletConnectReceiver } from "@thirdweb-dev/wallets";
import { useCallback, useEffect, useState } from "react";
import Box from "../base/Box";
import BaseButton from "../base/BaseButton";
import DisconnectIcon from "../../assets/disconnect";
import { useTheme } from "@shopify/restyle";
import { TextInput } from "../base/TextInput";
import RightArrowIcon from "../../assets/right-arrow";
import { StyleSheet, View } from "react-native";
import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import WalletConnectIcon from "../../assets/wallet-connect";
import QrCodeIcon from "../../assets/qr-code";
import { QRCodeScan } from "./QRCodeScan";
const ConnectAppField = () => {
const theme = useTheme();
const [showWCInput, setShowWCInput] = useState(false);
const [wcUri, setWCUri] = useState<string | undefined>();
const [appMeta, setAppMeta] = useState<{ name: string; iconUrl: string }>();
const wallet = useWallet();
const [showQRCodeScan, setShowQRCodeScan] = useState(false);
const getAppMeta = useCallback(() => {
if (wallet && "isWCReceiverEnabled" in wallet) {
const sessions = (
wallet as unknown as IWalletConnectReceiver
).getActiveSessions();
if (Object.keys(sessions).length > 0) {
setAppMeta({
name: sessions[0].peer.metadata.name,
iconUrl: sessions[0].peer.metadata.icons[0],
});
}
}
}, [wallet]);
const onSmartWalletWCMessage = useCallback(
({ type }: { type: string }) => {
if (type === "session_approved") {
getAppMeta();
} else if (type === "session_delete") {
reset();
}
},
[getAppMeta],
);
useEffect(() => {
if (wallet) {
wallet.addListener("message", onSmartWalletWCMessage);
getAppMeta();
}
return () => {
if (wallet) {
wallet.removeListener("message", onSmartWalletWCMessage);
}
};
}, [getAppMeta, onSmartWalletWCMessage, wallet]);
const onConnectDappPress = () => {
if (appMeta) {
reset();
(wallet as unknown as IWalletConnectReceiver).disconnectSession();
} else {
setShowWCInput(true);
}
};
const reset = () => {
setAppMeta(undefined);
setShowWCInput(false);
};
const onAddressChangeText = (text: string) => {
setWCUri(text);
};
const onQRCodeScan = (data: string) => {
if (wcUri !== data && data.startsWith("wc:")) {
setWCUri(data);
setShowQRCodeScan(false);
onWCPress(data);
}
};
const onQRClose = () => {
setShowQRCodeScan(false);
};
const onWCPress = (uri?: string) => {
if (!(wcUri || uri) || !wallet) {
return;
}
const uriToUse = uri || wcUri;
if (uriToUse?.startsWith("wc:")) {
(wallet as unknown as IWalletConnectReceiver).connectApp(uriToUse);
}
};
const onScanQRPress = () => {
setShowQRCodeScan(true);
};
return (
<>
{!appMeta && showWCInput ? (
<Box
flexDirection="row"
mb="sm"
borderColor="border"
borderWidth={1}
borderRadius="md"
>
<TextInput
onChangeText={onAddressChangeText}
flex={1}
value={wcUri}
placeholder={"wc://..."}
placeholderTextColor={theme.colors.textSecondary}
/>
<BaseButton
onPress={() => onWCPress()}
justifyContent="center"
alignItems="center"
>
<RightArrowIcon
height={20}
width={30}
color={theme.colors.iconPrimary}
/>
</BaseButton>
<BaseButton
onPress={onScanQRPress}
justifyContent="center"
alignItems="center"
marginHorizontal="xs"
>
<QrCodeIcon
height={30}
width={30}
color={theme.colors.iconPrimary}
/>
</BaseButton>
</Box>
) : (
<BaseButton
backgroundColor="background"
borderColor="border"
mb="sm"
justifyContent="space-between"
style={styles.exportWallet}
onPress={onConnectDappPress}
>
<>
{appMeta ? (
<WalletIcon size={32} iconUri={appMeta.iconUrl} />
) : (
<WalletConnectIcon width={16} height={16} />
)}
<View style={styles.exportWalletInfo}>
<Text variant="bodySmall">
{appMeta ? appMeta.name : "Connect app"}
</Text>
</View>
</>
{appMeta ? (
<DisconnectIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
) : (
<RightArrowIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
)}
</BaseButton>
)}
<QRCodeScan
isVisible={showQRCodeScan}
onQRCodeScan={onQRCodeScan}
onClose={onQRClose}
/>
</>
);
};
export default ConnectAppField;
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,
},
});
@@ -5,9 +5,10 @@ import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import { useWallet, useBalance } from "@thirdweb-dev/react-core";
import { useActiveChain } from "@thirdweb-dev/react-core/evm";
import { StyleSheet, View } from "react-native";
import { StyleSheet } from "react-native";
import { LocalWallet } from "@thirdweb-dev/wallets";
import { useModalState } from "../../providers/ui-context-provider";
import Box from "../base/Box";
export type ConnectWalletDetailsProps = {
address: string;
@@ -46,9 +47,9 @@ export const ConnectWalletDetails = ({
{detailsButton ? (
detailsButton
) : (
<>
<Box flex={1} flexDirection="row" justifyContent="space-between">
<ChainIcon size={32} chainIconUrl={chain?.icon?.url} />
<View style={styles.walletInfo}>
<Box justifyContent="center" alignItems="flex-start">
<Text variant="bodySmall">
{balanceQuery.data?.displayValue.slice(0, 5)}{" "}
{balanceQuery.data?.symbol}
@@ -58,12 +59,12 @@ export const ConnectWalletDetails = ({
) : (
<Address variant="bodySmallSecondary" address={address} />
)}
</View>
</Box>
<WalletIcon
size={32}
iconUri={activeWallet?.getMeta().iconURL || ""}
/>
</>
</Box>
)}
</BaseButton>
</>
@@ -71,14 +72,6 @@ export const ConnectWalletDetails = ({
};
const styles = StyleSheet.create({
walletInfo: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
alignContent: "center",
flexDirection: "column",
marginLeft: 5,
},
walletDetails: {
display: "flex",
flexDirection: "row",
@@ -6,7 +6,6 @@ import {
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";
@@ -19,6 +18,7 @@ import { usePersonalWalletAddress } from "../../wallets/hooks/usePersonalWalletA
import { shortenWalletAddress } from "../../utils/addresses";
import { WalletIcon } from "../base/WalletIcon";
import { LocalWallet } from "../../wallets/wallets/LocalWallet";
import { TWModal } from "../base/modal/TWModal";
export type ExportLocalWalletModalProps = {
isVisible: boolean;
@@ -142,7 +142,7 @@ export const ExportLocalWalletModal = ({
};
return (
<Modal isVisible={isVisible} backdropOpacity={0.7}>
<TWModal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
<Box
flexDirection="column"
@@ -194,7 +194,7 @@ export const ExportLocalWalletModal = ({
</Box>
</Box>
</KeyboardAvoidingView>
</Modal>
</TWModal>
);
};
@@ -0,0 +1,33 @@
import { RNCamera } from "react-native-camera";
import { TWModal } from "../base/modal/TWModal";
import { ModalHeaderTextClose } from "../base/modal/ModalHeaderTextClose";
export const QRCodeScan = ({
isVisible,
onQRCodeScan,
onClose,
}: {
isVisible: boolean;
onQRCodeScan: (data: string) => void;
onClose: () => void;
}) => {
return (
<TWModal isVisible={isVisible} backdropOpacity={1}>
<ModalHeaderTextClose headerText={"Scan to Connect"} onClose={onClose} />
<RNCamera
style={{ flex: 1 }}
type={RNCamera.Constants.Type.back}
captureAudio={false}
androidCameraPermissionOptions={{
title: "Permission to use camera",
message: "We need your permission to use your camera",
buttonPositive: "Ok",
buttonNegative: "Cancel",
}}
onBarCodeRead={({ data }) => {
onQRCodeScan(data);
}}
/>
</TWModal>
);
};
@@ -0,0 +1,76 @@
import { useWallet } from "@thirdweb-dev/react-core";
import Box from "../base/Box";
import BaseButton from "../base/BaseButton";
import Text from "../base/Text";
import { IWalletConnectReceiver } from "@thirdweb-dev/wallets";
import {
CLOSE_MODAL_STATE,
WalletConnectSessionProposalModal,
} from "../../utils/modalTypes";
import { useModalState } from "../../providers/ui-context-provider";
export const SessionProposalModal = () => {
const { modalState, setModalState } = useModalState();
const { data: proposalData } =
modalState as WalletConnectSessionProposalModal;
const wallet = useWallet();
const onClose = () => {
setModalState(CLOSE_MODAL_STATE("SessionProposalModal"));
};
return (
<Box
flexDirection="column"
backgroundColor="background"
borderRadius="md"
p="lg"
>
<Text variant="bodyLarge">Connect to App</Text>
<Text variant="bodyLarge">{proposalData.proposer.metadata.name}</Text>
<Box flexDirection="row" justifyContent="space-evenly" mt="lg">
<BaseButton
alignContent="center"
alignItems="center"
borderRadius="sm"
borderWidth={0.5}
paddingHorizontal="sm"
paddingVertical="md"
minWidth={100}
borderColor="border"
onPress={async () => {
(wallet as unknown as IWalletConnectReceiver).rejectSession();
onClose();
}}
>
<Text variant="bodySmall">Reject</Text>
</BaseButton>
<BaseButton
alignContent="center"
alignItems="center"
borderRadius="sm"
borderWidth={0.5}
paddingHorizontal="sm"
paddingVertical="md"
minWidth={100}
backgroundColor="white"
borderColor="border"
onPress={async () => {
if (!wallet) {
throw new Error("Wallet not connected.");
}
await (
wallet as unknown as IWalletConnectReceiver
).approveSession();
onClose();
}}
>
<Text variant="bodySmall" color="black">
Approve
</Text>
</BaseButton>
</Box>
</Box>
);
};
@@ -0,0 +1,158 @@
import { useChain, useWallet } from "@thirdweb-dev/react-core";
import Box from "../base/Box";
import BaseButton from "../base/BaseButton";
import Text from "../base/Text";
import {
EIP155_SIGNING_METHODS,
IWalletConnectReceiver,
} from "@thirdweb-dev/wallets";
import { useModalState } from "../../providers/ui-context-provider";
import {
CLOSE_MODAL_STATE,
WalletConnectSessionRequestModal,
} from "../../utils/modalTypes";
import { ActivityIndicator, Dimensions } from "react-native";
import { shortenWalletAddress } from "../../utils/addresses";
import { useCallback, useState } from "react";
const getTitle = (method: string) => {
switch (method) {
case EIP155_SIGNING_METHODS.SWITCH_CHAIN:
return "Switch Chain";
case EIP155_SIGNING_METHODS.ETH_SIGN:
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
return "Sign this message?";
default:
return "Send / Sign Transaction";
}
};
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
export const SessionRequestModal = () => {
const { modalState, setModalState } = useModalState();
const { data: requestData } = modalState as WalletConnectSessionRequestModal;
const [approvingRequest, setApprovingRequest] = useState(false);
const wallet = useWallet();
const chain = useChain();
const onClose = () => {
setModalState(CLOSE_MODAL_STATE("SessionRequestModal"));
};
const onApprove = async () => {
if (!wallet) {
throw new Error("Wallet not connected.");
}
setApprovingRequest(true);
(wallet as unknown as IWalletConnectReceiver)
.approveRequest()
.finally(() => {
setApprovingRequest(false);
onClose();
});
};
const getContent = useCallback(() => {
switch (requestData.method) {
case EIP155_SIGNING_METHODS.SWITCH_CHAIN:
return (
<Text variant="bodySmall" textAlign="left">
{`Switch to ${
requestData.params[0].chainId === chain?.chainId
? chain?.slug
: requestData.params[0].chainId
}`}
</Text>
);
case EIP155_SIGNING_METHODS.ETH_SIGN:
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
return (
<Text variant="bodySmall" textAlign="left">
{requestData.params[0]}
</Text>
);
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
const { params } = requestData;
const transaction = params[0];
const from = transaction.from;
const to = transaction.to;
return (
<Box>
<Text variant="bodySmall" textAlign="left">
{`from: ${shortenWalletAddress(from)}`}
</Text>
<Text variant="bodySmall" textAlign="left" mt="sm">
{`to: ${shortenWalletAddress(to)}`}
</Text>
</Box>
);
default:
throw new Error(`Method not implemented: ${requestData.method}`);
}
}, [requestData]);
return (
<Box
flexDirection="column"
backgroundColor="background"
borderRadius="md"
p="lg"
>
<Text variant="bodyLarge" mb="md">
{requestData.peer.metadata.name}
</Text>
<Text variant="bodySmallSecondary" textAlign="center" fontSize={15}>
{getTitle(requestData.method)}
</Text>
<Box maxHeight={MODAL_HEIGHT} mt="md">
{getContent()}
</Box>
<Box flexDirection="row" justifyContent="space-evenly" mt="lg">
<BaseButton
alignContent="center"
alignItems="center"
borderRadius="sm"
borderWidth={0.5}
disabled={approvingRequest}
paddingHorizontal="sm"
paddingVertical="md"
minWidth={100}
borderColor="border"
onPress={async () => {
(wallet as unknown as IWalletConnectReceiver).rejectRequest();
onClose();
}}
>
<Text variant="bodySmall">Reject</Text>
</BaseButton>
<BaseButton
alignContent="center"
alignItems="center"
borderRadius="sm"
borderWidth={0.5}
disabled={approvingRequest}
paddingHorizontal="sm"
paddingVertical="md"
minWidth={100}
backgroundColor="white"
borderColor="border"
onPress={onApprove}
>
{approvingRequest ? (
<ActivityIndicator size="small" />
) : (
<Text variant="bodySmall" color="black">
Approve
</Text>
)}
</BaseButton>
</Box>
</Box>
);
};
@@ -14,6 +14,7 @@ import { useWalletContext, useWallet } from "@thirdweb-dev/react-core";
import { useEffect, useState } from "react";
import { useSmartWallet } from "../../providers/context-provider";
import RightArrowIcon from "../../assets/right-arrow";
import ConnectAppField from "./ConnectAppField";
import { useAppTheme } from "../../styles/hooks";
export const SmartWalletAdditionalActions = ({
@@ -93,6 +94,9 @@ export const SmartWalletAdditionalActions = ({
color={theme.colors.iconPrimary}
/>
</BaseButton>
{!showSmartWallet && smartWallet?.enableConnectApp ? (
<ConnectAppField />
) : null}
{wallet?.walletId === walletIds.localWallet ||
activeWallet?.walletId === walletIds.localWallet ? (
<>
@@ -122,7 +126,7 @@ export const SmartWalletAdditionalActions = ({
</BaseButton>
<Text variant="error">
{
"This is a temporary guest wallet. Download a backup if you don't want to lose access to it."
"This is a temporary guest wallet. Download a backup if you don't want to loose access to it."
}
</Text>
</>
@@ -5,10 +5,11 @@ import BaseButton from "../base/BaseButton";
import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import { useWallet, useBalance } from "@thirdweb-dev/react-core";
import { StyleSheet, View } from "react-native";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import * as Clipboard from "expo-clipboard";
import Box from "../base/Box";
import CopyIcon from "../../assets/copy";
import { useState } from "react";
interface WalletDetailsModalHeaderProps {
address: string;
@@ -25,12 +26,18 @@ export const WalletDetailsModalHeader = ({
const theme = useAppTheme();
const balanceQuery = useBalance();
const activeWallet = useWallet();
const [showLoading, setShowLoading] = useState(false);
const onAddressPress = async () => {
await Clipboard.setStringAsync(address);
onAddressCopied?.();
};
const onDisconnectPressInternal = () => {
setShowLoading(true);
onDisconnectPress();
};
return (
<>
<View style={styles.header}>
@@ -60,13 +67,17 @@ export const WalletDetailsModalHeader = ({
{balanceQuery.data?.symbol}
</Text>
</BaseButton>
<Icon
type="disconnect"
width={18}
height={18}
onPress={onDisconnectPress}
color={theme.colors.iconHighlight}
/>
{showLoading ? (
<ActivityIndicator size="small" color={theme.colors.iconHighlight} />
) : (
<Icon
type="disconnect"
width={18}
height={18}
onPress={onDisconnectPressInternal}
color={theme.colors.iconHighlight}
/>
)}
</View>
</>
);
@@ -10,9 +10,9 @@ import { View } from "react-native";
export type ChooseWalletProps = {
headerText?: ReactNode | string;
subHeaderText?: ReactNode | string;
onChooseWallet: (wallet: WalletConfig<any, any>) => void;
onChooseWallet: (wallet: WalletConfig<any, any>, data?: any) => void;
onClose: () => void;
wallets: WalletConfig[];
wallets: WalletConfig<any, any>[];
excludeWalletIds?: string[];
showGuestWalletAsButton?: boolean;
};
@@ -2,11 +2,13 @@ import { useMemo } from "react";
import type { WalletConfig } from "@thirdweb-dev/react-core";
import { StyleSheet, View, FlatList } from "react-native";
import { WalletButton } from "../../base/WalletButton";
import Box from "../../base/Box";
import { useTheme } from "@shopify/restyle";
interface ChooseWalletContentProps {
wallets: WalletConfig[];
excludeWalletIds?: string[];
onChooseWallet: (wallet: WalletConfig) => void;
onChooseWallet: (wallet: WalletConfig, data?: any) => void;
}
export const ChooseWalletContent = ({
@@ -19,6 +21,7 @@ export const ChooseWalletContent = ({
(w) => !!!excludeWalletIds?.find((ewId) => ewId === w.id),
);
}, [wallets, excludeWalletIds]);
const theme = useTheme();
return (
<View style={styles.explorerContainer}>
@@ -28,13 +31,35 @@ export const ChooseWalletContent = ({
renderItem={({ item, index }) => {
const marginBottom =
index === walletsToDisplay.length - 1 ? "none" : "xxs";
return (
<WalletButton
walletIconUrl={item.meta.iconURL}
name={item.meta.name}
onPress={() => onChooseWallet(item)}
mb={marginBottom}
/>
<>
{item.selectUI ? (
<Box
mb={marginBottom}
flexDirection="row"
justifyContent="space-between"
alignItems="center"
borderRadius="sm"
>
<item.selectUI
theme={theme}
supportedWallets={wallets}
onSelect={(data) => {
onChooseWallet(item, data);
}}
walletConfig={item}
/>
</Box>
) : (
<WalletButton
walletIconUrl={item.meta.iconURL}
name={item.meta.name}
onPress={() => onChooseWallet(item)}
mb={marginBottom}
/>
)}
</>
);
}}
/>
@@ -20,62 +20,76 @@ export const ConnectWalletFlow = () => {
const [modalVisible, setModalVisible] = useState(false);
const [activeWallet, setActiveWallet] = useState<WalletConfig | undefined>();
const [isConnecting, setIsConnecting] = useState(false);
const [selectionData, setSelectionData] = useState<any>();
const supportedWallets = useWallets();
const theme = useColorScheme();
const connect = useConnect();
const onChooseWallet = useCallback((wallet: WalletConfig) => {
setActiveWallet(() => wallet);
const onClose = useCallback(
(reset?: boolean) => {
setModalState(CLOSE_MODAL_STATE("ConnectWalletFlow"));
// TODO: Change for !wallet.connectUI
if (wallet.id !== SmartWallet.id) {
connectActiveWallet(wallet);
}
}, []);
if (reset) {
resetModal();
}
},
[setModalState],
);
const connectActiveWallet = useCallback(
async (wallet: WalletConfig, data?: any) => {
setIsConnecting(true);
connect(wallet, { ...data })
.catch((error) => {
console.error("Error connecting to the wallet", error);
})
.finally(() => {
onClose(true);
});
},
[connect, onClose],
);
const onChooseWallet = useCallback(
(wallet: WalletConfig, data?: any) => {
setActiveWallet(() => wallet);
setSelectionData(data);
// If not smart wallet (sw has it's own flow, need to migrate it to connectUI)
// &&
// If the wallet has no custom connect UI, then connect it
if (wallet.id !== SmartWallet.id && !wallet.connectUI) {
connectActiveWallet(wallet, data);
}
},
[connectActiveWallet],
);
useEffect(() => {
// case when only one wallet is passed in supportedWallets
if (walletConfig) {
onChooseWallet(walletConfig);
}
}, [onChooseWallet, walletConfig]);
const onClose = (reset?: boolean) => {
setModalState(CLOSE_MODAL_STATE("ConnectWalletFlow"));
if (reset) {
resetModal();
}
};
const onOpenModal = () => {
setModalVisible(true);
};
const connectActiveWallet = async (wallet: WalletConfig) => {
setIsConnecting(true);
connect(wallet, {})
.catch((error) => {
console.error("Error connecting to the wallet", error);
})
.finally(() => {
onClose(true);
});
};
const onBackPress = () => {
const onBackPress = useCallback(() => {
resetModal();
};
}, []);
const onConnected = () => {
const onConnected = useCallback(() => {
onClose(true);
};
}, [onClose]);
const resetModal = () => {
setActiveWallet(undefined);
setIsConnecting(false);
};
function getComponentForWallet() {
const getComponentForWallet = useCallback(() => {
switch (activeWallet?.id) {
case SmartWallet.id:
return <SmartWalletFlow onClose={onClose} onConnect={onConnected} />;
@@ -86,17 +100,26 @@ export const ConnectWalletFlow = () => {
<activeWallet.connectUI
theme={theme || "dark"}
goBack={onBackPress}
close={onClose}
close={() => onClose(true)}
isOpen={modalVisible}
open={onOpenModal}
walletConfig={activeWallet}
supportedWallets={supportedWallets}
selectionData={undefined} // TODO
selectionData={selectionData}
setSelectionData={() => {}} // TODO
/>
);
}
}
}, [
activeWallet,
modalVisible,
onBackPress,
onClose,
onConnected,
selectionData,
supportedWallets,
theme,
]);
return (
<>
@@ -4,7 +4,6 @@ import {
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";
@@ -17,6 +16,7 @@ import type {
} from "../../wallets/types/local-wallet";
import * as DocumentPicker from "expo-document-picker";
import * as FileSystem from "expo-file-system";
import { TWModal } from "../base/modal/TWModal";
export type LocalWalletImportModalProps = {
isVisible: boolean;
@@ -110,7 +110,7 @@ export const LocalWalletImportModal = ({
};
return (
<Modal isVisible={isVisible} backdropOpacity={0.7}>
<TWModal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
<Box
flexDirection="column"
@@ -168,7 +168,7 @@ export const LocalWalletImportModal = ({
</Box>
</Box>
</KeyboardAvoidingView>
</Modal>
</TWModal>
);
};
@@ -18,6 +18,7 @@ import BaseButton from "../../base/BaseButton";
import Text from "../../base/Text";
import { walletIds } from "@thirdweb-dev/wallets";
import { useAppTheme } from "../../../styles/hooks";
import { DEFAULT_WALLETS } from "../../../constants/wallets";
export const SmartWalletFlow = ({
onClose,
@@ -45,6 +46,34 @@ export const SmartWalletFlow = ({
? personalWalletChainId !== targetChain.chainId
: false;
const connectPersonalWallet = useCallback(
async (wallet: WalletConfig) => {
setIsConnecting(true);
const walletInstance = createWalletInstance(wallet);
await walletInstance.connect();
setConnectedPersonalWallet(walletInstance);
},
[createWalletInstance],
);
const onChoosePersonalWallet = useCallback(
async (wallet: WalletConfig) => {
// if (wallet.id === LocalWallet.id) {
// setShowLocalWalletFlow(true);
// } else {
connectPersonalWallet(wallet);
// }
},
[connectPersonalWallet],
);
useEffect(() => {
if (walletObj.config.personalWallets?.length === 1) {
onChoosePersonalWallet(walletObj.config.personalWallets[0]);
}
}, [onChoosePersonalWallet, walletObj.config.personalWallets]);
useEffect(() => {
(async () => {
if (connectedPersonalWallet) {
@@ -74,34 +103,12 @@ export const SmartWalletFlow = ({
}
}, [connectSmartWallet, connectedPersonalWallet, mismatch]);
const connectPersonalWallet = useCallback(
async (wallet: WalletConfig) => {
setIsConnecting(true);
const walletInstance = createWalletInstance(wallet);
await walletInstance.connect();
setConnectedPersonalWallet(walletInstance);
},
[createWalletInstance],
);
const onConnectedLocalWallet = async (wallet: WalletInstance) => {
setIsConnecting(true);
connectSmartWallet(wallet);
};
const onChoosePersonalWallet = useCallback(
async (wallet: WalletConfig) => {
// if (wallet.id === LocalWallet.id) {
// setShowLocalWalletFlow(true);
// } else {
connectPersonalWallet(wallet);
// }
},
[connectPersonalWallet],
);
const onLocalWalletBackPress = () => {
setShowLocalWalletFlow(false);
};
@@ -196,7 +203,7 @@ export const SmartWalletFlow = ({
</Text>
</Text>
}
wallets={walletObj.config.personalWallets}
wallets={walletObj.config.personalWallets || DEFAULT_WALLETS}
onChooseWallet={onChoosePersonalWallet}
onClose={onClose}
/>
@@ -1,46 +1,17 @@
import { StyleSheet, TextInput } from "react-native";
import Box from "../../base/Box";
import { TextInput } from "react-native";
import Text from "../../base/Text";
import { useAppTheme } from "../../../styles/hooks";
export const UsernameInput = ({
onChangeText,
}: {
onChangeText: TextInput["props"]["onChangeText"];
}) => {
const theme = useAppTheme();
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>
<TextInput onChangeText={onChangeText} />
</>
);
};
const styles = StyleSheet.create({
textInput: {
textAlign: "left",
flex: 1,
height: 40,
paddingLeft: 5,
},
});
@@ -1,4 +1,3 @@
import Modal from "react-native-modal";
import { useModalState } from "../providers/ui-context-provider";
import { ConnectWalletFlow } from "./ConnectWalletFlow/ConnectWalletFlow";
import { Dimensions, StyleSheet, View } from "react-native";
@@ -7,6 +6,9 @@ import { ConnectWalletDetailsModal } from "./ConnectWalletDetails/ConnectWalletD
import { CLOSE_MODAL_STATE } from "../utils/modalTypes";
import { ThemeProvider } from "../styles/ThemeProvider";
import { useAppTheme } from "../styles/hooks";
import { SessionRequestModal } from "./ConnectWalletDetails/SessionRequestModal";
import { SessionProposalModal } from "./ConnectWalletDetails/SessionProposalModal";
import { TWModal } from "./base/modal/TWModal";
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
const DEVICE_WIDTH = Dimensions.get("window").width;
@@ -24,6 +26,10 @@ export const MainModal = () => {
return <ConnectWalletFlow />;
case "WalletDetails":
return <ConnectWalletDetailsModal />;
case "WalletConnectSessionRequestModal":
return <SessionRequestModal />;
case "WalletConnectSessionProposalModal":
return <SessionProposalModal />;
default:
return null;
}
@@ -35,12 +41,7 @@ export const MainModal = () => {
return (
<ThemeProvider theme={theme}>
<Modal
useNativeDriver
hideModalContentWhileAnimating={true}
isVisible={isOpen}
onBackdropPress={onBackdropPress}
>
<TWModal isVisible={isOpen} onBackdropPress={onBackdropPress}>
{isSheet ? (
<View
style={[styles.modal, { backgroundColor: theme.colors.background }]}
@@ -50,7 +51,7 @@ export const MainModal = () => {
) : (
view
)}
</Modal>
</TWModal>
</ThemeProvider>
);
};
@@ -3,7 +3,7 @@ import { Image } from "react-native";
import { SvgUri } from "react-native-svg";
const ImageSvgUri = ({
imageUrl,
imageUrl = "",
width,
height,
imageAlt = "",
@@ -0,0 +1,45 @@
import { StyleSheet, TextInput as TextInputRN } from "react-native";
import Box from "./Box";
import { useTheme } from "@shopify/restyle";
type TextInputProps = (typeof Box)["arguments"] & TextInputRN["props"];
export const TextInput = ({
onChangeText,
placeholder,
...props
}: TextInputProps) => {
const theme = useTheme();
return (
<Box
flexDirection="row"
alignItems="center"
borderColor="border"
borderWidth={1}
borderRadius="md"
pr="xs"
{...props}
>
<TextInputRN
style={{ ...styles.textInput, color: theme.colors.textPrimary }}
returnKeyType={"done"}
clearTextOnFocus={false}
placeholder={placeholder}
autoCapitalize="none"
autoCorrect={false}
onChangeText={onChangeText}
{...props}
/>
</Box>
);
};
const styles = StyleSheet.create({
textInput: {
textAlign: "left",
flex: 1,
height: 40,
paddingLeft: 5,
},
});
@@ -1,43 +1,10 @@
import { useAppTheme } from "../../../styles/hooks";
import { PropsWithChildren } from "react";
import { StyleSheet, View, Dimensions } from "react-native";
import Modal, { ModalProps } from "react-native-modal";
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
const DEVICE_WIDTH = Dimensions.get("window").width;
export type TWModalProps = PropsWithChildren<
Pick<ModalProps, "isVisible"> &
Pick<Partial<ModalProps>, "onBackButtonPress" | "onBackdropPress">
>;
// Populate with the data...
export function TWModal({ children, isVisible, ...props }: TWModalProps) {
const theme = useAppTheme();
export function TWModal(props: Partial<ModalProps>) {
return (
<Modal useNativeDriver hideModalContentWhileAnimating={true} isVisible={isVisible} {...props}>
<View
style={[styles.modal, { backgroundColor: theme.colors.background }]}
>
<View style={styles.contentContainer}>{children}</View>
</View>
<Modal {...props} useNativeDriver hideModalContentWhileAnimating={true}>
{props.children}
</Modal>
);
}
const styles = StyleSheet.create({
modal: {
position: "absolute",
bottom: -20,
left: -20,
width: DEVICE_WIDTH,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
padding: 24,
},
contentContainer: {
maxHeight: MODAL_HEIGHT,
display: "flex",
},
});
@@ -3,7 +3,7 @@ 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: WalletConfig[] = [
export const DEFAULT_WALLETS: WalletConfig<any, any>[] = [
metamaskWallet(),
rainbowWallet(),
trustWallet(),
+3
View File
@@ -15,6 +15,8 @@ export { TrustWallet, trustWallet } from "./wallets/wallets/trust-wallet";
export { smartWallet } from "./wallets/wallets/smart-wallet";
export { localWallet } from "./wallets/wallets/local-wallet";
export { LocalWallet } from "./wallets/wallets/LocalWallet";
export { magicWallet } from "./wallets/wallets/magic-wallet";
export { MagicWallet } from "./wallets/wallets/MagicWallet";
export { useCoinbaseWallet } from "./wallets/hooks/useCoinbaseWallet";
export { useMetaMaskWallet } from "./wallets/hooks/useMetaMaskWallet";
@@ -27,6 +29,7 @@ export { Web3Button } from "./components/Web3Button";
// utilities
export * from "./utils/uri";
export * from "./utils/addresses";
export { createSyncStorage as createLocalStorage } from "../core/AsyncStorage";
export { createAsyncLocalStorage } from "../core/AsyncStorage";
export { createSecureStorage } from "../core/SecureStorage";
@@ -1,19 +1,57 @@
import { SmartWallet } from "@thirdweb-dev/wallets";
import { createContext, useContext, useState } from "react";
import { SmartWallet, walletIds } from "@thirdweb-dev/wallets";
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react";
import { useWalletConnectListener } from "../wallets/hooks/useWalletConnectListener";
import { MagicWallet } from "../wallets/wallets/MagicWallet";
import { useWalletContext } from "@thirdweb-dev/react-core";
type DappContextType = {
smartWallet?: SmartWallet;
setSmartWallet?: (value?: SmartWallet) => void;
magicWallet?: MagicWallet;
setMagicWallet?: (value?: MagicWallet) => void;
};
const DappContext = createContext<DappContextType>({});
export const DappContextProvider = (props: React.PropsWithChildren<{}>) => {
const [smartWallet, setSmartWallet] = useState<SmartWallet | undefined>();
const [magicWallet, setMagicWallet] = useState<MagicWallet | undefined>();
const createdWalletInstance = useWalletContext().createdWalletInstance;
useEffect(() => {
if (createdWalletInstance?.walletId === walletIds.magicLink) {
setMagicWallet(createdWalletInstance as MagicWallet);
}
}, [createdWalletInstance, setMagicWallet]);
useWalletConnectListener();
const magicSDK = useCallback(() => {
if (magicWallet) {
const magic = magicWallet.getMagicSDK();
return <magic.Relayer />;
}
return null;
}, [magicWallet]);
return (
<DappContext.Provider value={{ smartWallet, setSmartWallet }}>
<DappContext.Provider
value={{
smartWallet,
setSmartWallet,
magicWallet: magicWallet,
setMagicWallet: setMagicWallet,
}}
>
{props.children}
{magicSDK()}
</DappContext.Provider>
);
};
@@ -27,3 +65,12 @@ export const useSmartWallet = () => {
return [context.smartWallet, context.setSmartWallet] as const;
};
export const useMagicWallet = () => {
const context = useContext(DappContext);
return {
magicWallet: context.magicWallet,
setMagicWallet: context.setMagicWallet,
} as const;
};
@@ -5,7 +5,7 @@ import {
ThirdwebProviderCoreProps,
WalletConfig,
} from "@thirdweb-dev/react-core";
import { PropsWithChildren } from "react";
import { PropsWithChildren, useMemo } from "react";
import type { Chain, defaultChains } from "@thirdweb-dev/chains";
import { SecureStorage } from "../../core/SecureStorage";
import { useCoinbaseWalletListener } from "../wallets/hooks/useCoinbaseWalletListener";
@@ -14,6 +14,8 @@ import { DappContextProvider } from "./context-provider";
import { UIContextProvider } from "./ui-context-provider";
import { MainModal } from "../components/MainModal";
import { ThemeProvider } from "../styles/ThemeProvider";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { walletIds } from "@thirdweb-dev/wallets";
interface ThirdwebProviderProps<TChains extends Chain[]>
extends Omit<ThirdwebProviderCoreProps<TChains>, "supportedWallets"> {
@@ -30,7 +32,7 @@ interface ThirdwebProviderProps<TChains extends Chain[]>
* />
* ```
*/
supportedWallets?: WalletConfig[];
supportedWallets?: WalletConfig<any, any>[];
}
/**
@@ -65,6 +67,11 @@ export const ThirdwebProvider = <
}: PropsWithChildren<ThirdwebProviderProps<TChains>>) => {
useCoinbaseWalletListener();
const hasMagicConfig = useMemo(
() => !!supportedWallets.find((wc) => wc.id === walletIds.magicLink),
[supportedWallets],
);
return (
<ThirdwebProviderCore
thirdwebApiKey={thirdwebApiKey}
@@ -79,14 +86,23 @@ export const ThirdwebProvider = <
createWalletStorage={createWalletStorage}
{...restProps}
>
<DappContextProvider>
<ThemeProvider theme={theme}>
<UIContextProvider>
{children}
<MainModal />
</UIContextProvider>
</ThemeProvider>
</DappContextProvider>
<ThemeProvider theme={theme}>
<UIContextProvider>
{hasMagicConfig ? (
<SafeAreaProvider>
<DappContextProvider>
{children}
<MainModal />
</DappContextProvider>
</SafeAreaProvider>
) : (
<DappContextProvider>
{children}
<MainModal />
</DappContextProvider>
)}
</UIContextProvider>
</ThemeProvider>
</ThirdwebProviderCore>
);
};
@@ -1,4 +1,5 @@
import { WalletConfig } from "@thirdweb-dev/react-core";
import { WCProposal, WCRequest } from "@thirdweb-dev/wallets";
export const CLOSE_MODAL_STATE = (caller: Caller): ModalState => {
return {
@@ -25,7 +26,11 @@ export type Caller =
| "ConnectWalletDetails"
| "ConnectWalletDetailsModal"
| "ConnectWalletFlow"
| "MainModal";
| "MainModal"
| "SessionRequestModal"
| "SessionProposalModal"
| "WCSessionProposalListener"
| "WCSessionRequestListener";
export type SheetModal = {
isOpen: boolean;
@@ -65,7 +70,20 @@ export type WalletDetailsModal = {
data: WalletDetailsData;
} & SheetModal;
// wallet connect
export type WalletConnectSessionRequestModal = {
view: "WalletConnectSessionRequestModal";
data: WCRequest;
} & DialogModal;
export type WalletConnectSessionProposalModal = {
view: "WalletConnectSessionProposalModal";
data: WCProposal;
} & DialogModal;
export type ModalState =
| ClosedModal
| ConnectWalletFlowModal
| WalletDetailsModal;
| WalletDetailsModal
| WalletConnectSessionRequestModal
| WalletConnectSessionProposalModal;
@@ -0,0 +1,3 @@
export const hasMethod = (obj: any, method: string): boolean => {
return method in obj && typeof obj[method] === "function";
};
@@ -0,0 +1,198 @@
import {
Magic,
MagicSDKAdditionalConfiguration,
} from "@magic-sdk/react-native-bare";
import { Chain, Connector, normalizeChainId } from "@thirdweb-dev/wallets";
import { Signer, ethers, providers } from "ethers";
import { defaultChains } from "@thirdweb-dev/chains";
import { MagicConnectorOptions } from "./types";
export class MagicConnector extends Connector<MagicConnectorOptions> {
magicSDK: Magic;
magicOptions: MagicConnectorOptions;
provider: any | undefined;
chains: Chain[];
magicSdkConfiguration: MagicSDKAdditionalConfiguration | undefined;
connectedChainId: number | undefined;
constructor(options: MagicConnectorOptions) {
super();
this.magicOptions = options;
this.chains = options.chains ? options.chains : defaultChains;
this.magicSdkConfiguration = options.magicSdkConfiguration;
this.magicSDK = this.initializeMagicSDK({ chainId: options?.chainId || 0 });
}
async connect(options: MagicConnectorOptions): Promise<string> {
if (!this.magicOptions.apiKey) {
throw new Error("Magic API Key is not provided.");
}
// if (options.chainId) {
// this.initializeMagicSDK({ chainId: options.chainId });
// }
await this.getProvider();
this.setupListeners();
this.emit("message", { type: "connecting" });
// Check if there is a user logged in
const isAuthenticated = await this.isConnected();
// Check if we have a chainId, in case of error just assign 0 for legacy
let chainId: number;
try {
chainId = await this.getChainId();
} catch (e) {
chainId = 0;
}
this.connectedChainId = chainId;
// if there is a user logged in, return the user
if (isAuthenticated) {
return await this.getAddress();
}
const magic = this.getMagicSDK();
// LOGIN WITH MAGIC LINK WITH EMAIL
if (options.email) {
await magic.auth.loginWithEmailOTP({
email: options.email,
});
}
// LOGIN WITH MAGIC LINK WITH PHONE NUMBER
if (options.phoneNumber) {
await magic.auth.loginWithSMS({
phoneNumber: options.phoneNumber,
});
}
const signer = await this.getSigner();
let address = await signer.getAddress();
if (!address.startsWith("0x")) {
address = `0x${address}`;
}
return address;
}
async disconnect(): Promise<void> {
const magic = this.getMagicSDK();
await magic.user.logout();
}
async getAddress(): Promise<string> {
const signer = await this.getSigner();
const account = await signer.getAddress();
if (account.startsWith("0x")) {
return account;
}
return `0x${account}`;
}
async getSigner(): Promise<Signer> {
const provider = new ethers.providers.Web3Provider(
(await this.getProvider()) as any, // TODO: fix type mismatch
);
const signer = await provider.getSigner();
return signer;
}
getProvider(): Promise<providers.Provider> {
if (this.provider) {
return this.provider;
}
const magic = this.getMagicSDK();
this.provider = magic.rpcProvider;
return this.provider;
}
switchChain(chainId: number): Promise<void> {
const chain = this.chains.find((c) => c.chainId === chainId);
if (!chain) {
throw new Error("Chain not found");
}
if (this.connectedChainId !== chainId) {
this.initializeMagicSDK({ chainId });
}
return Promise.resolve();
}
isConnected(): Promise<boolean> {
const magic = this.getMagicSDK();
try {
return magic.user.isLoggedIn();
} catch (e) {
return Promise.resolve(false);
}
}
async setupListeners(): Promise<void> {
this.provider?.on("accountsChanged", () => {
throw new Error("Accounts changed not implemented");
});
this.provider?.on("chainChanged", this.onChainChanged);
this.provider?.on("disconnect", this.onDisconnect);
return Promise.resolve();
}
updateChains(chains: Chain[]): void {
this.chains = chains;
}
// my methods
onDisconnect(): void {
this.emit("disconnect");
}
getMagicSDK() {
if (!this.magicSDK) {
return this.initializeMagicSDK();
}
return this.magicSDK;
}
initializeMagicSDK({ chainId }: { chainId?: number } = {}) {
if (chainId) {
const chain = this.chains.find((c) => c.chainId === chainId);
if (chain) {
this.magicSdkConfiguration = this.magicSdkConfiguration || {};
this.magicSdkConfiguration.network = {
rpcUrl: chain.rpc[0],
chainId: chain.chainId,
};
}
}
this.magicSDK = new Magic(
this.magicOptions.apiKey,
this.magicSdkConfiguration,
);
this.provider = this.magicSDK.rpcProvider;
return this.magicSDK;
}
async getChainId(): Promise<number> {
const networkOptions = this.magicSdkConfiguration?.network;
if (typeof networkOptions === "object") {
const chainID = networkOptions.chainId;
if (chainID) {
return normalizeChainId(chainID);
}
}
throw new Error("Chain ID is not defined");
}
protected isChainUnsupported(chainId: number) {
return !this.chains.some((x) => x.chainId === chainId);
}
protected onChainChanged(chainId: string | number): void {
const id = normalizeChainId(chainId);
const unsupported = this.isChainUnsupported(id);
this.emit("change", { chain: { id, unsupported } });
}
}
@@ -0,0 +1,14 @@
import { MagicSDKAdditionalConfiguration } from "@magic-sdk/react-native-bare";
import { Chain } from "@thirdweb-dev/chains";
import { WalletOptions } from "@thirdweb-dev/wallets";
export interface MagicConnectorOptions {
apiKey: string;
magicSdkConfiguration?: MagicSDKAdditionalConfiguration;
chains?: Chain[];
chainId?: number;
email?: string;
phoneNumber?: string;
}
export type MagicLinkOptions = WalletOptions<MagicConnectorOptions>;
@@ -0,0 +1,64 @@
import { useWallet } from "@thirdweb-dev/react-core";
import { useCallback, useEffect } from "react";
import { useModalState } from "../../providers/ui-context-provider";
import {
IWalletConnectReceiver,
WCProposal,
WCRequest,
} from "@thirdweb-dev/wallets";
/**
* Registers listeners for wallet connect if the active wallet
* is a smart wallet and has connect to app enabled
*/
export function useWalletConnectListener() {
const activeWallet = useWallet();
const { setModalState } = useModalState();
const onSmartWalletWCMessage = useCallback(
({ type, data }: { type: string; data?: unknown }) => {
switch (type) {
case "session_proposal":
setModalState({
view: "WalletConnectSessionProposalModal",
caller: "WCSessionProposalListener",
data: data as WCProposal,
isOpen: true,
isSheet: false,
});
break;
case "session_delete":
// reset();
break;
case "session_request":
setModalState({
view: "WalletConnectSessionRequestModal",
caller: "WCSessionRequestListener",
data: data as WCRequest,
isOpen: true,
isSheet: false,
});
break;
default:
// method not implemented
}
},
[setModalState],
);
useEffect(() => {
if (
activeWallet &&
"isWCReceiverEnabled" in activeWallet &&
(activeWallet as unknown as IWalletConnectReceiver).isWCReceiverEnabled()
) {
activeWallet.addListener("message", onSmartWalletWCMessage);
}
return () => {
if (activeWallet) {
activeWallet.removeListener("message", onSmartWalletWCMessage);
}
};
}, [activeWallet, onSmartWalletWCMessage]);
}
@@ -0,0 +1,70 @@
import { AbstractClientWallet, walletIds } from "@thirdweb-dev/wallets";
import {
MagicConnectorOptions,
MagicLinkOptions,
} from "../connectors/magic/types";
import type { MagicConnector as MagicConnectorType } from "../connectors/magic/magic-connector";
import { MagicConnector } from "../connectors/magic/magic-connector";
export class MagicWallet extends AbstractClientWallet<
MagicLinkOptions,
MagicConnectorOptions
> {
connector?: MagicConnectorType;
options: MagicLinkOptions;
static meta = {
iconURL:
"ipfs://QmUMBFZGXxBpgDmZzZAHhbcCL5nYvZnVaYLTajsNjLcxMU/1-Icon_Magic_Color.svg",
name: "Magic Link",
};
static id = walletIds.magicLink;
constructor(options: MagicLinkOptions) {
super(walletIds.magicLink, options);
this.options = options;
this.initializeConnector();
}
async getConnector(): Promise<MagicConnectorType> {
if (!this.connector) {
return await this.initializeConnector();
}
return this.connector;
}
// my methods
initializeConnector() {
this.connector = new MagicConnector({
...this.options,
chainId: this.options.chainId,
chains: this.chains,
});
return this.connector;
}
getMagicSDK() {
return (this.connector as MagicConnector)?.getMagicSDK();
}
async autoConnect(options?: MagicConnectorOptions) {
this.connector?.initializeMagicSDK(options);
const magic = this.getMagicSDK();
if (await magic.user.isLoggedIn()) {
return super.autoConnect(options);
} else {
throw new Error("Magic user is not logged in");
}
}
async disconnect() {
const magic = this.getMagicSDK();
await magic.user.logout();
return super.disconnect();
}
}
@@ -0,0 +1,132 @@
import { walletIds } from "@thirdweb-dev/wallets";
import {
ConnectUIProps,
SelectUIProps,
WalletConfig,
WalletOptions,
useCreateWalletInstance,
useSetConnectedWallet,
useSetConnectionStatus,
useWalletContext,
} from "@thirdweb-dev/react-core";
import { MagicLinkOptions } from "../connectors/magic/types";
import { MagicWallet } from "./MagicWallet";
import { useEffect, useRef } from "react";
import Box from "../../components/base/Box";
import { TextInput } from "../../components/base/TextInput";
import Text from "../../components/base/Text";
import { ActivityIndicator } from "react-native";
import { useMagicWallet } from "../../providers/context-provider";
export const magicWallet = (
config: MagicLinkOptions,
): WalletConfig<MagicWallet, MagicLinkOptions> => {
return {
id: walletIds.magicLink,
meta: MagicWallet.meta,
create: (options: WalletOptions) => {
return new MagicWallet({
...options,
...config,
chainId: options.chain.chainId,
});
},
/**
* UI for connecting wallet
*/
connectUI: MagicConnectionUI,
/**
* UI for selecting wallet - this UI is rendered in the wallet selection screen
*/
selectUI: (props: SelectUIProps<MagicWallet, MagicLinkOptions>) => {
return (
<Box flex={1}>
<TextInput
placeholder="Enter your email or phone number"
placeholderTextColor="gray"
onEndEditing={(
e: (typeof TextInput)["arguments"]["onEndEditing"],
) => {
props.onSelect(e.nativeEvent.text);
}}
/>
<Text
marginVertical="sm"
variant="bodySmallSecondary"
textAlign="center"
>
---- OR ----
</Text>
</Box>
);
},
isInstalled: () => {
return true;
},
config: {
...config,
},
};
};
const MagicConnectionUI: React.FC<
ConnectUIProps<MagicWallet, MagicLinkOptions>
> = ({ selectionData, walletConfig, close }) => {
const createWalletInstance = useCreateWalletInstance();
const setConnectedWallet = useSetConnectedWallet();
const chainToConnect = useWalletContext().chainToConnect;
const setConnectionStatus = useSetConnectionStatus();
const { magicWallet: ctxMagicWallet, setMagicWallet } = useMagicWallet();
useEffect(() => {
const inst = createWalletInstance(walletConfig);
setMagicWallet?.(inst);
}, [createWalletInstance, setMagicWallet, walletConfig]);
const connectPrompted = useRef(false);
useEffect(() => {
if (connectPrompted.current || !ctxMagicWallet) {
return;
}
connectPrompted.current = true;
const isEmail = (selectionData as string).includes("@");
(async () => {
// close();
try {
setConnectionStatus("connecting");
const connectParams = {
chainId: chainToConnect?.chainId,
...walletConfig.config,
...(isEmail
? { email: selectionData }
: { phoneNumber: selectionData }),
};
close();
await ctxMagicWallet.connect(connectParams);
await ctxMagicWallet.getMagicSDK().user.getMetadata();
setConnectedWallet(ctxMagicWallet, connectParams);
setConnectionStatus("connected");
} catch (e) {
setConnectionStatus("disconnected");
console.error("Error connecting to magic", e);
}
})();
}, [
selectionData,
walletConfig,
close,
ctxMagicWallet,
setConnectedWallet,
setConnectionStatus,
chainToConnect?.chainId,
]);
return (
<Box minHeight={500}>
<ActivityIndicator size="small" />
</Box>
);
};
@@ -1,29 +1,34 @@
import type { WalletConfig, WalletOptions } from "@thirdweb-dev/react-core";
import { SmartWallet } from "@thirdweb-dev/wallets";
import {
SmartWallet,
SmartWalletConfig as SmartWalletConfigWallets,
createAsyncLocalStorage,
} from "@thirdweb-dev/wallets";
import { DEFAULT_WALLETS } from "../../constants/wallets";
import { createSyncStorage } from "../../../core/AsyncStorage";
type SafeWalletConfig = {
factoryAddress: string;
thirdwebApiKey: string;
gasless: boolean;
personalWallets: WalletConfig[];
};
type SmartWalletConfig = {
personalWallets?: WalletConfig<any, any>[];
} & Omit<SmartWalletConfigWallets, "chain">;
export type SmartWalletObj = WalletConfig<SmartWallet, SafeWalletConfig>;
export type SmartWalletObj = WalletConfig<SmartWallet, SmartWalletConfig>;
export const smartWallet = (
config: Omit<SafeWalletConfig, "personalWallets"> & {
personalWallets?: WalletConfig[];
},
) => {
config: SmartWalletConfig,
): WalletConfig<SmartWallet, SmartWalletConfig> => {
return {
id: SmartWallet.id,
meta: SmartWallet.meta,
create: (options: WalletOptions) =>
new SmartWallet({ ...options, ...config }),
new SmartWallet({
...options,
...config,
walletStorage: createAsyncLocalStorage("smart-wallet"),
wcStorage: createSyncStorage("smart-wallet"),
}),
config: {
...config,
personalWallets: config.personalWallets || DEFAULT_WALLETS,
},
} satisfies WalletConfig<SmartWallet, SafeWalletConfig>;
};
};
+27
View File
@@ -1,5 +1,32 @@
# @thirdweb-dev/react
## 3.12.4
### Patch Changes
- Updated dependencies [[`23d90b3e`](https://github.com/thirdweb-dev/js/commit/23d90b3e779a5bfdb7058b8c51349d9c278fcbce), [`cc56037e`](https://github.com/thirdweb-dev/js/commit/cc56037e64560b9e0fc16eb0ac7cc2e47e2c9fdf)]:
- @thirdweb-dev/sdk@3.10.19
- @thirdweb-dev/react-core@3.12.4
- @thirdweb-dev/wallets@0.2.24
## 3.12.3
### Patch Changes
- [#1068](https://github.com/thirdweb-dev/js/pull/1068) [`fd7111d5`](https://github.com/thirdweb-dev/js/commit/fd7111d5449b8315d326c308a021eed335446e19) Thanks [@MananTank](https://github.com/MananTank)! - add `theme` in `WalletConfig.selectUI` to allow creating selection UI that follows the theme of the wallet Modal
- [#1084](https://github.com/thirdweb-dev/js/pull/1084) [`74f898ac`](https://github.com/thirdweb-dev/js/commit/74f898ac2830c532907626f70509820e30304855) Thanks [@MananTank](https://github.com/MananTank)! - Fix Local Wallet Backup throwing error when wallet is not connected
- [#1078](https://github.com/thirdweb-dev/js/pull/1078) [`f5ae61ae`](https://github.com/thirdweb-dev/js/commit/f5ae61aebaa152485b92b6adf60765a7eaf5dbf0) Thanks [@MananTank](https://github.com/MananTank)! - Fixes the issue of Magic Link's "Switch Network" not working with Smart Wallet and Safe
- [#1067](https://github.com/thirdweb-dev/js/pull/1067) [`e21bdd03`](https://github.com/thirdweb-dev/js/commit/e21bdd0328d9c52d58295aa4012fc11cde83b60a) Thanks [@MananTank](https://github.com/MananTank)! - Fix `usePaperWallet` hook's type definition
- Updated dependencies [[`2f1df0b5`](https://github.com/thirdweb-dev/js/commit/2f1df0b5354a8ee55089b2c1e61c058788d890f1), [`189daf02`](https://github.com/thirdweb-dev/js/commit/189daf0280a90ed730200088948526a594da3408), [`afae0873`](https://github.com/thirdweb-dev/js/commit/afae0873b0e3f9741f5a9c44c5d255f38c6a9111), [`bba9767a`](https://github.com/thirdweb-dev/js/commit/bba9767adfe20e41055450b86e4448fcb2119855), [`c6e74ef0`](https://github.com/thirdweb-dev/js/commit/c6e74ef0b00210f52e6778c548061376d3ba7001), [`fd7111d5`](https://github.com/thirdweb-dev/js/commit/fd7111d5449b8315d326c308a021eed335446e19), [`ee4c7de2`](https://github.com/thirdweb-dev/js/commit/ee4c7de25cb63f99f33b90da8e26293bbfbe6f3e), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`68fa1896`](https://github.com/thirdweb-dev/js/commit/68fa1896f75d3514e00cc380924fd8bc623064f0), [`e21bdd03`](https://github.com/thirdweb-dev/js/commit/e21bdd0328d9c52d58295aa4012fc11cde83b60a), [`f7b352a5`](https://github.com/thirdweb-dev/js/commit/f7b352a585a23726eaa3be116f65db56b005f4d8), [`4a1d7581`](https://github.com/thirdweb-dev/js/commit/4a1d75811058d6974616bdc12a6040cea5444e40), [`bdabbef7`](https://github.com/thirdweb-dev/js/commit/bdabbef71a2421a2dceb384f93bb6a59a3ddf007), [`59206233`](https://github.com/thirdweb-dev/js/commit/59206233e15ccfe3dc32047060055219d35938f2), [`292a321a`](https://github.com/thirdweb-dev/js/commit/292a321a95ed2d847097eed205353dd69eeb8d54), [`98efd090`](https://github.com/thirdweb-dev/js/commit/98efd090f63cfd9dfed7b89b20b6e43db88cf75c), [`8eecf4c2`](https://github.com/thirdweb-dev/js/commit/8eecf4c2d5b0d6447ad5b9cdbf0269818bbb3498), [`bd86661f`](https://github.com/thirdweb-dev/js/commit/bd86661f54ca2f1eb09cbae35c704dc79be1b63a), [`f3b2ae3f`](https://github.com/thirdweb-dev/js/commit/f3b2ae3f6d9c66356c521d3b9c2a6c096dbb4b57), [`d5651006`](https://github.com/thirdweb-dev/js/commit/d565100614d7d4e256554f998b8ce978a566051c), [`4f99ccb4`](https://github.com/thirdweb-dev/js/commit/4f99ccb49c584946de709fbc01017611d2828b76), [`da576108`](https://github.com/thirdweb-dev/js/commit/da5761080288c3b325f54fb56c80f96405a1cb5d), [`c85810ee`](https://github.com/thirdweb-dev/js/commit/c85810eee318b10eee4ada61828adaa51f94ea6c), [`6fd10f94`](https://github.com/thirdweb-dev/js/commit/6fd10f94b469dc5659e2ff4ce92a5aff86f3c89d), [`5f1e6abb`](https://github.com/thirdweb-dev/js/commit/5f1e6abb391f5c58dbdb207f569b3dd0b5d4729c), [`a034b032`](https://github.com/thirdweb-dev/js/commit/a034b0321fd0113ed51d95d538b5c3020615c227), [`35984362`](https://github.com/thirdweb-dev/js/commit/35984362b0a60e5b9c3d3c9731450a8f47deb1c4)]:
- @thirdweb-dev/sdk@3.10.18
- @thirdweb-dev/wallets@0.2.23
- @thirdweb-dev/react-core@3.12.3
- @thirdweb-dev/chains@0.1.19
## 3.12.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.12.2",
"version": "3.12.4",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -11,11 +11,18 @@ import type { PaperSupportedChainId } from "@thirdweb-dev/wallets/evm/connectors
export function usePaperWallet() {
const connect = useConnect();
return useCallback(
async (options: { chainId?: PaperSupportedChainId; clientId: string }) => {
async (options: {
chainId?: PaperSupportedChainId;
clientId: string;
email?: string;
}) => {
const { paperWallet } = await import(
"../../../wallet/wallets/paperWallet"
);
return connect(paperWallet({ clientId: options.clientId }), options);
return connect(paperWallet({ clientId: options.clientId }), {
chainId: options.chainId,
email: options.email,
});
},
[connect],
);
@@ -1,14 +1,12 @@
import { useConnect } from "@thirdweb-dev/react-core";
import type {
SmartWalletConnectionArgs,
SmartWalletConfig,
} from "@thirdweb-dev/wallets/evm/wallets/smart-wallet";
import type { SmartWalletConfigOptions } from "../../../wallet/wallets/smartWallet/types";
import type { SmartWalletConnectionArgs } from "@thirdweb-dev/wallets/evm/wallets/smart-wallet";
import { useCallback } from "react";
export function useSmartWallet() {
const connect = useConnect();
return useCallback(
async (options: SmartWalletConnectionArgs & SmartWalletConfig) => {
async (options: SmartWalletConnectionArgs & SmartWalletConfigOptions) => {
const { smartWallet } = await import(
"../../../wallet/wallets/smartWallet/smartWallet"
);
@@ -41,13 +41,14 @@ import {
} from "@thirdweb-dev/react-core";
import { useState } from "react";
import { fadeInAnimation } from "../../components/FadeIn";
import { LocalWallet, MetaMaskWallet, walletIds } from "@thirdweb-dev/wallets";
import { MetaMaskWallet, walletIds } from "@thirdweb-dev/wallets";
import { Flex } from "../../components/basic";
import { FundsIcon } from "./icons/FundsIcon";
import { ExportLocalWallet } from "../wallets/localWallet/ExportLocalWallet";
import { ErrorMessage } from "../../components/formElements";
import { useWalletContext } from "@thirdweb-dev/react-core";
import { useWalletConfig } from "@thirdweb-dev/react-core";
import { LocalWalletConfig } from "../wallets/localWallet/types";
export type DropDownPosition = {
side: "top" | "bottom" | "left" | "right";
@@ -424,7 +425,7 @@ export const ConnectedWalletDetails: React.FC<{
}}
>
<ExportLocalWallet
localWallet={activeWallet as LocalWallet}
localWalletConfig={activeWalletConfig as LocalWalletConfig}
onBack={() => {
setShowExportModal(false);
}}
@@ -14,7 +14,10 @@ import {
import styled from "@emotion/styled";
import { WalletConfig } from "@thirdweb-dev/react-core";
import { walletIds } from "@thirdweb-dev/wallets";
import { SetModalConfigCtx } from "../../evm/providers/wallet-ui-states-provider";
import {
ModalConfigCtx,
SetModalConfigCtx,
} from "../../evm/providers/wallet-ui-states-provider";
export const WalletSelector: React.FC<{
walletConfigs: WalletConfig[];
@@ -81,6 +84,7 @@ export const WalletSelection: React.FC<{
walletConfigs: WalletConfig[];
selectWallet: (wallet: WalletConfig) => void;
}> = (props) => {
const modalConfig = useContext(ModalConfigCtx);
const setModalConfig = useContext(SetModalConfigCtx);
const walletConfigs = props.walletConfigs
// show the installed wallets first
@@ -117,6 +121,7 @@ export const WalletSelection: React.FC<{
<li key={walletConfig.id}>
{walletConfig.selectUI ? (
<walletConfig.selectUI
theme={modalConfig.theme}
supportedWallets={props.walletConfigs}
onSelect={(data) => {
props.selectWallet(walletConfig);
@@ -15,12 +15,12 @@ import { Flex } from "../../../components/basic";
import { TextDivider } from "../../../components/TextDivider";
import { Spinner } from "../../../components/Spinner";
import { spacing } from "../../../design-system";
import { LocalConfiguredWallet } from "./types";
import { LocalWalletConfig } from "./types";
export const CreateLocalWallet_Password: React.FC<{
onConnect: () => void;
goBack: () => void;
localWalletConf: LocalConfiguredWallet;
localWalletConf: LocalWalletConfig;
renderBackButton: boolean;
}> = (props) => {
const [password, setPassword] = useState("");
@@ -190,7 +190,7 @@ export const CreateLocalWallet_Password: React.FC<{
export const CreateLocalWallet_Guest: React.FC<{
onConnect: () => void;
goBack: () => void;
localWallet: LocalConfiguredWallet;
localWallet: LocalWalletConfig;
}> = (props) => {
const { localWallet } = useLocalWalletInfo(props.localWallet);
const { setConnectedWallet } = useWalletContext();
@@ -10,13 +10,19 @@ import styled from "@emotion/styled";
import { fontSize } from "../../../design-system";
import { EyeClosedIcon, EyeOpenIcon } from "@radix-ui/react-icons";
import { FormFieldWithIconButton } from "../../../components/formFields";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { shortenAddress } from "../../../evm/utils/addresses";
import type { LocalWallet } from "@thirdweb-dev/wallets";
import { LocalWallet } from "@thirdweb-dev/wallets";
import type { WalletData } from "@thirdweb-dev/wallets/evm/wallets/local-wallet";
import { Img } from "../../../components/Img";
import { Spinner } from "../../../components/Spinner";
import { Flex } from "../../../components/basic";
import {
useAddress,
useCreateWalletInstance,
useWallet,
} from "@thirdweb-dev/react-core";
import { LocalWalletConfig } from "./types";
const localWalletIcon =
"ipfs://QmbQzSNGvmNYZzem9jZRuYeLe9K2W4pqbdnVUp7Y6edQ8Y/local-wallet.svg";
@@ -24,68 +30,94 @@ const localWalletIcon =
export const ExportLocalWallet: React.FC<{
onBack: () => void;
onExport: () => void;
localWallet: LocalWallet;
localWalletConfig: LocalWalletConfig;
}> = (props) => {
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [isWrongPassword, setIsWrongPassword] = useState(false);
const [address, setAddress] = useState("");
const [savedData, setSavedData] = useState<WalletData | null | "loading">(
"loading",
);
const [passwordIsRequired, setPasswordIsRequired] = useState(false);
useEffect(() => {
props.localWallet.getAddress().then((add) => {
setAddress(add);
});
}, [props.localWallet]);
const wallet = useWallet();
const address = useAddress();
const [savedAddress, setSavedAddress] = useState("");
const createWalletInstance = useCreateWalletInstance();
// set savedAddress and passwordIsRequired on mount
const mounted = useRef(false);
useEffect(() => {
if (!address) {
if (mounted.current) {
return;
}
props.localWallet.getSavedData().then((data) => {
if (data) {
if (data.address === address) {
setSavedData(data);
} else {
setSavedData(null);
mounted.current = true;
(async () => {
// if local wallet is connected - show the address of the connected wallet
if (wallet && wallet instanceof LocalWallet) {
if (address) {
setSavedAddress(address);
}
// if walletData of it is not already saved - password is required
const savedData = await wallet.getSavedData();
if (savedData?.address !== address) {
setPasswordIsRequired(true);
}
} else {
setSavedData(null);
}
});
}, [props.localWallet, address]);
// if localWallet is not connected - get address from storage, password is not required
else {
const localWallet = createWalletInstance(props.localWalletConfig);
const data = await localWallet.getSavedData();
if (data) {
setSavedAddress(data.address);
}
}
})();
}, [
wallet,
props.localWalletConfig,
createWalletInstance,
password,
address,
]);
const exportFromLocalStorage = async () => {
if (!props.localWallet || savedData === "loading") {
throw new Error("invalid state");
// if a local wallet is connected - export it
if (wallet && wallet instanceof LocalWallet) {
const savedData = await wallet.getSavedData();
// if already saved - no password required
if (savedData && savedData.address === address) {
downloadJsonWalletFile(savedData.data);
props.onExport();
}
// if not already saved - password is required
else {
try {
const dataStr = await wallet.export({
password,
strategy: "encryptedJson",
});
downloadJsonWalletFile(dataStr);
props.onExport();
} catch (e) {
console.error(e);
setIsWrongPassword(true);
}
}
}
if (savedData) {
downloadAsFile(
JSON.parse(savedData.data),
"wallet.json",
"application/json",
);
// if local wallet is not connected - get data from storage
else {
const localWallet = createWalletInstance(props.localWalletConfig);
const savedData = (await localWallet.getSavedData()) as WalletData;
downloadJsonWalletFile(savedData.data);
props.onExport();
} else {
try {
const json = await props.localWallet.export({
strategy: "encryptedJson",
password,
});
downloadAsFile(JSON.parse(json), "wallet.json", "application/json");
props.onExport();
} catch (e) {
setIsWrongPassword(true);
return;
}
}
};
if (savedData === "loading") {
if (!savedAddress) {
return (
<Flex
justifyContent="center"
@@ -99,7 +131,7 @@ export const ExportLocalWallet: React.FC<{
);
}
const disabled = isWrongPassword;
const exportDisabled = isWrongPassword;
return (
<>
@@ -116,8 +148,15 @@ export const ExportLocalWallet: React.FC<{
<Spacer y="md" />
<ModalDescription>
This will download a JSON file containing your wallet information onto
your device encrypted with the password.
This will download a JSON file containing the wallet information onto
your device encrypted with the password
</ModalDescription>
<Spacer y="sm" />
<ModalDescription>
You can use this JSON file to import the account in MetaMask using the
same password
</ModalDescription>
<Spacer y="xl" />
@@ -131,13 +170,11 @@ export const ExportLocalWallet: React.FC<{
<Label>Wallet Address</Label>
<Spacer y="sm" />
<SavedWalletAddress>
{address ? shortenAddress(address) : "Loading"}
</SavedWalletAddress>
<SavedWalletAddress>{shortenAddress(savedAddress)}</SavedWalletAddress>
<Spacer y="lg" />
{!savedData && (
{passwordIsRequired && (
<>
{/* Hidden Account Address as Username */}
<input
@@ -175,10 +212,10 @@ export const ExportLocalWallet: React.FC<{
<FormFooter>
<Button
disabled={disabled}
disabled={exportDisabled}
variant="inverted"
style={{
opacity: disabled ? 0.5 : 1,
opacity: exportDisabled ? 0.5 : 1,
}}
type="submit"
>
@@ -190,15 +227,16 @@ export const ExportLocalWallet: React.FC<{
);
};
function downloadAsFile(data: any, fileName: string, fileType: string) {
const blob = new Blob([JSON.stringify(data, null, 2)], {
type: fileType,
function downloadJsonWalletFile(data: string) {
const dataObj = JSON.parse(data);
const blob = new Blob([JSON.stringify(dataObj, null, 2)], {
type: "application/json",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = fileName;
a.download = "wallet.json";
document.body.appendChild(a);
a.style.display = "none";
a.click();
@@ -16,12 +16,12 @@ import { useLocalWalletInfo } from "./useLocalWalletInfo";
import { FormFooter } from "../../../components/formElements";
import { LocalWallet } from "@thirdweb-dev/wallets";
import { LocalWalletModalHeader } from "./common";
import { LocalConfiguredWallet } from "./types";
import { LocalWalletConfig } from "./types";
export const ImportLocalWallet: React.FC<{
onConnect: () => void;
goBack: () => void;
localWalletConf: LocalConfiguredWallet;
localWalletConf: LocalWalletConfig;
}> = (props) => {
const [jsonString, setJsonString] = useState<string | undefined>();
const { setLocalWallet, meta } = useLocalWalletInfo(props.localWalletConf);
@@ -6,12 +6,12 @@ import {
import { ReconnectLocalWallet } from "./ReconnectLocalWallet";
import { Flex } from "../../../components/basic";
import { ConnectUIProps } from "@thirdweb-dev/react-core";
import { LocalWalletConfig } from "./types";
import { LocalWalletConfigOptions } from "./types";
import { useLocalWalletInfo } from "./useLocalWalletInfo";
import type { LocalWallet } from "@thirdweb-dev/wallets";
export const LocalWalletConnectUI = (
props: ConnectUIProps<LocalWallet, LocalWalletConfig>,
props: ConnectUIProps<LocalWallet, LocalWalletConfigOptions>,
) => {
const { walletData } = useLocalWalletInfo(props.walletConfig);
@@ -18,12 +18,12 @@ import { CreateLocalWallet_Password } from "./CreateLocalWallet";
import { OverrideConfirmation } from "./overrideConfirmation";
import { ExportLocalWallet } from "./ExportLocalWallet";
import { useLocalWalletInfo } from "./useLocalWalletInfo";
import { LocalConfiguredWallet } from "./types";
import { LocalWalletConfig } from "./types";
type ReconnectLocalWalletProps = {
onConnect: () => void;
goBack: () => void;
localWallet: LocalConfiguredWallet;
localWallet: LocalWalletConfig;
supportedWallets: WalletConfig[];
renderBackButton: boolean;
};
@@ -59,7 +59,7 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
return (
<ExportLocalWallet
localWallet={localWallet}
localWalletConfig={props.localWallet}
onBack={() => {
setShowExport(false);
}}
@@ -79,10 +79,6 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
onBackup={() => {
setShowExport(true);
}}
onSkip={() => {
setShowBackupConfirmation(false);
setShowCreate(true);
}}
onBack={() => {
setShowBackupConfirmation(false);
}}
@@ -1,10 +1,10 @@
import { LocalWallet, WalletOptions } from "@thirdweb-dev/wallets";
import { LocalWalletConfig, LocalConfiguredWallet } from "./types";
import { LocalWalletConfigOptions, LocalWalletConfig } from "./types";
import { LocalWalletConnectUI } from "./LocalWalletConnectUI";
export const localWallet = (
config?: LocalWalletConfig,
): LocalConfiguredWallet => {
config?: LocalWalletConfigOptions,
): LocalWalletConfig => {
return {
id: LocalWallet.id,
meta: { ...LocalWallet.meta, name: "Guest Wallet" },

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