Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1b05fcea3 | ||
|
|
426c75a330 | ||
|
|
a9854e69ce | ||
|
|
2097e233cb | ||
|
|
c29042b71e | ||
|
|
b5b7e5243d | ||
|
|
d5fafddea5 | ||
|
|
b6df6b8957 | ||
|
|
45112a613e | ||
|
|
ea5b9c3ecd | ||
|
|
bd18e4f5ef | ||
|
|
1018eb56a6 | ||
|
|
def6d400ab | ||
|
|
2ce89cfea9 | ||
|
|
48906a9d8e | ||
|
|
64528263f4 | ||
|
|
cbbb8ccbe3 | ||
|
|
e2e6bdd4cd | ||
|
|
d66ff413de | ||
|
|
9d553746b0 | ||
|
|
57af96c288 | ||
|
|
94bdcc142a | ||
|
|
dd3d1a87c2 | ||
|
|
4268775f9c | ||
|
|
710739c7d2 | ||
|
|
c54db48c0d | ||
|
|
903145a4ae | ||
|
|
43f188c8a7 |
@@ -1,5 +1,12 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.42",
|
||||
"version": "3.2.43",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @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
|
||||
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://blx.org",
|
||||
"shortName": "blxq",
|
||||
"shortName": "tblxq",
|
||||
"chainId": 1107,
|
||||
"networkId": 1107,
|
||||
"explorers": [
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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": [
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
@@ -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": {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "The Krest Network",
|
||||
"chain": "Krest",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreid3bhzhughhjwq3rpgiic5zesj5mekqktawt646itdyqtvjxoupca",
|
||||
"width": 257,
|
||||
"height": 257,
|
||||
"format": "svg"
|
||||
},
|
||||
"rpc": [
|
||||
"https://the-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": "the-krest-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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": {
|
||||
|
||||
@@ -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/"
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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": [
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -27,8 +27,8 @@ export default {
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Celoscan",
|
||||
"url": "https://celoscan.io",
|
||||
"name": "Alfajoresscan",
|
||||
"url": "https://alfajores.celoscan.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.52",
|
||||
"version": "0.1.53",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -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
@@ -1,5 +1,17 @@
|
||||
# thirdweb
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.5",
|
||||
"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",
|
||||
|
||||
@@ -1,5 +1,63 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.15.0",
|
||||
"version": "3.16.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -90,6 +90,7 @@ type ThirdwebWalletContextData = {
|
||||
*/
|
||||
getWalletConfig: (walletInstance: WalletInstance) => WalletConfig | undefined;
|
||||
activeChainSetExplicitly: boolean;
|
||||
clientId?: string;
|
||||
};
|
||||
|
||||
const ThirdwebWalletContext = /* @__PURE__ */ createContext<
|
||||
@@ -483,6 +484,7 @@ export function ThirdwebWalletProvider(
|
||||
return walletInstanceToConfig.get(walletInstance);
|
||||
},
|
||||
activeChainSetExplicitly: props.activeChainSetExplicitly,
|
||||
clientId: props.clientId,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.62
|
||||
|
||||
## 0.2.61
|
||||
|
||||
## 0.2.60
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.61",
|
||||
"version": "0.2.62",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 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/react-core@3.16.0
|
||||
- @thirdweb-dev/chains@0.1.53
|
||||
- @thirdweb-dev/wallets@1.3.0
|
||||
- @thirdweb-dev/sdk@3.10.62
|
||||
|
||||
## 0.2.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.61",
|
||||
"version": "0.2.62",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -42,6 +42,7 @@
|
||||
"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",
|
||||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
|
||||
@@ -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,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,113 @@
|
||||
export const LOCAL_WALLET_ICON = `<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="16" cy="16" r="16" fill="url(#paint0_linear_2103_3904)"/>
|
||||
<rect x="14" y="22" width="4" height="3" fill="#E6DEFC"/>
|
||||
<path d="M11 26C10.45 26 9.979 25.8218 9.587 25.4655C9.195 25.1091 8.99934 24.6812 9 24.1818V7.81818C9 7.31818 9.196 6.89 9.588 6.53364C9.98 6.17727 10.4507 5.9994 11 6H21C21.55 6 22.021 6.17818 22.413 6.53455C22.805 6.89091 23.0007 7.31879 23 7.81818V24.1818C23 24.6818 22.804 25.11 22.412 25.4664C22.02 25.8227 21.5493 26.0006 21 26H11ZM16 23.7273C16.2833 23.7273 16.521 23.64 16.713 23.4655C16.905 23.2909 17.0007 23.0751 17 22.8182C17 22.5606 16.904 22.3445 16.712 22.17C16.52 21.9955 16.2827 21.9085 16 21.9091C15.7167 21.9091 15.479 21.9964 15.287 22.1709C15.095 22.3455 14.9993 22.5612 15 22.8182C15 23.0758 15.096 23.2918 15.288 23.4664C15.48 23.6409 15.7173 23.7279 16 23.7273ZM11 17.6364C11 18.7409 11.8954 19.6364 13 19.6364H19C20.1046 19.6364 21 18.7409 21 17.6364V12.5455C21 11.4409 20.1046 10.5455 19 10.5455H13C11.8954 10.5455 11 11.4409 11 12.5455V17.6364Z" fill="black"/>
|
||||
<path d="M11 26C10.45 26 9.979 25.8218 9.587 25.4655C9.195 25.1091 8.99934 24.6812 9 24.1818V7.81818C9 7.31818 9.196 6.89 9.588 6.53364C9.98 6.17727 10.4507 5.9994 11 6H21C21.55 6 22.021 6.17818 22.413 6.53455C22.805 6.89091 23.0007 7.31879 23 7.81818V24.1818C23 24.6818 22.804 25.11 22.412 25.4664C22.02 25.8227 21.5493 26.0006 21 26H11ZM16 23.7273C16.2833 23.7273 16.521 23.64 16.713 23.4655C16.905 23.2909 17.0007 23.0751 17 22.8182C17 22.5606 16.904 22.3445 16.712 22.17C16.52 21.9955 16.2827 21.9085 16 21.9091C15.7167 21.9091 15.479 21.9964 15.287 22.1709C15.095 22.3455 14.9993 22.5612 15 22.8182C15 23.0758 15.096 23.2918 15.288 23.4664C15.48 23.6409 15.7173 23.7279 16 23.7273ZM11 17.6364C11 18.7409 11.8954 19.6364 13 19.6364H19C20.1046 19.6364 21 18.7409 21 17.6364V12.5455C21 11.4409 20.1046 10.5455 19 10.5455H13C11.8954 10.5455 11 11.4409 11 12.5455V17.6364Z" fill="url(#paint1_linear_2103_3904)"/>
|
||||
<rect x="11" y="8" width="10" height="16" rx="1.5" fill="#BB0FAE"/>
|
||||
<rect x="13" y="9" width="6" height="2" rx="1" fill="#F8F5FF"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_2103_3904" x1="15" y1="-9.12696e-08" x2="15" y2="35.5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#D311AA"/>
|
||||
<stop offset="1" stop-color="#8409B7"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_2103_3904" x1="16" y1="6" x2="16" y2="26" 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,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;
|
||||
@@ -8,7 +8,7 @@ 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";
|
||||
@@ -16,6 +16,7 @@ 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 = {
|
||||
/**
|
||||
@@ -45,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 = ({
|
||||
@@ -57,6 +77,7 @@ export const ConnectWallet = ({
|
||||
switchToActiveChain,
|
||||
termsOfServiceUrl,
|
||||
privacyPolicyUrl,
|
||||
supportedTokens,
|
||||
}: ConnectWalletProps) => {
|
||||
const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||
const address = useAddress();
|
||||
@@ -81,6 +102,20 @@ export const ConnectWallet = ({
|
||||
}
|
||||
}, [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 }}>
|
||||
@@ -115,6 +150,7 @@ export const ConnectWallet = ({
|
||||
detailsButton={detailsButton}
|
||||
extraRows={extraRows}
|
||||
hideTestnetFaucet={hideTestnetFaucet}
|
||||
supportedTokens={supportedTokensMemo}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
||||
@@ -113,7 +113,7 @@ const ConnectAppField = () => {
|
||||
{!appMeta && showWCInput ? (
|
||||
<Box
|
||||
flexDirection="row"
|
||||
mb="sm"
|
||||
mt="xs"
|
||||
borderColor="border"
|
||||
borderWidth={1}
|
||||
borderRadius="md"
|
||||
@@ -157,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} />
|
||||
|
||||
+31
-1
@@ -23,6 +23,10 @@ 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";
|
||||
|
||||
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
|
||||
const DEVICE_WIDTH = Dimensions.get("window").width;
|
||||
@@ -33,12 +37,16 @@ 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 [isExportModalVisible, setIsExportModalVisible] = useState(false);
|
||||
const activeWallet = useWallet();
|
||||
@@ -49,6 +57,11 @@ export const ConnectWalletDetailsModal = ({
|
||||
const [isImportModalVisible, setIsImportModalVisible] = useState(false);
|
||||
const setConnectedWallet = useSetConnectedWallet();
|
||||
|
||||
const tokenAddress =
|
||||
chain?.chainId && displayBalanceToken
|
||||
? displayBalanceToken[chain?.chainId]
|
||||
: undefined;
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
if (addressCopied) {
|
||||
@@ -181,10 +194,15 @@ export const ConnectWalletDetailsModal = ({
|
||||
onClose={onExportModalClose}
|
||||
/>
|
||||
<WalletDetailsModalHeader
|
||||
tokenAddress={tokenAddress}
|
||||
address={address}
|
||||
onDisconnectPress={onDisconnectPress}
|
||||
onAddressCopied={onAddressCopied}
|
||||
/>
|
||||
<Box flexDirection="row" justifyContent="space-evenly" mt="md">
|
||||
<SendButton supportedTokens={supportedTokens} />
|
||||
<ReceiveButton />
|
||||
</Box>
|
||||
<View style={styles.currentNetwork}>
|
||||
<Text variant="bodySmallSecondary">Current Network</Text>
|
||||
</View>
|
||||
@@ -193,7 +211,7 @@ export const ConnectWalletDetailsModal = ({
|
||||
<IconTextButton
|
||||
mt="xs"
|
||||
text="Request Testnet Funds"
|
||||
icon={<MoneyIcon height={10} width={10} />}
|
||||
icon={<MoneyIcon height={16} width={16} />}
|
||||
onPress={() => {
|
||||
if (chain?.faucets?.[0]) {
|
||||
Linking.openURL(chain.faucets[0]);
|
||||
@@ -201,6 +219,18 @@ export const ConnectWalletDetailsModal = ({
|
||||
}}
|
||||
/>
|
||||
) : 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 ? (
|
||||
|
||||
+18
-35
@@ -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}
|
||||
|
||||
+36
-27
@@ -1,21 +1,39 @@
|
||||
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 { useWallet } from "@thirdweb-dev/react-core";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { LocalWallet } from "@thirdweb-dev/wallets";
|
||||
import Box from "../base/Box";
|
||||
import { ConnectWalletDetailsModal } from "./ConnectWalletDetailsModal";
|
||||
import { useState } from "react";
|
||||
import { TextBalance } from "../base/TextBalance";
|
||||
import { SupportedTokens } from "../SendFunds/defaultTokens";
|
||||
|
||||
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,21 +41,13 @@ export const WalletDetailsButton = ({
|
||||
detailsButton,
|
||||
extraRows,
|
||||
hideTestnetFaucet,
|
||||
supportedTokens,
|
||||
displayBalanceToken,
|
||||
}: ConnectWalletDetailsProps) => {
|
||||
const activeWallet = useWallet();
|
||||
const chain = useChain();
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
||||
const onPress = () => {
|
||||
// setModalState({
|
||||
// view: "WalletDetails",
|
||||
// data: {
|
||||
// address: address,
|
||||
// },
|
||||
// isOpen: true,
|
||||
// isSheet: true,
|
||||
// caller: "ConnectWalletDetails",
|
||||
// });
|
||||
setIsModalVisible(!isModalVisible);
|
||||
};
|
||||
|
||||
@@ -49,6 +59,8 @@ export const WalletDetailsButton = ({
|
||||
extraRows={extraRows}
|
||||
address={address}
|
||||
hideTestnetFaucet={hideTestnetFaucet}
|
||||
supportedTokens={supportedTokens}
|
||||
displayBalanceToken={displayBalanceToken}
|
||||
/>
|
||||
{detailsButton ? (
|
||||
detailsButton({ onPress })
|
||||
@@ -59,28 +71,25 @@ 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" justifyContent="flex-start">
|
||||
<WalletIcon
|
||||
size={32}
|
||||
iconUri={activeWallet?.getMeta().iconURL || ""}
|
||||
/>
|
||||
<Box ml="md" justifyContent="center" alignItems="flex-start">
|
||||
{activeWallet?.walletId === LocalWallet.id ? (
|
||||
<Text variant="error">Guest</Text>
|
||||
<Text variant="bodySmall" color="red">
|
||||
Guest
|
||||
</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>
|
||||
)}
|
||||
|
||||
+6
-1
@@ -16,12 +16,14 @@ interface WalletDetailsModalHeaderProps {
|
||||
onDisconnectPress: () => void;
|
||||
onAddressCopied?: () => void;
|
||||
loading?: boolean;
|
||||
tokenAddress?: string;
|
||||
}
|
||||
|
||||
export const WalletDetailsModalHeader = ({
|
||||
address,
|
||||
onDisconnectPress,
|
||||
onAddressCopied,
|
||||
tokenAddress,
|
||||
}: WalletDetailsModalHeaderProps) => {
|
||||
const theme = useAppTheme();
|
||||
const activeWallet = useWallet();
|
||||
@@ -66,7 +68,10 @@ export const WalletDetailsModalHeader = ({
|
||||
color={theme.colors.textSecondary}
|
||||
/>
|
||||
</Box>
|
||||
<TextBalance textVariant="bodySmallSecondary" />
|
||||
<TextBalance
|
||||
textVariant="bodySmallSecondary"
|
||||
tokenAddress={tokenAddress}
|
||||
/>
|
||||
</BaseButton>
|
||||
{showLoading ? (
|
||||
<ActivityIndicator size="small" color={theme.colors.iconHighlight} />
|
||||
|
||||
+3
-2
@@ -1,5 +1,4 @@
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { localWallet } from "../../../wallets/wallets/local-wallet";
|
||||
import { ModalHeaderTextClose } from "../../base/modal/ModalHeaderTextClose";
|
||||
import { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { ReactNode, useState } from "react";
|
||||
@@ -53,7 +52,9 @@ export function ChooseWallet({
|
||||
const onContinueAsGuestPress = () => {
|
||||
setIsConnecting(true);
|
||||
setTimeout(() => {
|
||||
onChooseWallet(localWallet());
|
||||
if (guestWallet) {
|
||||
onChooseWallet(guestWallet);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ 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 {
|
||||
@@ -60,10 +59,8 @@ export const ConnectWalletFlow = () => {
|
||||
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);
|
||||
}
|
||||
},
|
||||
@@ -85,10 +82,6 @@ export const ConnectWalletFlow = () => {
|
||||
resetModal();
|
||||
}, []);
|
||||
|
||||
const onConnected = useCallback(() => {
|
||||
onClose(true);
|
||||
}, [onClose]);
|
||||
|
||||
const resetModal = () => {
|
||||
setActiveWallet(undefined);
|
||||
setIsConnecting(false);
|
||||
@@ -99,11 +92,6 @@ 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
|
||||
@@ -125,8 +113,6 @@ export const ConnectWalletFlow = () => {
|
||||
handleClose,
|
||||
modalVisible,
|
||||
onBackPress,
|
||||
onClose,
|
||||
onConnected,
|
||||
selectionData,
|
||||
supportedWallets,
|
||||
theme,
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ export function ConnectingWallet({
|
||||
subHeaderText={subHeaderText}
|
||||
onClose={onClose}
|
||||
/>
|
||||
<WalletLoadingThumbnail imageSize={80}>
|
||||
<WalletLoadingThumbnail imageSize={100}>
|
||||
<ImageSvgUri height={80} width={80} imageUrl={wallet.meta.iconURL} />
|
||||
</WalletLoadingThumbnail>
|
||||
<View style={styles.connectingContainer}>
|
||||
@@ -42,7 +42,7 @@ export function ConnectingWallet({
|
||||
Connecting your wallet
|
||||
</Text>
|
||||
<Text variant="bodySmallSecondary" mt="lg" textAlign="center">
|
||||
Login and connect your wallet through the metamask pop-up
|
||||
{`Login and connect your wallet through the ${wallet.meta.name} pop-up`}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
+102
-156
@@ -1,121 +1,83 @@
|
||||
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 { StyleSheet, View } from "react-native";
|
||||
import BaseButton from "../../base/BaseButton";
|
||||
import Text from "../../base/Text";
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import { DEFAULT_WALLETS } from "../../../constants/wallets";
|
||||
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";
|
||||
|
||||
export const SmartWalletFlow = ({
|
||||
onClose,
|
||||
onConnect,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
onConnect: () => void;
|
||||
}) => {
|
||||
const [showLocalWalletFlow, setShowLocalWalletFlow] = useState<boolean>();
|
||||
close,
|
||||
goBack,
|
||||
walletConfig,
|
||||
}: ConnectUIProps<SmartWallet>) => {
|
||||
const [connectedPersonalWallet, setConnectedPersonalWallet] =
|
||||
useState<WalletInstance>();
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [personalWalletChainId, setPersonalWalletChaindId] = useState<
|
||||
number | undefined
|
||||
>();
|
||||
const theme = useAppTheme();
|
||||
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 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]) {
|
||||
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);
|
||||
};
|
||||
}, [connectPersonalWallet, walletConfig.personalWallets]);
|
||||
|
||||
const onConnectingClosePress = () => {
|
||||
connectedPersonalWallet?.disconnect();
|
||||
reset();
|
||||
close();
|
||||
};
|
||||
|
||||
const onConnectingBackPress = () => {
|
||||
connectedPersonalWallet?.disconnect();
|
||||
reset();
|
||||
goBack();
|
||||
};
|
||||
|
||||
const onSwitchNetworkPress = async () => {
|
||||
@@ -124,90 +86,74 @@ export const SmartWalletFlow = ({
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setIsConnecting(false);
|
||||
setConnectedPersonalWallet(undefined);
|
||||
setPersonalWalletChaindId(undefined);
|
||||
};
|
||||
|
||||
const onLearnMorePress = () => {
|
||||
Linking.openURL("https://portal.thirdweb.com/wallet/smart-wallet");
|
||||
};
|
||||
|
||||
if (isConnecting) {
|
||||
return (
|
||||
<>
|
||||
<ModalHeaderTextClose
|
||||
marginHorizontal="xl"
|
||||
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
|
||||
modalSize="compact"
|
||||
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
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ChooseWallet
|
||||
headerText={"Link key"}
|
||||
subHeaderText={
|
||||
<Text variant="subHeader" marginHorizontal="xl">
|
||||
{
|
||||
"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.
|
||||
<>
|
||||
<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">
|
||||
{mismatch
|
||||
? "Network Mismatch"
|
||||
: `Connecting ${walletConfig.meta.name}`}
|
||||
</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="flex-start"
|
||||
alignItems="center"
|
||||
paddingHorizontal="md"
|
||||
paddingVertical="sm"
|
||||
borderRadius="sm"
|
||||
backgroundColor="backgroundHighlight"
|
||||
onPress={onSwitchNetworkPress}
|
||||
>
|
||||
<Text variant="bodyLarge" textAlign="center">
|
||||
Switch Network
|
||||
</Text>
|
||||
</Text>
|
||||
}
|
||||
wallets={walletObj.personalWallets || DEFAULT_WALLETS}
|
||||
onChooseWallet={onChoosePersonalWallet}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</BaseButton>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
connectingContainer: {
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 4,
|
||||
marginBottom: 24,
|
||||
marginTop: 18,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
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";
|
||||
|
||||
// type SendButtonProps = {
|
||||
// chain?: Chain;
|
||||
// onPress?: () => void;
|
||||
// switchChainOnPress?: boolean;
|
||||
// onChainSwitched?: () => void;
|
||||
// };
|
||||
|
||||
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
|
||||
onBackPress={onCloseInternal}
|
||||
headerText="Receive Funds"
|
||||
/>
|
||||
<Text
|
||||
variant="bodySmallSecondary"
|
||||
textAlign="center"
|
||||
mt="md"
|
||||
marginHorizontal="xmd"
|
||||
>
|
||||
Paste the wallet address or scan the QR code to send funds to this
|
||||
wallet.
|
||||
</Text>
|
||||
<Text mt="lg" variant="bodySmallSecondary">
|
||||
Current Network
|
||||
</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" />
|
||||
<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="md"
|
||||
>
|
||||
{props.token?.icon ? (
|
||||
<ImageSvgUri width={32} height={32} imageUrl={props.token.icon} />
|
||||
) : (
|
||||
<ChainIcon chainIconUrl={chain?.icon?.url} size={32} active={false} />
|
||||
)}
|
||||
<Box ml="md" alignItems="flex-start" justifyContent="center" height={36}>
|
||||
<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,360 @@
|
||||
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 } 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 [token, setToken] = useState<TokenInfo | undefined>();
|
||||
const [showTokenSelector, setShowTokenSelector] = useState(false);
|
||||
|
||||
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
|
||||
onBackPress={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}
|
||||
active={false}
|
||||
/>
|
||||
)}
|
||||
<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,
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -22,7 +22,11 @@ export const IconTextButton = ({
|
||||
<BaseButton
|
||||
p={p || "sm"}
|
||||
backgroundColor="background"
|
||||
style={styles.networkContainer}
|
||||
borderRadius="md"
|
||||
borderWidth={0.5}
|
||||
flexDirection="row"
|
||||
justifyContent="flex-start"
|
||||
alignItems="center"
|
||||
onPress={onPress}
|
||||
borderColor="border"
|
||||
{...args}
|
||||
@@ -38,14 +42,6 @@ export const IconTextButton = ({
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
networkText: {
|
||||
marginLeft: 16,
|
||||
},
|
||||
networkContainer: {
|
||||
borderRadius: 8,
|
||||
borderWidth: 0.5,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
marginLeft: 8,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useStorage } from "@thirdweb-dev/react-core";
|
||||
import { useState } from "react";
|
||||
import { Image } from "react-native";
|
||||
import { SvgUri } from "react-native-svg";
|
||||
import { SvgUri, SvgXml } from "react-native-svg";
|
||||
import { isAppBundleIdPresentInGlobal } from "../../utils/global";
|
||||
import Box from "./Box";
|
||||
|
||||
@@ -17,6 +17,12 @@ const ImageSvgUri = ({
|
||||
imageAlt?: string;
|
||||
}) => {
|
||||
const storage = useStorage();
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
if (imageUrl.startsWith("<svg")) {
|
||||
return <SvgXml width={width} height={height} xml={imageUrl} />;
|
||||
}
|
||||
|
||||
const resolvedImageUrl = storage
|
||||
? storage.resolveScheme(imageUrl) +
|
||||
(isAppBundleIdPresentInGlobal()
|
||||
@@ -24,8 +30,6 @@ const ImageSvgUri = ({
|
||||
: "")
|
||||
: imageUrl.replace("ipfs://", "https://ipfs.io/ipfs/");
|
||||
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
if (!resolvedImageUrl || resolvedImageUrl === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ import { baseTheme } from "../../styles/theme";
|
||||
|
||||
type TextBalance = {
|
||||
textVariant: keyof typeof baseTheme.textVariants;
|
||||
tokenAddress?: string;
|
||||
};
|
||||
|
||||
export const TextBalance = ({ textVariant }: TextBalance) => {
|
||||
const balanceQuery = useBalance();
|
||||
export const TextBalance = ({ textVariant, tokenAddress }: TextBalance) => {
|
||||
const balanceQuery = useBalance(tokenAddress);
|
||||
|
||||
return !balanceQuery.data ? (
|
||||
<LoadingTextAnimation text="Fetching..." textVariant={textVariant} />
|
||||
|
||||
@@ -40,6 +40,5 @@ const styles = StyleSheet.create({
|
||||
textAlign: "left",
|
||||
flex: 1,
|
||||
height: 40,
|
||||
paddingLeft: 5,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -62,7 +62,6 @@ const styles = StyleSheet.create({
|
||||
alignContent: "center",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
alignSelf: "stretch",
|
||||
height: TOAST_HEIGHT,
|
||||
marginHorizontal: 10,
|
||||
padding: 10,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { View } from "react-native";
|
||||
import { Icon } from "../../../assets/icon";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import Box from "../Box";
|
||||
@@ -5,7 +6,7 @@ import Text from "../Text";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface ModalHeaderTextCloseProps {
|
||||
onClose: () => void;
|
||||
onClose?: () => void;
|
||||
headerText?: ReactNode | string;
|
||||
subHeaderText?: ReactNode | string;
|
||||
onBackPress?: () => void;
|
||||
@@ -41,13 +42,17 @@ export const ModalHeaderTextClose = ({
|
||||
) : (
|
||||
headerText
|
||||
)}
|
||||
<Icon
|
||||
type="close"
|
||||
width={16}
|
||||
height={16}
|
||||
color={theme.colors.iconSecondary}
|
||||
onPress={onClose}
|
||||
/>
|
||||
{onClose ? (
|
||||
<Icon
|
||||
type="close"
|
||||
width={16}
|
||||
height={16}
|
||||
color={theme.colors.iconSecondary}
|
||||
onPress={onClose}
|
||||
/>
|
||||
) : (
|
||||
<View />
|
||||
)}
|
||||
</Box>
|
||||
<Box flexDirection="row" justifyContent="space-between" mt="md">
|
||||
{typeof subHeaderText === "string" ? (
|
||||
|
||||
@@ -72,8 +72,15 @@ export const ThirdwebProvider = <
|
||||
...restProps
|
||||
}: PropsWithChildren<ThirdwebProviderProps<TChains>>) => {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const coinbaseWalletObj = supportedWallets.find(
|
||||
(w) => w.id === walletIds.coinbase,
|
||||
);
|
||||
useCoinbaseWalletListener(
|
||||
!!supportedWallets.find((w) => w.id === walletIds.coinbase),
|
||||
!!coinbaseWalletObj,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
coinbaseWalletObj?.config?.callbackURL,
|
||||
);
|
||||
|
||||
const hasMagicConfig = useMemo(
|
||||
|
||||
@@ -11,15 +11,14 @@ import { useCoinbaseWalletListener } from "./useCoinbaseWalletListener";
|
||||
* @param callbackURL The Universal Link used by Coinbase Wallet to return responses to your application.
|
||||
* @returns connect function to connect to the Coinbase wallet
|
||||
*/
|
||||
export function useCoinbaseWallet(callbackURL: string) {
|
||||
export function useCoinbaseWallet(callbackURL: URL) {
|
||||
const connect = useConnect();
|
||||
useCoinbaseWalletListener(true);
|
||||
useCoinbaseWalletListener(true, callbackURL);
|
||||
|
||||
return useCallback(
|
||||
async (connectOptions?: { chainId?: number; callbackURL: string }) => {
|
||||
async (connectOptions?: { chainId?: number }) => {
|
||||
const { coinbaseWallet } = await import("../wallets/coinbase-wallet");
|
||||
return connect(
|
||||
// @ts-expect-error - Passing a URL object to callbackURL crashes the function @fixme: @manan
|
||||
coinbaseWallet({ callbackURL: callbackURL }),
|
||||
connectOptions,
|
||||
);
|
||||
|
||||
@@ -7,16 +7,24 @@ import { Linking } from "react-native";
|
||||
*
|
||||
* This hook sets up the UniversalLinks listener.
|
||||
*/
|
||||
export function useCoinbaseWalletListener(enable: boolean) {
|
||||
export function useCoinbaseWalletListener(enable: boolean, callbackURL?: URL) {
|
||||
useEffect(() => {
|
||||
if (!enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sub = Linking.addEventListener("url", ({ url }) => {
|
||||
// @ts-expect-error - Passing a URL object to handleResponse crashes the function
|
||||
handleResponse(url);
|
||||
const incomingUrl = new URL(url);
|
||||
if (
|
||||
callbackURL &&
|
||||
incomingUrl.host === callbackURL.host &&
|
||||
incomingUrl.protocol === callbackURL.protocol &&
|
||||
incomingUrl.hostname === callbackURL.hostname
|
||||
) {
|
||||
// @ts-expect-error - Passing a URL object to handleResponse crashes the function
|
||||
handleResponse(url);
|
||||
}
|
||||
});
|
||||
return () => sub?.remove();
|
||||
}, [enable]);
|
||||
}, [callbackURL, enable]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import {
|
||||
SmartWallet,
|
||||
SmartWalletConfig as SmartWalletConfigWallets,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
|
||||
export type SmartWalletConfig = Omit<
|
||||
SmartWalletConfigWallets,
|
||||
"chain" | "clientId" | "secretKey"
|
||||
>;
|
||||
|
||||
export type SmartWalletObj = WalletConfig<SmartWallet>;
|
||||
@@ -3,12 +3,12 @@ import {
|
||||
Connector,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { ethers, utils } from "ethers";
|
||||
import { LOCAL_WALLET_ICON } from "../../assets/svgs";
|
||||
|
||||
export class LocalWallet extends LocalWalletCore {
|
||||
static meta = {
|
||||
name: "Guest Wallet",
|
||||
iconURL:
|
||||
"ipfs://QmQAyJG3y2wZf9u6JXxn8U9Kd1ZVfjtQkf5aua8FcWr8Gm/local-wallet-mobile.svg",
|
||||
iconURL: LOCAL_WALLET_ICON,
|
||||
};
|
||||
|
||||
getMeta() {
|
||||
|
||||
@@ -11,10 +11,8 @@ import {
|
||||
WalletOptions,
|
||||
walletIds,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import {
|
||||
WalletConfig,
|
||||
WalletOptions as WalletOptionsRC,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { WalletOptions as WalletOptionsRC } from "@thirdweb-dev/react-core";
|
||||
import { COINBASE_ICON } from "../../assets/svgs";
|
||||
|
||||
type CoinbaseWalletOptions = Omit<
|
||||
WalletOptions<CoinbaseWalletConnectorOptions>,
|
||||
@@ -24,8 +22,7 @@ type CoinbaseWalletOptions = Omit<
|
||||
export class CoinbaseWallet extends AbstractClientWallet<CoinbaseWalletConnectorOptions> {
|
||||
static meta = {
|
||||
name: "Coinbase Wallet",
|
||||
iconURL:
|
||||
"ipfs://QmcJBHopbwfJcLqJpX2xEufSS84aLbF7bHavYhaXUcrLaH/coinbase.svg",
|
||||
iconURL: COINBASE_ICON,
|
||||
};
|
||||
|
||||
connector?: Connector;
|
||||
@@ -80,6 +77,7 @@ export const coinbaseWallet = (config?: {
|
||||
meta: CoinbaseWallet.meta,
|
||||
create: (options: WalletOptionsRC) =>
|
||||
new CoinbaseWallet({ ...options, callbackURL: callbackURLNonNull }),
|
||||
config: config,
|
||||
recommended: config?.recommended,
|
||||
} satisfies WalletConfig<CoinbaseWallet>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,13 +3,13 @@ import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WCMeta } from "../types/wc";
|
||||
import { WalletConnectBase } from "./wallet-connect/WalletConnectBase";
|
||||
import { WalletConnectConfig } from "./wallet-connect/wallet-connect";
|
||||
import { METAMASK_ICON } from "../../assets/svgs";
|
||||
|
||||
export class MetaMaskWallet extends WalletConnectBase {
|
||||
static id = walletIds.metamask;
|
||||
static meta = {
|
||||
name: "MetaMask",
|
||||
iconURL:
|
||||
"ipfs://QmZZHcw7zcXursywnLDAyY6Hfxzqop5GKgwoq8NB9jjrkN/metamask.svg",
|
||||
iconURL: METAMASK_ICON,
|
||||
links: {
|
||||
native: "metamask:",
|
||||
universal: "https://metamask.app.link",
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { WalletConnectBase } from "./wallet-connect/WalletConnectBase";
|
||||
import { WalletConnectConfig } from "./wallet-connect/wallet-connect";
|
||||
import { RAINBOW_ICON } from "../../assets/svgs";
|
||||
|
||||
export class RainbowWallet extends WalletConnectBase {
|
||||
static id = "rainbow" as const;
|
||||
static meta = {
|
||||
name: "Rainbow",
|
||||
iconURL:
|
||||
"ipfs://QmSZn47p4DVVBfzvg9BAX2EqwnPxkT1YAE7rUnrtd9CybQ/rainbow-logo.png",
|
||||
iconURL: RAINBOW_ICON,
|
||||
links: {
|
||||
native: "rainbow:",
|
||||
universal: "https://rnbwapp.com",
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import type { WalletConfig, WalletOptions } from "@thirdweb-dev/react-core";
|
||||
import {
|
||||
SmartWallet,
|
||||
SmartWalletConfig as SmartWalletConfigWallets,
|
||||
createAsyncLocalStorage,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { DEFAULT_WALLETS } from "../../constants/wallets";
|
||||
import { createSyncStorage } from "../../../core/AsyncStorage";
|
||||
|
||||
type SmartWalletConfig = {
|
||||
personalWallets?: WalletConfig<any>[];
|
||||
recommended?: boolean;
|
||||
} & Omit<SmartWalletConfigWallets, "chain" | "clientId" | "secretKey">;
|
||||
|
||||
export type SmartWalletObj = WalletConfig<SmartWallet>;
|
||||
|
||||
export const smartWallet = (
|
||||
config: SmartWalletConfig,
|
||||
): WalletConfig<SmartWallet> => {
|
||||
return {
|
||||
id: SmartWallet.id,
|
||||
meta: SmartWallet.meta,
|
||||
create: (options: WalletOptions) =>
|
||||
new SmartWallet({
|
||||
...options,
|
||||
...config,
|
||||
walletStorage: createAsyncLocalStorage("smart-wallet"),
|
||||
wcStorage: createSyncStorage("smart-wallet"),
|
||||
}),
|
||||
personalWallets: config.personalWallets || DEFAULT_WALLETS,
|
||||
recommended: config.recommended,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { WalletConfig, WalletOptions } from "@thirdweb-dev/react-core";
|
||||
import { SmartWallet, createAsyncLocalStorage } from "@thirdweb-dev/wallets";
|
||||
import { createSyncStorage } from "../../../core/AsyncStorage";
|
||||
import { SmartWalletConfig } from "../types/smart-wallet";
|
||||
import { SmartWalletFlow } from "../../components/ConnectWalletFlow/SmartWallet/SmartWalletFlow";
|
||||
|
||||
export const smartWallet = (
|
||||
wallet: WalletConfig<any>,
|
||||
config: SmartWalletConfig,
|
||||
): WalletConfig<SmartWallet> => {
|
||||
const WalletSelectUI = wallet.selectUI;
|
||||
|
||||
return {
|
||||
...wallet,
|
||||
create: (options: WalletOptions) =>
|
||||
new SmartWallet({
|
||||
...options,
|
||||
...config,
|
||||
walletStorage: createAsyncLocalStorage("smart-wallet"),
|
||||
wcStorage: createSyncStorage("smart-wallet"),
|
||||
}),
|
||||
connectUI(props) {
|
||||
return <SmartWalletFlow {...props} />;
|
||||
},
|
||||
selectUI: WalletSelectUI
|
||||
? (props) => {
|
||||
return <WalletSelectUI {...props} walletConfig={wallet} />;
|
||||
}
|
||||
: undefined,
|
||||
personalWallets: [wallet],
|
||||
};
|
||||
};
|
||||
@@ -2,13 +2,13 @@ import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WCMeta } from "../types/wc";
|
||||
import { WalletConnectBase } from "./wallet-connect/WalletConnectBase";
|
||||
import { WalletConnectConfig } from "./wallet-connect/wallet-connect";
|
||||
import { TRUST_ICON } from "../../assets/svgs";
|
||||
|
||||
export class TrustWallet extends WalletConnectBase {
|
||||
static id = "trust" as const;
|
||||
static meta = {
|
||||
name: "Trust Wallet",
|
||||
iconURL:
|
||||
"ipfs://QmNigQbXk7wKZwDcgN38Znj1ZZQ3JEG3DD6fUKLBU8SUTP/trust%20wallet.svg",
|
||||
iconURL: TRUST_ICON,
|
||||
links: {
|
||||
native: "trust:",
|
||||
universal: "https://link.trustwallet.com",
|
||||
|
||||
+10
-7
@@ -5,6 +5,9 @@ import { useAppTheme } from "../../../styles/hooks";
|
||||
|
||||
const AnimatedRect = Animated.createAnimatedComponent(Rect);
|
||||
|
||||
const PADDING = 10;
|
||||
const INTERNAL_PADDING = 6;
|
||||
|
||||
interface Props {
|
||||
children?: React.ReactNode;
|
||||
imageSize?: number;
|
||||
@@ -43,16 +46,16 @@ function WalletLoadingThumbnail({
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Svg
|
||||
width={imageSize + 10}
|
||||
height={imageSize + 10}
|
||||
viewBox={`0 0 ${imageSize + 10} ${imageSize + 10}`}
|
||||
width={imageSize + PADDING}
|
||||
height={imageSize + PADDING}
|
||||
viewBox={`0 0 ${imageSize + PADDING} ${imageSize + PADDING}`}
|
||||
style={styles.loader}
|
||||
>
|
||||
<AnimatedRect
|
||||
x="2"
|
||||
y="2"
|
||||
width={imageSize + 6}
|
||||
height={imageSize + 6}
|
||||
width={imageSize + INTERNAL_PADDING}
|
||||
height={imageSize + INTERNAL_PADDING}
|
||||
rx={15}
|
||||
stroke={showError ? "transparent" : Theme.colors.linkPrimary}
|
||||
strokeWidth={2}
|
||||
@@ -67,8 +70,8 @@ function WalletLoadingThumbnail({
|
||||
{
|
||||
position: "absolute",
|
||||
borderWidth: 2,
|
||||
height: imageSize + 6,
|
||||
width: imageSize + 6,
|
||||
height: imageSize + INTERNAL_PADDING,
|
||||
width: imageSize + INTERNAL_PADDING,
|
||||
borderRadius: 30 / 3.5,
|
||||
borderColor: Theme.colors.border,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,80 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.16.0
|
||||
|
||||
### Minor 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
|
||||
|
||||
- [#1622](https://github.com/thirdweb-dev/js/pull/1622) [`4268775f`](https://github.com/thirdweb-dev/js/commit/4268775f9c81d559e19af72887b1f2d1fb893e51) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - feat(react): add `embeddedWallet` wallet type
|
||||
|
||||
- [#1598](https://github.com/thirdweb-dev/js/pull/1598) [`43f188c8`](https://github.com/thirdweb-dev/js/commit/43f188c8a7ec02f394604120b414a039a2650525) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - feat(wallets): Add `EmbeddedWallet` and `EmbeddedWalletConnector` to `@thirdweb-dev/wallets` for use in vanilla JS clients
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1650](https://github.com/thirdweb-dev/js/pull/1650) [`1018eb56`](https://github.com/thirdweb-dev/js/commit/1018eb56a6560d97a2768b1d6d726082cd91a728) Thanks [@MananTank](https://github.com/MananTank)! - - show the first token given to `supportedTokens` as the default selected token in the "Send Funds" screen
|
||||
|
||||
- Show smart wallet icon in "Receive Funds" screen when connected to a smart wallet
|
||||
- only show "Connected to smart wallet" link if the smart wallet is deployed
|
||||
|
||||
- [#1653](https://github.com/thirdweb-dev/js/pull/1653) [`bd18e4f5`](https://github.com/thirdweb-dev/js/commit/bd18e4f5ef0378cc141009287d3555b4445081dd) Thanks [@MananTank](https://github.com/MananTank)! - NetworkSelector component UI tweaks
|
||||
|
||||
- [#1659](https://github.com/thirdweb-dev/js/pull/1659) [`ea5b9c3e`](https://github.com/thirdweb-dev/js/commit/ea5b9c3ecdd588461fb00f0e9da463de4a30ed1d) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - fix(wallets/react): Show recovery modal for `USER_MANAGED` wallets in `paperWallet` implementation
|
||||
|
||||
- [#1664](https://github.com/thirdweb-dev/js/pull/1664) [`a9854e69`](https://github.com/thirdweb-dev/js/commit/a9854e69ced6657db758b7b000a5b12580276370) Thanks [@MananTank](https://github.com/MananTank)! - Fix Img component crashing app on invalid URL
|
||||
|
||||
- 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]
|
||||
|
||||
## 3.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.15.0",
|
||||
"version": "3.16.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -9,6 +9,7 @@ export const CopyIcon: React.FC<{
|
||||
tip: string;
|
||||
side?: "top" | "bottom" | "left" | "right";
|
||||
align?: "start" | "center" | "end";
|
||||
hasCopied?: boolean;
|
||||
}> = (props) => {
|
||||
const { hasCopied, onCopy } = useClipboard(props.text);
|
||||
|
||||
@@ -22,7 +23,7 @@ export const CopyIcon: React.FC<{
|
||||
}}
|
||||
>
|
||||
<ToolTip tip={props.tip} side={props.side} align={props.align}>
|
||||
{hasCopied ? <CheckIconStyled /> : <CopyIconSVG />}
|
||||
{props.hasCopied || hasCopied ? <CheckIconStyled /> : <CopyIconSVG />}
|
||||
</ToolTip>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { UploadIcon } from "@radix-ui/react-icons";
|
||||
import { Theme, fontSize, iconSize, radius, spacing } from "../design-system";
|
||||
import { Theme, iconSize, radius, spacing } from "../design-system";
|
||||
import styled from "@emotion/styled";
|
||||
import { Spacer } from "./Spacer";
|
||||
import { isMobile } from "../evm/utils/isMobile";
|
||||
import type { IconFC } from "../wallet/ConnectWallet/icons/types";
|
||||
import { Text } from "./text";
|
||||
import { Container } from "./basic";
|
||||
|
||||
export const DragNDrop: React.FC<{
|
||||
extension: string;
|
||||
@@ -93,30 +95,29 @@ export const DragNDrop: React.FC<{
|
||||
{" "}
|
||||
<UploadIconSecondary width={iconSize.lg} height={iconSize.lg} />
|
||||
<Spacer y="md" />
|
||||
<Message
|
||||
style={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
<Text color="primaryText" weight={600} center multiline>
|
||||
{" "}
|
||||
{message}
|
||||
</Message>
|
||||
<Spacer y="md" />
|
||||
</Text>
|
||||
<Spacer y="lg" />
|
||||
{error ? (
|
||||
<ErrorMessage>
|
||||
<Text color="danger" size="sm">
|
||||
{" "}
|
||||
Please upload a {props.extension} file{" "}
|
||||
</ErrorMessage>
|
||||
</Text>
|
||||
) : (
|
||||
<ExtensionText> {props.extension} </ExtensionText>
|
||||
<Text size="sm"> {props.extension} </Text>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Message>{uploaded.name} uploaded successfully</Message>
|
||||
<Text weight={600} color="primaryText" center multiline>
|
||||
{uploaded.name} uploaded successfully
|
||||
</Text>
|
||||
<Spacer y="md" />
|
||||
<CheckCircleIcon size={iconSize.xl} />
|
||||
<Container color="success">
|
||||
<CheckCircleIcon size={iconSize.xl} />
|
||||
</Container>
|
||||
</>
|
||||
)}
|
||||
</DropContainer>
|
||||
@@ -157,17 +158,6 @@ const DropContainer = styled.div<{ theme?: Theme }>`
|
||||
}
|
||||
`;
|
||||
|
||||
const ErrorMessage = styled.p<{ theme?: Theme }>`
|
||||
color: ${(p) => p.theme.colors.danger};
|
||||
font-size: ${fontSize.sm};
|
||||
margin: 0;
|
||||
`;
|
||||
|
||||
const ExtensionText = styled.span<{ theme?: Theme }>`
|
||||
color: ${(p) => p.theme.colors.secondaryText};
|
||||
font-size: ${fontSize.sm};
|
||||
`;
|
||||
|
||||
const CheckCircleIcon: IconFC = (props) => (
|
||||
<svg
|
||||
width={props.size}
|
||||
@@ -178,24 +168,17 @@ const CheckCircleIcon: IconFC = (props) => (
|
||||
>
|
||||
<path
|
||||
d="M35.6666 17.4671V19.0004C35.6645 22.5945 34.5008 26.0916 32.3488 28.9701C30.1969 31.8487 27.1721 33.9546 23.7255 34.9736C20.279 35.9926 16.5954 35.8703 13.224 34.6247C9.85272 33.3792 6.97434 31.0773 5.01819 28.0622C3.06203 25.0472 2.1329 21.4805 2.36938 17.8943C2.60586 14.308 3.99526 10.8943 6.33039 8.16221C8.66551 5.43012 11.8212 3.52606 15.3269 2.734C18.8326 1.94194 22.5004 2.30432 25.7833 3.76709"
|
||||
stroke="#5BD58C"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3.33333"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M35.6667 5.66699L19 22.3503L14 17.3503"
|
||||
stroke="#5BD58C"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3.33333"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const Message = styled.p<{ theme?: Theme }>`
|
||||
color: ${(p) => p.theme.colors.primaryText};
|
||||
font-size: ${fontSize.md};
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
@@ -10,15 +10,22 @@ export const Img: React.FC<{
|
||||
style?: React.CSSProperties;
|
||||
}> = (props) => {
|
||||
const storage = useStorage();
|
||||
|
||||
const getSrc = () => {
|
||||
try {
|
||||
return storage
|
||||
? storage.resolveScheme(props.src)
|
||||
: props.src.replace("ipfs://", "https://ipfs.io/ipfs/");
|
||||
} catch {
|
||||
return props.src;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<img
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
src={
|
||||
storage
|
||||
? storage.resolveScheme(props.src)
|
||||
: props.src.replace("ipfs://", "https://ipfs.io/ipfs/")
|
||||
}
|
||||
src={getSrc()}
|
||||
alt={props.alt || ""}
|
||||
loading={props.loading}
|
||||
decoding="async"
|
||||
@@ -26,6 +33,7 @@ export const Img: React.FC<{
|
||||
height: props.height ? props.height + "px" : undefined,
|
||||
width: props.width ? props.width + "px" : undefined,
|
||||
userSelect: "none",
|
||||
...props.style,
|
||||
}}
|
||||
draggable={false}
|
||||
className={props.className}
|
||||
|
||||
@@ -10,7 +10,7 @@ export const QRCode: React.FC<{
|
||||
QRIcon?: React.ReactNode;
|
||||
size?: number;
|
||||
}> = (props) => {
|
||||
const size = props.size || 280;
|
||||
const size = props.size || 310;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -24,7 +24,7 @@ export const QRCode: React.FC<{
|
||||
uri={props.qrCodeUri}
|
||||
size={size + 20}
|
||||
ecl="M"
|
||||
clearSize={70}
|
||||
clearSize={props.QRIcon ? 70 : undefined}
|
||||
/>
|
||||
</QRCodeContainer>
|
||||
) : (
|
||||
|
||||
@@ -14,11 +14,12 @@ export const Button = styled.button<{
|
||||
border-radius: ${radius.md};
|
||||
padding: ${fontSize.sm} ${fontSize.sm};
|
||||
font-size: ${fontSize.md};
|
||||
font-weight: ${(p) => (p.variant === "link" ? 400 : 500)};
|
||||
font-weight: 500;
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
line-height: 1;
|
||||
flex-shrink: 0;
|
||||
transition: border 200ms ease;
|
||||
|
||||
${(p) => p.fullWidth && `width: 100%;`};
|
||||
|
||||
@@ -56,6 +57,9 @@ export const Button = styled.button<{
|
||||
if (p.variant === "outline") {
|
||||
return `
|
||||
border: 1.5px solid ${p.theme.colors.borderColor};
|
||||
&:hover {
|
||||
border-color: ${p.theme.colors.accentText};
|
||||
}
|
||||
`;
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { fontSize, radius, spacing, Theme } from "../design-system";
|
||||
import { fontSize, radius, Theme, spacing } from "../design-system";
|
||||
import styled from "@emotion/styled";
|
||||
|
||||
export const Label = styled.label<{ theme?: Theme }>`
|
||||
export const Label = styled.label<{
|
||||
theme?: Theme;
|
||||
color?: keyof Theme["colors"];
|
||||
}>`
|
||||
font-size: ${fontSize.sm};
|
||||
color: ${(p) => p.theme.colors.primaryText};
|
||||
color: ${(p) => p.theme.colors[p.color || "primaryText"]};
|
||||
display: block;
|
||||
`;
|
||||
|
||||
export const Input = styled.input<{
|
||||
variant: "outline" | "transparent";
|
||||
sm?: boolean;
|
||||
theme?: Theme;
|
||||
}>`
|
||||
font-size: ${fontSize.md};
|
||||
display: block;
|
||||
padding: ${fontSize.sm};
|
||||
padding: ${(p) => (p.sm ? spacing.sm : fontSize.sm)};
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
@@ -106,17 +110,3 @@ export const InputContainer = styled.div<{ theme?: Theme }>`
|
||||
box-shadow: 0 0 0px 2px ${(p) => p.theme.colors.danger};
|
||||
}
|
||||
`;
|
||||
|
||||
export const ErrorMessage = styled.p<{ theme?: Theme }>`
|
||||
all: unset;
|
||||
font-size: ${fontSize.sm};
|
||||
display: block;
|
||||
color: ${(p) => p.theme.colors.danger};
|
||||
line-height: 1;
|
||||
`;
|
||||
|
||||
export const FormFooter = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: ${spacing.sm};
|
||||
`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Spacer } from "./Spacer";
|
||||
import { InputButton } from "./buttons";
|
||||
import { ErrorMessage, Input, InputContainer, Label } from "./formElements";
|
||||
import { Input, InputContainer, Label } from "./formElements";
|
||||
import { Text } from "./text";
|
||||
|
||||
export const FormFieldWithIconButton: React.FC<{
|
||||
name: string;
|
||||
@@ -27,6 +28,7 @@ export const FormFieldWithIconButton: React.FC<{
|
||||
|
||||
<InputContainer data-error={!!props.error}>
|
||||
<Input
|
||||
sm
|
||||
variant="transparent"
|
||||
required={props.required}
|
||||
name={props.name}
|
||||
@@ -54,7 +56,9 @@ export const FormFieldWithIconButton: React.FC<{
|
||||
{props.error && (
|
||||
<>
|
||||
<Spacer y="sm" />
|
||||
<ErrorMessage> {props.error} </ErrorMessage>
|
||||
<Text color="danger" size="sm">
|
||||
{props.error}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -96,7 +100,9 @@ export const FormField: React.FC<{
|
||||
{props.errorMessage && (
|
||||
<>
|
||||
<Spacer y="xs" />
|
||||
<ErrorMessage>{props.errorMessage}</ErrorMessage>
|
||||
<Text color="danger" size="sm">
|
||||
{props.errorMessage}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ export const Text = styled.span<{
|
||||
color: ${(p) => p.theme.colors[p.color || "secondaryText"]};
|
||||
margin: 0;
|
||||
display: ${(p) => (p.inline ? "inline" : "block")};
|
||||
font-weight: ${(p) => p.weight || 400};
|
||||
font-weight: ${(p) => p.weight || 500};
|
||||
line-height: ${(p) => (p.multiline ? 1.5 : 1)};
|
||||
${(p) => (p.center ? `text-align: center;` : "")};
|
||||
text-wrap: ${(p) => (p.balance ? "balance" : "inherit")};
|
||||
@@ -24,24 +24,25 @@ export const Text = styled.span<{
|
||||
export const Link = styled.a<{
|
||||
theme?: Theme;
|
||||
size?: keyof typeof fontSize;
|
||||
secondary?: boolean;
|
||||
weight?: 400 | 500 | 600 | 700;
|
||||
inline?: boolean;
|
||||
center?: boolean;
|
||||
color?: keyof Theme["colors"];
|
||||
hoverColor?: keyof Theme["colors"];
|
||||
}>`
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
color: ${(p) =>
|
||||
p.secondary ? p.theme.colors.secondaryText : p.theme.colors.accentText};
|
||||
color: ${(p) => p.theme.colors[p.color || "accentText"]};
|
||||
font-size: ${(p) => fontSize[p.size || "md"]};
|
||||
text-decoration: none;
|
||||
text-align: ${(p) => (p.center ? "center" : "left")};
|
||||
display: ${(p) => (p.inline ? "inline" : "block")};
|
||||
font-weight: ${(p) => p.weight || 400};
|
||||
font-weight: ${(p) => p.weight || 500};
|
||||
line-height: 1;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: ${(p) => p.theme.colors.primaryText};
|
||||
color: ${(p) => p.theme.colors[p.hoverColor || "primaryText"]};
|
||||
text-decoration: none;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2,15 +2,19 @@ import { useConnect } from "@thirdweb-dev/react-core";
|
||||
import type { SmartWalletConfigOptions } from "../../../wallet/wallets/smartWallet/types";
|
||||
import type { SmartWalletConnectionArgs } from "@thirdweb-dev/wallets/evm/wallets/smart-wallet";
|
||||
import { useCallback } from "react";
|
||||
import { WalletConfig } from "@thirdweb-dev/react-core/dist/declarations/src";
|
||||
|
||||
export function useSmartWallet() {
|
||||
const connect = useConnect();
|
||||
return useCallback(
|
||||
async (options: SmartWalletConnectionArgs & SmartWalletConfigOptions) => {
|
||||
async (
|
||||
wallet: WalletConfig<any>,
|
||||
options: SmartWalletConnectionArgs & SmartWalletConfigOptions,
|
||||
) => {
|
||||
const { smartWallet } = await import(
|
||||
"../../../wallet/wallets/smartWallet/smartWallet"
|
||||
);
|
||||
return connect(smartWallet(options), options);
|
||||
return connect(smartWallet(wallet, options), options);
|
||||
},
|
||||
[connect],
|
||||
);
|
||||
|
||||
@@ -71,7 +71,7 @@ export const ThirdwebProvider = <
|
||||
const theme = _theme || "dark";
|
||||
|
||||
return (
|
||||
<WalletUIStatesProvider theme={theme} modalSize="wide">
|
||||
<WalletUIStatesProvider theme={theme}>
|
||||
<CustomThemeProvider theme={theme}>
|
||||
<ThirdwebProviderCore
|
||||
{...restProps}
|
||||
|
||||
@@ -14,6 +14,7 @@ export type ModalConfig = {
|
||||
termsOfServiceUrl?: string;
|
||||
privacyPolicyUrl?: string;
|
||||
welcomeScreen?: WelcomeScreen;
|
||||
titleIconUrl?: string;
|
||||
};
|
||||
|
||||
const WalletModalOpen = /* @__PURE__ */ createContext(false);
|
||||
@@ -35,8 +36,9 @@ export const SetModalConfigCtx = /* @__PURE__ */ createContext<
|
||||
export const WalletUIStatesProvider = (
|
||||
props: React.PropsWithChildren<{
|
||||
theme?: "light" | "dark" | Theme;
|
||||
modalSize: "wide" | "compact";
|
||||
modalSize?: "wide" | "compact";
|
||||
title?: string;
|
||||
titleIconUrl?: string;
|
||||
termsOfServiceUrl?: string;
|
||||
privacyPolicyUrl?: string;
|
||||
welcomeScreen?: WelcomeScreen;
|
||||
@@ -49,10 +51,11 @@ export const WalletUIStatesProvider = (
|
||||
title: props.title || defaultModalTitle,
|
||||
theme: props.theme || "dark",
|
||||
data: undefined,
|
||||
modalSize: _isMobile ? "compact" : props.modalSize,
|
||||
modalSize: (_isMobile ? "compact" : props.modalSize) || "wide",
|
||||
termsOfServiceUrl: props.termsOfServiceUrl,
|
||||
privacyPolicyUrl: props.privacyPolicyUrl,
|
||||
welcomeScreen: props.welcomeScreen,
|
||||
titleIconUrl: props.titleIconUrl,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
export { defaultTokens } from "./wallet/ConnectWallet/defaultTokens";
|
||||
export { defaultWallets } from "./wallet/wallets/defaultWallets";
|
||||
|
||||
export { useSmartWallet } from "./evm/hooks/wallets/useSmartWallet";
|
||||
export { localWallet } from "./wallet/wallets/localWallet/localWallet";
|
||||
export { bloctoWallet } from "./wallet/wallets/blocto/bloctoWallet";
|
||||
export { coinbaseWallet } from "./wallet/wallets/coinbase/coinbaseWallet";
|
||||
export { embeddedWallet } from "./wallet/wallets/embeddedWallet/embeddedWallet";
|
||||
export { frameWallet } from "./wallet/wallets/frame/frameWallet";
|
||||
export { localWallet } from "./wallet/wallets/localWallet/localWallet";
|
||||
export { magicLink } from "./wallet/wallets/magic/magicLink";
|
||||
export { metamaskWallet } from "./wallet/wallets/metamask/metamaskWallet";
|
||||
export { phantomWallet } from "./wallet/wallets/phantom/phantomWallet";
|
||||
export { paperWallet } from "./wallet/wallets/paper/paperWallet";
|
||||
export { phantomWallet } from "./wallet/wallets/phantom/phantomWallet";
|
||||
export { rainbowWallet } from "./wallet/wallets/rainbow/RainbowWallet";
|
||||
export { safeWallet } from "./wallet/wallets/safe/safeWallet";
|
||||
export { smartWallet } from "./wallet/wallets/smartWallet/smartWallet";
|
||||
export { trustWallet } from "./wallet/wallets/trustWallet/TrustWallet";
|
||||
export { walletConnect } from "./wallet/wallets/walletConnect/walletConnect";
|
||||
export { walletConnectV1 } from "./wallet/wallets/walletConnectV1";
|
||||
export { smartWallet } from "./wallet/wallets/smartWallet/smartWallet";
|
||||
export { magicLink } from "./wallet/wallets/magic/magicLink";
|
||||
export { zerionWallet } from "./wallet/wallets/zerion/zerionWallet";
|
||||
export { bloctoWallet } from "./wallet/wallets/blocto/bloctoWallet";
|
||||
|
||||
export { lightTheme, darkTheme } from "./design-system/index";
|
||||
export { darkTheme, lightTheme } from "./design-system/index";
|
||||
export type { Theme, ThemeOverrides } from "./design-system/index";
|
||||
|
||||
// at the moment we'll re-export everything from the evm package
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
useWalletContext,
|
||||
useWallets,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { useContext, useState } from "react";
|
||||
import { useContext, useMemo, useState } from "react";
|
||||
import {
|
||||
SetModalConfigCtx,
|
||||
useSetIsWalletModalOpen,
|
||||
@@ -37,6 +37,7 @@ import { CustomThemeProvider } from "../../design-system/CustomThemeProvider";
|
||||
import { WelcomeScreen } from "./screens/types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { fadeInAnimation } from "../../design-system/animations";
|
||||
import { SupportedTokens, defaultTokens } from "./defaultTokens";
|
||||
|
||||
export type ConnectWalletProps = {
|
||||
className?: string;
|
||||
@@ -48,6 +49,14 @@ export type ConnectWalletProps = {
|
||||
* @default "Connect"
|
||||
*/
|
||||
modalTitle?: string;
|
||||
|
||||
/**
|
||||
* Replace the thirdweb icon next to modalTitle and set your own iconUrl
|
||||
*
|
||||
* Set to empty string to hide the icon
|
||||
*/
|
||||
modalTitleIconUrl?: string;
|
||||
|
||||
/**
|
||||
* render a custom button to display the connected wallet details instead of the default button
|
||||
*/
|
||||
@@ -108,6 +117,25 @@ export type ConnectWalletProps = {
|
||||
* or an object with title, subtitle and imgSrc to change the content of the default screen
|
||||
*/
|
||||
welcomeScreen?: WelcomeScreen;
|
||||
|
||||
/**
|
||||
* 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>;
|
||||
};
|
||||
|
||||
const TW_CONNECT_WALLET = "tw-connect-wallet";
|
||||
@@ -156,6 +184,20 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
|
||||
setShowSignatureModal(false);
|
||||
};
|
||||
|
||||
const supportedTokens = useMemo(() => {
|
||||
if (!props.supportedTokens) {
|
||||
return defaultTokens;
|
||||
}
|
||||
|
||||
const tokens = { ...defaultTokens };
|
||||
for (const k in props.supportedTokens) {
|
||||
const key = Number(k);
|
||||
tokens[key] = props.supportedTokens[key];
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}, [props.supportedTokens]);
|
||||
|
||||
return (
|
||||
<CustomThemeProvider theme={theme}>
|
||||
{showSignatureModal && (
|
||||
@@ -199,6 +241,7 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
|
||||
termsOfServiceUrl: props.termsOfServiceUrl,
|
||||
privacyPolicyUrl: props.privacyPolicyUrl,
|
||||
welcomeScreen: props.welcomeScreen,
|
||||
titleIconUrl: props.modalTitleIconUrl,
|
||||
});
|
||||
setIsWalletModalOpen(true);
|
||||
}}
|
||||
@@ -268,6 +311,8 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
|
||||
style={props.style}
|
||||
detailsBtn={props.detailsBtn}
|
||||
hideTestnetFaucet={props.hideTestnetFaucet}
|
||||
supportedTokens={supportedTokens}
|
||||
displayBalanceToken={props.displayBalanceToken}
|
||||
onDisconnect={() => {
|
||||
if (authConfig?.authUrl) {
|
||||
logout();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user