Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
af21d5be36 Version Packages (#1669)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-10-02 22:55:38 +02:00
Manan TankandGitHub 54f83a5013 [wallets, react] - add signer on ThirdwebProvider (#1637) 2023-10-02 18:49:50 +00:00
6a5bbfd2f5 [RN] Embedded fix textinput onfocus (#1691)
Co-authored-by: ElasticBottle <[email protected]>
2023-09-30 17:24:23 +00:00
Phillip HoandGitHub c5b3232e1a chore: Add usage check for EWS (#1690) 2023-09-30 02:57:22 +00:00
5dc372fc46 [ReactNative] Adds EmbeddedWallet (email) (#1561)
Co-authored-by: ElasticBottle <[email protected]>
2023-09-29 21:51:58 +00:00
Manan TankandGitHub fd378ec3e4 [react] ConnectWallet UI Fixes / Improvements (#1687) 2023-09-29 15:46:27 +00:00
iketwandGitHub 0e27f15eb9 [RN] Same color smart wallet active dot (#1685) 2023-09-28 21:49:42 +00:00
iketwandGitHub 211aab9c16 [RN] UI improvements + ENS support (#1684) 2023-09-28 21:07:18 +00:00
Manan TankandGitHub eb9e9f0ce8 [react] ConnectWallet UI improvements (#1682) 2023-09-28 17:38:29 +00:00
iketwandGitHub bd23cec7d1 [RN] Update guest wallet icon (#1683) 2023-09-28 17:32:57 +00:00
Joaquim VergesandGitHub c7e7ec9502 [SmartWallets] Fix gas estimation for first SW transaction (#1681) 2023-09-28 16:50:33 +00:00
Kien NgoandGitHub 6897ad6502 [SDK] Performance improvement to various function for ERC721 (#1678) 2023-09-28 16:41:09 +00:00
iketwandGitHub ed4172dddf [RN] Small UI improvements (#1680) 2023-09-28 16:20:09 +00:00
Kien NgoandGitHub de05c2da17 [SDK] Add unit test for ERC721 allOwners() (#1679) 2023-09-28 12:33:31 +00:00
Adam MajmudarandGitHub c085d69060 [Wallets] Add support for GCP KMS (#1665) 2023-09-27 23:32:10 +00:00
iketwandGitHub c2bfc77137 Downgrade sdk to patch update (#1677) 2023-09-27 23:17:00 +00:00
iketwandGitHub 81797ffde3 [RN] Minor version bump (#1676) 2023-09-27 21:08:58 +00:00
iketwandGitHub 69e8208538 [RN] Lots of small UI fixes (#1675) 2023-09-27 19:36:00 +00:00
Kien NgoandGitHub ee028e1209 [SDK] Improve data fetching for gas & transaction methods (#1672) 2023-09-27 18:51:24 +00:00
Joaquim VergesandGitHub b16c09df75 [SDK] Fix error waiting for transaction after gasless tx (#1674) 2023-09-27 18:10:00 +00:00
iketwandGitHub 879d4226f6 [CLI] Fix thirdweb create with options (#1673) 2023-09-27 17:00:24 +00:00
83905ef6c6 chore: minor code snippet fix (#1539)
Co-authored-by: Joaquim Verges <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2023-09-27 17:05:40 +02:00
Joaquim VergesandGitHub f8c8c12ebc [README] add chains to readme table (#1671) 2023-09-27 14:58:48 +00:00
Joaquim VergesandGitHub a9b4b0c5d8 [SDK] Expose proxy resolver helper function (#1670) 2023-09-27 14:44:22 +00:00
Kien NgoandGitHub d28b1c0f1e [SDK] Various improvement to data fetching in some erc721 modules (#1666) 2023-09-27 14:20:44 +00:00
Kien NgoandGitHub 96e832cc80 [SDK] Various improvement to data fetching in erc-20.ts (#1667) 2023-09-27 13:30:22 +00:00
Kien NgoandGitHub bdb2ccc7a6 [SDK] Slight improvement to getContract() (#1668) 2023-09-27 13:28:38 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
e1b05fcea3 Version Packages (#1625)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-27 13:49:09 +02:00
Phillip HoandGitHub 426c75a330 refactor: Update cf-worker to use sample rate + Redis (#1657) 2023-09-27 02:49:40 +00:00
Manan TankandGitHub a9854e69ce [react] Fix Img element crashing app on invalid URL (#1664) 2023-09-26 23:23:12 +00:00
FirekeeperandGitHub 2097e233cb [Unity] Add EmbeddedWallet option WebGL (#1663) 2023-09-26 22:12:15 +00:00
c29042b71e [SDK] Update Promise.all (#1660)
Co-authored-by: Jonas Daniels <[email protected]>
2023-09-26 15:08:19 -07:00
Adam MajmudarandGitHub b5b7e5243d [SDK] Add support for prepare to account extension (#1643) 2023-09-26 21:18:51 +00:00
Jonas DanielsandGitHub d5fafddea5 chore(chains): update (#1662) 2023-09-26 20:45:01 +00:00
Joaquim VergesandGitHub b6df6b8957 Fix not resolving custom chain currencies (#1661) 2023-09-26 20:01:25 +00:00
iketwandGitHub 45112a613e [RN] ConnectWalletV3 Details Modal (#1642) 2023-09-26 18:21:50 +00:00
Winston YeoandGitHub ea5b9c3ecd fix(react): show recovery password modal for USER_MANAGED in paperWallet (#1659) 2023-09-26 15:45:08 +00:00
Manan TankandGitHub bd18e4f5ef [react] NetworkSelector component UI tweaks (#1653) 2023-09-25 20:19:56 +00:00
Manan TankandGitHub 1018eb56a6 [react] ConnectWallet V3 updates/fixes (#1650) 2023-09-25 18:27:05 +00:00
Winston YeoandGitHub def6d400ab Winston/fix embedded wallet login type and paperWallet init with USER_MANAGED flow (#1647) 2023-09-25 16:14:51 +00:00
iketwandGitHub 2ce89cfea9 [RN] Update json upload to use new endpoint (#1644) 2023-09-22 13:03:33 +00:00
Adam MajmudarandGitHub 48906a9d8e [SDK] [Bug] Always update network if configured in fromSigner (#1624) 2023-09-22 04:51:47 +00:00
64528263f4 [react] ConnectWallet v3 ( v2 update ) (#1618)
Co-authored-by: ElasticBottle <[email protected]>
2023-09-21 22:52:04 +00:00
iketwandGitHub cbbb8ccbe3 [RN] Coinbase listener only handles Coinbase links (#1632) 2023-09-21 17:26:39 +00:00
Tair AsimandGitHub e2e6bdd4cd service-utils: add embedded wallets to service definitions (#1640) 2023-09-21 10:18:01 +00:00
Phillip HoandGitHub d66ff413de chore: Add platform metrics fields (#1641) 2023-09-21 03:20:07 +00:00
FirekeeperandGitHub 9d553746b0 [Unity] Pass wallets to wc modal from client + avoid throwing on paper init from bridge (#1638) 2023-09-20 17:29:06 +00:00
iketwandGitHub 57af96c288 [RN] Fix json upload (#1635) 2023-09-20 14:52:15 +00:00
Winston YeoandGitHub 94bdcc142a Winston/embeddedWallet polish (#1634) 2023-09-19 22:21:03 +00:00
Jonas DanielsandGitHub dd3d1a87c2 [tooling] faster chains generation (#1631) 2023-09-19 16:14:15 +00:00
4268775f9c Winston/add embedded wallet export for react (#1622)
Co-authored-by: Manan Tank <[email protected]>
2023-09-19 14:58:07 +00:00
Jonas DanielsandGitHub 710739c7d2 [cli] - unlock node 20 (#1628) 2023-09-19 06:38:57 +00:00
Phillip HoandGitHub c54db48c0d fix: try/catch logHttpRequest (#1627) 2023-09-19 01:17:35 +00:00
Tair AsimandGitHub 903145a4ae feat: rate limit worker (#1584) 2023-09-18 22:24:12 +00:00
Winston YeoandGitHub 43f188c8a7 Winston/add embedded wallet connector (#1598) 2023-09-18 20:56:18 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
8a3993d42b Version Packages (#1613)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-18 12:13:49 -07:00
Manan TankandGitHub bab39980e7 [react] ConnectWallet minor UI fixes (#1621) 2023-09-18 18:56:07 +00:00
48295c0604 feat(sdk): centralize all blockchain reads via a single entrypoint (#1534)
Co-authored-by: Joaquim Verges <[email protected]>
2023-09-18 17:21:37 +00:00
YashandGitHub 3fd39cea0d Update addresses (#1617) 2023-09-15 20:26:16 +00:00
1fe867e205 [ReactNative] Connect Wallet V3 (#1592)
Co-authored-by: Manan Tank <[email protected]>
2023-09-15 17:47:40 +00:00
Manan TankandGitHub f5991387ef [react] ConnectWallet UI improvements + code cleanup (#1615) 2023-09-15 14:29:55 +00:00
3f3c63c01e [react] ConnectWallet v3 UI (#1550)
Co-authored-by: Joaquim Verges <[email protected]>
2023-09-15 11:21:03 +00:00
YashandGitHub f80cf0e17e [SDK] Remove ipfs dependency in tests (#1612) 2023-09-15 02:43:17 +00:00
Phillip HoandGitHub 10b7648857 chore: add evmMethod to usage traacker body (#1611) 2023-09-14 12:14:00 -07:00
437 changed files with 49927 additions and 15202 deletions
+10 -9
View File
@@ -20,15 +20,16 @@
## Packages
| Package | Description | Latest Version |
| ---------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/wallets](./packages/wallets) | Unified web3 Wallet library to integrate any wallet into your applications. | <a href="https://www.npmjs.com/package/@thirdweb-dev/wallets"><img src="https://img.shields.io/npm/v/@thirdweb-dev/wallets?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react-native](./packages/react-native) | Ultimate collection of React hooks for your native mobile web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| Package | Description | Latest Version |
| ---------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [/sdk](./packages/sdk) | Best in class web3 SDK for Browser, Node and Mobile apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/wallets](./packages/wallets) | Unified web3 Wallet library to integrate any wallet into your applications. | <a href="https://www.npmjs.com/package/@thirdweb-dev/wallets"><img src="https://img.shields.io/npm/v/@thirdweb-dev/wallets?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react](./packages/react) | Ultimate collection of React hooks for your web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/react-native](./packages/react-native) | Ultimate collection of React hooks for your native mobile web3 apps | <a href="https://www.npmjs.com/package/@thirdweb-dev/react-native"><img src="https://img.shields.io/npm/v/@thirdweb-dev/react-native?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/chains](./packages/chains) | All EVM chain information as JS objects for easy handling | <a href="https://www.npmjs.com/package/@thirdweb-dev/chains"><img src="https://img.shields.io/npm/v/@thirdweb-dev/chains?color=red&label=npm&logo=npm" alt="npm version"/></a> |
## Documentation
+21
View File
@@ -1,5 +1,26 @@
# @thirdweb-dev/auth
## 3.2.44
### Patch Changes
- Updated dependencies [[`54f83a50`](https://github.com/thirdweb-dev/js/commit/54f83a5013ed65ddd5a787e13ba7e5d86625537d), [`c085d690`](https://github.com/thirdweb-dev/js/commit/c085d69060c68b3335761bdb2cc0c3e082548702), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3)]:
- @thirdweb-dev/wallets@1.3.1
## 3.2.43
### Patch Changes
- Updated dependencies [[`9d553746`](https://github.com/thirdweb-dev/js/commit/9d553746b025ac489f9b8ee357372c9d01c835e1), [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`94bdcc14`](https://github.com/thirdweb-dev/js/commit/94bdcc142a7fe1e9f53273560404fa6b5ac3a7c4), [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525), [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d), [`def6d400`](https://github.com/thirdweb-dev/js/commit/def6d400ab463bda3118d4c9cb00e5cc25a415c2)]:
- @thirdweb-dev/wallets@1.3.0
## 3.2.42
### Patch Changes
- Updated dependencies [[`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e)]:
- @thirdweb-dev/wallets@1.2.1
## 3.2.41
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.41",
"version": "3.2.44",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+14
View File
@@ -1,5 +1,19 @@
# @thirdweb-dev/chains
## 0.1.53
### Patch Changes
- [#1631](https://github.com/thirdweb-dev/js/pull/1631) [`dd3d1a87`](https://github.com/thirdweb-dev/js/commit/dd3d1a87c2dadbadecc9ac3722941a8992bc8131) Thanks [@jnsdls](https://github.com/jnsdls)! - add & update chains
- [#1662](https://github.com/thirdweb-dev/js/pull/1662) [`d5fafdde`](https://github.com/thirdweb-dev/js/commit/d5fafddea58bc307c9b514a1c9578cafd18b5861) Thanks [@jnsdls](https://github.com/jnsdls)! - added & updated chains
## 0.1.52
### Patch Changes
- [#1534](https://github.com/thirdweb-dev/js/pull/1534) [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - feat(chains): add new chain information
## 0.1.51
### Patch Changes
+7 -1
View File
@@ -20,7 +20,13 @@ export default {
{
"name": "Tectum explorer",
"url": "https://explorer.tectum.io",
"standard": "none"
"icon": {
"url": "ipfs://QmYvFVprVdAGJH4iHUCXGEmy7pq8MMfxEjM64SuXutz9qx",
"width": 256,
"height": 256,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
+3 -3
View File
@@ -30,9 +30,9 @@ export default {
"chainId": 1089,
"networkId": 1089,
"icon": {
"url": "ipfs://QmU83haX3TNifDDjBx6RP6ByqES1Kg9VqeJC87X9ipKyCS",
"width": 386,
"height": 397,
"url": "ipfs://QmX6XuoQDTTjYqAmdNJiieLDZSwHHyUx44yQb4E3tmHmEA",
"width": 400,
"height": 400,
"format": "png"
},
"explorers": [
+1 -1
View File
@@ -19,7 +19,7 @@ export default {
"decimals": 18
},
"infoURL": "https://blx.org",
"shortName": "blxq",
"shortName": "tblxq",
"chainId": 1107,
"networkId": 1107,
"explorers": [
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "BLXq Mainnet",
"chain": "BLXQ",
"icon": {
"url": "ipfs://QmS9kDKr1rgcz5W55yCQVfFs1vRTCneaLHt1t9cBizpqpH",
"width": 1000,
"height": 1000,
"format": "png"
},
"rpc": [
"https://blxq.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet.blxq.org"
],
"faucets": [],
"nativeCurrency": {
"name": "BLXQ",
"symbol": "BLXQ",
"decimals": 18
},
"infoURL": "https://blx.org",
"shortName": "blxq",
"chainId": 1108,
"networkId": 1108,
"explorers": [
{
"name": "BLXq Explorer",
"url": "https://explorer.blxq.org",
"icon": {
"url": "ipfs://QmS9kDKr1rgcz5W55yCQVfFs1vRTCneaLHt1t9cBizpqpH",
"width": 1000,
"height": 1000,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "blxq"
} as const satisfies Chain;
+32
View File
@@ -0,0 +1,32 @@
import type { Chain } from "../src/types";
export default {
"name": "Astar zkEVM",
"shortName": "astrzk",
"title": "Astar zkEVM Mainnet",
"chain": "ETH",
"icon": {
"url": "ipfs://QmZm2RfbEfWjnqu7MLSG5ChhAsjnKqTvmHM5eJWvYGAwG8",
"width": 800,
"height": 264,
"format": "png"
},
"rpc": [],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://astar.network",
"chainId": 12611,
"networkId": 12611,
"explorers": [],
"parent": {
"type": "L2",
"chain": "eip155-1",
"bridges": []
},
"status": "incubating",
"testnet": false,
"slug": "astar-zkevm"
} as const satisfies Chain;
+32
View File
@@ -0,0 +1,32 @@
import type { Chain } from "../src/types";
export default {
"name": "zKatana",
"shortName": "azktn",
"title": "Astar zkEVM Testnet zKatana",
"chain": "ETH",
"icon": {
"url": "ipfs://QmZm2RfbEfWjnqu7MLSG5ChhAsjnKqTvmHM5eJWvYGAwG8",
"width": 800,
"height": 264,
"format": "png"
},
"rpc": [],
"faucets": [],
"nativeCurrency": {
"name": "Sepolia Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://astar.network",
"chainId": 1261120,
"networkId": 1261120,
"explorers": [],
"parent": {
"type": "L2",
"chain": "eip155-11155111",
"bridges": []
},
"status": "incubating",
"testnet": true,
"slug": "zkatana"
} as const satisfies Chain;
+3 -3
View File
@@ -1,7 +1,7 @@
import type { Chain } from "../src/types";
export default {
"name": "Quantum Chain Testnet",
"chain": "QNET",
"chain": "tQNET",
"icon": {
"url": "ipfs://bafkreibwywok67uewqbtqdzgr7nlk3lvvg7hxmbgwtn7kdwxe34useucvm",
"width": 1024,
@@ -15,11 +15,11 @@ export default {
"faucets": [],
"nativeCurrency": {
"name": "Quantum Chain",
"symbol": "QNET",
"symbol": "tQNET",
"decimals": 18
},
"infoURL": "https://quantumnetwork.gg",
"shortName": "qnet",
"shortName": "tqnet",
"chainId": 12890,
"networkId": 12890,
"explorers": [
+2 -1
View File
@@ -10,7 +10,8 @@ export default {
},
"rpc": [
"https://flare.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://flare-api.flare.network/ext/C/rpc"
"https://flare-api.flare.network/ext/C/rpc",
"https://rpc.ftso.au/flare"
],
"faucets": [],
"nativeCurrency": {
+41
View File
@@ -0,0 +1,41 @@
import type { Chain } from "../src/types";
export default {
"name": "ShimmerEVM Mainnet",
"title": "ShimmerEVM Mainnet",
"chain": "ShimmerEVM",
"rpc": [
"https://shimmerevm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://json-rpc.evm.shimmer.network"
],
"faucets": [],
"nativeCurrency": {
"name": "SMR",
"symbol": "SMR",
"decimals": 18
},
"infoURL": "https://shimmer.network",
"shortName": "shimmerevm-mainnet",
"chainId": 148,
"networkId": 148,
"icon": {
"url": "ipfs://bafkreibky2sy6qhi6arktayvologkrgu5kudpgdxfkx4uosbvmstz7v4di",
"width": 720,
"height": 720,
"format": "png"
},
"explorers": [
{
"name": "explorer",
"url": "https://explorer.evm.shimmer.network",
"icon": {
"url": "ipfs://bafkreibky2sy6qhi6arktayvologkrgu5kudpgdxfkx4uosbvmstz7v4di",
"width": 720,
"height": 720,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "shimmerevm"
} as const satisfies Chain;
+35
View File
@@ -0,0 +1,35 @@
import type { Chain } from "../src/types";
export default {
"name": "Taiko Jolnir L2",
"chain": "ETH",
"status": "incubating",
"icon": {
"url": "ipfs://QmcHdmVr5VRUJq13jnM6tgah5Ge7hn3Dm14eY6vwivJ5ui",
"width": 288,
"height": 258,
"format": "png"
},
"rpc": [
"https://taiko-jolnir-l2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.jolnir.taiko.xyz"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://taiko.xyz",
"shortName": "tko-jolnir",
"chainId": 167007,
"networkId": 167007,
"explorers": [
{
"name": "blockscout",
"url": "https://explorer.jolnir.taiko.xyz",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "taiko-jolnir-l2"
} as const satisfies Chain;
+2 -1
View File
@@ -13,7 +13,8 @@ export default {
"https://songbird-api.flare.network/ext/C/rpc",
"https://sgb.ftso.com.au/ext/bc/C/rpc",
"https://sgb.lightft.so/rpc",
"https://sgb-rpc.ftso.eu"
"https://sgb-rpc.ftso.eu",
"https://rpc.ftso.au/songbird"
],
"faucets": [],
"nativeCurrency": {
+17 -3
View File
@@ -1,8 +1,11 @@
import type { Chain } from "../src/types";
export default {
"name": "Stratos Mainnet",
"name": "Stratos",
"chain": "STOS",
"rpc": [],
"rpc": [
"https://stratos.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://web3-rpc.thestratos.org"
],
"faucets": [],
"nativeCurrency": {
"name": "STOS",
@@ -13,7 +16,18 @@ export default {
"shortName": "stos-mainnet",
"chainId": 2048,
"networkId": 2048,
"status": "incubating",
"explorers": [
{
"name": "Stratos EVM Explorer (Blockscout)",
"url": "https://web3-explorer.thestratos.org",
"standard": "none"
},
{
"name": "Stratos Cosmos Explorer (BigDipper)",
"url": "https://explorer.thestratos.org",
"standard": "none"
}
],
"testnet": false,
"slug": "stratos"
} as const satisfies Chain;
+43
View File
@@ -0,0 +1,43 @@
import type { Chain } from "../src/types";
export default {
"name": "Movo Smart Chain Mainnet",
"chain": "MOVO",
"rpc": [
"https://movo-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://msc-rpc.movoscan.com",
"https://msc-rpc.movochain.org",
"https://msc-rpc.movoswap.com"
],
"faucets": [],
"nativeCurrency": {
"name": "Movo Smart Chain",
"symbol": "MOVO",
"decimals": 18
},
"infoURL": "https://movo.uk",
"shortName": "movo",
"chainId": 2049,
"networkId": 2049,
"slip44": 2050,
"icon": {
"url": "ipfs://QmbYjhXYych49hP6WY7C27pLGmSigSN35XYyocd5ftBew7",
"width": 800,
"height": 800,
"format": "png"
},
"explorers": [
{
"name": "movoscan",
"url": "https://movoscan.com",
"icon": {
"url": "ipfs://QmPqa6cJ92t4eQMgYxmVs6yr8t53ZgzchRDwz2zd2VFUwF",
"width": 256,
"height": 256,
"format": "png"
},
"standard": "none"
}
],
"testnet": false,
"slug": "movo-smart-chain"
} as const satisfies Chain;
+1 -1
View File
@@ -4,7 +4,7 @@ export default {
"chain": "REAP",
"rpc": [
"https://reapchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.reapchain.org"
"https://eth.reapchain.org"
],
"faucets": [],
"nativeCurrency": {
+39
View File
@@ -0,0 +1,39 @@
import type { Chain } from "../src/types";
export default {
"name": "Krest Network",
"chain": "Krest",
"icon": {
"url": "ipfs://bafkreid732273ib5at7krjdl2t7lteljlepwd3tvifqge7mu7g6naxavhe",
"width": 256,
"height": 256,
"format": "png"
},
"rpc": [
"https://krest-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://erpc-krest.peaq.network"
],
"faucets": [],
"nativeCurrency": {
"name": "Krest",
"symbol": "KRST",
"decimals": 18
},
"infoURL": "https://www.peaq.network",
"shortName": "KRST",
"chainId": 2241,
"networkId": 2241,
"explorers": [
{
"name": "Polkadot.js",
"url": "https://polkadot.js.org/apps/?rpc=wss://wss-krest.peaq.network#/explorer",
"standard": "none"
},
{
"name": "Subscan",
"url": "https://krest.subscan.io",
"standard": "none"
}
],
"testnet": false,
"slug": "krest-network"
} as const satisfies Chain;
+2 -2
View File
@@ -14,8 +14,8 @@ export default {
],
"faucets": [],
"nativeCurrency": {
"name": "MAP",
"symbol": "MAP",
"name": "MAPO",
"symbol": "MAPO",
"decimals": 18
},
"infoURL": "https://maplabs.io",
+23 -6
View File
@@ -1,30 +1,47 @@
import type { Chain } from "../src/types";
export default {
"name": "RSK Mainnet",
"chain": "RSK",
"name": "Rootstock Mainnet",
"chain": "Rootstock",
"rpc": [
"https://rsk.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rootstock.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://public-node.rsk.co",
"https://mycrypto.rsk.co"
],
"faucets": [],
"icon": {
"url": "ipfs://bafkreigidzbf22dnpmmlfxv6u7oifq6ln33j4n57ox4ipiproalufrheym",
"width": 3000,
"height": 3325,
"format": "png"
},
"nativeCurrency": {
"name": "Smart Bitcoin",
"symbol": "RBTC",
"decimals": 18
},
"infoURL": "https://rsk.co",
"infoURL": "https://rootstock.io",
"shortName": "rsk",
"chainId": 30,
"networkId": 30,
"slip44": 137,
"explorers": [
{
"name": "RSK Explorer",
"name": "blockscout",
"url": "https://rootstock.blockscout.com",
"icon": {
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
"width": 551,
"height": 540,
"format": "png"
},
"standard": "EIP3091"
},
{
"name": "Rootstock Explorer",
"url": "https://explorer.rsk.co",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "rsk"
"slug": "rootstock"
} as const satisfies Chain;
+11 -5
View File
@@ -1,21 +1,27 @@
import type { Chain } from "../src/types";
export default {
"name": "RSK Testnet",
"chain": "RSK",
"name": "Rootstock Testnet",
"chain": "Rootstock",
"rpc": [
"https://rsk-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rootstock-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://public-node.testnet.rsk.co",
"https://mycrypto.testnet.rsk.co"
],
"faucets": [
"https://faucet.rsk.co/"
],
"icon": {
"url": "ipfs://bafkreigidzbf22dnpmmlfxv6u7oifq6ln33j4n57ox4ipiproalufrheym",
"width": 3000,
"height": 3325,
"format": "png"
},
"nativeCurrency": {
"name": "Testnet Smart Bitcoin",
"symbol": "tRBTC",
"decimals": 18
},
"infoURL": "https://rsk.co",
"infoURL": "https://rootstock.io",
"shortName": "trsk",
"chainId": 31,
"networkId": 31,
@@ -27,5 +33,5 @@ export default {
}
],
"testnet": true,
"slug": "rsk-testnet"
"slug": "rootstock-testnet"
} as const satisfies Chain;
+2 -1
View File
@@ -12,7 +12,8 @@ export default {
"https://filecoin.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.node.glif.io/",
"https://rpc.ankr.com/filecoin",
"https://filecoin-mainnet.chainstacklabs.com/rpc/v1"
"https://filecoin-mainnet.chainstacklabs.com/rpc/v1",
"https://filfox.info/rpc/v1"
],
"faucets": [],
"nativeCurrency": {
+2 -1
View File
@@ -13,7 +13,8 @@ export default {
"https://api.calibration.node.glif.io/rpc/v1",
"https://rpc.ankr.com/filecoin_testnet",
"https://filecoin-calibration.chainstacklabs.com/rpc/v1",
"https://filecoin-calibration.chainup.net/rpc/v1"
"https://filecoin-calibration.chainup.net/rpc/v1",
"https://calibration.filfox.info/rpc/v1"
],
"faucets": [
"https://faucet.calibration.fildev.network/"
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Zilliqa EVM Isolated Server",
"chain": "ZIL",
"rpc": [
"https://zilliqa-evm-isolated-server.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://zilliqa-isolated-server.zilliqa.com/"
],
"faucets": [
"https://dev-wallet.zilliqa.com/faucet?network=isolated_server"
],
"nativeCurrency": {
"name": "Zilliqa",
"symbol": "ZIL",
"decimals": 18
},
"infoURL": "https://www.zilliqa.com/",
"shortName": "zil-isolated-server",
"chainId": 32990,
"networkId": 32990,
"icon": {
"url": "ipfs://QmTREXNgGtUhSoxFsrkhTe5LUnDBTKL5byaX8kpET6UuKp",
"width": 2048,
"height": 2048,
"format": "png"
},
"explorers": [
{
"name": "Zilliqa EVM Isolated Server Explorer",
"url": "https://devex.zilliqa.com/?network=https://zilliqa-isolated-server.zilliqa.com",
"standard": "none"
}
],
"testnet": false,
"slug": "zilliqa-evm-isolated-server"
} as const satisfies Chain;
+30
View File
@@ -0,0 +1,30 @@
import type { Chain } from "../src/types";
export default {
"name": "Oone Chain Testnet",
"chain": "OONE Testnet",
"rpc": [
"https://oone-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.testnet.oonechain.com"
],
"faucets": [
"https://apps-test.adigium.com/faucet"
],
"nativeCurrency": {
"name": "tOONE",
"symbol": "tOONE",
"decimals": 18
},
"infoURL": "https://oonechain.com",
"shortName": "oonetest",
"chainId": 333666,
"networkId": 333666,
"explorers": [
{
"name": "blockscout",
"url": "https://testnet.oonescan.com",
"standard": "none"
}
],
"testnet": true,
"slug": "oone-chain-testnet"
} as const satisfies Chain;
+10 -10
View File
@@ -1,30 +1,30 @@
import type { Chain } from "../src/types";
export default {
"name": "Oone Chain Testnet",
"chain": "OONE",
"name": "Oone Chain Devnet",
"chain": "OONE Devnet",
"rpc": [
"https://oone-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://blockchain-test.adigium.world"
"https://oone-chain-devnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.dev.oonechain.com"
],
"faucets": [
"https://apps-test.adigium.com/faucet"
],
"nativeCurrency": {
"name": "Oone",
"name": "tOONE",
"symbol": "tOONE",
"decimals": 18
},
"infoURL": "https://oone.world",
"shortName": "oonetest",
"infoURL": "https://oonechain.com",
"shortName": "oonedev",
"chainId": 333777,
"networkId": 333777,
"explorers": [
{
"name": "expedition",
"url": "https://explorer-test.adigium.world",
"name": "blockscout",
"url": "https://dev.oonescan.com",
"standard": "none"
}
],
"testnet": true,
"slug": "oone-chain-testnet"
"slug": "oone-chain-devnet"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Zilliqa EVM Devnet",
"chain": "ZIL",
"rpc": [
"https://zilliqa-evm-devnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.devnet.zilliqa.com/"
],
"faucets": [
"https://faucet.devnet.zilliqa.com/"
],
"nativeCurrency": {
"name": "Zilliqa",
"symbol": "ZIL",
"decimals": 18
},
"infoURL": "https://www.zilliqa.com/",
"shortName": "zil-devnet",
"chainId": 33385,
"networkId": 33385,
"icon": {
"url": "ipfs://QmTREXNgGtUhSoxFsrkhTe5LUnDBTKL5byaX8kpET6UuKp",
"width": 2048,
"height": 2048,
"format": "png"
},
"explorers": [
{
"name": "Zilliqa EVM Devnet Explorer",
"url": "https://otterscan.devnet.zilliqa.com",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "zilliqa-evm-devnet"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Zilliqa 2 EVM Devnet",
"chain": "ZIL",
"rpc": [
"https://zilliqa-2-evm-devnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.zq2-devnet.zilstg.dev"
],
"faucets": [
"https://faucet.zq2-devnet.zilstg.dev"
],
"nativeCurrency": {
"name": "Zilliqa",
"symbol": "ZIL",
"decimals": 18
},
"infoURL": "https://www.zilliqa.com/",
"shortName": "zq2-devnet",
"chainId": 33469,
"networkId": 33469,
"icon": {
"url": "ipfs://QmTREXNgGtUhSoxFsrkhTe5LUnDBTKL5byaX8kpET6UuKp",
"width": 2048,
"height": 2048,
"format": "png"
},
"explorers": [
{
"name": "Zilliqa 2 EVM Devnet Explorer",
"url": "https://explorer.zq2-devnet.zilstg.dev",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "zilliqa-2-evm-devnet"
} as const satisfies Chain;
+1 -1
View File
@@ -21,7 +21,7 @@ export default {
}
],
"infoURL": "https://manta-testnet.caldera.dev/",
"shortName": "manta",
"shortName": "mantaTestnet",
"chainId": 3441005,
"networkId": 3441005,
"icon": {
+3 -1
View File
@@ -11,7 +11,9 @@ export default {
"https://rpc.pulsechain.com",
"wss://rpc.pulsechain.com",
"https://pulsechain.publicnode.com",
"wss://pulsechain.publicnode.com"
"wss://pulsechain.publicnode.com",
"https://rpc-pulsechain.g4mm4.io",
"wss://rpc-pulsechain.g4mm4.io"
],
"slip44": 60,
"features": [
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "ConnectorManager",
"chain": "Rangers",
"icon": {
"url": "ipfs://QmXR5e5SDABWfQn6XT9uMsVYAo5Bv7vUv4jVs8DFqatZWG",
"width": 2000,
"height": 2000,
"format": "png"
},
"rpc": [
"https://connectormanager.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://cm.rangersprotocol.com/api/jsonrpc"
],
"faucets": [],
"nativeCurrency": {
"name": "Rangers Protocol Gas",
"symbol": "cmRPG",
"decimals": 18
},
"infoURL": "https://rangersprotocol.com",
"shortName": "cmrpg",
"chainId": 38400,
"networkId": 38400,
"explorers": [
{
"name": "rangersscan",
"url": "https://scan.rangersprotocol.com",
"standard": "none"
}
],
"testnet": false,
"slug": "connectormanager"
} as const satisfies Chain;
+35
View File
@@ -0,0 +1,35 @@
import type { Chain } from "../src/types";
export default {
"name": "Humans.ai Testnet",
"chain": "Humans Testnet",
"rpc": [
"https://humans-ai-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://evm-rpc.testnet.humans.zone"
],
"faucets": [],
"nativeCurrency": {
"name": "HEART",
"symbol": "HEART",
"decimals": 18
},
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"infoURL": "https://humans.ai",
"shortName": "humans_testnet",
"chainId": 4139,
"networkId": 4139,
"icon": {
"url": "ipfs://QmX6XuoQDTTjYqAmdNJiieLDZSwHHyUx44yQb4E3tmHmEA",
"width": 400,
"height": 400,
"format": "png"
},
"testnet": true,
"slug": "humans-ai-testnet"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Gesoten Verse Testnet",
"chain": "Gesoten Verse",
"rpc": [
"https://gesoten-verse-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.testnet.verse.gesoten.com/"
],
"faucets": [],
"nativeCurrency": {
"name": "OAS",
"symbol": "OAS",
"decimals": 18
},
"infoURL": "https://gesoten.com/",
"shortName": "GST",
"icon": {
"url": "ipfs://Qmb7oJY9zd9sTzxNNQNTVZQz2hkd1aA94mWm4cvXfJ9QxV",
"width": 1280,
"height": 1280,
"format": "png"
},
"chainId": 42801,
"networkId": 42801,
"explorers": [
{
"name": "Gesoten Verse Testnet Explorer",
"url": "https://explorer.testnet.verse.gesoten.com",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "gesoten-verse-testnet"
} as const satisfies Chain;
+6
View File
@@ -36,6 +36,12 @@ export default {
}
]
},
"icon": {
"url": "ipfs://QmX2Z71QszaZvpMppdNWeCLqmeWk8NA6KMDLMqAt5VRyVi/synapse.webp",
"height": 720,
"width": 720,
"format": "webp"
},
"testnet": true,
"slug": "synapse-chain-testnet"
} as const satisfies Chain;
+2 -2
View File
@@ -27,8 +27,8 @@ export default {
"standard": "EIP3091"
},
{
"name": "Celoscan",
"url": "https://celoscan.io",
"name": "Alfajoresscan",
"url": "https://alfajores.celoscan.io",
"standard": "EIP3091"
}
],
+2 -2
View File
@@ -15,11 +15,11 @@ export default {
"faucets": [],
"nativeCurrency": {
"name": "Areon",
"symbol": "AREA",
"symbol": "TAREA",
"decimals": 18
},
"infoURL": "https://areon.network",
"shortName": "area",
"shortName": "tarea",
"chainId": 462,
"networkId": 462,
"explorers": [
+13 -1
View File
@@ -16,7 +16,19 @@ export default {
"shortName": "hmnd",
"chainId": 5234,
"networkId": 5234,
"explorers": [],
"explorers": [
{
"name": "Subscan",
"url": "https://humanode.subscan.io",
"standard": "EIP3091",
"icon": {
"url": "ipfs://Qma2GfW5nQHuA7nGqdEfwaXPL63G9oTwRTQKaGTfjNtM2W",
"width": 400,
"height": 400,
"format": "png"
}
}
],
"testnet": false,
"slug": "humanode"
} as const satisfies Chain;
+10 -2
View File
@@ -5,7 +5,10 @@ export default {
"status": "active",
"rpc": [
"https://scroll-sepolia-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://sepolia-rpc.scroll.io/"
"https://sepolia-rpc.scroll.io",
"https://rpc.ankr.com/scroll_sepolia_testnet",
"https://scroll-sepolia.chainstacklabs.com",
"https://scroll-testnet-public.unifra.io"
],
"faucets": [],
"nativeCurrency": {
@@ -19,7 +22,12 @@ export default {
"networkId": 534351,
"explorers": [
{
"name": "Scroll Sepolia Testnet Block Explorer",
"name": "Scroll Sepolia Etherscan",
"url": "https://sepolia.scrollscan.dev",
"standard": "EIP3091"
},
{
"name": "Scroll Sepolia Blockscout",
"url": "https://sepolia-blockscout.scroll.io",
"standard": "EIP3091"
}
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "VEX EVM TESTNET",
"chain": "vex",
"icon": {
"url": "ipfs://QmcZiEAGFYEEax1uxYnDUh8X5YBvZqMi9K92yZoq4o2zeM",
"width": 451,
"height": 446,
"format": "png"
},
"rpc": [
"https://vex-evm-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.vexascan.com/evmapi"
],
"faucets": [
"https://t.me/vexfaucetbot"
],
"nativeCurrency": {
"name": "VEX EVM TESTNET",
"symbol": "VEX",
"decimals": 18
},
"infoURL": "https://vexanium.com",
"shortName": "VEX",
"chainId": 5522,
"networkId": 5522,
"explorers": [
{
"name": "Vexascan-EVM-TestNet",
"url": "https://testnet.vexascan.com/evmexplorer",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "vex-evm-testnet"
} as const satisfies Chain;
+41
View File
@@ -0,0 +1,41 @@
import type { Chain } from "../src/types";
export default {
"name": "Highbury",
"chain": "HIGHBURY",
"rpc": [
"https://highbury.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://highbury.furya.io",
"https://rest.furya.io"
],
"faucets": [],
"nativeCurrency": {
"name": "Fury",
"symbol": "FURY",
"decimals": 18
},
"infoURL": "https://www.fury.black",
"shortName": "fury",
"chainId": 710,
"networkId": 710,
"icon": {
"url": "ipfs://bafkreiby27m6esbsjthmknckq5ktsaaj2z6hylzljbsmvx4fgezdra3q4m",
"width": 512,
"height": 512,
"format": "png"
},
"explorers": [
{
"name": "Furya EVM Explorer",
"url": "https://explorer.furya.io",
"standard": "EIP3091",
"icon": {
"url": "ipfs://bafkreiby27m6esbsjthmknckq5ktsaaj2z6hylzljbsmvx4fgezdra3q4m",
"width": 512,
"height": 512,
"format": "png"
}
}
],
"testnet": false,
"slug": "highbury"
} as const satisfies Chain;
+7 -1
View File
@@ -6,7 +6,13 @@ export default {
"https://canto.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://canto.slingshot.finance",
"https://canto.neobase.one",
"https://mainnode.plexnode.org:8545"
"https://mainnode.plexnode.org:8545",
"https://canto.gravitychain.io/",
"https://canto.evm.chandrastation.com/",
"https://jsonrpc.canto.nodestake.top/",
"https://canto.dexvaults.com/",
"wss://canto.gravitychain.io:8546",
"wss://canto.dexvaults.com/ws"
],
"faucets": [],
"nativeCurrency": {
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Foundry Chain Testnet",
"chain": "tFNC",
"icon": {
"url": "ipfs://bafkreifx4vef7ubqz4iiaxckcvkdwjrp2hbliljwjlwu2vytlngg3r4pg4",
"width": 192,
"height": 192,
"format": "png"
},
"rpc": [
"https://foundry-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-rpc.foundryscan.org/"
],
"faucets": [
"https://faucet.foundryscan.org"
],
"nativeCurrency": {
"name": "Foundry Chain Testnet",
"symbol": "tFNC",
"decimals": 18
},
"infoURL": "https://foundrychain.org",
"shortName": "fnc",
"chainId": 77238,
"networkId": 77238,
"explorers": [
{
"name": "Foundry Scan Testnet",
"url": "https://testnet-explorer.foundryscan.org",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "foundry-chain-testnet"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Quantum Chain Mainnet",
"chain": "QNET",
"icon": {
"url": "ipfs://bafkreibwywok67uewqbtqdzgr7nlk3lvvg7hxmbgwtn7kdwxe34useucvm",
"width": 1024,
"height": 1024,
"format": "png"
},
"rpc": [
"https://quantum-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.quantumscan.org"
],
"faucets": [],
"nativeCurrency": {
"name": "Quantum Chain",
"symbol": "QNET",
"decimals": 18
},
"infoURL": "https://quantumnetwork.gg",
"shortName": "qnet",
"chainId": 81720,
"networkId": 81720,
"explorers": [
{
"name": "Quantum Scan Mainnet",
"url": "https://quantumscan.org",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "quantum-chain"
} as const satisfies Chain;
+6 -10
View File
@@ -14,10 +14,12 @@ export default {
"infoURL": "https://pulsechain.com",
"rpc": [
"https://pulsechain-testnet-v4.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.v4.testnet.pulsechain.com/",
"wss://rpc.v4.testnet.pulsechain.com/",
"https://rpc.v4.testnet.pulsechain.com",
"wss://rpc.v4.testnet.pulsechain.com",
"https://pulsechain-testnet.publicnode.com",
"wss://pulsechain-testnet.publicnode.com"
"wss://pulsechain-testnet.publicnode.com",
"https://rpc-testnet-pulsechain.g4mm4.io",
"wss://rpc-testnet-pulsechain.g4mm4.io"
],
"features": [
{
@@ -43,13 +45,7 @@ export default {
"explorers": [
{
"name": "blockscout",
"url": "https://scan.v4.testnet.pulsechain.com",
"icon": {
"url": "ipfs://QmYtUimyqHkkFxYdbXXRbUqNg2VLPUg6Uu2C2nmFWowiZM",
"width": 551,
"height": 540,
"format": "png"
},
"url": "https://otter-testnet-pulsechain.g4mm4.io",
"standard": "EIP3091"
}
],
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "BTC20 Smart Chain",
"chain": "BTC20",
"rpc": [
"https://btc20-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.bitcoincode.technology/"
],
"faucets": [],
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"nativeCurrency": {
"name": "BTCC",
"symbol": "BTCC",
"decimals": 18
},
"infoURL": "https://bitcoincode.technology",
"shortName": "btc20",
"chainId": 963,
"networkId": 963,
"icon": {
"url": "ipfs://QmRUzDpn3xqPYnjLuZvFs2Attio9VxGRUprXEjcNQDcpe5",
"width": 375,
"height": 456,
"format": "png"
},
"explorers": [
{
"name": "blockscout",
"url": "https://scan.bitcoincode.technology",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "btc20-smart-chain"
} as const satisfies Chain;
+9 -4
View File
@@ -3,10 +3,10 @@ export default {
"name": "Agung Network",
"chain": "Agung",
"icon": {
"url": "ipfs://bafkreih6nzctk6brx5cqkylxbhvi3vsr6q5ks4th5knolkrlfp4tdia2mu",
"width": 400,
"height": 400,
"format": "svg"
"url": "ipfs://bafkreibkqdof3ztkdhgukwvkacwgrjb27e23hgz5c6mmudzu5hipyvgisa",
"width": 256,
"height": 256,
"format": "png"
},
"rpc": [
"https://agung-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
@@ -27,6 +27,11 @@ export default {
"name": "Polkadot.js",
"url": "https://polkadot.js.org/apps/?rpc=wss://wsspc1-qa.agung.peaq.network#/explorer",
"standard": "none"
},
{
"name": "Subscan",
"url": "https://agung.subscan.io",
"standard": "none"
}
],
"testnet": false,
+12
View File
@@ -0,0 +1,12 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Partial<Chain>} */
export default {
icon: {
url: "ipfs://QmX2Z71QszaZvpMppdNWeCLqmeWk8NA6KMDLMqAt5VRyVi/synapse.webp",
height: 720,
width: 720,
format: "webp",
},
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.51",
"version": "0.1.53",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
+142 -118
View File
@@ -1,7 +1,7 @@
// @ts-check
import axios from "axios";
import merge from "deepmerge";
import fs from "fs";
import fs from "fs/promises";
import path from "path";
/** @typedef {import("../src/types").Chain} Chain */
@@ -73,7 +73,7 @@ let overrides = {};
// get all overides by reading the overrides directory and importing them
const overridesDir = path.join(process.cwd(), "./data/overrides");
const overridesFiles = fs.readdirSync(overridesDir);
const overridesFiles = await fs.readdir(overridesDir);
for (const file of overridesFiles) {
// file:// is required for windows builds
const override = await import(path.join("file://", overridesDir, file));
@@ -93,7 +93,7 @@ chains = chains.filter((c) => c.chainId !== 1337);
// get all additional chains by reading the additional chains directory and importing them
const additionalChainsDir = path.join(process.cwd(), "./data/additional");
const additionalChainsFiles = fs.readdirSync(additionalChainsDir);
const additionalChainsFiles = await fs.readdir(additionalChainsDir);
for (const file of additionalChainsFiles) {
// file:// is required for windows builds
const additionalChain = await import(
@@ -103,58 +103,10 @@ for (const file of additionalChainsFiles) {
chains = chains.filter((c) => c.chainId !== additionalChain.default.chainId);
chains.push(additionalChain.default);
}
chains = chains
// Keep scroll-alpha-testnet for now even though its deprecated
.filter((c) => c.status !== "deprecated" || c.chainId === 534353)
.map((chain) => {
if (overrides[chain.chainId]) {
chain = merge(chain, overrides[chain.chainId], {
arrayMerge: combineMerge,
});
}
// apparently this is the best way to do this off of raw data
const testnet =
chain.testnet === false
? false
: JSON.stringify(chain).toLowerCase().includes("test");
const resultChain = {
...chain,
testnet,
};
// only add the explroers if they were there in the first place
if (resultChain.explorers) {
resultChain.explorers = sortExplorers(resultChain.explorers);
// check every key that *could* contain a url and validate it
resultChain.explorers = filterOutErroringValues(
resultChain.explorers,
(explorer) => new URL(explorer.url),
);
}
if (resultChain.faucets) {
resultChain.faucets = filterOutErroringValues(
resultChain.faucets,
(faucet) => new URL(faucet),
);
}
if (resultChain.rpc) {
resultChain.rpc = filterOutErroringValues(
resultChain.rpc,
(rpc) => new URL(rpc),
);
}
if (resultChain.infoURL) {
try {
new URL(resultChain.infoURL);
} catch (e) {
delete resultChain.infoURL;
}
}
return resultChain;
});
// Keep scroll-alpha-testnet for now even though its deprecated
chains = chains.filter(
(c) => c.status !== "deprecated" || c.chainId === 534353,
);
/**
* Sort RPCs in chain
@@ -179,15 +131,9 @@ function sortRPCs(chain) {
});
chain.rpc = [...thirdwebRPCs, ...infuraRPCs, ...alchemyRPCs, ...otherRPCs];
return chain;
}
chains.forEach(sortRPCs);
const imports = [];
const exports = [];
const exportNames = [];
const exportNameToChain = {};
const takenSlugs = {};
const iconMetaMap = new Map();
@@ -261,81 +207,157 @@ function findSlug(chain) {
const chainDir = `${chainsDir}`;
// clean out the chains directory
fs.rmdirSync(chainDir, { recursive: true });
await fs.rmdir(chainDir, { recursive: true });
// make sure the chain directory exists
fs.mkdirSync(chainDir, { recursive: true });
await fs.mkdir(chainDir, { recursive: true });
for (const chain of chains) {
try {
if ("icon" in chain) {
if (typeof chain.icon === "string") {
const iconMeta = await downloadIcon(chain.icon);
if (iconMeta) {
chain.icon = iconMeta;
}
const results = await Promise.all(
chains.map(async (chain) => {
if (overrides[chain.chainId]) {
chain = merge(chain, overrides[chain.chainId], {
arrayMerge: combineMerge,
});
}
// apparently this is the best way to do this off of raw data
const testnet =
chain.testnet === false
? false
: JSON.stringify(chain).toLowerCase().includes("test");
chain = {
...chain,
testnet,
};
// only add the explroers if they were there in the first place
if (chain.explorers) {
chain.explorers = sortExplorers(chain.explorers);
// check every key that *could* contain a url and validate it
chain.explorers = filterOutErroringValues(
chain.explorers,
(explorer) => new URL(explorer.url),
);
}
if (chain.faucets) {
chain.faucets = filterOutErroringValues(
chain.faucets,
(faucet) => new URL(faucet),
);
}
if (chain.rpc) {
chain.rpc = filterOutErroringValues(chain.rpc, (rpc) => new URL(rpc));
}
if (chain.infoURL) {
try {
new URL(chain.infoURL);
} catch (e) {
delete chain.infoURL;
}
}
if ("explorers" in chain && Array.isArray(chain.explorers)) {
for (const explorer of chain.explorers) {
if ("icon" in explorer) {
if (typeof explorer.icon === "string") {
const iconMeta = await downloadIcon(explorer.icon);
if (iconMeta) {
explorer.icon = iconMeta;
chain = sortRPCs(chain);
try {
if ("icon" in chain) {
if (typeof chain.icon === "string") {
const iconMeta = await downloadIcon(chain.icon);
if (iconMeta) {
chain.icon = iconMeta;
}
}
}
if ("explorers" in chain && Array.isArray(chain.explorers)) {
for (const explorer of chain.explorers) {
if ("icon" in explorer) {
if (typeof explorer.icon === "string") {
const iconMeta = await downloadIcon(explorer.icon);
if (iconMeta) {
explorer.icon = iconMeta;
}
}
}
}
}
} catch (err) {
console.log(err.message);
}
} catch (err) {
console.log(err.message);
}
// figure out a slug for the chain
// figure out a slug for the chain
const slug = findSlug(chain);
chain.slug = slug;
// if the chain has RPCs that we can use then prepend our RPC to the list
const chainHasHttpRpc = chain.rpc.some((rpc) => rpc.startsWith("http"));
// if the chain has RPCs that we can use then prepend our RPC to the list
// we're exlcuding localhost because we don't want to use our RPC for localhost
if (chainHasHttpRpc && chain.chainId !== 1337) {
chain.rpc = [
`https://${slug}.rpc.thirdweb.com/${"${THIRDWEB_API_KEY}"}`,
...chain.rpc,
];
}
// unique rpcs
chain.rpc = [...new Set(chain.rpc)];
const slug = findSlug(chain);
chain.slug = slug;
// if the chain has RPCs that we can use then prepend our RPC to the list
const chainHasHttpRpc = chain.rpc.some((rpc) => rpc.startsWith("http"));
// if the chain has RPCs that we can use then prepend our RPC to the list
// we're exlcuding localhost because we don't want to use our RPC for localhost
if (chainHasHttpRpc && chain.chainId !== 1337) {
chain.rpc = [
`https://${slug}.rpc.thirdweb.com/${"${THIRDWEB_API_KEY}"}`,
...chain.rpc,
];
}
// unique rpcs
chain.rpc = [...new Set(chain.rpc)];
fs.writeFileSync(
`${chainDir}/${chain.chainId}.ts`,
`import type { Chain } from "../src/types";
// @ts-ignore
await fs.writeFile(
`${chainDir}/${chain.chainId}.ts`,
`import type { Chain } from "../src/types";
export default ${JSON.stringify(chain, null, 2)} as const satisfies Chain;`,
);
);
let exportName = slug
.split("-")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join("");
let exportName = slug
.split("-")
.map((s) => s[0].toUpperCase() + s.slice(1))
.join("");
// if chainName starts with a number, prepend an underscore
if (exportName.match(/^[0-9]/)) {
exportName = `_${exportName}`;
}
// if chainName starts with a number, prepend an underscore
if (exportName.match(/^[0-9]/)) {
exportName = `_${exportName}`;
}
imports.push(`import c${chain.chainId} from "../chains/${chain.chainId}";`);
// imports.push(`import c${chain.chainId} from "../chains/${chain.chainId}";`);
exports.push(
`export { default as ${exportName} } from "../chains/${chain.chainId}"`,
);
// exports.push(
// `export { default as ${exportName} } from "../chains/${chain.chainId}"`,
// );
const key = `c${chain.chainId}`;
exportNames.push(key);
exportNameToChain[key] = chain;
}
const key = `c${chain.chainId}`;
fs.writeFileSync(
// exportNames.push(key);
// exportNameToChain[key] = chain;
return {
imp: `import c${chain.chainId} from "../chains/${chain.chainId}";`,
exp: `export { default as ${exportName} } from "../chains/${chain.chainId}"`,
chain,
key,
exportName,
};
}),
);
const { imports, exports, exportNames, exportNameToChain } = results.reduce(
(acc, result) => {
// @ts-ignore
acc.imports.push(result.imp);
// @ts-ignore
acc.exports.push(result.exp);
// @ts-ignore
acc.exportNames.push(result.key);
acc.exportNameToChain[result.key] = result.chain;
return acc;
},
{
imports: [],
exports: [],
exportNames: [],
exportNameToChain: {},
},
);
// @ts-ignore
await fs.writeFile(
`./src/index.ts`,
`${imports.join("\n")}
import type { Chain } from "./types";
@@ -349,6 +371,7 @@ export const allChains: Chain[] = [${exportNames.join(", ")}];
type ChainsById = {
${exportNames
// @ts-ignore
.map((n) => `${exportNameToChain[n].chainId}: typeof ${n}`)
.join(",\n")}
};
@@ -356,6 +379,7 @@ type ChainsById = {
type ChainIdsBySlug = {
${exportNames
.map(
// @ts-ignore
(n) => `"${exportNameToChain[n].slug}": ${exportNameToChain[n].chainId}`,
)
.join(",\n")}
File diff suppressed because one or more lines are too long
+43
View File
@@ -1,5 +1,48 @@
# thirdweb
## 0.12.6
### Patch Changes
- [#1673](https://github.com/thirdweb-dev/js/pull/1673) [`879d4226`](https://github.com/thirdweb-dev/js/commit/879d4226f682795a48f37493d8fa1e6fbc1f2f7b) Thanks [@iketw](https://github.com/iketw)! - Fix thirdweb create with options
You can now correctly call:
- `npx thirdweb create --react`
- `npx thirdweb create --next`
- `npx thirdweb create --vite`
- `npx thirdweb create --node`
- `npx thirdweb create --express`
- `npx thirdweb create --pwaVite`
- `npx thirdweb create --reactNative`
- Updated dependencies [[`54f83a50`](https://github.com/thirdweb-dev/js/commit/54f83a5013ed65ddd5a787e13ba7e5d86625537d), [`a9b4b0c5`](https://github.com/thirdweb-dev/js/commit/a9b4b0c5d875dec660694466e5e322cc574bb21b), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3), [`96e832cc`](https://github.com/thirdweb-dev/js/commit/96e832cc80692da38279c53f1289265b3728cb19), [`b16c09df`](https://github.com/thirdweb-dev/js/commit/b16c09df75c7193a91b832db7d9c92612ae09357), [`6897ad65`](https://github.com/thirdweb-dev/js/commit/6897ad6502d585d55a8c7b2312b4af30663336c3), [`ee028e12`](https://github.com/thirdweb-dev/js/commit/ee028e12092fd306f076f6ea1d49a2295802dd6b), [`d28b1c0f`](https://github.com/thirdweb-dev/js/commit/d28b1c0f1e1e53eedc8f331be555e22b64fb920d), [`c085d690`](https://github.com/thirdweb-dev/js/commit/c085d69060c68b3335761bdb2cc0c3e082548702), [`de05c2da`](https://github.com/thirdweb-dev/js/commit/de05c2da174a69315f2d34dd32a811bbd9a0b604), [`bdb2ccc7`](https://github.com/thirdweb-dev/js/commit/bdb2ccc7a66c33ec5dc331b6fa792e6361769e88), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3)]:
- @thirdweb-dev/wallets@1.3.1
- @thirdweb-dev/sdk@3.10.63
- @thirdweb-dev/auth@3.2.44
## 0.12.5
### Patch Changes
- [#1628](https://github.com/thirdweb-dev/js/pull/1628) [`710739c7`](https://github.com/thirdweb-dev/js/commit/710739c7d20760711efbf291e287860f90630765) Thanks [@jnsdls](https://github.com/jnsdls)! - allow node20 usage
- Updated dependencies [[`dd3d1a87`](https://github.com/thirdweb-dev/js/commit/dd3d1a87c2dadbadecc9ac3722941a8992bc8131), [`9d553746`](https://github.com/thirdweb-dev/js/commit/9d553746b025ac489f9b8ee357372c9d01c835e1), [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`d5fafdde`](https://github.com/thirdweb-dev/js/commit/d5fafddea58bc307c9b514a1c9578cafd18b5861), [`c29042b7`](https://github.com/thirdweb-dev/js/commit/c29042b71e266cb11d70d67f0fe2ffcc0fc1f5fa), [`b5b7e524`](https://github.com/thirdweb-dev/js/commit/b5b7e5243df83e3ab60d0917c099fb6967b63439), [`b6df6b89`](https://github.com/thirdweb-dev/js/commit/b6df6b895723947427c515411a7a833edaa324c6), [`94bdcc14`](https://github.com/thirdweb-dev/js/commit/94bdcc142a7fe1e9f53273560404fa6b5ac3a7c4), [`48906a9d`](https://github.com/thirdweb-dev/js/commit/48906a9d8ef2cfdd9ac489822a72d50cbd825628), [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525), [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d), [`def6d400`](https://github.com/thirdweb-dev/js/commit/def6d400ab463bda3118d4c9cb00e5cc25a415c2)]:
- @thirdweb-dev/chains@0.1.53
- @thirdweb-dev/wallets@1.3.0
- @thirdweb-dev/sdk@3.10.62
- @thirdweb-dev/auth@3.2.43
## 0.12.4
### Patch Changes
- Updated dependencies [[`3fd39cea`](https://github.com/thirdweb-dev/js/commit/3fd39cea0df71f80255106329db62660f2fd6e3a), [`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b)]:
- @thirdweb-dev/sdk@3.10.61
- @thirdweb-dev/wallets@1.2.1
- @thirdweb-dev/chains@0.1.52
- @thirdweb-dev/auth@3.2.42
## 0.12.3
### Patch Changes
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.12.3",
"version": "0.12.6",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
"engines": {
"node": ">=16.0.0 <19"
"node": ">=16.0.0"
},
"devDependencies": {
"@gmrchk/cli-testing-library": "^0.1.2",
+15 -10
View File
@@ -254,12 +254,13 @@ const main = async () => {
.option("--forge", "Initialize as a Forge project.")
.option("--hardhat", "Initialize as a Hardhat project.")
.option("--extension", "Create a smart contract extension.")
.option("--cra", "Initialize as a Create React App project.")
.option("--react", "Initialize as a Create React App project.")
.option("--next", "Initialize as a Next.js project.")
.option("--vite", "Initialize as a Vite project.")
.option("--reactNative", "Initialize as a React Native project.")
.option("--express", "Initialize as a Express project.")
.option("--node", "Initialize as a Node project.")
.option("--pwaVite", "Initialize as a PWA project.")
.option(
"--use-npm",
"Explicitly tell the CLI to bootstrap the app using npm",
@@ -296,7 +297,9 @@ const main = async () => {
program
.command("deploy")
.description("Securely deploy your contract to any EVM network without having to deal with scripts, private keys, or ABIs")
.description(
"Securely deploy your contract to any EVM network without having to deal with scripts, private keys, or ABIs",
)
.option("-p, --path <project-path>", "path to project", ".")
.option("--clean", "clear the cache before building")
.option("--dry-run", "dry run (skip actually publishing)")
@@ -495,18 +498,20 @@ const main = async () => {
"Authorize your device to use the thirdweb CLI by authenticating with your wallet from our dashboard",
)
.action(async (options) => {
await loginUser({
credsConfigPath,
cliWalletPath,
tokenPath,
}, options, true);
await loginUser(
{
credsConfigPath,
cliWalletPath,
tokenPath,
},
options,
true,
);
});
program
.command("logout")
.description(
"Logout of the thirdweb CLI",
)
.description("Logout of the thirdweb CLI")
.action(async () => {
await logoutUser(credsConfigPath, tokenPath, cliWalletPath);
});
+46 -1
View File
@@ -43,6 +43,51 @@ export async function twCreate(
projectType = "extension";
}
// case where users use `npx thirdweb create --option` directly
if (!projectType && Object.keys(options).length > 0) {
if (options.react) {
projectType = "app";
language = "typescript";
framework = "cra";
}
if (options.next) {
projectType = "app";
language = "typescript";
framework = "next";
}
if (options.vite) {
projectType = "app";
language = "typescript";
framework = "vite";
}
if (options.node) {
projectType = "app";
language = "typescript";
framework = "node";
}
if (options.express) {
projectType = "app";
language = "typescript";
framework = "express";
}
if (options.pwaVite) {
projectType = "app";
language = "typescript";
framework = "pwa-vite";
}
if (options.reactNative) {
projectType = "app";
language = "typescript";
framework = "react-native";
}
}
if (projectType === "app") {
if (options.typescript) {
language = "typescript";
@@ -54,7 +99,7 @@ export async function twCreate(
if (options.next) {
framework = "next";
}
if (options.cra) {
if (options.react) {
framework = "cra";
}
if (options.vite) {
+79
View File
@@ -1,5 +1,84 @@
# @thirdweb-dev/react-core
## 3.16.1
### Patch Changes
- Updated dependencies [[`54f83a50`](https://github.com/thirdweb-dev/js/commit/54f83a5013ed65ddd5a787e13ba7e5d86625537d), [`a9b4b0c5`](https://github.com/thirdweb-dev/js/commit/a9b4b0c5d875dec660694466e5e322cc574bb21b), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3), [`96e832cc`](https://github.com/thirdweb-dev/js/commit/96e832cc80692da38279c53f1289265b3728cb19), [`b16c09df`](https://github.com/thirdweb-dev/js/commit/b16c09df75c7193a91b832db7d9c92612ae09357), [`6897ad65`](https://github.com/thirdweb-dev/js/commit/6897ad6502d585d55a8c7b2312b4af30663336c3), [`ee028e12`](https://github.com/thirdweb-dev/js/commit/ee028e12092fd306f076f6ea1d49a2295802dd6b), [`d28b1c0f`](https://github.com/thirdweb-dev/js/commit/d28b1c0f1e1e53eedc8f331be555e22b64fb920d), [`c085d690`](https://github.com/thirdweb-dev/js/commit/c085d69060c68b3335761bdb2cc0c3e082548702), [`de05c2da`](https://github.com/thirdweb-dev/js/commit/de05c2da174a69315f2d34dd32a811bbd9a0b604), [`bdb2ccc7`](https://github.com/thirdweb-dev/js/commit/bdb2ccc7a66c33ec5dc331b6fa792e6361769e88), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3)]:
- @thirdweb-dev/wallets@1.3.1
- @thirdweb-dev/sdk@3.10.63
- @thirdweb-dev/auth@3.2.44
## 3.16.0
### Patch Changes
- [#1618](https://github.com/thirdweb-dev/js/pull/1618) [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54) Thanks [@MananTank](https://github.com/MananTank)! - ## New smartWallet() API (Breaking Change)
### Before
In the previous API, adding a smart wallet created it's own new entry called "Smart wallet" in the ConnectWallet Modal and you had to pass in the personal wallets which was shown to the user when they clicked on the "Smart wallet".
```tsx
<ThirdwebProvider
supportedWallets={[
smartWalet({
personalWallets: [metamaskWallet(), coinbaseWallet()],
factoryAddress: "....",
gassless: true,
}),
]}
/>
```
### After
Since most users don't know what a smart wallet is, this was confusing. So with the new API, you can just use smart wallet under the hood for any wallet you want and it will just show up as that wallet and not a "smart wallet" in ConnectWallet Modal to improve the user experience.
Once the user is connected, the ConnectWallet Details button shows to the user that they are infact connected to a smart wallet.
```tsx
const config = {
factoryAddress: "....",
gassless: true,
}
<ThirdwebProvider
supportedWallets={[
smartWalet(metamaskWallet(), config),
smartWalet(coinbaseWallet(), config),
]}
/>
```
## New Features added to `ConnectWallet` component
- ENS Name + Avatar support added
- New 'Send funds' button added to ConnectWallet which users can use to send various tokens.
- New "Receive funds" button added to ConnectWallet which users scan the QR code from their wallet app on phone to send funds to their other wallet on desktop
- Added `supportedTokens` prop to customize the list of tokens for each network in for the "Send Funds" screen.
- "Transaction history" button added to ConnectWallet which opens the block explorer
- New wallet `embededWallet()` to sign in with Google / Email
- Ability to show balance of any token instead of just native token in the ConnectWallet details button using the `displayBalanceToken` prop
- Updated dependencies [[`dd3d1a87`](https://github.com/thirdweb-dev/js/commit/dd3d1a87c2dadbadecc9ac3722941a8992bc8131), [`9d553746`](https://github.com/thirdweb-dev/js/commit/9d553746b025ac489f9b8ee357372c9d01c835e1), [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`d5fafdde`](https://github.com/thirdweb-dev/js/commit/d5fafddea58bc307c9b514a1c9578cafd18b5861), [`c29042b7`](https://github.com/thirdweb-dev/js/commit/c29042b71e266cb11d70d67f0fe2ffcc0fc1f5fa), [`b5b7e524`](https://github.com/thirdweb-dev/js/commit/b5b7e5243df83e3ab60d0917c099fb6967b63439), [`b6df6b89`](https://github.com/thirdweb-dev/js/commit/b6df6b895723947427c515411a7a833edaa324c6), [`94bdcc14`](https://github.com/thirdweb-dev/js/commit/94bdcc142a7fe1e9f53273560404fa6b5ac3a7c4), [`48906a9d`](https://github.com/thirdweb-dev/js/commit/48906a9d8ef2cfdd9ac489822a72d50cbd825628), [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525), [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d), [`def6d400`](https://github.com/thirdweb-dev/js/commit/def6d400ab463bda3118d4c9cb00e5cc25a415c2)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 3.15.0
### Patch Changes
- [#1550](https://github.com/thirdweb-dev/js/pull/1550) [`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e) Thanks [@MananTank](https://github.com/MananTank)! - ConnectWallet v3 updates
- Updated dependencies [[`3fd39cea`](https://github.com/thirdweb-dev/js/commit/3fd39cea0df71f80255106329db62660f2fd6e3a), [`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 3.14.41
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.41",
"version": "3.16.1",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -13,6 +13,7 @@ import {
createAsyncLocalStorage,
CreateAsyncStorage,
DAppMetaData,
SignerWallet,
} from "@thirdweb-dev/wallets";
import React, { useMemo } from "react";
@@ -20,7 +21,7 @@ import React, { useMemo } from "react";
* The possible props for the ThirdwebProvider.
*/
export interface ThirdwebProviderCoreProps<TChains extends Chain[]>
extends ThirdwebSDKProviderProps<TChains> {
extends Omit<ThirdwebSDKProviderProps<TChains>, "signer"> {
/**
* An array of wallets that the dApp supports
* If not provided, will default to Metamask (injected), Coinbase wallet and Device wallet
@@ -70,6 +71,8 @@ export interface ThirdwebProviderCoreProps<TChains extends Chain[]>
* @defaultValue 15000
*/
autoConnectTimeout?: number;
signerWallet?: WalletConfig<SignerWallet>;
}
export const ThirdwebProviderCore = <TChains extends Chain[]>({
@@ -153,6 +156,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
autoConnectTimeout={props.autoConnectTimeout}
clientId={props.clientId}
activeChainSetExplicitly={!!props.activeChain}
signerWallet={props.signerWallet}
>
<ThirdwebSDKProviderWrapper
queryClient={props.queryClient}
@@ -10,6 +10,7 @@ import {
AsyncStorage,
ConnectParams,
CreateAsyncStorage,
SignerWallet,
walletIds,
} from "@thirdweb-dev/wallets";
import { Signer } from "ethers";
@@ -84,12 +85,13 @@ type ThirdwebWalletContextData = {
setConnectedWallet: (
wallet: WalletInstance,
params?: ConnectParams<Record<string, any>>,
) => void;
) => Promise<void>;
/**
* Get wallet config object from wallet instance
*/
getWalletConfig: (walletInstance: WalletInstance) => WalletConfig | undefined;
activeChainSetExplicitly: boolean;
clientId?: string;
};
const ThirdwebWalletContext = /* @__PURE__ */ createContext<
@@ -108,6 +110,7 @@ export function ThirdwebWalletProvider(
autoConnectTimeout?: number;
clientId?: string;
activeChainSetExplicitly: boolean;
signerWallet?: WalletConfig<SignerWallet>;
}>,
) {
const [signer, setSigner] = useState<Signer | undefined>(undefined);
@@ -264,6 +267,11 @@ export function ThirdwebWalletProvider(
// Auto Connect
useEffect(() => {
// do not auto connect if signerWallet is given
if (props.signerWallet) {
return;
}
if (autoConnectTriggered.current) {
return;
}
@@ -374,6 +382,7 @@ export function ThirdwebWalletProvider(
activeWallet,
connectionStatus,
autoConnectTimeout,
props.signerWallet,
]);
const connectWallet = useCallback(
@@ -461,6 +470,33 @@ export function ThirdwebWalletProvider(
};
}, [activeWallet, onWalletDisconnect]);
// connect signerWallet immediately if it's passed
// and disconnect it if it's not passed
const signerConnected = useRef<typeof props.signerWallet>();
useEffect(() => {
if (!props.signerWallet) {
if (signerConnected.current) {
disconnectWallet();
signerConnected.current = undefined;
}
return;
}
if (signerConnected.current === props.signerWallet) {
return;
}
const wallet = createWalletInstance(props.signerWallet);
setConnectedWallet(wallet);
signerConnected.current = props.signerWallet;
}, [
createWalletInstance,
props.supportedWallets,
setConnectedWallet,
props.signerWallet,
disconnectWallet,
]);
return (
<ThirdwebWalletContext.Provider
value={{
@@ -483,6 +519,7 @@ export function ThirdwebWalletProvider(
return walletInstanceToConfig.get(walletInstance);
},
activeChainSetExplicitly: props.activeChainSetExplicitly,
clientId: props.clientId,
}}
>
{props.children}
@@ -17,6 +17,7 @@ export type WalletClass<I extends WalletInstance = WalletInstance> = {
};
export type WalletConfig<I extends WalletInstance = WalletInstance> = {
category?: "socialLogin" | "walletLogin";
id: string;
meta: (typeof AbstractClientWallet)["meta"];
create: (options: WalletOptions) => I;
@@ -39,6 +40,11 @@ export type WalletConfig<I extends WalletInstance = WalletInstance> = {
* * ConnectWallet modal will reopen once the personal wallet is connected so that you can render UI for connecting your wallet as the next step
*/
personalWallets?: WalletConfig[];
/**
* If true, this wallet will be tagged as "recommended" in ConnectWallet Modal and will be shown at the top of the list
*/
recommended?: boolean;
};
export type ConnectUIProps<I extends WalletInstance = WalletInstance> = {
@@ -127,6 +133,20 @@ export type ConnectUIProps<I extends WalletInstance = WalletInstance> = {
* List of all supported wallets including your wallet.
*/
supportedWallets: WalletConfig[];
/**
* Size of the modal
*
* This is always `compact` on React Native
*/
modalSize: "compact" | "wide";
/**
* Called when the wallet is connected but it's
* part of another wallet's connection flow.
* @param walleInstance the instance of the connected wallet
*/
onLocallyConnected?: (walleInstance: WalletInstance) => void;
};
export type SelectUIProps<I extends WalletInstance = WalletInstance> = {
@@ -156,4 +176,11 @@ export type SelectUIProps<I extends WalletInstance = WalletInstance> = {
* theme of the connect wallet modal
*/
theme: "dark" | "light";
/**
* Size of the modal
*
* This is always `compact` on React Native
*/
modalSize: "compact" | "wide";
};
@@ -0,0 +1,57 @@
import { useQuery } from "@tanstack/react-query";
import { getChainProvider } from "@thirdweb-dev/sdk/evm";
import { providers } from "ethers";
import { useAddress } from "./wallet";
import { useSupportedChains } from "./useSupportedChains";
import { useWalletContext } from "../../core/providers/thirdweb-wallet-provider";
export function useENS() {
const address = useAddress();
const supportedChains = useSupportedChains();
const { clientId } = useWalletContext();
const ethereum = supportedChains.find((chain) => chain.chainId === 1);
return useQuery({
queryKey: ["ens", address, ethereum?.rpc],
cacheTime: 60 * 60 * 24 * 1000, // 24h
staleTime: 60 * 60 * 1000, // 1h
retry: false,
enabled: !!address,
queryFn: async () => {
if (!address) {
return null;
}
const provider = getChainProvider(1, {
clientId,
supportedChains: ethereum
? [
{
chainId: 1,
rpc: [...ethereum.rpc],
nativeCurrency: ethereum.nativeCurrency,
slug: ethereum.slug,
},
]
: undefined,
});
if (provider instanceof providers.JsonRpcProvider) {
const [ens, avatarUrl] = await Promise.all([
provider.lookupAddress(address),
provider.getAvatar(address),
] as const);
return {
ens,
avatarUrl,
};
}
return {
ens: await provider.lookupAddress(address),
avatarUrl: null,
};
},
});
}
+1
View File
@@ -245,6 +245,7 @@ export { useSigner } from "./hooks/useSigner";
export { useSupportedChains } from "./hooks/useSupportedChains";
export { useSupportedWallet } from "./hooks/useSupportedWallet";
export { useAppURI, useSetAppURI } from "./hooks/async/app";
export { useENS } from "./hooks/useENS";
// sdk provider
export { ThirdwebSDKProvider } from "./providers/thirdweb-sdk-provider";
+47
View File
@@ -1,5 +1,52 @@
# @thirdweb-dev/react-native-compat
## 0.3.0
### Patch Changes
- [#1561](https://github.com/thirdweb-dev/js/pull/1561) [`5dc372fc`](https://github.com/thirdweb-dev/js/commit/5dc372fc460beced53fdaa3a62c780c1163bcdf2) Thanks [@iketw](https://github.com/iketw)! - Adds EmbeddedWallet (email) to React Native
You can now do:
```javascript
import { ThirdwebProvider, embeddedWallet } from "@thirdweb-dev/react-native";
<ThirdwebProvider
clientId="your-client-id"
supportedWallets={[embeddedWallet()]}
>
<App />
</ThirdwebProvider>;
```
To use the `embeddedWallet` you need to add the following dependencies to your project:
- `"amazon-cognito-identity-js": "^6.3.3"`
- react-native-quick-base64
- react-native-quick-crypto
- There's an open issue on RN > 0.72: https://github.com/margelo/react-native-quick-crypto/issues/186 which you can [fix by](https://github.com/margelo/react-native-quick-crypto/issues/186#issuecomment-1663666739) adding the following to your `android/app/build.gradle` file:
```
packagingOptions {
pickFirst 'lib/x86/libcrypto.so'
pickFirst 'lib/x86_64/libcrypto.so'
pickFirst 'lib/armeabi-v7a/libcrypto.so'
pickFirst 'lib/arm64-v8a/libcrypto.so'
}
```
- When building the iOS app in release mode for RN 0.71 you need to enable the OpenSSL framework in XCode. There are several solutions for this here:
- https://github.com/margelo/react-native-quick-crypto/issues/121#issuecomment-1369924076
- https://github.com/margelo/react-native-quick-crypto/issues/121#issuecomment-1537576444
- react-native-aes-gcm-crypto
- This package requires minSdkVersion = 26 on Android
## 0.2.62
## 0.2.61
## 0.2.60
## 0.2.59
+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.60",
"version": "0.3.0",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+142
View File
@@ -1,5 +1,147 @@
# @thirdweb-dev/react-native
## 0.3.0
### Minor Changes
- [#1676](https://github.com/thirdweb-dev/js/pull/1676) [`81797ffd`](https://github.com/thirdweb-dev/js/commit/81797ffde34817b457fdbf5241b1c06a13627e51) Thanks [@iketw](https://github.com/iketw)! - Minor version bump for React Native
### Patch Changes
- [#1675](https://github.com/thirdweb-dev/js/pull/1675) [`69e82085`](https://github.com/thirdweb-dev/js/commit/69e8208538886a13072b640013a8f4b46850903b) Thanks [@iketw](https://github.com/iketw)! - Lots of small UI fixes
- [#1683](https://github.com/thirdweb-dev/js/pull/1683) [`bd23cec7`](https://github.com/thirdweb-dev/js/commit/bd23cec7d1101a422e5c0abebf683595f1bac99f) Thanks [@iketw](https://github.com/iketw)! - Update guest wallet icon
- [#1561](https://github.com/thirdweb-dev/js/pull/1561) [`5dc372fc`](https://github.com/thirdweb-dev/js/commit/5dc372fc460beced53fdaa3a62c780c1163bcdf2) Thanks [@iketw](https://github.com/iketw)! - Adds EmbeddedWallet (email) to React Native
You can now do:
```javascript
import { ThirdwebProvider, embeddedWallet } from "@thirdweb-dev/react-native";
<ThirdwebProvider
clientId="your-client-id"
supportedWallets={[embeddedWallet()]}
>
<App />
</ThirdwebProvider>;
```
To use the `embeddedWallet` you need to add the following dependencies to your project:
- `"amazon-cognito-identity-js": "^6.3.3"`
- react-native-quick-base64
- react-native-quick-crypto
- There's an open issue on RN > 0.72: https://github.com/margelo/react-native-quick-crypto/issues/186 which you can [fix by](https://github.com/margelo/react-native-quick-crypto/issues/186#issuecomment-1663666739) adding the following to your `android/app/build.gradle` file:
```
packagingOptions {
pickFirst 'lib/x86/libcrypto.so'
pickFirst 'lib/x86_64/libcrypto.so'
pickFirst 'lib/armeabi-v7a/libcrypto.so'
pickFirst 'lib/arm64-v8a/libcrypto.so'
}
```
- When building the iOS app in release mode for RN 0.71 you need to enable the OpenSSL framework in XCode. There are several solutions for this here:
- https://github.com/margelo/react-native-quick-crypto/issues/121#issuecomment-1369924076
- https://github.com/margelo/react-native-quick-crypto/issues/121#issuecomment-1537576444
- react-native-aes-gcm-crypto
- This package requires minSdkVersion = 26 on Android
- [#1680](https://github.com/thirdweb-dev/js/pull/1680) [`ed4172dd`](https://github.com/thirdweb-dev/js/commit/ed4172dddf63eca19cc6cce265bdfef8b702c5d1) Thanks [@iketw](https://github.com/iketw)! - Small UI improvements
- Updated dependencies [[`54f83a50`](https://github.com/thirdweb-dev/js/commit/54f83a5013ed65ddd5a787e13ba7e5d86625537d), [`a9b4b0c5`](https://github.com/thirdweb-dev/js/commit/a9b4b0c5d875dec660694466e5e322cc574bb21b), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3), [`96e832cc`](https://github.com/thirdweb-dev/js/commit/96e832cc80692da38279c53f1289265b3728cb19), [`b16c09df`](https://github.com/thirdweb-dev/js/commit/b16c09df75c7193a91b832db7d9c92612ae09357), [`6897ad65`](https://github.com/thirdweb-dev/js/commit/6897ad6502d585d55a8c7b2312b4af30663336c3), [`ee028e12`](https://github.com/thirdweb-dev/js/commit/ee028e12092fd306f076f6ea1d49a2295802dd6b), [`d28b1c0f`](https://github.com/thirdweb-dev/js/commit/d28b1c0f1e1e53eedc8f331be555e22b64fb920d), [`c085d690`](https://github.com/thirdweb-dev/js/commit/c085d69060c68b3335761bdb2cc0c3e082548702), [`de05c2da`](https://github.com/thirdweb-dev/js/commit/de05c2da174a69315f2d34dd32a811bbd9a0b604), [`bdb2ccc7`](https://github.com/thirdweb-dev/js/commit/bdb2ccc7a66c33ec5dc331b6fa792e6361769e88), [`c7e7ec95`](https://github.com/thirdweb-dev/js/commit/c7e7ec9502b46312d36cad5177c4f4a50c34f1a3)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.62
### Patch Changes
- [#1644](https://github.com/thirdweb-dev/js/pull/1644) [`2ce89cfe`](https://github.com/thirdweb-dev/js/commit/2ce89cfea905a669511acfcca43be2044579ab90) Thanks [@iketw](https://github.com/iketw)! - Update ipfs json upload to new endpoint
- [#1632](https://github.com/thirdweb-dev/js/pull/1632) [`cbbb8ccb`](https://github.com/thirdweb-dev/js/commit/cbbb8ccbe3435b6cc7b3f6ab83d412626e9550de) Thanks [@iketw](https://github.com/iketw)! - Coinbase url listener should only listen for the Coinbase callbackURL
- [#1635](https://github.com/thirdweb-dev/js/pull/1635) [`57af96c2`](https://github.com/thirdweb-dev/js/commit/57af96c28845d5e292970655e2ff967169f3724c) Thanks [@iketw](https://github.com/iketw)! - Correctly return json uploads results
- Updated dependencies [[`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`dd3d1a87`](https://github.com/thirdweb-dev/js/commit/dd3d1a87c2dadbadecc9ac3722941a8992bc8131), [`9d553746`](https://github.com/thirdweb-dev/js/commit/9d553746b025ac489f9b8ee357372c9d01c835e1), [`64528263`](https://github.com/thirdweb-dev/js/commit/64528263f42bd2c564aad5e777f9f6dbba30af54), [`d5fafdde`](https://github.com/thirdweb-dev/js/commit/d5fafddea58bc307c9b514a1c9578cafd18b5861), [`c29042b7`](https://github.com/thirdweb-dev/js/commit/c29042b71e266cb11d70d67f0fe2ffcc0fc1f5fa), [`b5b7e524`](https://github.com/thirdweb-dev/js/commit/b5b7e5243df83e3ab60d0917c099fb6967b63439), [`b6df6b89`](https://github.com/thirdweb-dev/js/commit/b6df6b895723947427c515411a7a833edaa324c6), [`94bdcc14`](https://github.com/thirdweb-dev/js/commit/94bdcc142a7fe1e9f53273560404fa6b5ac3a7c4), [`48906a9d`](https://github.com/thirdweb-dev/js/commit/48906a9d8ef2cfdd9ac489822a72d50cbd825628), [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525), [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d), [`def6d400`](https://github.com/thirdweb-dev/js/commit/def6d400ab463bda3118d4c9cb00e5cc25a415c2)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.61
### Patch Changes
- [#1592](https://github.com/thirdweb-dev/js/pull/1592) [`1fe867e2`](https://github.com/thirdweb-dev/js/commit/1fe867e20510a43d2a19ba553709aeaca1d46bb3) Thanks [@iketw](https://github.com/iketw)! - Improved ConnectWallet UX/DevX :)
1. Devs can now pass a `recommended` field to `supportedWallets` to recommend wallets to users.
When recommending a wallet, this wallet will show up at the top of the wallets list.
```javascript
import { metamaskWallet, ThirdwebProvider } from "@thirdweb-dev/react-native";
<ThirdwebProvider
clientId="your-client-id"
supportedWallets={[
metamaskWallet({
recommended: true,
}),
]}
>
<App />
</ThirdwebProvider>;
```
2. Better theme customization
You can now more easily customize the theme of the ConnectWallet component:
```javascript
import { ConnectWallet, darkTheme } from "@thirdweb-dev/react-native";
<ConnectWallet
theme={darkTheme({
colors: {
textPrimary: "yellow",
textSecondary: "blue",
},
})}
buttonTitle="Enter web3"
modalTitle="Sign in"
/>;
```
Note that you can still pass `light` or `dark` if you want to use one of the predefined thems :)
3. You can now pass your Privacy Policy and Terms of Service urls, they will show up
at the bottom of the modal:
```javascript
import { ConnectWallet, darkTheme } from "@thirdweb-dev/react-native";
<ConnectWallet
privacyPolicyUrl="https://your-privacy-policy"
termsOfServiceUrl="https://your-terms-of-service"
/>;
```
4. Fixed a bug when you only specify an email wallet. In this case the app shouldn't auto connect, it should show the email field.
- [#1550](https://github.com/thirdweb-dev/js/pull/1550) [`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e) Thanks [@MananTank](https://github.com/MananTank)! - ConnectWallet v3 updates
- Updated dependencies [[`3fd39cea`](https://github.com/thirdweb-dev/js/commit/3fd39cea0df71f80255106329db62660f2fd6e3a), [`3f3c63c0`](https://github.com/thirdweb-dev/js/commit/3f3c63c01e34242ae1f074e62b51787b305c059e), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b), [`48295c06`](https://github.com/thirdweb-dev/js/commit/48295c060499371035980d08e362d9858d0fc18b)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.60
### Patch Changes
+13 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.60",
"version": "0.3.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -24,9 +24,12 @@
"android"
],
"dependencies": {
"@aws-sdk/client-lambda": "3.350.0",
"@aws-sdk/credential-providers": "3.350.0",
"@coinbase/wallet-mobile-sdk": "1.0.7",
"@magic-sdk/provider": "17.2.0",
"@magic-sdk/react-native-bare": "^18.5.0",
"@paperxyz/embedded-wallet-service-sdk": "^1.2.4",
"@shopify/restyle": "^2.4.2",
"@tanstack/react-query": "^4.33.0",
"@thirdweb-dev/chains": "workspace:*",
@@ -35,14 +38,16 @@
"@thirdweb-dev/storage": "workspace:*",
"@thirdweb-dev/wallets": "workspace:*",
"abitype": "^0.2.5",
"aws-amplify": "^5.3.8",
"expo-application": "^5.3.0",
"expo-clipboard": "^4.1.2",
"expo-document-picker": "^11.2.2",
"expo-file-system": "^15.2.2",
"expo-secure-store": "^12.1.1",
"react-native-mmkv": "2.5.1",
"react-native-modal": "^13.0.1",
"react-native-qrcode-svg": "6.2.0",
"react-native-svg": "^13.9.0",
"secrets.js-34r7h": "^2.0.2",
"tiny-invariant": "^1.2.0"
},
"devDependencies": {
@@ -71,6 +76,7 @@
"react-native": "^0.71.11",
"react-native-camera": "^4.2.1",
"react-native-device-info": "10.6.0",
"react-native-mmkv": "2.5.1",
"react-native-safe-area-context": "4.5.3",
"react-native-webview": "12.1.0",
"typescript": "^5.1.6"
@@ -79,7 +85,11 @@
"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"
"react-native-webview": "12.1.0",
"amazon-cognito-identity-js": "^6.3.3",
"react-native-quick-base64": "^2.0.7",
"react-native-quick-crypto": "^0.6.1",
"react-native-aes-gcm-crypto": "^0.2.2"
},
"peerDependencies": {
"ethers": ">=5.5.1 <6",
@@ -6,6 +6,7 @@ import {
} from "@thirdweb-dev/storage";
import { IpfsUploaderOptions, UploadDataValue } from "./types";
import * as Application from "expo-application";
import { Platform } from "react-native";
const APP_BUNDLE_ID = Application.applicationId;
const METADATA_NAME = "Storage React Native SDK";
@@ -38,6 +39,11 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
keyvalues: { ...options?.metadata },
};
// this is on purpose because we can't import package.json as a module as it is outside rootDir
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { version, name: packageName } = require("../../../package.json");
const platform = `react-native-${Platform.OS}`;
if ("uri" in data[0] && "type" in data[0] && "name" in data[0]) {
// then it's an array of files
return new Promise(async (resolve, reject) => {
@@ -142,6 +148,10 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
xhr.setRequestHeader("x-client-id", this.clientId);
}
xhr.setRequestHeader("x-sdk-version", version);
xhr.setRequestHeader("x-sdk-name", packageName);
xhr.setRequestHeader("x-sdk-platform", platform);
xhr.send(form);
});
} else {
@@ -153,21 +163,34 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
});
try {
const res = await fetch(`${TW_UPLOAD_SERVER_URL}/ipfs/pin-json`, {
method: "POST",
headers: {
"x-bundle-id": APP_BUNDLE_ID || "", // only empty on web
...(this.clientId ? { "x-client-id": this.clientId } : {}),
"Content-Type": "application/json",
const res = await fetch(
`${TW_UPLOAD_SERVER_URL}/ipfs/batch-pin-json`,
{
method: "POST",
headers: {
"x-bundle-id": APP_BUNDLE_ID || "", // only empty on web
...(this.clientId ? { "x-client-id": this.clientId } : {}),
"Content-Type": "application/json",
"x-sdk-version": version,
"x-sdk-name": packageName,
"x-sdk-platform": platform,
},
body: fetchBody,
},
body: fetchBody,
});
);
if (res.ok) {
const ipfs = await res.json();
const cid = ipfs.IpfsHash;
const ipfsResults = await res.json();
return resolve([`ipfs://${cid}`]);
const results = ipfsResults.results.map(
(ipfs: { IpfsHash: string; PinSize: number }) => {
const cid = ipfs.IpfsHash;
return `ipfs://${cid}`;
},
);
return resolve(results);
}
} catch (error) {
reject(error);
@@ -0,0 +1,19 @@
import Svg, { Path } from "react-native-svg";
import { IconStyleProp } from "./types";
import React from "react";
const CheckIcon = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 18 13" fill="none">
<Path
d="M17 1L6 12L1 7"
stroke={color}
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</Svg>
);
};
export default CheckIcon;
@@ -0,0 +1,24 @@
import { IconStyleProp } from "./types";
import Svg, { Line, Path } from "react-native-svg";
const DownloadIcon = ({ width, height, color = "white" }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 18 18" fill="none">
<Path
d="M9.05088 12.9506C9.26009 13.1598 9.59929 13.1598 9.80849 12.9506L13.2178 9.54132C13.427 9.33211 13.427 8.99291 13.2178 8.78371C13.0085 8.5745 12.6694 8.5745 12.4601 8.78371L9.42969 11.8142L6.39923 8.78371C6.19002 8.5745 5.85082 8.5745 5.64162 8.78371C5.43241 8.99292 5.43241 9.33211 5.64162 9.54132L9.05088 12.9506ZM9.9654 3.28606C9.9654 2.9902 9.72555 2.75035 9.42969 2.75035C9.13382 2.75035 8.89397 2.9902 8.89397 3.28606L9.9654 3.28606ZM9.9654 12.5718L9.9654 3.28606L8.89397 3.28606L8.89397 12.5718L9.9654 12.5718Z"
fill={color}
/>
<Line
x1="5.68025"
y1="14.1791"
x2="13.1802"
y2="14.1791"
stroke={color}
stroke-width="1.07143"
stroke-linecap="round"
/>
</Svg>
);
};
export default DownloadIcon;
@@ -0,0 +1,33 @@
import { IconStyleProp } from "./types";
import Svg, { Path, Rect } from "react-native-svg";
const Email = ({ width, height }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 18 18" fill="none">
<Rect
x="0.633333"
y="0.633333"
width="16.4667"
height="16.4667"
rx="4.43333"
fill="#3385FF"
/>
<Rect x="2.2168" y="4.43359" width="13.3" height="8.86667" fill="white" />
<Path
d="M14.7775 2.95557H2.95532C2.14254 2.95557 1.48493 3.62057 1.48493 4.43334L1.47754 13.3C1.47754 14.1128 2.14254 14.7778 2.95532 14.7778H14.7775C15.5903 14.7778 16.2553 14.1128 16.2553 13.3V4.43334C16.2553 3.62057 15.5903 2.95557 14.7775 2.95557ZM14.7775 5.91112L8.86643 9.60557L2.95532 5.91112V4.43334L8.86643 8.12779L14.7775 4.43334V5.91112Z"
fill="#3385FF"
/>
<Rect
x="0.633333"
y="0.633333"
width="16.4667"
height="16.4667"
rx="4.43333"
stroke="#1177FD"
stroke-width="1.26667"
/>
</Svg>
);
};
export default Email;
@@ -1,7 +1,11 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const RightArrowIcon = ({ width, height, color }: IconStyleProp) => {
const RightArrowIcon = ({
width,
height,
color = "#646D7A",
}: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 5 8" fill="none">
<Path
@@ -0,0 +1,15 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const SendIcon = ({ width, height, color = "white" }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 18 18" fill="none">
<Path
d="M15.378 3.05027C15.2429 2.9161 15.0734 2.82178 14.8882 2.77768C14.7029 2.73357 14.5091 2.74139 14.328 2.80027L3.87803 6.28598C3.68423 6.34739 3.51296 6.46486 3.38588 6.62355C3.2588 6.78224 3.18159 6.97502 3.16401 7.17757C3.14643 7.38011 3.18927 7.58332 3.28711 7.76153C3.38496 7.93974 3.53342 8.08496 3.71375 8.17884L8.04946 10.3217L10.1923 14.6717C10.2784 14.842 10.4102 14.9849 10.573 15.0846C10.7357 15.1842 10.9229 15.2366 11.1137 15.236H11.1852C11.3895 15.2209 11.5846 15.1448 11.7451 15.0174C11.9056 14.89 12.0241 14.7173 12.0852 14.5217L15.6209 4.10027C15.684 3.92022 15.6947 3.72594 15.6517 3.54005C15.6087 3.35416 15.5138 3.18431 15.378 3.05027ZM4.32089 7.2717L13.4423 4.22884L8.37803 9.29312L4.32089 7.2717ZM11.1637 14.1074L9.13518 10.0503L14.1995 4.98598L11.1637 14.1074Z"
fill={color}
/>
</Svg>
);
};
export default SendIcon;
@@ -0,0 +1,171 @@
export const EMAIL_WALLET_ICON = `<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
<g clip-path="url(#clip0_3589_8649)">
<rect width="48" height="48" rx="8" fill="url(#paint0_linear_3589_8649)"/>
<rect x="-1" y="-1" width="50" height="50" rx="9.8" fill="url(#paint1_linear_3589_8649)"/>
<g clip-path="url(#clip1_3589_8649)">
<path d="M24 14.25C18.6172 14.25 14.25 18.6172 14.25 24C14.25 29.3828 18.6172 33.75 24 33.75C24.8988 33.75 25.625 34.4762 25.625 35.375C25.625 36.2738 24.8988 37 24 37C16.8195 37 11 31.1805 11 24C11 16.8195 16.8195 11 24 11C31.1805 11 37 16.8195 37 24V25.625C37 28.3164 34.8164 30.5 32.125 30.5C30.6371 30.5 29.3016 29.8297 28.4078 28.7785C27.25 29.8449 25.7012 30.5 24 30.5C20.4098 30.5 17.5 27.5902 17.5 24C17.5 20.4098 20.4098 17.5 24 17.5C25.4168 17.5 26.727 17.952 27.7934 18.7238C28.0828 18.4699 28.4586 18.3125 28.875 18.3125C29.7738 18.3125 30.5 19.0387 30.5 19.9375V25.625C30.5 26.5238 31.2262 27.25 32.125 27.25C33.0238 27.25 33.75 26.5238 33.75 25.625V24C33.75 18.6172 29.3828 14.25 24 14.25ZM27.25 24C27.25 23.138 26.9076 22.3114 26.2981 21.7019C25.6886 21.0924 24.862 20.75 24 20.75C23.138 20.75 22.3114 21.0924 21.7019 21.7019C21.0924 22.3114 20.75 23.138 20.75 24C20.75 24.862 21.0924 25.6886 21.7019 26.2981C22.3114 26.9076 23.138 27.25 24 27.25C24.862 27.25 25.6886 26.9076 26.2981 26.2981C26.9076 25.6886 27.25 24.862 27.25 24Z" fill="white"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_3589_8649" x1="25.5" y1="-6.29572e-06" x2="30.2016" y2="47.535" gradientUnits="userSpaceOnUse">
<stop stop-color="#8358BA"/>
<stop offset="1" stop-color="#7B1CF7"/>
</linearGradient>
<linearGradient id="paint1_linear_3589_8649" x1="25.5625" y1="-1.00001" x2="30.46" y2="48.5156" gradientUnits="userSpaceOnUse">
<stop stop-color="#8358BA"/>
<stop offset="1" stop-color="#7B1CF7"/>
</linearGradient>
<clipPath id="clip0_3589_8649">
<rect width="48" height="48" rx="8" fill="white"/>
</clipPath>
<clipPath id="clip1_3589_8649">
<rect width="26" height="26" fill="white" transform="translate(11 11)"/>
</clipPath>
</defs>
</svg>`;
export const SMART_WALLET_ICON = `<svg width="80" height="80" viewBox="0 0 80 80" fill="none">
<rect width="80" height="80" rx="12" fill="url(#paint0_linear_1_91)"/>
<path d="M39.9969 18L40.2333 18.0156L40.3513 18.0333L40.4736 18.0622L40.6958 18.1378C40.8494 18.2006 40.9953 18.2842 41.1305 18.3867L41.3387 18.5689L41.8493 19.0533C45.8891 22.7768 50.9947 24.7762 56.2458 24.6911L56.9307 24.6689C57.3783 24.6462 57.82 24.7909 58.1849 25.0798C58.5498 25.3687 58.8167 25.785 58.9431 26.2622C59.9271 29.9769 60.2283 33.8731 59.8287 37.7194C59.4289 41.5658 58.3367 45.2836 56.6165 48.6523C54.8965 52.0207 52.5836 54.9714 49.8156 57.3285C47.0476 59.6856 43.8809 61.4012 40.5036 62.3734C40.174 62.4683 39.828 62.4683 39.4982 62.3734C36.1209 61.4014 32.9538 59.686 30.1856 57.3289C27.4176 54.9718 25.1045 52.0214 23.3842 48.6529C21.6638 45.2843 20.5713 41.5662 20.1715 37.7198C19.7717 33.8734 20.0727 29.9769 21.0567 26.2622C21.1831 25.785 21.4501 25.3687 21.815 25.0798C22.1799 24.7909 22.6215 24.6462 23.0693 24.6689C28.5513 24.947 33.9293 22.9444 38.1507 19.0533L38.6773 18.5533L38.8696 18.3867C39.0047 18.2842 39.1505 18.2006 39.304 18.1378L39.5282 18.0622C39.6069 18.0412 39.6865 18.0256 39.7667 18.0156L39.9969 18ZM40.0009 33.5556C38.9905 33.5551 38.0173 33.9787 37.2765 34.7411C36.5356 35.5036 36.0816 36.5485 36.0058 37.6667L35.9958 38L36.0058 38.3334C36.0551 39.0547 36.2625 39.7518 36.6098 40.364C36.9569 40.9762 37.4336 41.4851 37.9985 41.8467V45.7778L38.0125 46.0378C38.0727 46.6003 38.3242 47.1158 38.7156 47.4794C39.1071 47.8429 39.6087 48.0269 40.1182 47.9938C40.6278 47.9605 41.1067 47.7127 41.4571 47.3009C41.8076 46.8889 42.0029 46.3442 42.0036 45.7778L42.0056 41.8489C42.7691 41.3596 43.366 40.6042 43.7034 39.7002C44.0407 38.796 44.0996 37.7938 43.8711 36.8487C43.6427 35.9036 43.1396 35.0685 42.4398 34.4731C41.74 33.8776 40.8827 33.5551 40.0009 33.5556Z" fill="url(#paint1_linear_1_91)"/>
<defs>
<linearGradient id="paint0_linear_1_91" x1="40" y1="0" x2="40" y2="80" gradientUnits="userSpaceOnUse">
<stop stop-color="#8356BD"/>
<stop offset="1" stop-color="#7C20F4"/>
</linearGradient>
<linearGradient id="paint1_linear_1_91" x1="40" y1="18" x2="40" y2="62.4445" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#E1D8FB"/>
</linearGradient>
</defs>
</svg>`;
export const WALLETCONNECT_ICON = `<svg width="80" height="80" viewBox="0 0 80 80" fill="none">
<rect width="80" height="80" rx="12" fill="#1C7DFC"/>
<rect width="80" height="80" rx="12" fill="url(#paint0_radial_1_46)"/>
<path d="M26.4227 31.4731C33.9171 24.1756 46.0829 24.1756 53.5773 31.4731L54.4796 32.358C54.858 32.7207 54.858 33.3155 54.4796 33.6782L51.3945 36.6813C51.2053 36.8699 50.8997 36.8699 50.7105 36.6813L49.4736 35.4772C44.2347 30.385 35.7653 30.385 30.5264 35.4772L29.2021 36.7684C29.013 36.957 28.7074 36.957 28.5182 36.7684L25.4331 33.7653C25.0547 33.4026 25.0547 32.8078 25.4331 32.4451L26.4227 31.4731ZM59.9658 37.6824L62.7162 40.3518C63.0946 40.7145 63.0946 41.3093 62.7162 41.672L50.3322 53.728C49.9538 54.0907 49.3426 54.0907 48.9788 53.728L40.1892 45.1684C40.1019 45.0813 39.9418 45.0813 39.8545 45.1684L31.0649 53.728C30.6865 54.0907 30.0753 54.0907 29.7115 53.728L17.2838 41.672C16.9054 41.3093 16.9054 40.7145 17.2838 40.3518L20.0342 37.6824C20.4125 37.3197 21.0237 37.3197 21.3875 37.6824L30.1772 46.242C30.2645 46.329 30.4245 46.329 30.5119 46.242L39.3015 37.6824C39.6799 37.3197 40.291 37.3197 40.6549 37.6824L49.4445 46.242C49.5318 46.329 49.6919 46.329 49.7792 46.242L58.5688 37.6824C58.9763 37.3197 59.5875 37.3197 59.9658 37.6824Z" fill="white"/>
<defs>
<radialGradient id="paint0_radial_1_46" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(0.000247955 40.0012) scale(80)">
<stop stop-color="#5D9DF6"/>
<stop offset="1" stop-color="#006FFF"/>
</radialGradient>
</defs>
</svg>`;
export const LOCAL_WALLET_ICON = `<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
<rect width="48" height="48" rx="7.2" fill="url(#paint0_linear_4221_3214)"/>
<rect width="48" height="48" rx="7.2" fill="url(#paint1_linear_4221_3214)"/>
<path d="M16.5 39C15.675 39 14.9685 38.7327 14.3805 38.1982C13.7925 37.6636 13.499 37.0218 13.5 36.2727V11.7273C13.5 10.9773 13.794 10.335 14.382 9.80046C14.97 9.26591 15.676 8.99909 16.5 9H31.5C32.325 9 33.0315 9.26728 33.6195 9.80182C34.2075 10.3364 34.501 10.9782 34.5 11.7273V36.2727C34.5 37.0227 34.206 37.665 33.618 38.1995C33.03 38.7341 32.324 39.0009 31.5 39H16.5ZM24 35.5909C24.425 35.5909 24.7815 35.46 25.0695 35.1982C25.3575 34.9364 25.501 34.6127 25.5 34.2273C25.5 33.8409 25.356 33.5168 25.068 33.255C24.78 32.9932 24.424 32.8627 24 32.8636C23.575 32.8636 23.2185 32.9945 22.9305 33.2564C22.6425 33.5182 22.499 33.8418 22.5 34.2273C22.5 34.6136 22.644 34.9377 22.932 35.1995C23.22 35.4614 23.576 35.5918 24 35.5909ZM16.5 24.4545C16.5 27.216 18.7386 29.4545 21.5 29.4545H26.5C29.2614 29.4545 31.5 27.216 31.5 24.4545V20.8182C31.5 18.0568 29.2614 15.8182 26.5 15.8182H21.5C18.7386 15.8182 16.5 18.0568 16.5 20.8182V24.4545Z" fill="black"/>
<path d="M16.5 39C15.675 39 14.9685 38.7327 14.3805 38.1982C13.7925 37.6636 13.499 37.0218 13.5 36.2727V11.7273C13.5 10.9773 13.794 10.335 14.382 9.80046C14.97 9.26591 15.676 8.99909 16.5 9H31.5C32.325 9 33.0315 9.26728 33.6195 9.80182C34.2075 10.3364 34.501 10.9782 34.5 11.7273V36.2727C34.5 37.0227 34.206 37.665 33.618 38.1995C33.03 38.7341 32.324 39.0009 31.5 39H16.5ZM24 35.5909C24.425 35.5909 24.7815 35.46 25.0695 35.1982C25.3575 34.9364 25.501 34.6127 25.5 34.2273C25.5 33.8409 25.356 33.5168 25.068 33.255C24.78 32.9932 24.424 32.8627 24 32.8636C23.575 32.8636 23.2185 32.9945 22.9305 33.2564C22.6425 33.5182 22.499 33.8418 22.5 34.2273C22.5 34.6136 22.644 34.9377 22.932 35.1995C23.22 35.4614 23.576 35.5918 24 35.5909ZM16.5 24.4545C16.5 27.216 18.7386 29.4545 21.5 29.4545H26.5C29.2614 29.4545 31.5 27.216 31.5 24.4545V20.8182C31.5 18.0568 29.2614 15.8182 26.5 15.8182H21.5C18.7386 15.8182 16.5 18.0568 16.5 20.8182V24.4545Z" fill="url(#paint2_linear_4221_3214)"/>
<rect x="16.5" y="12" width="15" height="24" rx="2.25" fill="#B70FAF"/>
<rect x="19.5" y="13.5" width="9" height="3" rx="1.5" fill="#F8F5FF"/>
<defs>
<linearGradient id="paint0_linear_4221_3214" x1="25.5" y1="-6.29572e-06" x2="30.2016" y2="47.535" gradientUnits="userSpaceOnUse">
<stop stop-color="#8358BA"/>
<stop offset="0.422496" stop-color="#803FD4"/>
<stop offset="1" stop-color="#7B1CF7"/>
</linearGradient>
<linearGradient id="paint1_linear_4221_3214" x1="22.5" y1="-1.36904e-07" x2="22.5" y2="53.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#D311AA"/>
<stop offset="1" stop-color="#8409B7"/>
</linearGradient>
<linearGradient id="paint2_linear_4221_3214" x1="24" y1="9" x2="24" y2="39" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#E1D8FB"/>
</linearGradient>
</defs>
</svg>`;
export const COINBASE_ICON = `<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" rx="8" fill="#0555FF"/>
<g clip-path="url(#clip0_3303_8634)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.3312 4H35.6672C40.2704 4 44 8.0128 44 12.9632V35.0368C44 39.9872 40.2704 44 35.6688 44H12.3312C7.7296 44 4 39.9872 4 35.0368V12.9632C4 8.0128 7.7296 4 12.3312 4Z" fill="#0052FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.0003 9.79346C31.8467 9.79346 38.2067 16.1535 38.2067 23.9999C38.2067 31.8463 31.8467 38.2063 24.0003 38.2063C16.1539 38.2063 9.79395 31.8463 9.79395 23.9999C9.79395 16.1535 16.1539 9.79346 24.0003 9.79346Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.5006 19.459H27.4974C28.0734 19.459 28.539 19.9614 28.539 20.579V27.419C28.539 28.0382 28.0718 28.539 27.4974 28.539H20.5006C19.9246 28.539 19.459 28.0366 19.459 27.419V20.579C19.459 19.9614 19.9262 19.459 20.5006 19.459Z" fill="#0052FF"/>
</g>
<defs>
<clipPath id="clip0_3303_8634">
<rect width="40" height="40" fill="white" transform="translate(4 4)"/>
</clipPath>
</defs>
</svg>`;
export const TRUST_ICON = `<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="80" rx="12" fill="white"/>
<path d="M40.5303 17.1425C48.2477 23.6857 57.156 23.3518 59.7003 23.3707C58.8698 60.2513 54.6835 52.9058 40.1887 63.1412C25.8474 52.6916 21.579 59.9744 21.2964 23.0855C23.8142 23.1042 32.7165 23.5704 40.5303 17.1425Z" stroke="#3375BB" stroke-width="7" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`;
export const METAMASK_ICON = `<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="80" rx="12" fill="#FFE6CE"/>
<path d="M64.9712 14.179L43.2903 30.2817L47.2996 20.7814L64.9712 14.179Z" fill="#E2761B" stroke="#E2761B" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.9198 14.179L36.4264 30.4343L32.6132 20.7814L14.9198 14.179ZM57.1704 51.5051L51.3961 60.3518L63.751 63.751L67.3027 51.7012L57.1704 51.5051ZM12.6319 51.7012L16.1619 63.751L28.5167 60.3518L22.7424 51.5051L12.6319 51.7012Z" fill="#E4761B" stroke="#E4761B" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M27.8194 36.5572L24.3766 41.765L36.6444 42.3097L36.2086 29.1268L27.8194 36.5572ZM52.0716 36.5572L43.5735 28.9743L43.2903 42.3097L55.5362 41.765L52.0716 36.5572ZM28.5167 60.3517L35.8817 56.7564L29.5191 51.7883L28.5167 60.3517ZM44.0093 56.7564L51.3961 60.3517L50.372 51.7883L44.0093 56.7564Z" fill="#E4761B" stroke="#E4761B" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M51.3961 60.3517L44.0093 56.7564L44.5977 61.572L44.5323 63.5984L51.3961 60.3517ZM28.5167 60.3517L35.3805 63.5984L35.337 61.572L35.8817 56.7564L28.5167 60.3517Z" fill="#D7C1B3" stroke="#D7C1B3" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M35.4895 48.607L29.3447 46.7984L33.6809 44.8156L35.4895 48.607ZM44.4015 48.607L46.2101 44.8156L50.5681 46.7984L44.4015 48.607Z" fill="#233447" stroke="#233447" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M28.5167 60.3517L29.5626 51.505L22.7424 51.7011L28.5167 60.3517ZM50.3502 51.505L51.3961 60.3517L57.1704 51.7011L50.3502 51.505ZM55.5362 41.765L43.2903 42.3097L44.4233 48.607L46.2319 44.8155L50.5899 46.7984L55.5362 41.765ZM29.3447 46.7984L33.7027 44.8155L35.4895 48.607L36.6443 42.3097L24.3766 41.765L29.3447 46.7984Z" fill="#CD6116" stroke="#CD6116" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M24.3766 41.765L29.5191 51.7883L29.3447 46.7984L24.3766 41.765ZM50.5899 46.7984L50.372 51.7883L55.5362 41.765L50.5899 46.7984ZM36.6444 42.3097L35.4895 48.607L36.9276 56.0373L37.2545 46.2537L36.6444 42.3097ZM43.2903 42.3097L42.7019 46.2319L42.9634 56.0373L44.4233 48.607L43.2903 42.3097Z" fill="#E4751F" stroke="#E4751F" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M44.4233 48.607L42.9634 56.0374L44.0093 56.7564L50.372 51.7883L50.5899 46.7985L44.4233 48.607ZM29.3447 46.7985L29.519 51.7883L35.8817 56.7564L36.9276 56.0374L35.4895 48.607L29.3447 46.7985Z" fill="#F6851B" stroke="#F6851B" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M44.5323 63.5984L44.5977 61.572L44.0529 61.0926H35.8381L35.337 61.572L35.3805 63.5984L28.5167 60.3517L30.9136 62.3128L35.7728 65.6903H44.1183L48.9992 62.3128L51.3961 60.3517L44.5323 63.5984Z" fill="#C0AD9E" stroke="#C0AD9E" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M44.0093 56.7564L42.9634 56.0374H36.9276L35.8817 56.7564L35.337 61.572L35.8381 61.0926H44.0529L44.5977 61.572L44.0093 56.7564Z" fill="#161616" stroke="#161616" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M65.8864 31.3277L67.7385 22.4374L64.9712 14.179L44.0093 29.737L52.0716 36.5572L63.4677 39.8911L65.9953 36.9494L64.9058 36.165L66.649 34.5743L65.2981 33.5284L67.0412 32.1992L65.8864 31.3277ZM12.1743 22.4374L14.0265 31.3277L12.8498 32.1992L14.593 33.5284L13.2638 34.5743L15.007 36.165L13.9175 36.9494L16.4233 39.8911L27.8195 36.5572L35.8817 29.737L14.9198 14.179L12.1743 22.4374Z" fill="#763D16" stroke="#763D16" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M63.4677 39.891L52.0716 36.5572L55.5362 41.765L50.372 51.7883L57.1704 51.7012H67.3027L63.4677 39.891ZM27.8194 36.5572L16.4233 39.891L12.6319 51.7012H22.7424L29.5191 51.7883L24.3766 41.765L27.8194 36.5572ZM43.2903 42.3097L44.0093 29.737L47.3214 20.7813H32.6132L35.8817 29.737L36.6443 42.3097L36.9058 46.2755L36.9276 56.0373H42.9634L43.007 46.2755L43.2903 42.3097Z" fill="#F6851B" stroke="#F6851B" stroke-width="0.124514" stroke-linecap="round" stroke-linejoin="round"/>
</svg>`;
export const RAINBOW_ICON = `<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5_149)">
<path d="M80 0H0V80H80V0Z" fill="url(#paint0_linear_5_149)"/>
<path d="M13.3333 25.3334H17.3333C37.9519 25.3334 54.6666 42.0481 54.6666 62.6667V66.6667H62.6666C64.8758 66.6667 66.6666 64.8758 66.6666 62.6667C66.6666 35.4206 44.5794 13.3334 17.3333 13.3334C15.1242 13.3334 13.3333 15.1242 13.3333 17.3334V25.3334Z" fill="url(#paint1_radial_5_149)"/>
<path d="M56 62.6666H66.6667C66.6667 64.8758 64.8758 66.6666 62.6667 66.6666H56V62.6666Z" fill="url(#paint2_linear_5_149)"/>
<path d="M17.3333 13.3334V24H13.3333V17.3334C13.3333 15.1242 15.1242 13.3334 17.3333 13.3334Z" fill="url(#paint3_linear_5_149)"/>
<path d="M13.3333 24H17.3333C38.6883 24 56 41.3117 56 62.6667V66.6667H44V62.6667C44 47.9391 32.0609 36 17.3333 36H13.3333V24Z" fill="url(#paint4_radial_5_149)"/>
<path d="M45.3333 62.6666H56V66.6666H45.3333V62.6666Z" fill="url(#paint5_linear_5_149)"/>
<path d="M13.3333 34.6667V24H17.3333V34.6667H13.3333Z" fill="url(#paint6_linear_5_149)"/>
<path d="M13.3333 41.3333C13.3333 43.5424 15.1242 45.3333 17.3333 45.3333C26.9062 45.3333 34.6666 53.0937 34.6666 62.6666C34.6666 64.8758 36.4575 66.6666 38.6666 66.6666H45.3333V62.6666C45.3333 47.2026 32.7973 34.6666 17.3333 34.6666H13.3333V41.3333Z" fill="url(#paint7_radial_5_149)"/>
<path d="M34.6667 62.6666H45.3334V66.6666H38.6667C36.4576 66.6666 34.6667 64.8758 34.6667 62.6666Z" fill="url(#paint8_radial_5_149)"/>
<path d="M17.3333 45.3333C15.1242 45.3333 13.3333 43.5424 13.3333 41.3333V34.6666H17.3333V45.3333Z" fill="url(#paint9_radial_5_149)"/>
</g>
<defs>
<linearGradient id="paint0_linear_5_149" x1="40" y1="0" x2="40" y2="80" gradientUnits="userSpaceOnUse">
<stop stop-color="#174299"/>
<stop offset="1" stop-color="#001E59"/>
</linearGradient>
<radialGradient id="paint1_radial_5_149" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.3333 62.6667) rotate(-90) scale(49.3333)">
<stop offset="0.770277" stop-color="#FF4000"/>
<stop offset="1" stop-color="#8754C9"/>
</radialGradient>
<linearGradient id="paint2_linear_5_149" x1="55.3333" y1="64.6666" x2="66.6667" y2="64.6666" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF4000"/>
<stop offset="1" stop-color="#8754C9"/>
</linearGradient>
<linearGradient id="paint3_linear_5_149" x1="15.3333" y1="13.3334" x2="15.3333" y2="24.6667" gradientUnits="userSpaceOnUse">
<stop stop-color="#8754C9"/>
<stop offset="1" stop-color="#FF4000"/>
</linearGradient>
<radialGradient id="paint4_radial_5_149" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.3333 62.6667) rotate(-90) scale(38.6667)">
<stop offset="0.723929" stop-color="#FFF700"/>
<stop offset="1" stop-color="#FF9901"/>
</radialGradient>
<linearGradient id="paint5_linear_5_149" x1="45.3333" y1="64.6666" x2="56" y2="64.6666" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF700"/>
<stop offset="1" stop-color="#FF9901"/>
</linearGradient>
<linearGradient id="paint6_linear_5_149" x1="15.3333" y1="34.6667" x2="15.3333" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF700"/>
<stop offset="1" stop-color="#FF9901"/>
</linearGradient>
<radialGradient id="paint7_radial_5_149" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.3333 62.6666) rotate(-90) scale(28)">
<stop offset="0.59513" stop-color="#00AAFF"/>
<stop offset="1" stop-color="#01DA40"/>
</radialGradient>
<radialGradient id="paint8_radial_5_149" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(34 64.6666) scale(11.3333 30.2222)">
<stop stop-color="#00AAFF"/>
<stop offset="1" stop-color="#01DA40"/>
</radialGradient>
<radialGradient id="paint9_radial_5_149" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.3333 46) rotate(-90) scale(11.3333 214.913)">
<stop stop-color="#00AAFF"/>
<stop offset="1" stop-color="#01DA40"/>
</radialGradient>
<clipPath id="clip0_5_149">
<rect width="80" height="80" rx="12" fill="white"/>
</clipPath>
</defs>
</svg>`;
@@ -0,0 +1,35 @@
import { IconStyleProp } from "./types";
import Svg, { ClipPath, Defs, G, Path, Rect } from "react-native-svg";
const ThirdwebLogo = ({ width, height, color }: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 26 16" fill="none">
<G clip-path="url(#clip0_3185_13519)">
<Path
d="M13.6795 0.5C13.8386 0.531779 13.9887 0.595721 14.1196 0.6875C14.2673 0.797724 14.3804 0.944328 14.4467 1.11141C14.8623 2.10272 15.279 3.09348 15.6968 4.0837L17.089 7.39022C17.3322 7.96902 17.5736 8.5462 17.8202 9.12337C17.8727 9.24121 17.8998 9.36791 17.8998 9.49592C17.8998 9.62393 17.8727 9.75064 17.8202 9.86848C17.1147 11.5446 16.4086 13.2217 15.7019 14.9C15.6444 15.0572 15.542 15.196 15.4062 15.3009C15.2703 15.4057 15.1065 15.4724 14.933 15.4935C14.7188 15.5315 14.4972 15.4982 14.3057 15.399C14.1143 15.2998 13.9645 15.1409 13.8816 14.9489C13.4843 14.0196 13.0956 13.087 12.7034 12.1543C12.0367 10.575 11.3717 8.99457 10.7085 7.41304C10.1159 6.00543 9.52401 4.59891 8.93265 3.19348C8.73572 2.72717 8.54564 2.25761 8.34015 1.79293C8.28363 1.66705 8.25686 1.53087 8.26173 1.39405C8.26661 1.25722 8.30301 1.12309 8.36836 1.00114C8.43371 0.879187 8.52641 0.772402 8.6399 0.688339C8.75339 0.604275 8.8849 0.544988 9.02512 0.514673C9.04225 0.514673 9.05766 0.504891 9.07478 0.5H13.6795Z"
fill={color}
/>
<Path
d="M5.41171 0.5C5.46479 0.514674 5.51617 0.526087 5.56754 0.542392C5.70064 0.581915 5.82278 0.64928 5.925 0.739555C6.02722 0.829829 6.10694 0.940727 6.15833 1.06413C6.61498 2.13913 7.06821 3.21413 7.51801 4.28913C7.96781 5.36413 8.42446 6.45109 8.88796 7.55L9.56095 9.14456C9.61135 9.25806 9.63731 9.38004 9.63731 9.50326C9.63731 9.62648 9.61135 9.74846 9.56095 9.86196C9.31094 10.4587 9.05978 11.0565 8.80748 11.6554L7.42554 14.931C7.35297 15.1012 7.22895 15.2471 7.0692 15.3501C6.90946 15.4532 6.72117 15.5087 6.52822 15.5098C6.32467 15.5125 6.12519 15.4554 5.95696 15.3463C5.78872 15.2372 5.65991 15.0814 5.58809 14.9C5.15998 13.8712 4.73187 12.844 4.29348 11.8168L2.53823 7.64946L0.753866 3.41033C0.529536 2.87554 0.305206 2.33913 0.0688893 1.80435C-0.0308499 1.58161 -0.0356895 1.33067 0.0553906 1.10459C0.146471 0.878515 0.326331 0.695028 0.556936 0.592935C0.641014 0.560457 0.727427 0.533759 0.815514 0.513044L5.41171 0.5Z"
fill={color}
/>
<Path
d="M25.9999 9.64348C25.8766 10.0478 25.6968 10.4293 25.5255 10.8239C25.0609 11.9315 24.5934 13.0397 24.123 14.1484C24.0151 14.4109 23.9055 14.6554 23.8011 14.9114C23.7264 15.091 23.595 15.244 23.4251 15.3495C23.2552 15.4549 23.0551 15.5075 22.8524 15.5C22.6589 15.495 22.4714 15.4353 22.3137 15.3284C22.156 15.2216 22.0354 15.0724 21.9671 14.9C21.2889 13.2848 20.6097 11.6696 19.9292 10.0543C19.3425 8.66522 18.7534 7.27283 18.162 5.87717C17.5912 4.51087 17.0204 3.14456 16.4496 1.77826C16.3942 1.65338 16.3684 1.51844 16.374 1.383C16.3795 1.24756 16.4163 1.11494 16.4816 0.994528C16.547 0.874117 16.6393 0.768861 16.7522 0.686219C16.865 0.603577 16.9955 0.545569 17.1345 0.516304L17.1911 0.5H21.7924L21.8352 0.513044C21.9973 0.545507 22.1481 0.616718 22.2733 0.719974C22.3985 0.82323 22.4941 0.955132 22.551 1.10326C22.8181 1.73913 23.0864 2.37554 23.3558 3.0125C24.0579 4.68206 24.76 6.35163 25.4621 8.02119C25.6471 8.46141 25.8526 8.89348 26.0033 9.34511L25.9999 9.64348Z"
fill={color}
/>
</G>
<Defs>
<ClipPath id="clip0_3185_13519">
<Rect
width={width}
height={height}
fill={color}
transform="translate(0 0.5)"
/>
</ClipPath>
</Defs>
</Svg>
);
};
export default ThirdwebLogo;
@@ -0,0 +1,43 @@
import { IconStyleProp } from "./types";
import Svg, { Path } from "react-native-svg";
const TransactionIcon = ({
width,
height,
color = "#646D7A",
}: IconStyleProp) => {
return (
<Svg width={width} height={height} viewBox="0 0 16 16" fill="none">
<Path
d="M11.3333 6.6665H2"
stroke={color}
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M14 4H2"
stroke={color}
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M14 9.3335H2"
stroke={color}
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<Path
d="M11.3333 12H2"
stroke={color}
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
</Svg>
);
};
export default TransactionIcon;
@@ -1,4 +1,3 @@
import { ThemeProvider } from "../styles/ThemeProvider";
import {
ConnectWalletDetailsProps,
WalletDetailsButton,
@@ -9,12 +8,15 @@ import {
useSwitchChain,
useWalletContext,
} from "@thirdweb-dev/react-core";
import { useEffect, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { ActivityIndicator, Animated, StyleSheet } from "react-native";
import { ConnectWalletButton } from "./ConnectWalletFlow/ConnectWalletButton";
import { ConnectWalletButtonProps } from "./ConnectWalletFlow/ConnectWalletButton";
import BaseButton from "./base/BaseButton";
import Text from "./base/Text";
import { useUIContext } from "../providers/ui-context-provider";
import { ThemeProvider } from "../styles/ThemeProvider";
import { SupportedTokens, defaultTokens } from "./SendFunds/defaultTokens";
export type ConnectWalletProps = {
/**
@@ -44,6 +46,25 @@ export type ConnectWalletProps = {
* @default false
*/
switchToActiveChain?: boolean;
/**
* Override the default supported tokens for each network
*
* These tokens will be displayed in "Send Funds" Modal
*/
supportedTokens?: SupportedTokens;
/**
* Show balance of ERC20 token instead of the native token in the "Connected" button when connected to certain network
*
* @example
* ```tsx
* <ConnectWallet balanceToken={{
* 1: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" // show USDC balance when connected to Ethereum mainnet
* }} />
* ```
*/
displayBalanceToken?: Record<number, string>;
} & ConnectWalletButtonProps;
export const ConnectWallet = ({
@@ -51,9 +72,14 @@ export const ConnectWallet = ({
theme,
buttonTitle,
modalTitle,
modalTitleIconUrl,
extraRows,
hideTestnetFaucet,
displayBalanceToken,
switchToActiveChain,
termsOfServiceUrl,
privacyPolicyUrl,
supportedTokens,
}: ConnectWalletProps) => {
const fadeAnim = useRef(new Animated.Value(0)).current;
const address = useAddress();
@@ -62,6 +88,7 @@ export const ConnectWallet = ({
const { activeChain } = useWalletContext();
const switchChain = useSwitchChain();
const [switching, setSwitching] = useState(false);
const setTheme = useUIContext().setTheme;
useEffect(() => {
Animated.timing(fadeAnim, {
@@ -71,6 +98,26 @@ export const ConnectWallet = ({
}).start();
}, [fadeAnim]);
useEffect(() => {
if (theme) {
setTheme(theme);
}
}, [setTheme, theme]);
const supportedTokensMemo = useMemo(() => {
if (!supportedTokens) {
return defaultTokens;
}
const tokens = { ...defaultTokens };
for (const k in supportedTokens) {
const key = Number(k);
tokens[key] = supportedTokens[key];
}
return tokens;
}, [supportedTokens]);
return (
<ThemeProvider theme={theme}>
<Animated.View style={{ opacity: fadeAnim }}>
@@ -105,13 +152,18 @@ export const ConnectWallet = ({
detailsButton={detailsButton}
extraRows={extraRows}
hideTestnetFaucet={hideTestnetFaucet}
supportedTokens={supportedTokensMemo}
displayBalanceToken={displayBalanceToken}
/>
)
) : (
<ConnectWalletButton
modalTitle={modalTitle}
buttonTitle={buttonTitle}
modalTitleIconUrl={modalTitleIconUrl}
theme={theme}
termsOfServiceUrl={termsOfServiceUrl}
privacyPolicyUrl={privacyPolicyUrl}
/>
)}
</Animated.View>
@@ -113,17 +113,21 @@ const ConnectAppField = () => {
{!appMeta && showWCInput ? (
<Box
flexDirection="row"
mb="sm"
mt="xs"
borderColor="border"
borderWidth={1}
borderRadius="md"
>
<TextInput
onChangeText={onAddressChangeText}
flex={1}
value={wcUri}
placeholder={"wc://..."}
placeholderTextColor={theme.colors.textSecondary}
textInputProps={{
onChangeText: onAddressChangeText,
value: wcUri,
placeholder: "wc://...",
placeholderTextColor: theme.colors.textSecondary,
}}
containerProps={{
flex: 1,
}}
/>
<BaseButton
onPress={() => onWCPress()}
@@ -153,13 +157,13 @@ const ConnectAppField = () => {
<BaseButton
backgroundColor="background"
borderColor="border"
mb="sm"
mt="xs"
justifyContent="space-between"
style={styles.exportWallet}
onPress={onConnectDappPress}
>
<>
{appMeta ? (
{appMeta?.iconUrl ? (
<WalletIcon size={32} iconUri={appMeta.iconUrl} />
) : (
<WalletConnectIcon width={16} height={16} />
@@ -18,11 +18,17 @@ import { useSmartWallet } from "../../providers/context-provider";
import BaseButton from "../base/BaseButton";
import { SmartWalletAdditionalActions } from "./SmartWalletAdditionalActions";
import Text from "../base/Text";
import { useAppTheme } from "../../styles/hooks";
import { LocalWalletImportModal } from "../ConnectWalletFlow/LocalWalletImportModal";
import { IconTextButton } from "../base/IconTextButton";
import MoneyIcon from "../../assets/money";
import { TWModal } from "../base/modal/TWModal";
import { ThemeProvider } from "../../styles/ThemeProvider";
import TransactionIcon from "../../assets/transaction";
import { ReceiveButton } from "../ReceiveButton";
import { SendButton } from "../SendFunds/SendButton";
import { SupportedTokens } from "../SendFunds/defaultTokens";
import { ActiveDot } from "../base";
import { EmbeddedWallet } from "../../wallets/wallets/embedded/EmbeddedWallet";
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
const DEVICE_WIDTH = Dimensions.get("window").width;
@@ -33,14 +39,17 @@ export const ConnectWalletDetailsModal = ({
extraRows,
address,
hideTestnetFaucet,
supportedTokens,
displayBalanceToken,
}: {
isVisible: boolean;
onClosePress: () => void;
extraRows?: React.FC;
address?: string;
hideTestnetFaucet?: boolean;
supportedTokens: SupportedTokens;
displayBalanceToken?: Record<number, string>;
}) => {
const theme = useAppTheme();
const [isExportModalVisible, setIsExportModalVisible] = useState(false);
const activeWallet = useWallet();
const chain = useChain();
@@ -50,6 +59,24 @@ export const ConnectWalletDetailsModal = ({
const [isImportModalVisible, setIsImportModalVisible] = useState(false);
const setConnectedWallet = useSetConnectedWallet();
const tokenAddress =
chain?.chainId && displayBalanceToken
? displayBalanceToken[chain?.chainId]
: undefined;
const [isSmartWalletDeployed, setIsSmartWalletDeployed] = useState(false);
useEffect(() => {
if (activeWallet && activeWallet.walletId === walletIds.smartWallet) {
const connectedSmartWallet = activeWallet as SmartWallet;
connectedSmartWallet.isDeployed().then((isDeployed) => {
setIsSmartWalletDeployed(isDeployed);
});
} else {
setIsSmartWalletDeployed(false);
}
}, [activeWallet]);
useEffect(() => {
const timeout = setTimeout(() => {
if (addressCopied) {
@@ -126,11 +153,7 @@ export const ConnectWalletDetailsModal = ({
<Text variant="bodySmall">Backup wallet</Text>
</View>
</>
<RightArrowIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
<RightArrowIcon height={10} width={10} />
</BaseButton>
<BaseButton
@@ -147,11 +170,7 @@ export const ConnectWalletDetailsModal = ({
<Text variant="bodySmall">Import wallet</Text>
</View>
</>
<RightArrowIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
<RightArrowIcon height={10} width={10} />
</BaseButton>
<LocalWalletImportModal
@@ -161,7 +180,7 @@ export const ConnectWalletDetailsModal = ({
/>
{activeWallet?.walletId === LocalWallet.id ? (
<Text variant="error" textAlign="left">
<Text variant="error" textAlign="left" mb="sm">
{
"This is a temporary guest wallet. Download a backup if you don't want to lose access to it."
}
@@ -178,48 +197,96 @@ export const ConnectWalletDetailsModal = ({
onExportLocalWalletPress,
onWalletImported,
smartWallet,
theme.colors.iconPrimary,
]);
return (
<TWModal isVisible={isVisible} onBackdropPress={onClosePress}>
<View
style={[styles.modal, { backgroundColor: theme.colors.background }]}
>
<Box style={styles.contentContainer}>
<ExportLocalWalletModal
isVisible={isExportModalVisible}
onClose={onExportModalClose}
/>
<WalletDetailsModalHeader
address={address}
onDisconnectPress={onDisconnectPress}
onAddressCopied={onAddressCopied}
/>
<View style={styles.currentNetwork}>
<Text variant="bodySmallSecondary">Current Network</Text>
</View>
<NetworkButton chain={chain} enableSwitchModal={true} />
{!hideTestnetFaucet && chain?.testnet && chain?.faucets?.length ? (
<IconTextButton
mt="xs"
text="Request Testnet Funds"
icon={<MoneyIcon height={10} width={10} />}
onPress={() => {
if (chain?.faucets?.[0]) {
Linking.openURL(chain.faucets[0]);
}
}}
<ThemeProvider>
<TWModal isVisible={isVisible} onBackdropPress={onClosePress}>
<Box backgroundColor="background" style={styles.modal}>
<Box style={styles.contentContainer}>
<ExportLocalWalletModal
isVisible={isExportModalVisible}
onClose={onExportModalClose}
/>
) : null}
{getAdditionalActions()}
{extraRows ? extraRows({}) : null}
{addressCopied === true ? (
<Toast text={"Address copied to clipboard"} />
) : null}
<WalletDetailsModalHeader
tokenAddress={tokenAddress}
address={address}
onDisconnectPress={onDisconnectPress}
onAddressCopied={onAddressCopied}
/>
{activeWallet?.walletId === SmartWallet.id ? (
<BaseButton
disabled={!isSmartWalletDeployed}
onPress={() => {
Linking.openURL(
`https://thirdweb.com/${chain?.slug}/${address}/account`,
);
}}
flexDirection="row"
alignItems="center"
justifyContent="space-between"
mt="md"
>
<Box flexDirection="row" alignItems="center">
<ActiveDot width={10} height={10} />
<Text variant="bodySmallSecondary" ml="xxs">
Connected to a Smart Wallet
</Text>
</Box>
{isSmartWalletDeployed ? (
<RightArrowIcon width={10} height={10} />
) : null}
</BaseButton>
) : null}
{activeWallet?.walletId === EmbeddedWallet.id ? (
<Box flexDirection="row" alignItems="center" mt="md">
<ActiveDot width={10} height={10} />
<Text variant="bodySmallSecondary" ml="xxs">
{(activeWallet as EmbeddedWallet).getEmail()}
</Text>
</Box>
) : null}
<Box flexDirection="row" justifyContent="space-evenly" mt="md">
<SendButton supportedTokens={supportedTokens} />
<ReceiveButton />
</Box>
<View style={styles.currentNetwork}>
<Text variant="bodySmallSecondary">Current Network</Text>
</View>
<NetworkButton chain={chain} enableSwitchModal={true} />
{!hideTestnetFaucet && chain?.testnet && chain?.faucets?.length ? (
<IconTextButton
mt="xs"
text="Request Testnet Funds"
icon={<MoneyIcon height={16} width={16} />}
onPress={() => {
if (chain?.faucets?.[0]) {
Linking.openURL(chain.faucets[0]);
}
}}
/>
) : null}
{chain?.explorers && chain?.explorers?.[0] && (
<IconTextButton
mt="xs"
text="View Transaction History"
icon={<TransactionIcon height={16} width={16} />}
onPress={() => {
Linking.openURL(
chain?.explorers?.[0].url + "/address/" + address,
);
}}
/>
)}
{getAdditionalActions()}
{extraRows ? extraRows({}) : null}
{addressCopied === true ? (
<Toast text={"Address copied to clipboard"} />
) : null}
</Box>
</Box>
</View>
</TWModal>
</TWModal>
</ThemeProvider>
);
};
@@ -16,7 +16,6 @@ import * as FileSystem from "expo-file-system";
import { SmartWallet } from "@thirdweb-dev/wallets";
import { usePersonalWalletAddress } from "../../wallets/hooks/usePersonalWalletAddress";
import { shortenWalletAddress } from "../../utils/addresses";
import { WalletIcon } from "../base/WalletIcon";
import { LocalWallet } from "../../wallets/wallets/LocalWallet";
import { TWModal } from "../base/modal/TWModal";
@@ -150,13 +149,10 @@ export const ExportLocalWalletModal = ({
borderRadius="md"
p="lg"
>
<Box flexDirection="row" justifyContent="space-between" mb="sm">
<WalletIcon size={32} iconUri={LocalWallet.meta.iconURL} />
<ModalHeaderTextClose flex={1} onClose={onCloseInternal} />
</Box>
<Text variant="header" textAlign="left">
Backup your Wallet
</Text>
<ModalHeaderTextClose
onClose={onCloseInternal}
headerText="Backup your Wallet"
/>
<Text variant="subHeader" mt="md" textAlign="left">
{
"This will download a JSON file containing your wallet information onto your device encrypted with the password."
@@ -1,28 +1,26 @@
import { StyleSheet, View } from "react-native";
import PocketWalletIcon from "../../assets/wallet";
import BaseButton from "../base/BaseButton";
import { WalletIcon } from "../base/WalletIcon";
import {
AbstractClientWallet,
SmartWallet,
walletIds,
} from "@thirdweb-dev/wallets";
import { AddressDisplay } from "../base/AddressDisplay";
import Text from "../base/Text";
import { usePersonalWalletAddress } from "../../wallets/hooks/usePersonalWalletAddress";
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";
import DisconnectIcon from "../../assets/disconnect";
import { IconTextButton } from "../base/IconTextButton";
export const SmartWalletAdditionalActions = ({
onExportPress,
}: {
onExportPress: () => void;
}) => {
const personalWalletAddress = usePersonalWalletAddress();
const { setConnectedWallet } = useWalletContext();
const [smartWallet, setSmartWallet] = useSmartWallet();
const [smartWalletAddress, setSmartWalletAddress] = useState<string>("");
@@ -62,38 +60,22 @@ export const SmartWalletAdditionalActions = ({
return (
<>
<View style={styles.currentNetwork}>
<Text variant="bodySmallSecondary">
{showSmartWallet ? "Smart Wallet" : "Personal Wallet"}
</Text>
</View>
<BaseButton
backgroundColor="background"
borderColor="border"
justifyContent="space-between"
mb="md"
style={styles.walletDetails}
<IconTextButton
mt="xs"
text={
showSmartWallet
? "Switch to Smart Wallet"
: "Switch to Personal Wallet"
}
icon={
<DisconnectIcon
width={14}
height={14}
color={theme.colors.iconPrimary}
/>
}
onPress={onWalletPress}
>
<>
{wallet?.getMeta().iconURL ? (
<WalletIcon size={32} iconUri={wallet?.getMeta().iconURL || ""} />
) : null}
<View style={styles.walletInfo}>
<AddressDisplay
variant="bodyLarge"
address={
showSmartWallet ? smartWalletAddress : personalWalletAddress
}
/>
</View>
</>
<RightArrowIcon
height={10}
width={10}
color={theme.colors.iconPrimary}
/>
</BaseButton>
/>
{!showSmartWallet && smartWallet?.enableConnectApp ? (
<ConnectAppField />
) : null}
@@ -104,6 +86,7 @@ export const SmartWalletAdditionalActions = ({
backgroundColor="background"
borderColor="border"
mb="sm"
mt="xs"
justifyContent="space-between"
style={styles.exportWallet}
onPress={onExportPress}
@@ -124,7 +107,7 @@ export const SmartWalletAdditionalActions = ({
color={theme.colors.iconPrimary}
/>
</BaseButton>
<Text variant="error" textAlign="left">
<Text variant="error" textAlign="left" mb="sm">
{
"This is a temporary guest wallet. Download a backup if you don't want to loose access to it."
}
@@ -1,21 +1,40 @@
import { AddressDisplay } from "../base/AddressDisplay";
import BaseButton from "../base/BaseButton";
import { ChainIcon } from "../base/ChainIcon";
import Text from "../base/Text";
import { WalletIcon } from "../base/WalletIcon";
import { useWallet, useChain } from "@thirdweb-dev/react-core";
import { StyleSheet, View } from "react-native";
import { LocalWallet } from "@thirdweb-dev/wallets";
import { useENS, useWallet } from "@thirdweb-dev/react-core";
import { StyleSheet } from "react-native";
import { LocalWallet, walletIds } from "@thirdweb-dev/wallets";
import Box from "../base/Box";
import { ConnectWalletDetailsModal } from "./ConnectWalletDetailsModal";
import { useState } from "react";
import { useMemo, useState } from "react";
import { TextBalance } from "../base/TextBalance";
import { SupportedTokens } from "../SendFunds/defaultTokens";
import { SMART_WALLET_ICON } from "../../assets/svgs";
export type ConnectWalletDetailsProps = {
address?: string;
detailsButton?: React.FC<{ onPress: () => void }>;
extraRows?: React.FC;
hideTestnetFaucet?: boolean;
/**
* Override the default supported tokens for each network
*
* These tokens will be displayed in "Send Funds" Modal
*/
supportedTokens: SupportedTokens;
/**
* Show balance of ERC20 token instead of the native token in the "Connected" button when connected to certain network
*
* @example
* ```tsx
* <ConnectWallet balanceToken={{
* 1: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599" // show USDC balance when connected to Ethereum mainnet
* }} />
* ```
*/
displayBalanceToken?: Record<number, string>;
};
export const WalletDetailsButton = ({
@@ -23,24 +42,28 @@ export const WalletDetailsButton = ({
detailsButton,
extraRows,
hideTestnetFaucet,
supportedTokens,
displayBalanceToken,
}: ConnectWalletDetailsProps) => {
const activeWallet = useWallet();
const chain = useChain();
const [isModalVisible, setIsModalVisible] = useState(false);
const ensQuery = useENS();
const onPress = () => {
// setModalState({
// view: "WalletDetails",
// data: {
// address: address,
// },
// isOpen: true,
// isSheet: true,
// caller: "ConnectWalletDetails",
// });
setIsModalVisible(!isModalVisible);
};
const ens = useMemo(() => ensQuery.data?.ens, [ensQuery.data?.ens]);
const avatarUrl = useMemo(
() => ensQuery.data?.avatarUrl,
[ensQuery.data?.avatarUrl],
);
const walletIconUrl =
activeWallet?.walletId === walletIds.smartWallet
? SMART_WALLET_ICON
: activeWallet?.getMeta().iconURL || "";
return (
<>
<ConnectWalletDetailsModal
@@ -49,6 +72,8 @@ export const WalletDetailsButton = ({
extraRows={extraRows}
address={address}
hideTestnetFaucet={hideTestnetFaucet}
supportedTokens={supportedTokens}
displayBalanceToken={displayBalanceToken}
/>
{detailsButton ? (
detailsButton({ onPress })
@@ -59,28 +84,29 @@ export const WalletDetailsButton = ({
style={styles.walletDetails}
onPress={onPress}
>
<Box flex={1} flexDirection="row" justifyContent="space-between">
<View>
<ChainIcon size={32} chainIconUrl={chain?.icon?.url} />
</View>
<Box justifyContent="center" alignItems="flex-start">
<TextBalance textVariant="bodySmall" />
<Box
flex={1}
flexDirection="row"
alignContent="center"
justifyContent="flex-start"
>
<WalletIcon size={32} iconUri={avatarUrl || walletIconUrl} />
<Box ml="md" justifyContent="center" alignItems="flex-start">
{activeWallet?.walletId === LocalWallet.id ? (
<Text variant="error">Guest</Text>
<Text variant="bodySmall" color="red">
Guest
</Text>
) : ens ? (
<Text variant="bodySmall">{ens}</Text>
) : (
<AddressDisplay
variant="bodySmallSecondary"
variant="bodySmall"
extraShort={false}
address={address}
/>
)}
<TextBalance textVariant="bodySmallSecondary" />
</Box>
<View>
<WalletIcon
size={32}
iconUri={activeWallet?.getMeta().iconURL || ""}
/>
</View>
</Box>
</BaseButton>
)}
@@ -3,29 +3,35 @@ import { useAppTheme } from "../../styles/hooks";
import { AddressDisplay } from "../base/AddressDisplay";
import BaseButton from "../base/BaseButton";
import { WalletIcon } from "../base/WalletIcon";
import { useWallet } from "@thirdweb-dev/react-core";
import { useENS, useWallet } from "@thirdweb-dev/react-core";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import * as Clipboard from "expo-clipboard";
import Box from "../base/Box";
import CopyIcon from "../../assets/copy";
import { useState } from "react";
import { useMemo, useState } from "react";
import { TextBalance } from "../base/TextBalance";
import { walletIds } from "@thirdweb-dev/wallets";
import { SMART_WALLET_ICON } from "../../assets/svgs";
import Text from "../base/Text";
interface WalletDetailsModalHeaderProps {
address?: string;
onDisconnectPress: () => void;
onAddressCopied?: () => void;
loading?: boolean;
tokenAddress?: string;
}
export const WalletDetailsModalHeader = ({
address,
onDisconnectPress,
onAddressCopied,
tokenAddress,
}: WalletDetailsModalHeaderProps) => {
const theme = useAppTheme();
const activeWallet = useWallet();
const [showLoading, setShowLoading] = useState(false);
const ensQuery = useENS();
const onAddressPress = async () => {
if (!address) {
@@ -42,10 +48,21 @@ export const WalletDetailsModalHeader = ({
}, 0);
};
const ens = useMemo(() => ensQuery.data?.ens, [ensQuery.data?.ens]);
const avatarUrl = useMemo(
() => ensQuery.data?.avatarUrl,
[ensQuery.data?.avatarUrl],
);
const walletIconUrl =
activeWallet?.walletId === walletIds.smartWallet
? SMART_WALLET_ICON
: activeWallet?.getMeta().iconURL || "";
return (
<>
<View style={styles.header}>
<WalletIcon size={40} iconUri={activeWallet?.getMeta().iconURL || ""} />
<WalletIcon size={40} iconUri={avatarUrl || walletIconUrl} />
<BaseButton
flex={1}
justifyContent="flex-start"
@@ -59,14 +76,23 @@ export const WalletDetailsModalHeader = ({
justifyContent="center"
alignItems="center"
>
<AddressDisplay mr="xs" address={address} extraShort={false} />
{ens ? (
<Text mr="xs" variant="bodyLarge">
{ens}
</Text>
) : (
<AddressDisplay mr="xs" address={address} extraShort={false} />
)}
<CopyIcon
width={14}
height={14}
color={theme.colors.textSecondary}
/>
</Box>
<TextBalance textVariant="bodySmallSecondary" />
<TextBalance
textVariant="bodySmallSecondary"
tokenAddress={tokenAddress}
/>
</BaseButton>
{showLoading ? (
<ActivityIndicator size="small" color={theme.colors.iconHighlight} />
@@ -1,11 +1,15 @@
import { walletIds } from "@thirdweb-dev/wallets";
import { localWallet } from "../../../wallets/wallets/local-wallet";
import { ModalFooter } from "../../base/modal/ModalFooter";
import { ModalHeaderTextClose } from "../../base/modal/ModalHeaderTextClose";
import { ChooseWalletContent } from "./ChooseWalletContent";
import { WalletConfig } from "@thirdweb-dev/react-core";
import { ReactNode, useState } from "react";
import { View } from "react-native";
import Box from "../../base/Box";
import Text from "../../base/Text";
import ThirdwebLogo from "../../../assets/thirdweb-logo";
import { useAppTheme } from "../../../styles/hooks";
import { ChooseWalletContent } from "./ChooseWalletContent";
import { BaseButton, ImageSvgUri, WalletButton } from "../../base";
import { ActivityIndicator, Linking } from "react-native";
import { useTheme } from "@shopify/restyle";
export type ChooseWalletProps = {
headerText?: ReactNode | string;
@@ -14,7 +18,9 @@ export type ChooseWalletProps = {
onClose: () => void;
wallets: WalletConfig<any>[];
excludeWalletIds?: string[];
showGuestWalletAsButton?: boolean;
modalTitleIconUrl?: string;
termsOfServiceUrl?: string;
privacyPolicyUrl?: string;
};
export function ChooseWallet({
@@ -22,42 +28,294 @@ export function ChooseWallet({
subHeaderText,
wallets,
onChooseWallet,
modalTitleIconUrl,
onClose,
excludeWalletIds = [],
showGuestWalletAsButton = false,
termsOfServiceUrl,
privacyPolicyUrl,
}: ChooseWalletProps) {
const theme = useAppTheme();
const themeLightDark = useTheme();
const [isConnecting, setIsConnecting] = useState(false);
const [isConnectAWalletEnabled, setIsConnectAWalletEnabled] = useState(false);
const guestWallet = wallets.find((w) => w.id === walletIds.localWallet);
const emailWallet = wallets.find(
(w) => w.id === walletIds.magicLink || w.id === walletIds.embeddedWallet,
);
const connectionWallets = wallets
.filter(
(wallet) =>
wallet.id !== walletIds.magicLink &&
wallet.id !== walletIds.embeddedWallet &&
wallet.id !== walletIds.localWallet,
)
.slice(0, 2);
const showToSPrivacyPolicy = termsOfServiceUrl || privacyPolicyUrl;
const onContinueAsGuestPress = () => {
setIsConnecting(true);
onChooseWallet(localWallet());
setTimeout(() => {
if (guestWallet) {
onChooseWallet(guestWallet);
}
}, 0);
};
const onConnectAWalletPress = () => {
setIsConnectAWalletEnabled(true);
};
const onSingleWalletPress = () => {
onChooseWallet(connectionWallets[0]);
};
const onBackPress = () => {
setIsConnectAWalletEnabled(false);
};
const onGetStartedPress = () => {
Linking.openURL("https://ethereum.org/en/wallets/find-wallet/");
};
const onToSPressed = () => {
if (termsOfServiceUrl) {
Linking.openURL(termsOfServiceUrl);
}
};
const onPrivacyPolicyPress = () => {
if (privacyPolicyUrl) {
Linking.openURL(privacyPolicyUrl);
}
};
return (
<View>
<Box flexDirection="column">
<ModalHeaderTextClose
paddingHorizontal="xl"
onBackPress={isConnectAWalletEnabled ? onBackPress : undefined}
onClose={onClose}
headerText={headerText ? headerText : "Choose your wallet"}
headerText={
headerText ? (
headerText
) : (
<Box
flexDirection="row"
alignItems="center"
alignContent="center"
justifyContent="center"
>
{modalTitleIconUrl !== undefined ? (
modalTitleIconUrl.length === 0 ? null : (
<ImageSvgUri
width={26}
height={15}
imageUrl={modalTitleIconUrl}
/>
)
) : (
<ThirdwebLogo
width={26}
height={15}
color={theme.colors.backgroundInverted}
/>
)}
<Text
variant="header"
ml="xxs"
fontWeight="700"
fontSize={20}
lineHeight={24}
>
Connect
</Text>
</Box>
)
}
subHeaderText={subHeaderText}
/>
<ChooseWalletContent
wallets={wallets}
excludeWalletIds={
showGuestWalletAsButton
? excludeWalletIds
: [...excludeWalletIds, walletIds.localWallet]
}
onChooseWallet={onChooseWallet}
/>
{guestWallet && !showGuestWalletAsButton ? (
<ModalFooter
footer={"Continue as Guest"}
isLoading={isConnecting}
onPress={onContinueAsGuestPress}
{!emailWallet || isConnectAWalletEnabled ? (
<>
<ChooseWalletContent
wallets={wallets}
excludeWalletIds={[
...excludeWalletIds,
walletIds.localWallet,
walletIds.magicLink,
walletIds.embeddedWallet,
]}
onChooseWallet={onChooseWallet}
/>
<Box
pt="md"
flexGrow={0}
borderTopColor="border"
borderTopWidth={1}
paddingHorizontal="xl"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
>
<Text variant="bodySmall">New to wallets?</Text>
<BaseButton onPress={onGetStartedPress}>
<Text variant="link">Get started</Text>
</BaseButton>
</Box>
</>
) : emailWallet.selectUI ? (
<emailWallet.selectUI
modalSize="compact"
theme={themeLightDark}
supportedWallets={wallets}
onSelect={(data: any) => {
onChooseWallet(emailWallet, data);
}}
walletConfig={emailWallet}
/>
) : null}
</View>
{emailWallet &&
!isConnectAWalletEnabled &&
(guestWallet || connectionWallets.length > 0) ? (
<Box
mb="md"
mt="md"
marginHorizontal="xl"
flexDirection="row"
justifyContent="center"
alignItems="center"
>
<Box height={1} flex={1} backgroundColor="border" />
<Text variant="subHeader" textAlign="center" marginHorizontal="xxs">
OR
</Text>
<Box height={1} flex={1} backgroundColor="border" />
</Box>
) : null}
{emailWallet &&
!isConnectAWalletEnabled &&
connectionWallets.length > 0 ? (
connectionWallets.length === 1 ? (
<WalletButton
marginHorizontal="xl"
paddingHorizontal="none"
paddingVertical="none"
mb="md"
walletIconUrl={connectionWallets[0].meta.iconURL}
name={connectionWallets[0].meta.name}
onPress={onSingleWalletPress}
/>
) : (
<BaseButton
marginHorizontal="xl"
justifyContent="center"
borderRadius="lg"
paddingVertical="md"
borderColor="border"
flexDirection="row"
alignItems="center"
borderWidth={1}
onPress={onConnectAWalletPress}
>
{connectionWallets.map((wallet) => {
return (
<Box key={wallet.meta.name} mr="xxs">
<ImageSvgUri
height={20}
width={20}
imageUrl={wallet.meta.iconURL}
/>
</Box>
);
})}
<Text variant="bodySmall" fontWeight="700">
Connect a wallet
</Text>
</BaseButton>
)
) : null}
{guestWallet ? (
<BaseButton
marginHorizontal="xl"
mt="sm"
paddingVertical="md"
justifyContent="center"
borderRadius="lg"
borderColor="border"
borderWidth={1}
onPress={onContinueAsGuestPress}
>
{isConnecting ? (
<ActivityIndicator
size={"small"}
color={theme.colors.textPrimary}
/>
) : (
<Text variant="bodySmall" fontWeight="700">
Continue as guest
</Text>
)}
</BaseButton>
) : null}
{showToSPrivacyPolicy ? (
<Box
mt="md"
pt="md"
height={50}
marginHorizontal={!isConnectAWalletEnabled ? "xl" : "none"}
alignItems="center"
>
<Text variant="bodySmallSecondary" fontSize={10} lineHeight={14}>
By connecting, you agree to the
</Text>
<Box flexDirection="row" alignItems="center" justifyContent="center">
{termsOfServiceUrl ? (
<BaseButton
onPress={onToSPressed}
flexDirection="row"
padding="none"
>
<Text
variant="link"
fontSize={10}
padding="none"
lineHeight={14}
>
Terms of Service
</Text>
</BaseButton>
) : null}
{termsOfServiceUrl && privacyPolicyUrl ? (
<Text
variant="bodySmallSecondary"
fontSize={10}
padding="none"
lineHeight={14}
>
{" & "}
</Text>
) : null}
{privacyPolicyUrl ? (
<BaseButton
onPress={onPrivacyPolicyPress}
flexDirection="row"
padding="none"
>
<Text
variant="link"
fontSize={10}
padding="none"
lineHeight={14}
>
Privacy Policy
</Text>
</BaseButton>
) : null}
</Box>
</Box>
) : null}
</Box>
);
}
@@ -1,6 +1,6 @@
import { useMemo } from "react";
import type { WalletConfig } from "@thirdweb-dev/react-core";
import { StyleSheet, View, FlatList } from "react-native";
import { Dimensions, ScrollView, View } from "react-native";
import { WalletButton } from "../../base/WalletButton";
import Box from "../../base/Box";
import { useTheme } from "@shopify/restyle";
@@ -11,29 +11,45 @@ interface ChooseWalletContentProps {
onChooseWallet: (wallet: WalletConfig, data?: any) => void;
}
const MAX_HEIGHT = Dimensions.get("window").height * 0.3;
export const ChooseWalletContent = ({
wallets,
excludeWalletIds,
onChooseWallet,
}: ChooseWalletContentProps) => {
const walletsToDisplay = useMemo(() => {
return wallets.filter(
(w) => !!!excludeWalletIds?.find((ewId) => ewId === w.id),
);
}, [wallets, excludeWalletIds]);
const theme = useTheme();
const walletsToDisplay = useMemo(() => {
const filteredWallets = wallets.filter(
(w) => !!!excludeWalletIds?.find((ewId) => ewId === w.id),
);
const trueItems = filteredWallets.filter(
(item) => item.recommended === true,
);
const falseItems = filteredWallets.filter(
(item) => item.recommended !== true,
);
const sortedWallets = [...trueItems, ...falseItems];
return sortedWallets;
}, [wallets, excludeWalletIds]);
return (
<View style={styles.explorerContainer}>
<FlatList
keyExtractor={(item) => item.meta.name}
data={walletsToDisplay}
renderItem={({ item, index }) => {
<View style={{ flexDirection: "column", maxHeight: MAX_HEIGHT }}>
<ScrollView
style={{
marginTop: 16,
paddingBottom: 16,
paddingHorizontal: 16,
}}
>
{walletsToDisplay.map((item, index) => {
const marginBottom =
index === walletsToDisplay.length - 1 ? "none" : "xxs";
return (
<>
<Box key={item.id}>
{item.selectUI ? (
<Box
mb={marginBottom}
@@ -43,6 +59,7 @@ export const ChooseWalletContent = ({
borderRadius="sm"
>
<item.selectUI
modalSize="compact"
theme={theme}
supportedWallets={wallets}
onSelect={(data) => {
@@ -55,26 +72,16 @@ export const ChooseWalletContent = ({
<WalletButton
walletIconUrl={item.meta.iconURL}
name={item.meta.name}
recommended={item.recommended}
onPress={() => onChooseWallet(item)}
mb={marginBottom}
paddingVertical="xxs"
/>
)}
</>
</Box>
);
}}
/>
})}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
explorerContainer: {
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 4,
marginTop: 25,
},
});
@@ -0,0 +1,93 @@
import { useMemo } from "react";
import type { WalletConfig } from "@thirdweb-dev/react-core";
import { FlatList, Dimensions } from "react-native";
import Box from "../../base/Box";
import { useTheme } from "@shopify/restyle";
import { WalletButtonSquare } from "../../base/WalletButtonSquare";
import Text from "../../base/Text";
const SCREEN_WIDTH = Dimensions.get("screen").width;
const SCREEN_HEIGHT = Dimensions.get("screen").height;
const MAX_HEIGHT = SCREEN_HEIGHT * 0.4;
const NUM_COLUMNS = 3;
const TILE_SIZE = SCREEN_WIDTH / NUM_COLUMNS;
interface ChooseWalletContentProps {
wallets: WalletConfig[];
excludeWalletIds?: string[];
onChooseWallet: (wallet: WalletConfig, data?: any) => void;
}
export const ChooseWalletContentSquare = ({
wallets,
excludeWalletIds,
onChooseWallet,
}: ChooseWalletContentProps) => {
const walletsToDisplay = useMemo(() => {
return wallets.filter(
(w) => !!!excludeWalletIds?.find((ewId) => ewId === w.id),
);
}, [wallets, excludeWalletIds]);
const theme = useTheme();
return (
<Box marginTop="sm" flexDirection="column">
{walletsToDisplay.map((wallet) => {
if (!wallet.selectUI) {
return null;
}
return (
<Box
key={wallet.id}
flexDirection="row"
justifyContent="space-between"
alignItems="center"
borderRadius="sm"
>
<wallet.selectUI
modalSize="compact"
theme={theme}
supportedWallets={wallets}
onSelect={(data) => {
onChooseWallet(wallet, data);
}}
walletConfig={wallet}
/>
</Box>
);
})}
<FlatList
keyExtractor={(item) => item.meta.name}
data={walletsToDisplay}
numColumns={NUM_COLUMNS}
style={{ maxHeight: MAX_HEIGHT }}
fadingEdgeLength={10}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => {
return !item.selectUI ? (
<WalletButtonSquare
walletIconUrl={item.meta.iconURL}
name={item.meta.name}
size={TILE_SIZE}
onPress={() => onChooseWallet(item)}
/>
) : null;
}}
/>
<Box
height={60}
borderTopColor="border"
borderTopWidth={1}
borderBottomColor="border"
borderBottomWidth={1}
flexDirection="row"
justifyContent="space-between"
alignItems="center"
>
<Text variant="bodySmall">New to wallets?</Text>
<Text variant="link">Get started</Text>
</Box>
</Box>
);
};
@@ -4,6 +4,7 @@ import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core";
import { useState, useEffect } from "react";
import { useModalState } from "../../providers/ui-context-provider";
import { ThemeProvider, ThemeProviderProps } from "../../styles/ThemeProvider";
import { useAppTheme } from "../../styles/hooks";
export type ConnectWalletButtonProps = {
theme?: ThemeProviderProps["theme"];
@@ -17,13 +18,32 @@ export type ConnectWalletButtonProps = {
* @default "Choose your wallet"
*/
modalTitle?: string;
/**
* Replace the thirdweb icon next to modalTitle and set your own iconUrl
*
* Set to empty string to hide the icon
*/
modalTitleIconUrl?: string;
/**
* Set a custom terms of service url
*/
termsOfServiceUrl?: string;
/**
* Set a custom privacy policy url
*/
privacyPolicyUrl?: string;
};
export const ConnectWalletButton = ({
modalTitle,
modalTitleIconUrl,
termsOfServiceUrl,
privacyPolicyUrl,
buttonTitle,
theme,
}: ConnectWalletButtonProps) => {
const appTheme = useAppTheme();
const connectionStatus = useConnectionStatus();
const isWalletConnecting = connectionStatus === "connecting";
@@ -59,6 +79,9 @@ export const ConnectWalletButton = ({
view: "ConnectWalletFlow",
data: {
modalTitle,
modalTitleIconUrl,
termsOfServiceUrl,
privacyPolicyUrl,
walletConfig:
supportedWallets.length === 1 ? supportedWallets[0] : undefined,
},
@@ -67,7 +90,7 @@ export const ConnectWalletButton = ({
};
return (
<ThemeProvider theme={theme}>
<ThemeProvider theme={theme ? theme : appTheme}>
<BaseButton
backgroundColor="buttonBackgroundColor"
onPress={onConnectWalletPress}
@@ -3,19 +3,26 @@ import { ChooseWallet } from "./ChooseWallet/ChooseWallet";
import { ConnectingWallet } from "./ConnectingWallet/ConnectingWallet";
import { WalletConfig, useConnect, useWallets } from "@thirdweb-dev/react-core";
import { useCallback, useEffect, useState } from "react";
import { SmartWallet, walletIds } from "@thirdweb-dev/wallets";
import { SmartWalletFlow } from "./SmartWallet/SmartWalletFlow";
import { walletIds } from "@thirdweb-dev/wallets";
import { useColorScheme } from "react-native";
import { useModalState } from "../../providers/ui-context-provider";
import {
CLOSE_MODAL_STATE,
ConnectWalletFlowModal,
} from "../../utils/modalTypes";
import Box from "../base/Box";
import { ThemeProvider } from "../../styles/ThemeProvider";
import { useAppTheme } from "../../styles/hooks";
export const ConnectWalletFlow = () => {
const { modalState, setModalState } = useModalState();
const { modalTitle, walletConfig } = (modalState as ConnectWalletFlowModal)
.data;
const {
modalTitle,
modalTitleIconUrl,
privacyPolicyUrl,
termsOfServiceUrl,
walletConfig,
} = (modalState as ConnectWalletFlowModal).data;
const [modalVisible, setModalVisible] = useState(false);
const [activeWallet, setActiveWallet] = useState<WalletConfig | undefined>();
@@ -23,6 +30,7 @@ export const ConnectWalletFlow = () => {
const [selectionData, setSelectionData] = useState<any>();
const supportedWallets = useWallets();
const theme = useColorScheme();
const appTheme = useAppTheme();
const connect = useConnect();
const onClose = useCallback(
@@ -52,13 +60,11 @@ export const ConnectWalletFlow = () => {
const onChooseWallet = useCallback(
(wallet: WalletConfig, data?: any) => {
setActiveWallet(() => wallet);
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) {
if (!wallet.connectUI) {
connectActiveWallet(wallet, data);
}
},
@@ -68,7 +74,13 @@ export const ConnectWalletFlow = () => {
useEffect(() => {
// case when only one wallet is passed in supportedWallets
if (walletConfig) {
onChooseWallet(walletConfig);
if (walletConfig.connectUI) {
// if there's a connection UI, then show it
setActiveWallet(walletConfig);
} else {
// if there's no connection UI, then connect the wallet
onChooseWallet(walletConfig);
}
}
}, [onChooseWallet, walletConfig]);
@@ -80,10 +92,6 @@ export const ConnectWalletFlow = () => {
resetModal();
}, []);
const onConnected = useCallback(() => {
onClose(true);
}, [onClose]);
const resetModal = () => {
setActiveWallet(undefined);
setIsConnecting(false);
@@ -94,14 +102,10 @@ export const ConnectWalletFlow = () => {
}, [onClose]);
const getComponentForWallet = useCallback(() => {
switch (activeWallet?.id) {
case SmartWallet.id:
return <SmartWalletFlow onClose={onClose} onConnect={onConnected} />;
}
if (activeWallet?.connectUI) {
return (
<activeWallet.connectUI
modalSize="compact"
theme={theme || "dark"}
goBack={onBackPress}
close={handleClose}
@@ -119,40 +123,44 @@ export const ConnectWalletFlow = () => {
handleClose,
modalVisible,
onBackPress,
onClose,
onConnected,
selectionData,
supportedWallets,
theme,
]);
return (
<>
{activeWallet ? (
isConnecting ? (
<ConnectingWallet
content={
activeWallet.id === walletIds.localWallet ? (
<Text variant="bodySmallSecondary" mt="md">
Creating, encrypting and securing your device wallet.
</Text>
) : undefined
}
wallet={activeWallet}
onClose={onClose}
onBackPress={onBackPress}
/>
<ThemeProvider theme={appTheme}>
<Box flexDirection="column">
{activeWallet ? (
isConnecting ? (
<ConnectingWallet
subHeaderText=""
content={
activeWallet.id === walletIds.localWallet ? (
<Text variant="bodySmallSecondary" mt="md" textAlign="center">
Creating, encrypting and securing your device wallet.
</Text>
) : undefined
}
wallet={activeWallet}
onClose={onClose}
onBackPress={onBackPress}
/>
) : (
getComponentForWallet()
)
) : (
getComponentForWallet()
)
) : (
<ChooseWallet
headerText={modalTitle}
wallets={supportedWallets}
onChooseWallet={onChooseWallet}
onClose={onClose}
/>
)}
</>
<ChooseWallet
headerText={modalTitle}
modalTitleIconUrl={modalTitleIconUrl}
privacyPolicyUrl={privacyPolicyUrl}
termsOfServiceUrl={termsOfServiceUrl}
wallets={supportedWallets}
onChooseWallet={onChooseWallet}
onClose={onClose}
/>
)}
</Box>
</ThemeProvider>
);
};
@@ -1,10 +1,10 @@
import { useAppTheme } from "../../../styles/hooks";
import WalletLoadingThumbnail from "../../../wallets/wallets/wallet-connect/WalletLoadingThumbnail";
import { Box, ImageSvgUri } from "../../base";
import Text from "../../base/Text";
import { ModalFooter } from "../../base/modal/ModalFooter";
import { ConnectWalletHeader } from "./ConnectingWalletHeader";
import type { WalletConfig } from "@thirdweb-dev/react-core";
import { ReactNode } from "react";
import { ActivityIndicator, Linking, StyleSheet, View } from "react-native";
import { StyleSheet, View } from "react-native";
export type ConnectingWalletProps = {
subHeaderText?: string;
@@ -12,7 +12,7 @@ export type ConnectingWalletProps = {
content?: ReactNode;
onClose: () => void;
onBackPress: () => void;
wallet: WalletConfig;
wallet: WalletConfig<any>;
};
export function ConnectingWallet({
@@ -23,51 +23,43 @@ export function ConnectingWallet({
onClose,
onBackPress,
}: ConnectingWalletProps) {
const theme = useAppTheme();
const onFooterPress = () => {
Linking.openURL("https://support.thirdweb.com/");
};
return (
<View>
<Box paddingHorizontal="xl">
<ConnectWalletHeader
onBackPress={onBackPress}
walletLogoUrl={wallet.meta.iconURL}
subHeaderText={subHeaderText}
onClose={onClose}
/>
<WalletLoadingThumbnail imageSize={100}>
<ImageSvgUri height={80} width={80} imageUrl={wallet.meta.iconURL} />
</WalletLoadingThumbnail>
<View style={styles.connectingContainer}>
<ActivityIndicator size="small" color={theme.colors.linkPrimary} />
{content ? (
content
) : (
<Text variant="bodySmallSecondary" mt="md">
Connect your wallet through the {wallet.meta.name} application.
</Text>
<>
<Text variant="header" mt="lg">
Connecting your wallet
</Text>
<Text variant="bodySmallSecondary" mt="lg" textAlign="center">
{`Login and connect your wallet through the ${wallet.meta.name} pop-up`}
</Text>
</>
)}
</View>
{footer ? (
footer
) : (
<ModalFooter
footer={`Having troubles connecting to ${wallet.meta.name}?`}
onPress={onFooterPress}
/>
)}
</View>
{footer ? footer : null}
</Box>
);
}
const styles = StyleSheet.create({
connectingContainer: {
display: "flex",
flexDirection: "column",
flexWrap: "wrap",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
paddingHorizontal: 4,
marginBottom: 24,
marginTop: 18,
},
});
@@ -1,13 +1,12 @@
import { Icon } from "../../../assets/icon";
import { useAppTheme } from "../../../styles/hooks";
import ImageSvgUri from "../../base/ImageSvgUri";
import Text from "../../base/Text";
import { FlexAlignType, StyleSheet, View } from "react-native";
interface ConnectWalletHeaderProps {
onClose: () => void;
onBackPress?: () => void;
walletLogoUrl?: string;
middleContent?: React.ReactNode;
headerText?: string;
subHeaderText?: string;
alignHeader?: FlexAlignType;
@@ -17,7 +16,7 @@ export const ConnectWalletHeader = ({
headerText,
subHeaderText = "Connecting your wallet",
alignHeader = "center",
walletLogoUrl,
middleContent,
onClose,
onBackPress,
}: ConnectWalletHeaderProps) => {
@@ -36,9 +35,7 @@ export const ConnectWalletHeader = ({
) : (
<View />
)}
{walletLogoUrl ? (
<ImageSvgUri width={56} height={56} imageUrl={walletLogoUrl} />
) : null}
{middleContent ? middleContent : null}
<Icon
type="close"
width={14}
@@ -12,6 +12,7 @@ import {
} from "@thirdweb-dev/react-core";
import { LocalWalletImportModal } from "./LocalWalletImportModal";
import { LocalWallet } from "../../wallets/wallets/LocalWallet";
import Box from "../base/Box";
type LocalWalletFlowUIProps = ConnectUIProps<LocalWallet> & {
onConnected?: (wallet: WalletInstance) => void;
@@ -78,9 +79,19 @@ export function LocalWalletFlow({
</Text>
)}
</BaseButton>
<Text variant="subHeader" mt="lg">
-------- OR --------
</Text>
<Box
mt="lg"
marginHorizontal="xl"
flexDirection="row"
justifyContent="center"
alignItems="center"
>
<Box height={1} flex={1} backgroundColor="border" />
<Text variant="subHeader" textAlign="center">
OR
</Text>
<Box height={1} flex={1} backgroundColor="border" />
</Box>
<ModalFooter footer={"Import a wallet"} onPress={onImportPress} />
</View>
@@ -164,10 +164,10 @@ export const LocalWalletImportModal = ({
borderRadius="md"
p="lg"
>
<ModalHeaderTextClose headerText={""} onClose={onCloseInternal} />
<Text variant="header" textAlign="center">
Import JSON Wallet
</Text>
<ModalHeaderTextClose
headerText={"Import JSON Wallet"}
onClose={onCloseInternal}
/>
<Text variant="subHeader" mt="md" textAlign="center">
{
"The application can authorize any transactions on behalf of the wallet without any approvals. We recommend only connecting to trusted applications."
@@ -192,14 +192,26 @@ export const LocalWalletImportModal = ({
<Text variant="bodySmall" color="red" mt="xs" textAlign="left">
{error}
</Text>
<Text variant="bodySmall" m="xs" textAlign="center">
---- Or Private key or Mnemonic ----
</Text>
<Box
mb="xs"
flexDirection="row"
justifyContent="center"
alignItems="center"
>
<Box height={1} flex={1} backgroundColor="border" />
<Text variant="bodySmall" textAlign="center" marginHorizontal="xxs">
Or Private key or Mnemonic
</Text>
<Box height={1} flex={1} backgroundColor="border" />
</Box>
<TextInput
secureTextEntry={true}
placeholder={"Private key / Mnemonic"}
placeholderTextColor={theme.colors.textSecondary}
onChangeText={onPrivateKeyEntered}
textInputProps={{
secureTextEntry: true,
placeholder: "Private key / Mnemonic",
placeholderTextColor: theme.colors.textSecondary,
onChangeText: onPrivateKeyEntered,
}}
containerProps={{ pl: "xxs" }}
/>
<Box
flexDirection="row"
@@ -1,211 +1,195 @@
import { useCallback, useEffect, useState } from "react";
import {
ConnectUIProps,
WalletConfig,
WalletInstance,
useConnect,
useCreateWalletInstance,
useSupportedWallet,
useWalletContext,
useWallets,
} from "@thirdweb-dev/react-core";
import { SmartWalletObj } from "../../../wallets/wallets/smart-wallet";
import { localWallet } from "../../../wallets/wallets/local-wallet";
import { ChooseWallet } from "../ChooseWallet/ChooseWallet";
import { LocalWalletFlow } from "../LocalWalletFlow";
import { ModalHeaderTextClose } from "../../base/modal/ModalHeaderTextClose";
import { ActivityIndicator, Linking, useColorScheme } from "react-native";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import BaseButton from "../../base/BaseButton";
import Text from "../../base/Text";
import { walletIds } from "@thirdweb-dev/wallets";
import { SmartWallet } from "@thirdweb-dev/wallets";
import WalletLoadingThumbnail from "../../../wallets/wallets/wallet-connect/WalletLoadingThumbnail";
import ImageSvgUri from "../../base/ImageSvgUri";
import Box from "../../base/Box";
import { ConnectWalletHeader } from "../ConnectingWallet/ConnectingWalletHeader";
import { useAppTheme } from "../../../styles/hooks";
import { DEFAULT_WALLETS } from "../../../constants/wallets";
export const SmartWalletFlow = ({
onClose,
onConnect,
}: {
onClose: () => void;
onConnect: () => void;
}) => {
const [showLocalWalletFlow, setShowLocalWalletFlow] = useState<boolean>();
close,
goBack,
walletConfig,
personalWalletConfig,
...props
}: ConnectUIProps<SmartWallet> & { personalWalletConfig: WalletConfig }) => {
const theme = useAppTheme();
const [connectedPersonalWallet, setConnectedPersonalWallet] =
useState<WalletInstance>();
const [isConnecting, setIsConnecting] = useState(false);
const [personalWalletChainId, setPersonalWalletChaindId] = useState<
number | undefined
>();
const theme = useAppTheme();
const [switchingNetwork, setSwitchingNetwork] = useState(false);
const createWalletInstance = useCreateWalletInstance();
const walletObj = useSupportedWallet(walletIds.smartWallet) as SmartWalletObj;
const connect = useConnect();
const targetChain = useWalletContext().activeChain;
const colorScheme = useColorScheme();
const supportedWallets = useWallets();
const mismatch = personalWalletChainId
? personalWalletChainId !== targetChain.chainId
: false;
const PersonalWalletConfigUI = personalWalletConfig.connectUI;
const connectSmartWallet = useCallback(
async (personalWallet: WalletInstance) => {
const eoaWalletChainId = await personalWallet.getChainId();
if (eoaWalletChainId === targetChain.chainId) {
await connect(walletConfig, {
personalWallet: personalWallet,
});
close();
} else {
setPersonalWalletChaindId(eoaWalletChainId);
}
},
[close, connect, targetChain.chainId, walletConfig],
);
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);
// }
connectSmartWallet(walletInstance);
},
[connectPersonalWallet],
[connectSmartWallet, createWalletInstance],
);
useEffect(() => {
if (walletObj.personalWallets?.length === 1) {
onChoosePersonalWallet(walletObj.personalWallets[0]);
if (walletConfig.personalWallets?.[0] && !PersonalWalletConfigUI) {
connectPersonalWallet(walletConfig.personalWallets[0]);
}
}, [onChoosePersonalWallet, walletObj.personalWallets]);
useEffect(() => {
(async () => {
if (connectedPersonalWallet) {
const chainId = await connectedPersonalWallet.getChainId();
setPersonalWalletChaindId(chainId);
}
})();
}, [connectedPersonalWallet]);
const connectSmartWallet = useCallback(
async (personalWallet: WalletInstance) => {
if (!mismatch && personalWalletChainId) {
await connect(walletObj, {
personalWallet: personalWallet,
});
onConnect();
}
},
[connect, mismatch, onConnect, personalWalletChainId, walletObj],
);
useEffect(() => {
if (connectedPersonalWallet) {
if (!mismatch) {
connectSmartWallet(connectedPersonalWallet);
}
}
}, [connectSmartWallet, connectedPersonalWallet, mismatch]);
const onConnectedLocalWallet = async (wallet: WalletInstance) => {
setIsConnecting(true);
connectSmartWallet(wallet);
};
const onLocalWalletBackPress = () => {
setShowLocalWalletFlow(false);
};
}, [
PersonalWalletConfigUI,
connectPersonalWallet,
walletConfig.personalWallets,
]);
const onConnectingClosePress = () => {
connectedPersonalWallet?.disconnect();
reset();
close();
};
const onConnectingBackPress = () => {
connectedPersonalWallet?.disconnect();
reset();
goBack();
};
const onSwitchNetworkPress = async () => {
await connectedPersonalWallet?.switchChain(targetChain.chainId);
setPersonalWalletChaindId(targetChain.chainId);
if (connectedPersonalWallet) {
setSwitchingNetwork(true);
await connectedPersonalWallet?.switchChain(targetChain.chainId);
setSwitchingNetwork(false);
setPersonalWalletChaindId(targetChain.chainId);
connectSmartWallet(connectedPersonalWallet);
}
};
const reset = () => {
setIsConnecting(false);
setConnectedPersonalWallet(undefined);
setPersonalWalletChaindId(undefined);
};
const onLearnMorePress = () => {
Linking.openURL("https://portal.thirdweb.com/wallet/smart-wallet");
};
if (isConnecting) {
return (
<>
<ModalHeaderTextClose
onClose={onConnectingClosePress}
headerText={mismatch ? "Network Mismatch" : "Connecting smart wallet"}
subHeaderText={
mismatch
? "There's a network mismatch between your contract and your wallet"
: ""
}
/>
{mismatch ? null : (
<ActivityIndicator size="large" color={theme.colors.linkPrimary} />
)}
{mismatch === true ? (
<BaseButton
marginVertical="sm"
flexDirection="row"
justifyContent="flex-start"
alignItems="center"
paddingHorizontal="md"
paddingVertical="sm"
borderRadius="sm"
backgroundColor="backgroundHighlight"
onPress={onSwitchNetworkPress}
>
<Text variant="bodyLarge">Switch Network</Text>
</BaseButton>
) : null}
</>
);
}
if (showLocalWalletFlow) {
return (
<LocalWalletFlow
theme={colorScheme || "dark"}
close={onClose}
goBack={onLocalWalletBackPress}
onConnected={onConnectedLocalWallet}
isOpen={false}
open={() => {}}
walletConfig={localWallet()}
selectionData={undefined} // TODO
setSelectionData={() => {}} // TODO
supportedWallets={supportedWallets} // TODO - pass personal wallets instead
/>
);
}
const onPersonalWalletConnected = useCallback(
(walletInstance: WalletInstance) => {
setConnectedPersonalWallet(walletInstance);
connectSmartWallet(walletInstance);
},
[connectSmartWallet],
);
return (
<ChooseWallet
headerText={"Link key"}
subHeaderText={
<Text variant="subHeader">
{
"Choose a personal wallet that acts as your account's key. This controls access to your account. "
}
<Text
variant="subHeader"
color="linkPrimary"
onPress={onLearnMorePress}
>
Learn more.
</Text>
</Text>
}
wallets={walletObj.personalWallets || DEFAULT_WALLETS}
onChooseWallet={onChoosePersonalWallet}
onClose={onClose}
/>
<>
{PersonalWalletConfigUI && !connectedPersonalWallet ? (
<PersonalWalletConfigUI
{...props}
close={close}
goBack={goBack}
walletConfig={personalWalletConfig}
onLocallyConnected={onPersonalWalletConnected}
/>
) : (
<Box paddingHorizontal="xl">
<ConnectWalletHeader
subHeaderText=""
onBackPress={onConnectingBackPress}
onClose={onConnectingClosePress}
/>
<WalletLoadingThumbnail imageSize={100}>
<ImageSvgUri
height={80}
width={80}
imageUrl={walletConfig.meta.iconURL}
/>
</WalletLoadingThumbnail>
<View style={styles.connectingContainer}>
<>
<Text variant="header" mt="lg" textAlign="center">
{mismatch ? "Network Mismatch" : "Connecting..."}
</Text>
{mismatch ? (
<Text variant="bodySmallSecondary" mt="lg" textAlign="center">
{
"There's a network mismatch between your contract and your wallet"
}
</Text>
) : null}
</>
</View>
</Box>
)}
{mismatch === true ? (
<BaseButton
marginVertical="sm"
mt="md"
marginHorizontal="xl"
flexDirection="row"
justifyContent="center"
alignItems="center"
paddingHorizontal="md"
paddingVertical="sm"
borderRadius="sm"
backgroundColor="backgroundHighlight"
onPress={onSwitchNetworkPress}
>
{switchingNetwork ? (
<ActivityIndicator size="small" color={theme.colors.textPrimary} />
) : (
<Text variant="bodyLarge" textAlign="center">
Switch Network
</Text>
)}
</BaseButton>
) : null}
</>
);
};
const styles = StyleSheet.create({
connectingContainer: {
flexDirection: "column",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
paddingHorizontal: 4,
marginBottom: 24,
marginTop: 18,
},
});
@@ -2,20 +2,19 @@ import { useModalState } from "../providers/ui-context-provider";
import { ConnectWalletFlow } from "./ConnectWalletFlow/ConnectWalletFlow";
import { Dimensions, StyleSheet, View } from "react-native";
import { useMemo } from "react";
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";
import Box from "./base/Box";
import { useAppTheme } from "../styles/hooks";
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
const MODAL_HEIGHT = Dimensions.get("window").height * 0.6;
const DEVICE_WIDTH = Dimensions.get("window").width;
export const MainModal = () => {
const theme = useAppTheme();
const { modalState, setModalState } = useModalState();
const { modalState } = useModalState();
const { isOpen, isSheet } = modalState;
@@ -34,19 +33,13 @@ export const MainModal = () => {
}
}, [modalState.view]);
const onBackdropPress = () => {
setModalState(CLOSE_MODAL_STATE("MainModal"));
};
return (
<ThemeProvider theme={theme}>
<TWModal isVisible={isOpen} onBackdropPress={onBackdropPress}>
<TWModal isVisible={isOpen}>
{isSheet ? (
<View
style={[styles.modal, { backgroundColor: theme.colors.background }]}
>
<Box backgroundColor="background" style={styles.modal}>
<View style={styles.contentContainer}>{view}</View>
</View>
</Box>
) : (
view
)}
@@ -63,8 +56,8 @@ const styles = StyleSheet.create({
width: DEVICE_WIDTH,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
padding: 24,
paddingBottom: 40,
paddingTop: 32,
paddingBottom: 28,
},
contentContainer: {
maxHeight: MODAL_HEIGHT,
@@ -25,12 +25,15 @@ export const PasswordInput = ({
borderWidth={1}
borderRadius="md"
pr="xs"
pl="xxs"
>
<TextInput
style={{ ...styles.textInput, color: theme.colors.textPrimary }}
secureTextEntry={!showPassword}
textContentType="none"
returnKeyType={"done"}
placeholder="Password"
placeholderTextColor={theme.colors.textSecondary}
clearTextOnFocus={false}
autoCapitalize="none"
autoCorrect={false}
@@ -60,6 +63,5 @@ const styles = StyleSheet.create({
textAlign: "left",
flex: 1,
height: 40,
paddingLeft: 5,
},
});
@@ -0,0 +1,153 @@
import React, { useEffect, useState } from "react";
import { IconTextButton } from "./base/IconTextButton";
import { useAddress } from "@thirdweb-dev/react-core";
import { Dimensions, KeyboardAvoidingView } from "react-native";
import { useAppTheme } from "../styles/hooks";
import {
TWModal,
Box,
ModalHeaderTextClose,
Text,
AddressDisplay,
BaseButton,
Toast,
} from "./base";
import DownloadIcon from "../assets/download";
import CopyIcon from "../assets/copy";
import QRCode from "react-native-qrcode-svg";
export const ReceiveButton = () => {
const theme = useAppTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const onClose = () => {
setIsModalVisible(false);
};
const onReceivePress = () => {
setIsModalVisible(true);
};
return (
<>
<IconTextButton
flex={1}
ml="xs"
text="Receive"
justifyContent="center"
icon={
<DownloadIcon
height={16}
width={16}
color={theme.colors.textPrimary}
/>
}
onPress={onReceivePress}
/>
<ReceiveFundsModal isVisible={isModalVisible} onClose={onClose} />
</>
);
};
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
export type ReceiveFundsModalProps = {
isVisible: boolean;
onClose: () => void;
};
export const ReceiveFundsModal = ({
isVisible,
onClose,
}: ReceiveFundsModalProps) => {
const theme = useAppTheme();
const address = useAddress();
const [addressCopied, setAddressCopied] = useState(false);
useEffect(() => {
const timeout = setTimeout(() => {
if (addressCopied) {
setAddressCopied(false);
}
}, 2000);
return () => clearTimeout(timeout);
}, [addressCopied]);
const onCloseInternal = () => {
onClose();
};
const onAddressPress = () => {
setAddressCopied(true);
};
return (
<TWModal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
<Box
flexDirection="column"
backgroundColor="background"
maxHeight={MODAL_HEIGHT}
borderRadius="md"
p="lg"
>
<ModalHeaderTextClose
onClose={onCloseInternal}
headerText="Receive Funds"
/>
<Text
variant="bodySmallSecondary"
textAlign="center"
mt="md"
marginHorizontal="xmd"
>
Copy the wallet address or scan the QR code to send funds to this
wallet.
</Text>
<Text mt="lg" variant="bodySmallSecondary">
Your address
</Text>
<BaseButton
mt="xs"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
borderColor="border"
borderWidth={1}
borderRadius="md"
onPress={onAddressPress}
p="md"
>
<AddressDisplay
address={address}
variant="bodySmall"
extraShort={false}
/>
<CopyIcon width={14} height={14} color={theme.colors.iconPrimary} />
</BaseButton>
<Text mt="lg" variant="bodySmallSecondary">
QR Code
</Text>
<Box
mt="xs"
flexDirection="row"
alignItems="center"
justifyContent="center"
borderColor="border"
backgroundColor="white"
borderWidth={1}
borderRadius="md"
p="md"
>
<QRCode value={address} size={150} />
</Box>
{addressCopied === true ? (
<Toast text={"Address copied to clipboard"} />
) : null}
</Box>
</KeyboardAvoidingView>
</TWModal>
);
};
@@ -0,0 +1,42 @@
import { useBalance, useChain } from "@thirdweb-dev/react-core";
import { TokenInfo } from "./defaultTokens";
import { BaseButton, Box, ChainIcon, ImageSvgUri, Text } from "../base";
import LoadingTextAnimation from "../base/LoadingTextAnimation";
export function SelectTokenButton(props: {
token?: TokenInfo;
onPress: () => void;
}) {
const balanceQuery = useBalance(props.token?.address);
const chain = useChain();
const tokenName = props.token?.name || balanceQuery.data?.name;
return (
<BaseButton
flexDirection="row"
alignItems="center"
onPress={props.onPress}
mb="sm"
>
{props.token?.icon ? (
<ImageSvgUri width={32} height={32} imageUrl={props.token.icon} />
) : (
<ChainIcon chainIconUrl={chain?.icon?.url} size={32} />
)}
<Box ml="md" alignItems="flex-start" justifyContent="center">
<Text variant="bodyLarge">{tokenName}</Text>
{!balanceQuery.data ? (
<LoadingTextAnimation
text="Fetching..."
textVariant={"bodySmallSecondary"}
/>
) : (
<Text variant="bodySmallSecondary" fontSize={12}>
{Number(balanceQuery.data?.displayValue).toFixed(3)}{" "}
{balanceQuery.data.symbol}
</Text>
)}
</Box>
</BaseButton>
);
}
@@ -0,0 +1,368 @@
import { useAppTheme } from "../../styles/hooks";
import React, { useEffect, useMemo, useState } from "react";
import SendIcon from "../../assets/send";
import {
BaseButton,
Box,
ChainIcon,
IconTextButton,
ImageSvgUri,
ModalHeaderTextClose,
TWModal,
Text,
} from "../base";
import {
ActivityIndicator,
Dimensions,
KeyboardAvoidingView,
TextInput as TextInputRN,
} from "react-native";
import {
TransactionResult,
useBalance,
useChain,
useChainId,
useWallet,
} from "@thirdweb-dev/react-core";
import { SupportedTokens, TokenInfo, defaultTokens } from "./defaultTokens";
import { useMutation } from "@tanstack/react-query";
import { utils } from "ethers";
import LoadingTextAnimation from "../base/LoadingTextAnimation";
import CheckIcon from "../../assets/check";
import { TokenSelector } from "./TokenSelector";
export const SendButton = ({
supportedTokens,
}: {
supportedTokens: SupportedTokens;
}) => {
const theme = useAppTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const onClose = () => {
setIsModalVisible(false);
};
const onSendPress = () => {
setIsModalVisible(true);
};
return (
<>
<IconTextButton
flex={1}
text="Send"
justifyContent="center"
icon={
<SendIcon height={16} width={16} color={theme.colors.textPrimary} />
}
onPress={onSendPress}
/>
<SendFundsModal
isVisible={isModalVisible}
onClose={onClose}
supportedTokens={supportedTokens}
/>
</>
);
};
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
type TXError = Error & { data?: { message?: string } };
export type SendFundsModalProps = {
isVisible: boolean;
onClose: () => void;
supportedTokens: SupportedTokens;
};
export const SendFundsModal = ({
isVisible,
onClose,
supportedTokens,
}: SendFundsModalProps) => {
const [showTokenSelector, setShowTokenSelector] = useState(false);
const chainId = useChainId();
let defaultToken: TokenInfo | undefined = undefined;
if (
// if we know chainId
chainId &&
// if there is a list of tokens for this chain
supportedTokens[chainId] &&
// if the list of tokens is not the default list
supportedTokens[chainId] !== defaultTokens[chainId]
) {
// use the first token in the list as default selected
defaultToken = supportedTokens[chainId][0];
}
const [token, setToken] = useState<TokenInfo | undefined>(defaultToken);
const onTokenSelectorPress = () => {
setShowTokenSelector(true);
};
return (
<TWModal isVisible={isVisible} backdropOpacity={0.7}>
<KeyboardAvoidingView behavior="padding">
{showTokenSelector ? (
<TokenSelector
supportedTokens={supportedTokens}
onBack={() => {
setShowTokenSelector(false);
}}
onTokenSelect={(_token) => {
setToken(_token);
setShowTokenSelector(false);
}}
/>
) : (
<SendFundsForm
onClose={onClose}
token={token}
onTokenSelectorPress={onTokenSelectorPress}
/>
)}
</KeyboardAvoidingView>
</TWModal>
);
};
const SendFundsForm = ({
onClose,
onTokenSelectorPress,
token,
}: {
onClose: () => void;
onTokenSelectorPress: () => void;
token?: TokenInfo;
}) => {
const theme = useAppTheme();
const chain = useChain();
const wallet = useWallet();
const chainId = useChainId();
const [receiverAddress, setReceiverAddress] = useState("");
const [amount, setAmount] = useState("");
const [showIcon, setShowIcon] = useState(false);
const tokenAddress = token?.address;
const balanceQuery = useBalance(
tokenAddress && utils.isAddress(tokenAddress) ? tokenAddress : undefined,
);
const tokenName = token?.name || balanceQuery?.data?.name;
const tokenSymbol = token?.symbol || balanceQuery.data?.symbol;
// Ethereum or Rinkeby or Goerli
const isENSSupprted = chainId === 1 || chainId === 5 || chainId === 4;
const isValidReceieverAddress = useMemo(() => {
const isENS = receiverAddress.endsWith(".eth");
if (!isENSSupprted && isENS) {
return false;
}
return isENS || utils.isAddress(receiverAddress);
}, [receiverAddress, isENSSupprted]);
const showInvalidAddressError = receiverAddress && !isValidReceieverAddress;
const sendTokenMutation = useMutation<TransactionResult | undefined, TXError>(
async () => {
if (!wallet) {
return;
}
return wallet.transfer(receiverAddress, amount, tokenAddress);
},
);
useEffect(() => {
if (sendTokenMutation.isSuccess) {
setShowIcon(true);
setTimeout(() => {
setShowIcon(false);
}, 1000);
}
}, [sendTokenMutation.isSuccess]);
const onCloseInternal = () => {
onClose();
};
function getErrorMessage(error?: TXError) {
const message = error?.data?.message || error?.message;
if (!message) {
return "Transaction Failed";
}
if (message.includes("user rejected")) {
return "Transaction Rejected";
}
if (message.includes("insufficient funds")) {
return "Insufficient funds";
}
return "Transaction Failed";
}
return (
<Box
flexDirection="column"
backgroundColor="background"
maxHeight={MODAL_HEIGHT}
borderRadius="md"
p="lg"
>
<ModalHeaderTextClose onClose={onCloseInternal} headerText="Send Funds" />
<Text mt="lg" variant="bodySmallSecondary">
Select Token
</Text>
<BaseButton
mt="xs"
borderRadius="md"
borderWidth={0.5}
paddingHorizontal="md"
paddingVertical="sm"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
borderColor="border"
onPress={onTokenSelectorPress}
>
<Box flexDirection="row" alignItems="center">
{token?.icon ? (
<ImageSvgUri width={32} height={32} imageUrl={token.icon} />
) : (
<ChainIcon chainIconUrl={chain?.icon?.url} size={32} />
)}
<Box
ml="md"
alignItems="flex-start"
justifyContent="center"
height={36}
>
<Text variant="bodySmall">{tokenName}</Text>
{!balanceQuery.data ? (
<LoadingTextAnimation
text="Fetching..."
textVariant={"bodySmallSecondary"}
/>
) : (
<Text variant="bodySmallSecondary" fontSize={12}>
{Number(balanceQuery.data?.displayValue).toFixed(3)}{" "}
{balanceQuery.data.symbol}
</Text>
)}
</Box>
</Box>
</BaseButton>
<Text mt="md" variant="bodySmallSecondary">
Send to
</Text>
<Box
mt="xs"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
borderColor={showInvalidAddressError ? "red" : "border"}
borderWidth={1}
borderRadius="md"
pr="xs"
>
<TextInputRN
editable={!sendTokenMutation.isLoading}
returnKeyType={"done"}
clearTextOnFocus={false}
onChangeText={setReceiverAddress}
style={{
color: theme.colors.textPrimary,
textAlign: "left",
flex: 1,
height: 40,
paddingHorizontal: 16,
}}
value={receiverAddress}
placeholder={isENSSupprted ? `0x... / ENS name` : "0x..."}
placeholderTextColor={theme.colors.textSecondary}
autoCapitalize="none"
autoCorrect={false}
/>
</Box>
<Text mt="md" variant="bodySmallSecondary">
Amount
</Text>
<Box
mt="xs"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
borderColor="border"
borderWidth={1}
borderRadius="md"
pr="xs"
>
<TextInputRN
editable={!sendTokenMutation.isLoading}
returnKeyType={"done"}
keyboardType="numeric"
clearTextOnFocus={false}
style={{
color: theme.colors.textPrimary,
textAlign: "left",
flex: 1,
height: 40,
paddingHorizontal: 16,
}}
onChangeText={setAmount}
placeholder="0"
placeholderTextColor={theme.colors.textPrimary}
autoCapitalize="none"
autoCorrect={false}
/>
<Text variant="bodySmallSecondary">{tokenSymbol}</Text>
</Box>
<BaseButton
mt="md"
backgroundColor="accentButtonColor"
flexDirection="row"
alignItems="center"
justifyContent="center"
alignContent="center"
borderRadius="md"
borderWidth={0.5}
paddingVertical="md"
onPress={async () => {
if (!receiverAddress || !wallet || !amount) {
return;
}
await sendTokenMutation.mutateAsync();
}}
>
{sendTokenMutation.isLoading ? (
<ActivityIndicator size="small" color={theme.colors.textPrimary} />
) : showIcon ? (
<CheckIcon width={20} height={13} color={theme.colors.textPrimary} />
) : (
<Text variant="bodySmall" mr="sm">
Send
</Text>
)}
</BaseButton>
{sendTokenMutation.isError && (
<Text mt="sm" variant="error">
{getErrorMessage(sendTokenMutation.error || undefined)}
</Text>
)}
</Box>
);
};
@@ -0,0 +1,206 @@
import {
NATIVE_TOKEN_ADDRESS,
useBalance,
useChain,
useChainId,
} from "@thirdweb-dev/react-core";
import React, { useState } from "react";
import { TokenInfo, SupportedTokens } from "./defaultTokens";
import { utils } from "ethers";
import Box from "../base/Box";
import { ModalHeaderTextClose } from "../base/modal/ModalHeaderTextClose";
import {
ActivityIndicator,
Dimensions,
ScrollView,
TextInput,
} from "react-native";
import { useAppTheme } from "../../styles/hooks";
import { SelectTokenButton } from "./SelectTokenButton";
import CloseIcon from "../../assets/close";
import Text from "../base/Text";
export function useToken(tokenAddress: string): {
isLoading: boolean;
data: TokenInfo | undefined;
} {
const balanceQuery = useBalance(
utils.isAddress(tokenAddress) ? tokenAddress : undefined,
);
const chain = useChain();
if (!utils.isAddress(tokenAddress)) {
return {
isLoading: false,
data: undefined,
};
}
if (balanceQuery.isLoading) {
return {
isLoading: true,
data: undefined,
};
}
if (balanceQuery.data) {
return {
isLoading: false,
data: {
name: balanceQuery.data.name,
symbol: balanceQuery.data.symbol,
address: tokenAddress,
icon: chain?.icon?.url || "",
},
};
}
return {
isLoading: false,
data: undefined,
};
}
function useNativeToken(): TokenInfo | undefined {
const balanceQuery = useBalance();
const chain = useChain();
if (balanceQuery.data) {
return {
name: balanceQuery.data.name,
symbol: balanceQuery.data.symbol,
address: NATIVE_TOKEN_ADDRESS,
icon: chain?.icon?.url || "",
};
}
}
const MODAL_HEIGHT = Dimensions.get("window").height * 0.5;
export function TokenSelector(props: {
onTokenSelect: (token?: TokenInfo) => void;
onBack: () => void;
supportedTokens: SupportedTokens;
}) {
const theme = useAppTheme();
const [input, setInput] = useState("");
const chainId = useChainId();
const nativeTokenInfo = useNativeToken();
const { data: foundToken, isLoading: findingToken } = useToken(input);
let tokenList = (chainId ? props.supportedTokens[chainId] : undefined) || [];
if (nativeTokenInfo) {
tokenList = [nativeTokenInfo, ...tokenList];
}
if (foundToken) {
tokenList = [foundToken, ...tokenList];
}
const filteredList = input
? tokenList.filter((t) => {
const inputStr = input.toLowerCase();
return (
t.name.toLowerCase().includes(inputStr) ||
t.symbol.toLowerCase().includes(inputStr) ||
t.address.includes(input)
);
})
: tokenList;
return (
<Box
flexDirection="column"
backgroundColor="background"
maxHeight={MODAL_HEIGHT}
borderRadius="md"
p="lg"
>
<Box>
<ModalHeaderTextClose
onBackPress={props.onBack}
headerText="Select a Token"
/>
<Box
mt="xs"
mb="md"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
borderColor="border"
borderWidth={1}
borderRadius="md"
pr="xs"
>
<TextInput
returnKeyType={"done"}
clearTextOnFocus={false}
onChangeText={setInput}
style={{
color: theme.colors.textPrimary,
textAlign: "left",
flex: 1,
height: 40,
paddingHorizontal: 16,
}}
placeholder="Search or paste token address"
placeholderTextColor={theme.colors.textSecondary}
autoCapitalize="none"
autoCorrect={false}
/>
</Box>
</Box>
{filteredList.length > 0 && (
<Box
flexDirection="column"
paddingTop="none"
maxHeight={MODAL_HEIGHT - 150}
>
<ScrollView>
{filteredList.map((token) => {
return (
<SelectTokenButton
onPress={() => props.onTokenSelect(token)}
token={token}
key={token.address}
/>
);
})}
</ScrollView>
</Box>
)}
{findingToken && (
<Box
p="lg"
flexDirection="column"
gap="md"
alignItems="center"
justifyContent="center"
minHeight={150}
paddingTop="none"
>
<ActivityIndicator size="large" color={theme.colors.textSecondary} />
</Box>
)}
{filteredList.length === 0 && !findingToken && (
<Box
p="lg"
flexDirection="column"
gap="md"
alignItems="center"
justifyContent="center"
minHeight={150}
paddingTop="none"
>
<CloseIcon width={16} height={16} />
<Text variant="bodySmall">No Tokens found</Text>
</Box>
)}
</Box>
);
}
@@ -0,0 +1,306 @@
export type TokenInfo = {
name: string;
symbol: string;
address: string;
icon: string;
};
const wrappedEthIcon =
'<svg width="2500" height="2500" viewBox="0 0 32 32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#627EEA"/><g fill="#FFF" fill-rule="nonzero"><path fill-opacity=".602" d="M16.498 4v8.87l7.497 3.35z"/><path d="M16.498 4L9 16.22l7.498-3.35z"/><path fill-opacity=".602" d="M16.498 21.968v6.027L24 17.616z"/><path d="M16.498 27.995v-6.028L9 17.616z"/><path fill-opacity=".2" d="M16.498 20.573l7.497-4.353-7.497-3.348z"/><path fill-opacity=".602" d="M9 16.22l7.498 4.353v-7.701z"/></g></g></svg>';
const tetherUsdIcon =
'<svg id="Layer_1" data-name="Layer 1" viewBox="0 0 339.43 295.27"><title>tether-usdt-logo</title><path d="M62.15,1.45l-61.89,130a2.52,2.52,0,0,0,.54,2.94L167.95,294.56a2.55,2.55,0,0,0,3.53,0L338.63,134.4a2.52,2.52,0,0,0,.54-2.94l-61.89-130A2.5,2.5,0,0,0,275,0H64.45a2.5,2.5,0,0,0-2.3,1.45h0Z" style="fill:#50af95;fill-rule:evenodd"/><path d="M191.19,144.8v0c-1.2.09-7.4,0.46-21.23,0.46-11,0-18.81-.33-21.55-0.46v0c-42.51-1.87-74.24-9.27-74.24-18.13s31.73-16.25,74.24-18.15v28.91c2.78,0.2,10.74.67,21.74,0.67,13.2,0,19.81-.55,21-0.66v-28.9c42.42,1.89,74.08,9.29,74.08,18.13s-31.65,16.24-74.08,18.12h0Zm0-39.25V79.68h59.2V40.23H89.21V79.68H148.4v25.86c-48.11,2.21-84.29,11.74-84.29,23.16s36.18,20.94,84.29,23.16v82.9h42.78V151.83c48-2.21,84.12-11.73,84.12-23.14s-36.09-20.93-84.12-23.15h0Zm0,0h0Z" style="fill:#fff;fill-rule:evenodd"/></svg>';
const usdcIcon = `<svg data-name="86977684-12db-4850-8f30-233a7c267d11" viewBox="0 0 2000 2000">
<path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/>
<path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/>
<path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/>
</svg>
`;
const wrappedBtcIcon =
'<svg viewBox="0 0 109.26 109.26"><title>wrapped-bitcoin-wbtc</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="Page-1"><g id="wbtc_colour" data-name="wbtc colour"><path id="Shape" fill="#5a5564" d="M89.09,22.93l-3,3a42.47,42.47,0,0,1,0,57.32l3,3a46.76,46.76,0,0,0,0-63.39Z"/><path id="Shape-2" data-name="Shape" fill="#5a5564" d="M26,23.19a42.47,42.47,0,0,1,57.32,0l3-3a46.76,46.76,0,0,0-63.39,0Z"/><path id="Shape-3" data-name="Shape" fill="#5a5564" d="M23.19,83.28a42.47,42.47,0,0,1,0-57.29l-3-3a46.76,46.76,0,0,0,0,63.39Z"/><path id="Shape-4" data-name="Shape" fill="#5a5564" d="M83.28,86.05a42.47,42.47,0,0,1-57.32,0l-3,3a46.76,46.76,0,0,0,63.39,0Z"/><path id="Shape-5" data-name="Shape" fill="#f09242" d="M73.57,44.62c-.6-6.26-6-8.36-12.83-9V27H55.46v8.46c-1.39,0-2.81,0-4.22,0V27H46v8.68H35.29v5.65s3.9-.07,3.84,0a2.73,2.73,0,0,1,3,2.32V67.41a1.85,1.85,0,0,1-.64,1.29,1.83,1.83,0,0,1-1.36.46c.07.06-3.84,0-3.84,0l-1,6.31H45.9v8.82h5.28V75.6H55.4v8.65h5.29V75.53c8.92-.54,15.14-2.74,15.92-11.09.63-6.72-2.53-9.72-7.58-10.93C72.1,52,74,49.2,73.57,44.62ZM66.17,63.4c0,6.56-11.24,5.81-14.82,5.81V57.57C54.93,57.58,66.17,56.55,66.17,63.4ZM63.72,47c0,6-9.38,5.27-12.36,5.27V41.69C54.34,41.69,63.72,40.75,63.72,47Z"/><path id="Shape-6" data-name="Shape" fill="#282138" d="M54.62,109.26a54.63,54.63,0,1,1,54.64-54.64A54.63,54.63,0,0,1,54.62,109.26Zm0-105A50.34,50.34,0,1,0,105,54.62,50.34,50.34,0,0,0,54.62,4.26Z"/></g></g></g></g></svg>';
const maticIcon = `<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" >
<circle cx="512" cy="512" r="512" fill="#8247E5"/>
<path d="M681.469 402.456C669.189 395.312 653.224 395.312 639.716 402.456L543.928 457.228L478.842 492.949L383.055 547.721C370.774 554.865 354.81 554.865 341.301 547.721L265.162 504.856C252.882 497.712 244.286 484.614 244.286 470.325V385.786C244.286 371.498 251.654 358.4 265.162 351.256L340.073 309.581C352.353 302.437 368.318 302.437 381.827 309.581L456.737 351.256C469.018 358.4 477.614 371.498 477.614 385.786V440.558L542.7 403.646V348.874C542.7 334.586 535.332 321.488 521.824 314.344L383.055 235.758C370.774 228.614 354.81 228.614 341.301 235.758L200.076 314.344C186.567 321.488 179.199 334.586 179.199 348.874V507.237C179.199 521.525 186.567 534.623 200.076 541.767L341.301 620.353C353.582 627.498 369.546 627.498 383.055 620.353L478.842 566.772L543.928 529.86L639.716 476.279C651.996 469.135 667.961 469.135 681.469 476.279L756.38 517.953C768.66 525.098 777.257 538.195 777.257 552.484V637.023C777.257 651.312 769.888 664.409 756.38 671.553L681.469 714.419C669.189 721.563 653.224 721.563 639.716 714.419L564.805 672.744C552.525 665.6 543.928 652.502 543.928 638.214V583.442L478.842 620.353V675.125C478.842 689.414 486.21 702.512 499.719 709.656L640.944 788.242C653.224 795.386 669.189 795.386 682.697 788.242L823.922 709.656C836.203 702.512 844.799 689.414 844.799 675.125V516.763C844.799 502.474 837.431 489.377 823.922 482.232L681.469 402.456Z" fill="white"/>
</svg>
`;
const binanceCoinIcon =
'<svg width="32" height="32"><g fill="none"><circle cx="16" cy="16" r="16" fill="#F3BA2F"/><path fill="#FFF" d="M12.116 14.404L16 10.52l3.886 3.886 2.26-2.26L16 6l-6.144 6.144 2.26 2.26zM6 16l2.26-2.26L10.52 16l-2.26 2.26L6 16zm6.116 1.596L16 21.48l3.886-3.886 2.26 2.259L16 26l-6.144-6.144-.003-.003 2.263-2.257zM21.48 16l2.26-2.26L26 16l-2.26 2.26L21.48 16zm-3.188-.002h.002v.002L16 18.294l-2.291-2.29-.004-.004.004-.003.401-.402.195-.195L16 13.706l2.293 2.293z"/></g></svg>';
const BUSDIcon =
'<svg viewBox="0 0 336.41 337.42"><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path fill="#f0b90b" stroke="#f0b90b" d="M168.2.71l41.5,42.5L105.2,147.71l-41.5-41.5Z"/><path fill="#f0b90b" stroke="#f0b90b" d="M231.2,63.71l41.5,42.5L105.2,273.71l-41.5-41.5Z"/><path fill="#f0b90b" stroke="#f0b90b" d="M42.2,126.71l41.5,42.5-41.5,41.5L.7,169.21Z"/><path fill="#f0b90b" stroke="#f0b90b" d="M294.2,126.71l41.5,42.5L168.2,336.71l-41.5-41.5Z"/></g></g></svg>';
const fantomIcon =
'<svg viewBox="0 0 32 32"><defs><mask id="mask" x="10" y="6" width="93.1" height="20" maskUnits="userSpaceOnUse"><g id="a"><path fill="#fff" fill-rule="evenodd" d="M10,6h93.1V26H10Z"/></g></mask></defs><title>fa</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><circle fill="#13b5ec" cx="16" cy="16" r="16"/><g mask="url(#mask)"><path fill="#fff" fill-rule="evenodd" d="M17.2,12.9l3.6-2.1V15Zm3.6,9L16,24.7l-4.8-2.8V17L16,19.8,20.8,17ZM11.2,10.8l3.6,2.1L11.2,15Zm5.4,3.1L20.2,16l-3.6,2.1Zm-1.2,4.2L11.8,16l3.6-2.1Zm4.8-8.3L16,12.2,11.8,9.8,16,7.3ZM10,9.4V22.5l6,3.4,6-3.4V9.4L16,6Z"/></g></g></g></svg>';
export type SupportedTokens = Record<number, TokenInfo[]>;
export const defaultTokens: SupportedTokens = {
"1": [
{
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
name: "Tether USD",
symbol: "USDT",
icon: tetherUsdIcon,
},
{
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
{
address: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
name: "Wrapped Bitcoin",
symbol: "WBTC",
icon: wrappedBtcIcon,
},
{
address: "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0",
name: "Polygon",
symbol: "WMATIC",
icon: maticIcon,
},
],
"5": [
{
address: "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0x07865c6E87B9F70255377e024ace6630C1Eaa37F",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
],
"10": [
{
address: "0x4200000000000000000000000000000000000006",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
],
"56": [
{
address: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
name: "Wrapped Binance Chain Token",
symbol: "WBNB",
icon: binanceCoinIcon,
},
{
address: "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56",
name: "Binance USD",
symbol: "BUSD",
icon: BUSDIcon,
},
],
"97": [
{
address: "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd",
name: "Wrapped Binance Chain Testnet Token",
symbol: "WBNB",
icon: binanceCoinIcon,
},
{
address: "0xed24fc36d5ee211ea25a80239fb8c4cfd80f12ee",
name: "Binance USD",
symbol: "BUSD",
icon: BUSDIcon,
},
],
"137": [
{
address: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
name: "Wrapped Matic",
symbol: "WMATIC",
icon: maticIcon,
},
{
address: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
{
address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
name: "Tether USD",
symbol: "USDT",
icon: tetherUsdIcon,
},
{
address: "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6",
name: "Wrapped BTC",
symbol: "WBTC",
icon: wrappedBtcIcon,
},
],
"250": [
{
address: "0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83",
name: "Wrapped Fantom",
symbol: "WFTM",
icon: fantomIcon,
},
{
name: "Wrapped Ether",
address: "0x74b23882a30290451A17c44f4F05243b6b58C76d",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
name: "USD Coin",
address: "0x04068DA6C83AFCFA0e13ba15A6696662335D5B75",
symbol: "USDC",
icon: usdcIcon,
},
{
name: "Wrapped Bitcoin",
address: "0x321162Cd933E2Be498Cd2267a90534A804051b11",
symbol: "WBTC",
icon: wrappedBtcIcon,
},
],
"420": [
{
address: "0x4200000000000000000000000000000000000006",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
],
"4002": [
{
address: "0xf1277d1Ed8AD466beddF92ef448A132661956621",
name: "Wrapped Fantom",
symbol: "WFTM",
icon: fantomIcon,
},
],
"42161": [
{
address: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
],
"43113": [
{
address: "0xd00ae08403B9bbb9124bB305C09058E32C39A48c",
name: "Wrapped AVAX",
symbol: "WAVAX",
icon: `<svg width="1503" height="1504" viewBox="0 0 1503 1504" fill="none">
<rect x="287" y="258" width="928" height="844" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1502.5 752C1502.5 1166.77 1166.27 1503 751.5 1503C336.734 1503 0.5 1166.77 0.5 752C0.5 337.234 336.734 1 751.5 1C1166.27 1 1502.5 337.234 1502.5 752ZM538.688 1050.86H392.94C362.314 1050.86 347.186 1050.86 337.962 1044.96C327.999 1038.5 321.911 1027.8 321.173 1015.99C320.619 1005.11 328.184 991.822 343.312 965.255L703.182 330.935C718.495 303.999 726.243 290.531 736.021 285.55C746.537 280.2 759.083 280.2 769.599 285.55C779.377 290.531 787.126 303.999 802.438 330.935L876.42 460.079L876.797 460.738C893.336 489.635 901.723 504.289 905.385 519.669C909.443 536.458 909.443 554.169 905.385 570.958C901.695 586.455 893.393 601.215 876.604 630.549L687.573 964.702L687.084 965.558C670.436 994.693 661.999 1009.46 650.306 1020.6C637.576 1032.78 622.263 1041.63 605.474 1046.62C590.161 1050.86 573.004 1050.86 538.688 1050.86ZM906.75 1050.86H1115.59C1146.4 1050.86 1161.9 1050.86 1171.13 1044.78C1181.09 1038.32 1187.36 1027.43 1187.92 1015.63C1188.45 1005.1 1181.05 992.33 1166.55 967.307C1166.05 966.455 1165.55 965.588 1165.04 964.706L1060.43 785.75L1059.24 783.735C1044.54 758.877 1037.12 746.324 1027.59 741.472C1017.08 736.121 1004.71 736.121 994.199 741.472C984.605 746.453 976.857 759.552 961.544 785.934L857.306 964.891L856.949 965.507C841.69 991.847 834.064 1005.01 834.614 1015.81C835.352 1027.62 841.44 1038.5 851.402 1044.96C860.443 1050.86 875.94 1050.86 906.75 1050.86Z" fill="#E84142"/>
</svg>
`,
},
{
address: "0x5425890298aed601595a70AB815c96711a31Bc65",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
],
"43114": [
{
address: "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
name: "Wrapped AVAX",
symbol: "WAVAX",
icon: `<svg width="1503" height="1504" viewBox="0 0 1503 1504" fill="none">
<rect x="287" y="258" width="928" height="844" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1502.5 752C1502.5 1166.77 1166.27 1503 751.5 1503C336.734 1503 0.5 1166.77 0.5 752C0.5 337.234 336.734 1 751.5 1C1166.27 1 1502.5 337.234 1502.5 752ZM538.688 1050.86H392.94C362.314 1050.86 347.186 1050.86 337.962 1044.96C327.999 1038.5 321.911 1027.8 321.173 1015.99C320.619 1005.11 328.184 991.822 343.312 965.255L703.182 330.935C718.495 303.999 726.243 290.531 736.021 285.55C746.537 280.2 759.083 280.2 769.599 285.55C779.377 290.531 787.126 303.999 802.438 330.935L876.42 460.079L876.797 460.738C893.336 489.635 901.723 504.289 905.385 519.669C909.443 536.458 909.443 554.169 905.385 570.958C901.695 586.455 893.393 601.215 876.604 630.549L687.573 964.702L687.084 965.558C670.436 994.693 661.999 1009.46 650.306 1020.6C637.576 1032.78 622.263 1041.63 605.474 1046.62C590.161 1050.86 573.004 1050.86 538.688 1050.86ZM906.75 1050.86H1115.59C1146.4 1050.86 1161.9 1050.86 1171.13 1044.78C1181.09 1038.32 1187.36 1027.43 1187.92 1015.63C1188.45 1005.1 1181.05 992.33 1166.55 967.307C1166.05 966.455 1165.55 965.588 1165.04 964.706L1060.43 785.75L1059.24 783.735C1044.54 758.877 1037.12 746.324 1027.59 741.472C1017.08 736.121 1004.71 736.121 994.199 741.472C984.605 746.453 976.857 759.552 961.544 785.934L857.306 964.891L856.949 965.507C841.69 991.847 834.064 1005.01 834.614 1015.81C835.352 1027.62 841.44 1038.5 851.402 1044.96C860.443 1050.86 875.94 1050.86 906.75 1050.86Z" fill="#E84142"/>
</svg>
`,
},
{
address: "0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0xc7198437980c041c805A1EDcbA50c1Ce5db95118",
name: "Tether USD",
symbol: "USDT",
icon: tetherUsdIcon,
},
{
address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
{
address: "0x50b7545627a5162F82A992c33b87aDc75187B218",
name: "Wrapped BTC",
symbol: "WBTC",
icon: wrappedBtcIcon,
},
],
"80001": [
{
address: "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889",
name: "Wrapped Matic",
symbol: "WMATIC",
icon: maticIcon,
},
{
name: "Wrapped Ether",
address: "0xa6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0x0FA8781a83E46826621b3BC094Ea2A0212e71B23",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
{
name: "Tether USD",
address: "0x3813e82e6f7098b9583FC0F33a962D02018B6803",
symbol: "USDT",
icon: tetherUsdIcon,
},
],
"421613": [
{
address: "0xe39Ab88f8A4777030A534146A9Ca3B52bd5D43A3",
name: "Wrapped Ether",
symbol: "WETH",
icon: wrappedEthIcon,
},
{
address: "0xfd064A18f3BF249cf1f87FC203E90D8f650f2d63",
name: "USD Coin",
symbol: "USDC",
icon: usdcIcon,
},
],
};
@@ -18,6 +18,7 @@ import type { CallOverrides, ContractInterface } from "ethers";
import { PropsWithChildren, useEffect } from "react";
import { ActivityIndicator, StyleSheet } from "react-native";
import invariant from "tiny-invariant";
import { useUIContext } from "../providers/ui-context-provider";
type ActionFn = (contract: SmartContract) => Promise<any>;
@@ -82,11 +83,18 @@ export const Web3Button = <TAction extends ActionFn>({
const needToSwitchChain =
sdkChainId && walletChainId && sdkChainId !== walletChainId;
const connectionStatus = useConnectionStatus();
const setTheme = useUIContext().setTheme;
const queryClient = useQueryClient();
const { contract } = useContract(contractAddress, contractAbi || "custom");
useEffect(() => {
if (theme) {
setTheme(theme);
}
}, [setTheme, theme]);
const actionMutation = useMutation(
async () => {
invariant(contract, "contract is not ready yet");
@@ -153,7 +161,7 @@ export const Web3Button = <TAction extends ActionFn>({
}
return (
<ThemeProvider theme={theme}>
<ThemeProvider>
<BaseButton
backgroundColor="buttonBackgroundColor"
onPress={() => {

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