Compare commits

...
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
182a4e7e8f Version Packages (#1528)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-25 09:03:36 -07:00
iketwandGitHub 8b82f3c59c [CLI] Adds support for PWA Vite template (#1538) 2023-08-25 15:38:21 +00:00
YashandGitHub f59b729f8b [SDK] Fix auto-factory deployment: correct bytecode format (#1537) 2023-08-25 14:19:39 +00:00
iketwandGitHub 387dddbd87 [RN] Adds switchToActiveChain to the ConnectWallet button (#1536) 2023-08-25 13:10:17 +00:00
YashandGitHub 911e14fcac [Chains] Add Chiliz Spicy testnet (#1530) 2023-08-24 18:35:05 +00:00
cd6b07b591 feat(sdk): centralize contract reads (#1520)
Co-authored-by: Joaquim Verges <[email protected]>
2023-08-24 04:29:26 +00:00
YashandGitHub 154c55add5 Contracts version 3.9.3-0 (#1527) 2023-08-24 03:33:49 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
f202f597ca Version Packages (#1517)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-23 20:25:07 -07:00
YashandGitHub 91f0245be7 [SDK] Fix getChainProvider (#1526) 2023-08-24 00:00:03 +00:00
Joaquim VergesandGitHub ae74b8ef62 [SDK] separate ERC1155Supply extension from ERC1155 (#1523) 2023-08-23 22:23:17 +00:00
YashandGitHub 5a373a7509 [SDK] Correct polygon rpc for fetching published contract (#1525) 2023-08-23 19:22:16 +00:00
Manan TankandGitHub 088547f763 [react] various ConnectWallet improvements (#1522) 2023-08-23 17:48:04 +00:00
586e91dbe6 [SDK] Publish dynamic contract (#1488)
Co-authored-by: Nacho Iacovino <[email protected]>
2023-08-23 14:27:40 +00:00
Joaquim VergesandGitHub f65578d637 [SDK] Optimize contract resolution + Fallback to bytecode extension detection for un-imported contracts (#1498) 2023-08-23 00:03:52 +00:00
447d984653 [SDK] Airdrops (#1288)
Co-authored-by: Atharva Deosthale <[email protected]>
2023-08-22 13:26:31 +00:00
nkrishangandGitHub 34a3bb8ae3 [SDK][REACT] Update contracts release (#1518) 2023-08-22 04:31:36 +00:00
Joaquim VergesandGitHub bc003c2fef [SDK] Return early for claim checks when possible (#1516) 2023-08-22 00:01:06 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c88fa57591 Version Packages (#1509)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-21 12:17:36 -07:00
Jonas DanielsandGitHub c12f0874b4 feat(chains): add new chains (#1513) 2023-08-21 18:20:53 +00:00
Jonas DanielsandGitHub 184c325ab2 fix(chains): Update icon URL for chains 37 and 47 (#1508) 2023-08-19 02:19:31 +00:00
046c9ad604 moved res.json() to avoid getting JSON error in console (#1501)
Co-authored-by: Jonas Daniels <[email protected]>
2023-08-19 02:09:58 +00:00
153 changed files with 3855 additions and 741 deletions
+21
View File
@@ -1,5 +1,26 @@
# @thirdweb-dev/auth
## 3.2.37
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@1.1.20
## 3.2.36
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@1.1.19
## 3.2.35
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@1.1.18
## 3.2.34
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.34",
"version": "3.2.37",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+20
View File
@@ -1,5 +1,25 @@
# @thirdweb-dev/chains
## 0.1.48
### Patch Changes
- [#1530](https://github.com/thirdweb-dev/js/pull/1530) [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Add Chiliz Spicy testnet
## 0.1.47
### Patch Changes
- [#1518](https://github.com/thirdweb-dev/js/pull/1518) [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8) Thanks [@nkrishang](https://github.com/nkrishang)! - Update contracts package
## 0.1.46
### Patch Changes
- [#1508](https://github.com/thirdweb-dev/js/pull/1508) [`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f) Thanks [@jnsdls](https://github.com/jnsdls)! - update xpla chain icons
- [#1513](https://github.com/thirdweb-dev/js/pull/1513) [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34) Thanks [@jnsdls](https://github.com/jnsdls)! - add additonal chains
## 0.1.45
### Patch Changes
+5 -5
View File
@@ -1,10 +1,10 @@
import type { Chain } from "../src/types";
export default {
"name": "Omni Testnet 1",
"name": "Omni Testnet",
"chain": "Omni",
"rpc": [
"https://omni-testnet-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-1.omni.network"
"https://omni-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.omni.network"
],
"features": [
{
@@ -24,10 +24,10 @@ export default {
"explorers": [
{
"name": "Omni Explorer",
"url": "https://testnet-1.explorer.omni.network",
"url": "https://testnet.explorer.omni.network",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "omni-testnet-1"
"slug": "omni-testnet"
} as const satisfies Chain;
+2 -2
View File
@@ -11,8 +11,8 @@ export default {
},
"rpc": [
"https://horizen-gobi-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://gobi-testnet.horizenlabs.io/ethv1",
"https://rpc.ankr.com/horizen_testnet_evm"
"https://gobi-rpc.horizenlabs.io/ethv1",
"https://rpc.ankr.com/horizen_gobi_testnet"
],
"features": [
{
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "DeBank Testnet",
"chain": "DeBank",
"rpc": [
"https://debank-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"http://rpc.testnet.debank.com"
],
"faucets": [],
"icon": {
"url": "ipfs://QmW9pBps8WHRRWmyXhjLZrjZJUe8F48hUu7z98bu2RVsjN",
"width": 400,
"height": 400,
"format": "png"
},
"nativeCurrency": {
"name": "DeBank USD",
"symbol": "USD",
"decimals": 18
},
"infoURL": "https://debank.com",
"shortName": "dbk",
"chainId": 2021398,
"networkId": 2021398,
"explorers": [
{
"name": "DeBank Chain Explorer",
"url": "https://explorer.testnet.debank.com",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "debank-testnet"
} as const satisfies Chain;
+31
View File
@@ -0,0 +1,31 @@
import type { Chain } from "../src/types";
export default {
"name": "opBNB Mainnet",
"chain": "opBNB",
"rpc": [
"https://opbnb.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://opbnb-mainnet-rpc.bnbchain.org"
],
"faucets": [
"https://free-online-app.com/faucet-for-eth-evm-chains"
],
"nativeCurrency": {
"name": "BNB Chain Native Token",
"symbol": "BNB",
"decimals": 18
},
"infoURL": "https://opbnb.bnbchain.org/en",
"shortName": "obnb",
"chainId": 204,
"networkId": 204,
"slip44": 714,
"explorers": [
{
"name": "opbnbscan",
"url": "http://mainnet.opbnbscan.com",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "opbnb"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Ancient8 Testnet",
"chain": "Ancient8",
"icon": {
"url": "ipfs://QmSX8sHToRzyFupT8BvPQjVsegRWFYz2mdnLkVnqBFKohY",
"width": 901,
"height": 901,
"format": "png"
},
"rpc": [
"https://ancient8-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-testnet.ancient8.gg"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://ancient8.gg/",
"shortName": "a8",
"chainId": 2863311531,
"networkId": 2863311531,
"explorers": [
{
"name": "a8scan-testnet",
"url": "https://testnet.a8scan.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "ancient8-testnet"
} as const satisfies Chain;
+6
View File
@@ -5,6 +5,12 @@ export default {
"shortName": "POPTestnet",
"chainId": 331769,
"testnet": true,
"icon": {
"format": "png",
"url": "ipfs://QmP8rYvcc7aJB3c2YZxjxaySvHapHnoK8MnxuSuDT4PtF2",
"height": 400,
"width": 400
},
"rpc": [
"https://proofofpepe-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet01.proofofpepe.tech"
+33
View File
@@ -0,0 +1,33 @@
import type { Chain } from "../src/types";
export default {
"name": "POP Mainnet",
"chain": "POP",
"shortName": "POP",
"chainId": 331771,
"testnet": false,
"icon": {
"format": "png",
"url": "ipfs://QmP8rYvcc7aJB3c2YZxjxaySvHapHnoK8MnxuSuDT4PtF2",
"height": 400,
"width": 400
},
"rpc": [
"https://pop.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc00.proofofpepe.tech",
"https://rpc01.proofofpepe.tech",
"https://rpc02.proofofpepe.tech"
],
"nativeCurrency": {
"name": "Pepe",
"symbol": "PEPE",
"decimals": 18
},
"explorers": [
{
"name": "Pepescan",
"url": "https://pepescan.app",
"standard": "none"
}
],
"slug": "pop"
} as const satisfies Chain;
+6 -3
View File
@@ -3,7 +3,7 @@ export default {
"name": "Xpla Mainnet",
"chain": "XPLA",
"rpc": [
"https://xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://xpla-xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://dimension-evm-rpc.xpla.dev"
],
"nativeCurrency": {
@@ -15,7 +15,7 @@ export default {
"shortName": "xpla",
"chainId": 37,
"icon": {
"url": "ipfs://Qmf4GoxfpeA5VGqu7KP5eyv1WKaCpNDbvMxq1MjQBwFWxq",
"url": "ipfs://QmbvEAKZfgJckEziU3mpCwz6jqMeWRcLgd8TNsWA7g8sD9/xpla.png",
"width": 512,
"height": 512,
"format": "png"
@@ -28,5 +28,8 @@ export default {
}
],
"testnet": false,
"slug": "xpla"
"redFlags": [
"reusedChainId"
],
"slug": "xpla-xpla"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Xpla Mainnet",
"chain": "XPLA",
"rpc": [
"https://xpla.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://dimension-rpc.xpla.dev"
],
"faucets": [
"https://faucet.xpla.io/"
],
"nativeCurrency": {
"name": "XPLA",
"symbol": "XPLA",
"decimals": 18
},
"infoURL": "https://xpla.io/",
"shortName": "xpla",
"chainId": 3701,
"networkId": 3701,
"icon": {
"url": "ipfs://Qmf4GoxfpeA5VGqu7KP5eyv1WKaCpNDbvMxq1MjQBwFWxq",
"width": 512,
"height": 512,
"format": "png"
},
"explorers": [
{
"name": "XPLA Explorer",
"url": "https://explorer.xpla.io",
"standard": "none"
}
],
"testnet": false,
"slug": "xpla"
} as const satisfies Chain;
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "KalyChain Mainnet",
"chain": "KLC",
"icon": {
"url": "ipfs://QmUaXcPewLuQtY5a7xPTzJyVdjkH487VfV7gSR8UXrbxQ3",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://kalychain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.kalychain.io/rpc"
],
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"faucets": [],
"nativeCurrency": {
"name": "KalyCoin",
"symbol": "KLC",
"decimals": 18
},
"infoURL": "https://kalychain.io",
"shortName": "kalymainnet",
"chainId": 3888,
"networkId": 3888,
"explorers": [
{
"name": "KalyScan",
"url": "https://kalyscan.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "kalychain"
} as const satisfies Chain;
+42
View File
@@ -0,0 +1,42 @@
import type { Chain } from "../src/types";
export default {
"name": "KalyChain Testnet",
"chain": "KLC",
"icon": {
"url": "ipfs://QmUaXcPewLuQtY5a7xPTzJyVdjkH487VfV7gSR8UXrbxQ3",
"width": 512,
"height": 512,
"format": "png"
},
"rpc": [
"https://kalychain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnetrpc.kalychain.io/rpc"
],
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"faucets": [],
"nativeCurrency": {
"name": "KalyCoin",
"symbol": "KLC",
"decimals": 18
},
"infoURL": "https://kalychain.io",
"shortName": "kalytestnet",
"chainId": 3889,
"networkId": 3889,
"explorers": [
{
"name": "KalyScan",
"url": "https://testnet.kalyscan.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "kalychain-testnet"
} as const satisfies Chain;
+39
View File
@@ -0,0 +1,39 @@
import type { Chain } from "../src/types";
export default {
"name": "Beam",
"chain": "BEAM",
"rpc": [
"https://beam.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://subnets.avax.network/beam/mainnet/rpc"
],
"features": [
{
"name": "EIP1559"
}
],
"faucets": [],
"nativeCurrency": {
"name": "Merit Circle",
"symbol": "MC",
"decimals": 18
},
"infoURL": "https://www.onbeam.com",
"shortName": "beam",
"icon": {
"url": "ipfs://QmQJ21NWyGGDraicVEzS1Uqq1yXahM9NCuNZgnfYvtspdt",
"width": 512,
"height": 512,
"format": "png"
},
"chainId": 4337,
"networkId": 4337,
"explorers": [
{
"name": "Beam Explorer",
"url": "https://subnets.avax.network/beam",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "beam"
} as const satisfies Chain;
+4 -1
View File
@@ -18,7 +18,7 @@ export default {
"shortName": "xpla-test",
"chainId": 47,
"icon": {
"url": "ipfs://Qmf4GoxfpeA5VGqu7KP5eyv1WKaCpNDbvMxq1MjQBwFWxq",
"url": "ipfs://QmbvEAKZfgJckEziU3mpCwz6jqMeWRcLgd8TNsWA7g8sD9/xpla.png",
"width": 512,
"height": 512,
"format": "png"
@@ -31,5 +31,8 @@ export default {
}
],
"testnet": true,
"redFlags": [
"reusedChainId"
],
"slug": "xpla-testnet"
} as const satisfies Chain;
+23
View File
@@ -0,0 +1,23 @@
import type { Chain } from "../src/types";
export default {
"name": "Tanssi EVM ContainerChain",
"chain": "EVMCC",
"rpc": [
"https://tanssi-evm-containerchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://fraa-dancebox-3001-rpc.a.dancebox.tanssi.network",
"wss://fraa-dancebox-3001-rpc.a.dancebox.tanssi.network"
],
"faucets": [],
"nativeCurrency": {
"name": "Unit",
"symbol": "Unit",
"decimals": 18
},
"infoURL": "https://tanssi.network",
"shortName": "TanssiCC",
"chainId": 5678,
"networkId": 5678,
"explorers": [],
"testnet": false,
"slug": "tanssi-evm-containerchain"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "VELO Labs Mainnet",
"chain": "NOVA chain",
"rpc": [
"https://velo-labs.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://nova.velo.org"
],
"faucets": [
"https://nova-faucet.velo.org"
],
"nativeCurrency": {
"name": "Nova",
"symbol": "NOVA",
"decimals": 18
},
"infoURL": "https://velo.org",
"shortName": "VELO",
"chainId": 56789,
"networkId": 56789,
"icon": {
"url": "ipfs://QmYqvnW2jwPEKUv8BdaV4sbL8Audcwosat6SPn4GqYtKxc",
"width": 225,
"height": 225,
"format": "png"
},
"explorers": [
{
"name": "novascan",
"url": "https://novascan.velo.org",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "velo-labs"
} as const satisfies Chain;
+8 -10
View File
@@ -1,19 +1,17 @@
import type { Chain } from "../src/types";
export default {
"name": "BeOne Chain Testnet",
"chain": "BOC",
"name": "Testnet BeOne Chain",
"chain": "tBOC",
"rpc": [
"https://beone-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://pre-boc1.beonechain.com",
"https://pre-boc2.beonechain.com",
"https://pre-boc3.beonechain.com"
"https://testnet-beone-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://pre-boc1.beonechain.com"
],
"faucets": [
"https://testnet.beonescan.com/faucet"
],
"nativeCurrency": {
"name": "BeOne Chain Testnet",
"symbol": "BOC",
"name": "Testnet BeOne Chain",
"symbol": "tBOC",
"decimals": 18
},
"infoURL": "https://testnet.beonescan.com",
@@ -28,7 +26,7 @@ export default {
},
"explorers": [
{
"name": "BeOne Chain Testnet",
"name": "Testnet BeOne Chain",
"url": "https://testnet.beonescan.com",
"icon": {
"url": "ipfs://QmbVLQnaMDu86bPyKgCvTGhFBeYwjr15hQnrCcsp1EkAGL",
@@ -40,5 +38,5 @@ export default {
}
],
"testnet": true,
"slug": "beone-chain-testnet"
"slug": "testnet-beone-chain"
} as const satisfies Chain;
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Aerie Network",
"chain": "Aerie",
"rpc": [
"https://aerie-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet.aerielab.io"
],
"faucets": [],
"nativeCurrency": {
"name": "Aerie",
"symbol": "AER",
"decimals": 18
},
"infoURL": "https://aerielab.io/",
"shortName": "Aerie",
"chainId": 84886,
"networkId": 84886,
"icon": {
"url": "ipfs://bafkreig54jss26xllpjbclmfgwvot72m4ku7qxignhlqei6mijvwi2m4pu",
"width": 1062,
"height": 1069,
"format": "png"
},
"explorers": [
{
"name": "Aerie Explorer",
"url": "https://explorer.aerielab.io",
"icon": {
"url": "ipfs://bafkreig54jss26xllpjbclmfgwvot72m4ku7qxignhlqei6mijvwi2m4pu",
"width": 1062,
"height": 1069,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "aerie-network"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "Spicy Chain",
"chain": "Spicy",
"rpc": [
"https://spicy-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://spicy-rpc.chiliz.com/"
],
"faucets": [
"https://spicy-faucet.chiliz.com/"
],
"nativeCurrency": {
"name": "Chiliz",
"symbol": "CHZ",
"decimals": 18
},
"infoURL": "https://chiliz.com/",
"shortName": "Spicy",
"chainId": 88882,
"networkId": 88882,
"explorers": [
{
"name": "Spicy Explorer",
"url": "http://spicy-explorer.chiliz.com/",
"standard": "none"
}
],
"icon": {
"url": "ipfs://QmTGYofJ8VLkeNY4J69AvXi8e126kmbHmf34wLFoJ1FKAK",
"width": 400,
"height": 400,
"format": "png"
},
"testnet": true,
"slug": "spicy-chain"
} as const satisfies Chain;
+21
View File
@@ -0,0 +1,21 @@
import type { Chain } from "../src/types";
export default {
"name": "Worlds Appchain",
"chain": "WRLDS",
"shortName": "WRLDS",
"chainId": 91003,
"testnet": true,
"rpc": [
"https://worlds-appchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.evm.worlds.dev.eclipsenetwork.xyz/"
],
"nativeCurrency": {
"name": "WRLDS",
"symbol": "WRLDS",
"decimals": 18
},
"faucets": [
"https://faucet.evm.worlds.dev.eclipsenetwork.xyz/request_neon"
],
"slug": "worlds-appchain"
} as const satisfies Chain;
+2 -1
View File
@@ -10,7 +10,8 @@ export default {
},
"rpc": [
"https://mind-smart-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-msc.mindchain.info/"
"https://testnet-msc.mindchain.info/",
"wss://testnet-msc.mindchain.info/ws"
],
"faucets": [
"https://faucet.mindchain.info/"
@@ -8,6 +8,12 @@ export default {
shortName: "POPTestnet",
chainId: 331769,
testnet: true,
icon: {
format: "png",
url: "ipfs://QmP8rYvcc7aJB3c2YZxjxaySvHapHnoK8MnxuSuDT4PtF2",
height: 400,
width: 400,
},
rpc: ["https://testnet01.proofofpepe.tech"],
nativeCurrency: {
name: "POP",
@@ -0,0 +1,30 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "POP Mainnet",
chain: "POP",
shortName: "POP",
chainId: 331771,
testnet: false,
icon: {
format: "png",
url: "ipfs://QmP8rYvcc7aJB3c2YZxjxaySvHapHnoK8MnxuSuDT4PtF2",
height: 400,
width: 400,
},
rpc: [
"https://rpc00.proofofpepe.tech",
"https://rpc01.proofofpepe.tech",
"https://rpc02.proofofpepe.tech",
],
nativeCurrency: {
name: "Pepe",
symbol: "PEPE",
decimals: 18,
},
explorers: [
{ name: "Pepescan", url: "https://pepescan.app", standard: "none" },
],
};
+2 -1
View File
@@ -15,7 +15,7 @@ export default {
shortName: "xpla",
chainId: 37,
icon: {
url: "ipfs://Qmf4GoxfpeA5VGqu7KP5eyv1WKaCpNDbvMxq1MjQBwFWxq",
url: "ipfs://QmbvEAKZfgJckEziU3mpCwz6jqMeWRcLgd8TNsWA7g8sD9/xpla.png",
width: 512,
height: 512,
format: "png",
@@ -28,4 +28,5 @@ export default {
},
],
testnet: false,
redFlags: ["reusedChainId"],
};
+2 -1
View File
@@ -16,7 +16,7 @@ export default {
shortName: "xpla-test",
chainId: 47,
icon: {
url: "ipfs://Qmf4GoxfpeA5VGqu7KP5eyv1WKaCpNDbvMxq1MjQBwFWxq",
url: "ipfs://QmbvEAKZfgJckEziU3mpCwz6jqMeWRcLgd8TNsWA7g8sD9/xpla.png",
width: 512,
height: 512,
format: "png",
@@ -29,4 +29,5 @@ export default {
},
],
testnet: true,
redFlags: ["reusedChainId"],
};
+33
View File
@@ -0,0 +1,33 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "Spicy Chain",
chain: "Spicy",
rpc: ["https://spicy-rpc.chiliz.com/"],
faucets: ["https://spicy-faucet.chiliz.com/"],
nativeCurrency: {
name: "Chiliz",
symbol: "CHZ",
decimals: 18,
},
infoURL: "https://chiliz.com/",
shortName: "Spicy",
chainId: 88882,
networkId: 88882,
explorers: [
{
name: "Spicy Explorer",
url: "http://spicy-explorer.chiliz.com/",
standard: "none",
},
],
icon: {
url: "ipfs://QmTGYofJ8VLkeNY4J69AvXi8e126kmbHmf34wLFoJ1FKAK",
width: 400,
height: 400,
format: "png",
},
testnet: true,
};
+18
View File
@@ -0,0 +1,18 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "Worlds Appchain",
chain: "WRLDS",
shortName: "WRLDS",
chainId: 91003,
testnet: true,
rpc: ["https://api.evm.worlds.dev.eclipsenetwork.xyz/"],
nativeCurrency: {
name: "WRLDS",
symbol: "WRLDS",
decimals: 18,
},
faucets: ["https://faucet.evm.worlds.dev.eclipsenetwork.xyz/request_neon"],
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.45",
"version": "0.1.48",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
@@ -344,6 +344,7 @@ ${exports.join("\n")}
export * from "./types";
export * from "./utils";
export const defaultChains = [c1, c5, c8453, c84531, c137, c80001, c42161, c421613, c10, c420, c56, c97, c250, c4002, c43114, c43113, c1337];
// @ts-expect-error - TODO: fix this later
export const allChains: Chain[] = [${exportNames.join(", ")}];
type ChainsById = {
File diff suppressed because one or more lines are too long
+34
View File
@@ -1,5 +1,39 @@
# thirdweb
## 0.11.20
### Patch Changes
- [#1538](https://github.com/thirdweb-dev/js/pull/1538) [`8b82f3c5`](https://github.com/thirdweb-dev/js/commit/8b82f3c59cad6bd1167c13cb0b8a1cdc36475ab8) Thanks [@iketw](https://github.com/iketw)! - Adds support for creating PWA Vite apps
You can now run:
```bash
npx thirdweb@nightly create --template pwa-vite-typescript-starter
```
- Updated dependencies [[`f59b729f`](https://github.com/thirdweb-dev/js/commit/f59b729f8b09aa86655b8e8a70fba644fc52009b), [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c), [`cd6b07b5`](https://github.com/thirdweb-dev/js/commit/cd6b07b591606d2671794cebebf8edcb59076c32)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.11.19
### Patch Changes
- Updated dependencies [[`586e91db`](https://github.com/thirdweb-dev/js/commit/586e91dbe610588cc7b24fade59172fed6481074), [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8), [`91f0245b`](https://github.com/thirdweb-dev/js/commit/91f0245be78ae523e1faea26b1032bfb283467d9), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5), [`5a373a75`](https://github.com/thirdweb-dev/js/commit/5a373a75090da7e1e05724ed1a3a3a6aa9f7fd21), [`ae74b8ef`](https://github.com/thirdweb-dev/js/commit/ae74b8ef6200dba8affa8b52e7d834c5552350d0), [`bc003c2f`](https://github.com/thirdweb-dev/js/commit/bc003c2fef33fcf7ce5981d8634911ac4bcaa927), [`447d9846`](https://github.com/thirdweb-dev/js/commit/447d984653f77af6860ae907072e768b584b263d), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.11.18
### Patch Changes
- Updated dependencies [[`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f), [`046c9ad6`](https://github.com/thirdweb-dev/js/commit/046c9ad604587ff79bf028c4fe7b1f9c94f4ea54), [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.11.17
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.11.17",
"version": "0.11.20",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+6
View File
@@ -69,6 +69,9 @@ export async function twCreate(
if (options.reactNative) {
framework = "react-native";
}
if (options.pwaVite) {
framework = "pwa-vite";
}
if (options.solana) {
chain = "solana";
@@ -239,6 +242,7 @@ export async function twCreate(
{ title: "Next.js", value: "next" },
{ title: "Create React App", value: "cra" },
{ title: "Vite", value: "vite" },
{ title: "PWA Vite", value: "pwa-vite" },
{ title: "React Native", value: "react-native" },
{ title: "Node.js", value: "node" },
{ title: "Express", value: "express" },
@@ -265,6 +269,8 @@ export async function twCreate(
if (typeof res.project === "string") {
language = res.project.trim();
}
} else if (framework === "pwa-vite" || framework === "pwa-next") {
language = "typescript";
} else {
const res = await prompts({
type: "select",
@@ -220,7 +220,7 @@ export async function createApp({
}
let startOrDev: string | undefined;
if (framework && (framework === "next" || framework === "vite")) {
if (framework && (framework.includes("next") || framework.includes("vite"))) {
startOrDev = "dev";
} else if (template) {
startOrDev = await getStartOrDev(template);
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/contracts-js
## 1.3.12
### Patch Changes
- [#1518](https://github.com/thirdweb-dev/js/pull/1518) [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8) Thanks [@nkrishang](https://github.com/nkrishang)! - Update contracts package
## 1.3.11
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.3.11",
"version": "1.3.12",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"browser": {
@@ -10,7 +10,7 @@
"license": "Apache-2.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
"dependencies": {
"@thirdweb-dev/contracts": "3.8.3"
"@thirdweb-dev/contracts": "3.9.3-0"
},
"devDependencies": {
"@babel/preset-env": "^7.22.9",
+35
View File
@@ -1,5 +1,40 @@
# @thirdweb-dev/react-core
## 3.14.37
### Patch Changes
- Updated dependencies [[`f59b729f`](https://github.com/thirdweb-dev/js/commit/f59b729f8b09aa86655b8e8a70fba644fc52009b), [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c), [`cd6b07b5`](https://github.com/thirdweb-dev/js/commit/cd6b07b591606d2671794cebebf8edcb59076c32)]:
- @thirdweb-dev/sdk@3.10.56
- @thirdweb-dev/chains@0.1.48
- @thirdweb-dev/wallets@1.1.20
- @thirdweb-dev/auth@3.2.37
## 3.14.36
### Patch Changes
- [#1522](https://github.com/thirdweb-dev/js/pull/1522) [`088547f7`](https://github.com/thirdweb-dev/js/commit/088547f763294f1641c01ffe1aabac585f255dc0) Thanks [@MananTank](https://github.com/MananTank)! - - New prop `switchToActiveChain` added to `ConnectWallet`` component to show "Switch Network" button if wallet is not connected to the `activeChain`passed to the`ThirdwebProvider`
- Add max-height on `ConnectWallet` modal
- Local Wallet UI adjustments
- Updated dependencies [[`586e91db`](https://github.com/thirdweb-dev/js/commit/586e91dbe610588cc7b24fade59172fed6481074), [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8), [`91f0245b`](https://github.com/thirdweb-dev/js/commit/91f0245be78ae523e1faea26b1032bfb283467d9), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5), [`5a373a75`](https://github.com/thirdweb-dev/js/commit/5a373a75090da7e1e05724ed1a3a3a6aa9f7fd21), [`ae74b8ef`](https://github.com/thirdweb-dev/js/commit/ae74b8ef6200dba8affa8b52e7d834c5552350d0), [`bc003c2f`](https://github.com/thirdweb-dev/js/commit/bc003c2fef33fcf7ce5981d8634911ac4bcaa927), [`447d9846`](https://github.com/thirdweb-dev/js/commit/447d984653f77af6860ae907072e768b584b263d), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5)]:
- @thirdweb-dev/sdk@3.10.55
- @thirdweb-dev/chains@0.1.47
- @thirdweb-dev/storage@1.2.8
- @thirdweb-dev/wallets@1.1.19
- @thirdweb-dev/auth@3.2.36
## 3.14.35
### Patch Changes
- Updated dependencies [[`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f), [`046c9ad6`](https://github.com/thirdweb-dev/js/commit/046c9ad604587ff79bf028c4fe7b1f9c94f4ea54), [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34)]:
- @thirdweb-dev/chains@0.1.46
- @thirdweb-dev/storage@1.2.7
- @thirdweb-dev/sdk@3.10.54
- @thirdweb-dev/wallets@1.1.18
- @thirdweb-dev/auth@3.2.35
## 3.14.34
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.34",
"version": "3.14.37",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -98,7 +98,7 @@
"typescript": "^5.1.6"
},
"dependencies": {
"@tanstack/react-query": "^4.32.0",
"@tanstack/react-query": "^4.33.0",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/generated-abis": "workspace:^",
"@thirdweb-dev/sdk": "workspace:*",
@@ -152,6 +152,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
autoSwitch={props.autoSwitch}
autoConnectTimeout={props.autoConnectTimeout}
clientId={props.clientId}
activeChainSetExplicitly={!!props.activeChain}
>
<ThirdwebSDKProviderWrapper
queryClient={props.queryClient}
@@ -89,6 +89,7 @@ type ThirdwebWalletContextData = {
* Get wallet config object from wallet instance
*/
getWalletConfig: (walletInstance: WalletInstance) => WalletConfig | undefined;
activeChainSetExplicitly: boolean;
};
const ThirdwebWalletContext = /* @__PURE__ */ createContext<
@@ -106,6 +107,7 @@ export function ThirdwebWalletProvider(
autoSwitch?: boolean;
autoConnectTimeout?: number;
clientId?: string;
activeChainSetExplicitly: boolean;
}>,
) {
const [signer, setSigner] = useState<Signer | undefined>(undefined);
@@ -480,6 +482,7 @@ export function ThirdwebWalletProvider(
getWalletConfig: (walletInstance: WalletInstance) => {
return walletInstanceToConfig.get(walletInstance);
},
activeChainSetExplicitly: props.activeChainSetExplicitly,
}}
>
{props.children}
@@ -21,7 +21,6 @@ import {
} from "@tanstack/react-query";
import { getCachedAbiForContract, TransactionResult } from "@thirdweb-dev/sdk";
import type {
Abi,
CommonContractSchemaInput,
ContractEvent,
ContractForPrebuiltContractType,
@@ -33,6 +32,7 @@ import type {
ThirdwebSDK,
ValidContractInstance,
BaseContractForAddress,
PublishedMetadata,
} from "@thirdweb-dev/sdk";
import type { CallOverrides, ContractInterface, providers } from "ethers";
import { useEffect, useMemo } from "react";
@@ -88,19 +88,11 @@ export const contractType = {
// end contract type
type FetchCompilerMetadataReturnType = {
name: string;
metadata: Record<string, any>;
abi: Abi;
info: Record<string, any>;
licenses: string[];
};
// contract compiler metadata
function fetchCompilerMetadata(
contractAddress: RequiredParam<ContractAddress>,
sdk: RequiredParam<ThirdwebSDK>,
): Promise<FetchCompilerMetadataReturnType> | null {
): Promise<PublishedMetadata> | null {
if (!contractAddress || !sdk) {
return null;
}
@@ -114,7 +106,7 @@ function fetchCompilerMetadata(
export function useCompilerMetadata(
contractAddress: RequiredParam<ContractAddress>,
): UseQueryResult<FetchCompilerMetadataReturnType | null> {
): UseQueryResult<PublishedMetadata | null> {
const sdk = useSDK();
return useQueryWithNetwork(
+3
View File
@@ -251,6 +251,9 @@ export { ThirdwebSDKProvider } from "./providers/thirdweb-sdk-provider";
export { useSDK, useSDKChainId } from "./hooks/useSDK";
export type { ThirdwebSDKProviderProps } from "./providers/types";
// utils
export { invalidateContractAndBalances } from "./utils/cache-keys";
// types
export type {
Chain,
@@ -1,5 +1,11 @@
# @thirdweb-dev/react-native-compat
## 0.2.56
## 0.2.55
## 0.2.54
## 0.2.53
## 0.2.52
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.53",
"version": "0.2.56",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+46
View File
@@ -1,5 +1,51 @@
# @thirdweb-dev/react-native
## 0.2.56
### Patch Changes
- [#1536](https://github.com/thirdweb-dev/js/pull/1536) [`387dddbd`](https://github.com/thirdweb-dev/js/commit/387dddbd87ff6c1a53ffaf663564a44b89a3a2a5) Thanks [@iketw](https://github.com/iketw)! - Adds switchToActiveChain prop to the ConnectWallet button.
When set to true it will show a "Switch Network" button if the wallet
is connected to a different chain than the `activeChain` provided in `ThirdwebProvider`
**Note:** IF you support multiple networks in your app this prop should
be set to `false` to allow users to switch between networks.
Usage:
```javascript
<ConnectWallet switchToActiveChain={true} />
```
- Updated dependencies [[`f59b729f`](https://github.com/thirdweb-dev/js/commit/f59b729f8b09aa86655b8e8a70fba644fc52009b), [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c), [`cd6b07b5`](https://github.com/thirdweb-dev/js/commit/cd6b07b591606d2671794cebebf8edcb59076c32)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.55
### Patch Changes
- Updated dependencies [[`586e91db`](https://github.com/thirdweb-dev/js/commit/586e91dbe610588cc7b24fade59172fed6481074), [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8), [`91f0245b`](https://github.com/thirdweb-dev/js/commit/91f0245be78ae523e1faea26b1032bfb283467d9), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5), [`5a373a75`](https://github.com/thirdweb-dev/js/commit/5a373a75090da7e1e05724ed1a3a3a6aa9f7fd21), [`ae74b8ef`](https://github.com/thirdweb-dev/js/commit/ae74b8ef6200dba8affa8b52e7d834c5552350d0), [`bc003c2f`](https://github.com/thirdweb-dev/js/commit/bc003c2fef33fcf7ce5981d8634911ac4bcaa927), [`447d9846`](https://github.com/thirdweb-dev/js/commit/447d984653f77af6860ae907072e768b584b263d), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5), [`088547f7`](https://github.com/thirdweb-dev/js/commit/088547f763294f1641c01ffe1aabac585f255dc0)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.54
### Patch Changes
- Updated dependencies [[`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f), [`046c9ad6`](https://github.com/thirdweb-dev/js/commit/046c9ad604587ff79bf028c4fe7b1f9c94f4ea54), [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.53
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.53",
"version": "0.2.56",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -28,7 +28,7 @@
"@magic-sdk/provider": "17.2.0",
"@magic-sdk/react-native-bare": "^18.5.0",
"@shopify/restyle": "^2.4.2",
"@tanstack/react-query": "^4.32.0",
"@tanstack/react-query": "^4.33.0",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/sdk": "workspace:*",
@@ -3,11 +3,18 @@ import {
ConnectWalletDetailsProps,
WalletDetailsButton,
} from "./ConnectWalletDetails/WalletDetailsButton";
import { useAddress } from "@thirdweb-dev/react-core";
import { useEffect, useRef } from "react";
import { Animated } from "react-native";
import {
useAddress,
useNetworkMismatch,
useSwitchChain,
useWalletContext,
} from "@thirdweb-dev/react-core";
import { useEffect, useRef, useState } from "react";
import { ActivityIndicator, Animated, StyleSheet } from "react-native";
import { ConnectWalletButton } from "./ConnectWalletFlow/ConnectWalletButton";
import { ConnectWalletButtonProps } from "./ConnectWalletFlow/ConnectWalletButton";
import BaseButton from "./base/BaseButton";
import Text from "./base/Text";
export type ConnectWalletProps = {
/**
@@ -26,6 +33,17 @@ export type ConnectWalletProps = {
* @default false
*/
hideTestnetFaucet?: boolean;
/**
* Whether to show "Switch Network" button if the wallet is connected,
* but it is not connected to the `activeChain` provided in `ThirdwebProvider`
*
* Please, note that if you support multiple networks in your app this prop should
* be set to `false` to allow users to switch between networks.
*
* @default false
*/
switchToActiveChain?: boolean;
} & ConnectWalletButtonProps;
export const ConnectWallet = ({
@@ -35,9 +53,15 @@ export const ConnectWallet = ({
modalTitle,
extraRows,
hideTestnetFaucet,
switchToActiveChain,
}: ConnectWalletProps) => {
const fadeAnim = useRef(new Animated.Value(0)).current;
const address = useAddress();
const isNetworkMismatch = useNetworkMismatch();
const { activeChainSetExplicitly } = useWalletContext();
const { activeChain } = useWalletContext();
const switchChain = useSwitchChain();
const [switching, setSwitching] = useState(false);
useEffect(() => {
Animated.timing(fadeAnim, {
@@ -51,12 +75,38 @@ export const ConnectWallet = ({
<ThemeProvider theme={theme}>
<Animated.View style={{ opacity: fadeAnim }}>
{address ? (
<WalletDetailsButton
address={address}
detailsButton={detailsButton}
extraRows={extraRows}
hideTestnetFaucet={hideTestnetFaucet}
/>
switchToActiveChain &&
isNetworkMismatch &&
activeChainSetExplicitly ? (
<BaseButton
backgroundColor="buttonBackgroundColor"
onPress={async () => {
setSwitching(true);
try {
await switchChain(activeChain.chainId);
} catch {
// ignore
}
setSwitching(false);
}}
style={styles.connectWalletButton}
>
{switching ? (
<ActivityIndicator size="small" color="buttonTextColor" />
) : (
<Text variant="bodyLarge" color="buttonTextColor">
Switch Network
</Text>
)}
</BaseButton>
) : (
<WalletDetailsButton
address={address}
detailsButton={detailsButton}
extraRows={extraRows}
hideTestnetFaucet={hideTestnetFaucet}
/>
)
) : (
<ConnectWalletButton
modalTitle={modalTitle}
@@ -68,3 +118,17 @@ export const ConnectWallet = ({
</ThemeProvider>
);
};
const styles = StyleSheet.create({
connectWalletButton: {
display: "flex",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
justifyContent: "center",
borderRadius: 8,
paddingHorizontal: 10,
paddingVertical: 10,
minWidth: 150,
},
});
+33
View File
@@ -1,5 +1,38 @@
# @thirdweb-dev/react
## 3.14.37
### Patch Changes
- Updated dependencies [[`f59b729f`](https://github.com/thirdweb-dev/js/commit/f59b729f8b09aa86655b8e8a70fba644fc52009b), [`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c), [`cd6b07b5`](https://github.com/thirdweb-dev/js/commit/cd6b07b591606d2671794cebebf8edcb59076c32)]:
- @thirdweb-dev/sdk@3.10.56
- @thirdweb-dev/chains@0.1.48
- @thirdweb-dev/react-core@3.14.37
- @thirdweb-dev/wallets@1.1.20
## 3.14.36
### Patch Changes
- [#1522](https://github.com/thirdweb-dev/js/pull/1522) [`088547f7`](https://github.com/thirdweb-dev/js/commit/088547f763294f1641c01ffe1aabac585f255dc0) Thanks [@MananTank](https://github.com/MananTank)! - - New prop `switchToActiveChain` added to `ConnectWallet`` component to show "Switch Network" button if wallet is not connected to the `activeChain`passed to the`ThirdwebProvider`
- Add max-height on `ConnectWallet` modal
- Local Wallet UI adjustments
- Updated dependencies [[`586e91db`](https://github.com/thirdweb-dev/js/commit/586e91dbe610588cc7b24fade59172fed6481074), [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8), [`91f0245b`](https://github.com/thirdweb-dev/js/commit/91f0245be78ae523e1faea26b1032bfb283467d9), [`5a373a75`](https://github.com/thirdweb-dev/js/commit/5a373a75090da7e1e05724ed1a3a3a6aa9f7fd21), [`ae74b8ef`](https://github.com/thirdweb-dev/js/commit/ae74b8ef6200dba8affa8b52e7d834c5552350d0), [`bc003c2f`](https://github.com/thirdweb-dev/js/commit/bc003c2fef33fcf7ce5981d8634911ac4bcaa927), [`447d9846`](https://github.com/thirdweb-dev/js/commit/447d984653f77af6860ae907072e768b584b263d), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5), [`088547f7`](https://github.com/thirdweb-dev/js/commit/088547f763294f1641c01ffe1aabac585f255dc0)]:
- @thirdweb-dev/sdk@3.10.55
- @thirdweb-dev/chains@0.1.47
- @thirdweb-dev/react-core@3.14.36
- @thirdweb-dev/wallets@1.1.19
## 3.14.35
### Patch Changes
- Updated dependencies [[`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f), [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34)]:
- @thirdweb-dev/chains@0.1.46
- @thirdweb-dev/react-core@3.14.35
- @thirdweb-dev/sdk@3.10.54
- @thirdweb-dev/wallets@1.1.18
## 3.14.34
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.14.34",
"version": "3.14.37",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -131,7 +131,7 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.6",
"@react-icons/all-files": "^4.1.0",
"@tanstack/react-query": "^4.32.0",
"@tanstack/react-query": "^4.33.0",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/wallets": "workspace:*",
@@ -18,6 +18,7 @@ export const FormFieldWithIconButton: React.FC<{
error?: string;
noSave?: boolean;
dataTest?: string;
placeholder?: string;
}> = (props) => {
return (
<div>
@@ -42,6 +43,7 @@ export const FormFieldWithIconButton: React.FC<{
: undefined
}
data-test={props.dataTest}
placeholder={props.placeholder}
/>
<InputButton type="button" onClick={props.right.onClick}>
@@ -97,7 +97,8 @@ export const ConnectModal = () => {
>
<Modal
style={{
maxWidth: "480px",
maxWidth: "450px",
maxHeight: "70vh",
}}
open={isWalletModalOpen}
setOpen={(value) => {
@@ -7,9 +7,12 @@ import {
useConnectionStatus,
useLogin,
useLogout,
useNetworkMismatch,
useSwitchChain,
useThirdwebAuthContext,
useUser,
useWallet,
useWalletContext,
} from "@thirdweb-dev/react-core";
import { useContext, useState } from "react";
import {
@@ -54,6 +57,17 @@ type ConnectWalletProps = {
* @default false
*/
hideTestnetFaucet?: boolean;
/**
* Whether to show "Switch Network" button if the wallet is connected,
* but it is not connected to the `activeChain` provided in `ThirdwebProvider`
*
* Please, note that if you support multiple networks in your app this prop should
* be set to `false` to allow users to switch between networks.
*
* @default false
*/
switchToActiveChain?: boolean;
};
const TW_CONNECT_WALLET = "tw-connect-wallet";
@@ -83,6 +97,8 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
const { user } = useUser();
const { login } = useLogin();
const { logout } = useLogout();
const isNetworkMismatch = useNetworkMismatch();
const { activeChainSetExplicitly } = useWalletContext();
const requiresSignIn = props.auth?.loginOptional
? false
@@ -108,61 +124,87 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
/>
)}
{/* Sign In Button */}
{requiresSignIn && (
<Button
variant="inverted"
onClick={signIn}
data-theme={theme}
className={`${TW_CONNECT_WALLET}--sign-in ${props.className || ""}}`}
style={props.style}
>
<Flex
alignItems="center"
gap="sm"
style={{
paddingRight: spacing.xs,
borderRight: "1px solid",
marginRight: spacing.xs,
}}
>
<LockIcon size={iconSize.sm} />
<span> Sign in </span>
</Flex>
<span>{shortenAddress(address || "", true)}</span>
</Button>
)}
{(() => {
// wallet is not connected
if (!activeWallet) {
// Connect Wallet button
return (
<AnimatedButton
disabled={isLoading}
className={`${props.className || ""} ${TW_CONNECT_WALLET}`}
data-theme={theme}
data-is-loading={isLoading}
variant="inverted"
type="button"
style={{
minWidth: "140px",
...props.style,
}}
aria-label={
connectionStatus === "connecting" ? "Connecting" : btnTitle
}
onClick={() => {
setModalConfig({
title: props.modalTitle || "Choose your wallet",
theme,
data: undefined,
});
setIsWalletModalOpen(true);
}}
data-test="connect-wallet-button"
>
{isLoading ? <Spinner size="sm" color="inverted" /> : btnTitle}
</AnimatedButton>
);
}
{!requiresSignIn &&
(!activeWallet ? (
// connect wallet button
<AnimatedButton
disabled={isLoading}
className={`${props.className || ""} ${TW_CONNECT_WALLET}`}
data-theme={theme}
data-is-loading={isLoading}
variant="inverted"
type="button"
style={{
minWidth: "140px",
...props.style,
}}
aria-label={
connectionStatus === "connecting" ? "Connecting" : btnTitle
}
onClick={() => {
setModalConfig({
title: props.modalTitle || "Choose your wallet",
theme,
data: undefined,
});
setIsWalletModalOpen(true);
}}
data-test="connect-wallet-button"
>
{isLoading ? <Spinner size="sm" color="inverted" /> : btnTitle}
</AnimatedButton>
) : (
// switch network button
if (
props.switchToActiveChain &&
isNetworkMismatch &&
activeChainSetExplicitly
) {
return (
<SwitchNetworkButton
style={props.style}
theme={theme}
className={props.className}
/>
);
}
// sign in button
else if (requiresSignIn) {
return (
<Button
variant="inverted"
onClick={signIn}
data-theme={theme}
className={`${TW_CONNECT_WALLET}--sign-in ${
props.className || ""
}`}
style={props.style}
data-test="sign-in-button"
>
<Flex
alignItems="center"
gap="sm"
style={{
paddingRight: spacing.xs,
borderRight: "1px solid",
marginRight: spacing.xs,
}}
>
<LockIcon size={iconSize.sm} />
<span> Sign in </span>
</Flex>
<span>{shortenAddress(address || "", true)}</span>
</Button>
);
}
// wallet details button
return (
<ConnectedWalletDetails
networkSelector={props.networkSelector}
dropdownPosition={props.dropdownPosition}
@@ -178,11 +220,52 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
}
}}
/>
))}
);
})()}
</ThemeProvider>
);
};
function SwitchNetworkButton(props: {
style?: React.CSSProperties;
className?: string;
theme: "dark" | "light";
}) {
const { activeChain } = useWalletContext();
const switchChain = useSwitchChain();
const [switching, setSwitching] = useState(false);
return (
<AnimatedButton
className={`${TW_CONNECT_WALLET}--switch-network ${
props.className || ""
}`}
variant="inverted"
type="button"
data-theme={props.theme}
data-is-loading={switching}
data-test="switch-network-button"
disabled={switching}
onClick={async () => {
setSwitching(true);
try {
await switchChain(activeChain.chainId);
} catch {
// ignore
}
setSwitching(false);
}}
style={{
minWidth: "140px",
...props.style,
}}
aria-label={switching ? "Switching Network" : undefined}
>
{switching ? <Spinner size="sm" color="inverted" /> : "Switch Network"}
</AnimatedButton>
);
}
const AnimatedButton = /* @__PURE__ */ styled(Button)`
animation: ${fadeInAnimation} 300ms ease;
`;
@@ -113,7 +113,7 @@ export const WalletSelection: React.FC<{
});
return (
<WalletList>
<WalletListContainer>
{walletConfigs.map((walletConfig) => {
const isInstalled = walletConfig.isInstalled
? walletConfig.isInstalled()
@@ -150,11 +150,11 @@ export const WalletSelection: React.FC<{
</li>
);
})}
</WalletList>
</WalletListContainer>
);
};
const WalletList = styled.ul`
const WalletListContainer = styled.ul`
all: unset;
list-style-type: none;
display: flex;
@@ -1,6 +1,6 @@
import { Spacer } from "../../../components/Spacer";
import { Button } from "../../../components/buttons";
import { FormFooter, Label } from "../../../components/formElements";
import { Label } from "../../../components/formElements";
import {
ModalTitle,
ModalDescription,
@@ -172,7 +172,7 @@ export const ExportLocalWallet: React.FC<{
<SavedWalletAddress>{shortenAddress(savedAddress)}</SavedWalletAddress>
<Spacer y="lg" />
<Spacer y="xl" />
{passwordIsRequired && (
<>
@@ -207,22 +207,21 @@ export const ExportLocalWallet: React.FC<{
error={isWrongPassword ? "Wrong Password" : ""}
dataTest="current-password"
/>
<Spacer y="xl" />
<Spacer y="md" />
</>
)}
<FormFooter>
<Button
disabled={exportDisabled}
variant="inverted"
style={{
opacity: exportDisabled ? 0.5 : 1,
}}
type="submit"
>
Backup
</Button>
</FormFooter>
<Button
disabled={exportDisabled}
variant="inverted"
style={{
opacity: exportDisabled ? 0.5 : 1,
width: "100%",
}}
type="submit"
>
Backup
</Button>
</form>
</>
);
@@ -8,7 +8,7 @@ import {
import { EyeClosedIcon, EyeOpenIcon } from "@radix-ui/react-icons";
import { WalletConfig, useWalletContext } from "@thirdweb-dev/react-core";
import { useState } from "react";
import { FormFooter, Label } from "../../../components/formElements";
import { Label } from "../../../components/formElements";
import { spacing } from "../../../design-system";
import { Spinner } from "../../../components/Spinner";
import { shortenAddress } from "../../../evm/utils/addresses";
@@ -131,6 +131,7 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
meta={meta}
hideBack={!props.renderBackButton}
/>
<ModalTitle
style={{
textAlign: "left",
@@ -138,12 +139,13 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
>
Guest Wallet
</ModalTitle>
<Spacer y="xs" />
<ModalDescription>
Connect to saved wallet on your device
</ModalDescription>
<Spacer y="lg" />
<Spacer y="xl" />
<Label>Saved Wallet</Label>
@@ -153,7 +155,7 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
{savedAddress === "" ? "Loading..." : shortenAddress(savedAddress)}
</SecondaryText>
<Spacer y="lg" />
<Spacer y="xl" />
<form
onSubmit={(e) => {
@@ -190,27 +192,27 @@ export const ReconnectLocalWallet: React.FC<ReconnectLocalWalletProps> = (
value={password}
error={isWrongPassword ? "Wrong Password" : ""}
dataTest="current-password"
placeholder="Enter your password"
/>
<Spacer y="lg" />
<Spacer y="md" />
{/* Connect Button */}
<FormFooter>
<Button
variant="inverted"
type="submit"
style={{
display: "flex",
gap: spacing.sm,
}}
>
Connect
{isConnecting && <Spinner size="sm" color="inverted" />}
</Button>
</FormFooter>
<Button
variant="inverted"
type="submit"
style={{
display: "flex",
gap: spacing.sm,
width: "100%",
}}
>
Connect
{isConnecting && <Spinner size="sm" color="inverted" />}
</Button>
</form>
<Spacer y="xxl" />
<Spacer y="xl" />
<Button
variant="link"
@@ -18,7 +18,7 @@ export const LocalWalletModalHeader: React.FC<{
</>
)}
<Img src={props.meta.iconURL} width={iconSize.xl} height={iconSize.xl} />
<Spacer y="sm" />
<Spacer y="md" />
</>
);
};
+44
View File
@@ -1,5 +1,49 @@
# @thirdweb-dev/sdk
## 3.10.56
### Patch Changes
- [#1537](https://github.com/thirdweb-dev/js/pull/1537) [`f59b729f`](https://github.com/thirdweb-dev/js/commit/f59b729f8b09aa86655b8e8a70fba644fc52009b) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Fix auto-factory deployment: correct bytecode format
- [#1520](https://github.com/thirdweb-dev/js/pull/1520) [`cd6b07b5`](https://github.com/thirdweb-dev/js/commit/cd6b07b591606d2671794cebebf8edcb59076c32) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - internal(sdk): update read calls to be centralized in contract-wrapper.ts
- Updated dependencies [[`911e14fc`](https://github.com/thirdweb-dev/js/commit/911e14fcac743b07fa1a66440c72d662c08e971c)]:
- @thirdweb-dev/chains@0.1.48
## 3.10.55
### Patch Changes
- [#1488](https://github.com/thirdweb-dev/js/pull/1488) [`586e91db`](https://github.com/thirdweb-dev/js/commit/586e91dbe610588cc7b24fade59172fed6481074) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Dynamic contract detection and deployment using updated publish metadata
- [#1518](https://github.com/thirdweb-dev/js/pull/1518) [`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8) Thanks [@nkrishang](https://github.com/nkrishang)! - Update contracts package
- [#1526](https://github.com/thirdweb-dev/js/pull/1526) [`91f0245b`](https://github.com/thirdweb-dev/js/commit/91f0245be78ae523e1faea26b1032bfb283467d9) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Fix supported chains map in getChainProvider
- [#1525](https://github.com/thirdweb-dev/js/pull/1525) [`5a373a75`](https://github.com/thirdweb-dev/js/commit/5a373a75090da7e1e05724ed1a3a3a6aa9f7fd21) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Correct chain / polygon rpc for fetching published contract
- [#1523](https://github.com/thirdweb-dev/js/pull/1523) [`ae74b8ef`](https://github.com/thirdweb-dev/js/commit/ae74b8ef6200dba8affa8b52e7d834c5552350d0) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Separate ERC1155Supply extension
- [#1516](https://github.com/thirdweb-dev/js/pull/1516) [`bc003c2f`](https://github.com/thirdweb-dev/js/commit/bc003c2fef33fcf7ce5981d8634911ac4bcaa927) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Return early for claim checks when possible
- [#1288](https://github.com/thirdweb-dev/js/pull/1288) [`447d9846`](https://github.com/thirdweb-dev/js/commit/447d984653f77af6860ae907072e768b584b263d) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Airdrops
- [#1498](https://github.com/thirdweb-dev/js/pull/1498) [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Optimized fetching contract metadata, and fallback to bytecode extension detection for un-imported contracts
- Updated dependencies [[`34a3bb8a`](https://github.com/thirdweb-dev/js/commit/34a3bb8ae3c1d7a506e5568a9e79ab7e469557a8), [`f65578d6`](https://github.com/thirdweb-dev/js/commit/f65578d637decc8b87cada5b5b0c8c504064d9d5)]:
- @thirdweb-dev/contracts-js@1.3.12
- @thirdweb-dev/chains@0.1.47
- @thirdweb-dev/storage@1.2.8
## 3.10.54
### Patch Changes
- Updated dependencies [[`184c325a`](https://github.com/thirdweb-dev/js/commit/184c325ab2ef028022a050c4274f2ab12b1a3a7f), [`046c9ad6`](https://github.com/thirdweb-dev/js/commit/046c9ad604587ff79bf028c4fe7b1f9c94f4ea54), [`c12f0874`](https://github.com/thirdweb-dev/js/commit/c12f0874b4dac43c263c7edb20d0343c16381c34)]:
- @thirdweb-dev/chains@0.1.46
- @thirdweb-dev/storage@1.2.7
## 3.10.53
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.10.53",
"version": "3.10.56",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -14,13 +14,23 @@ export async function computeCloneFactoryAddress(
provider: providers.Provider,
storage: ThirdwebStorage,
create2Factory?: string,
clientId?: string,
secretKey?: string,
): Promise<string> {
if (!create2Factory) {
create2Factory = await getCreate2FactoryAddress(provider);
}
return (
await computeDeploymentInfo("infra", provider, storage, create2Factory, {
contractName: "TWCloneFactory",
})
await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "TWCloneFactory",
},
clientId,
secretKey,
)
).transaction.predictedAddress;
}
@@ -15,12 +15,15 @@ export function computeDeploymentAddress(
create2FactoryAddress: string,
salt?: string,
): string {
const saltHash = salt ? utils.id(salt) : getSaltHash(bytecode);
const bytecodePrefixed = bytecode.startsWith("0x")
? bytecode
: `0x${bytecode}`;
const saltHash = salt ? utils.id(salt) : getSaltHash(bytecodePrefixed);
// 1. create init bytecode hash with contract's bytecode and encoded args
const initBytecode = utils.solidityPack(
["bytes", "bytes"],
[bytecode, encodedArgs],
[bytecodePrefixed, encodedArgs],
);
// 2. abi-encode pack the deployer address, salt, and bytecode hash
@@ -7,7 +7,10 @@ import {
ContractOptions,
DeploymentPreset,
} from "../../types/any-evm/deploy-data";
import { fetchAndCachePublishedContractURI } from "./fetchAndCachePublishedContractURI";
import {
THIRDWEB_DEPLOYER,
fetchPublishedContractFromPolygon,
} from "./fetchPublishedContractFromPolygon";
import { fetchAndCacheDeployMetadata } from "./fetchAndCacheDeployMetadata";
import { isContractDeployed } from "./isContractDeployed";
import { getInitBytecodeWithSalt } from "./getInitBytecodeWithSalt";
@@ -26,8 +29,12 @@ export async function computeDeploymentInfo(
storage: ThirdwebStorage,
create2Factory: string,
contractOptions?: ContractOptions,
clientId?: string,
secretKey?: string,
): Promise<DeploymentPreset> {
const contractName = contractOptions && contractOptions.contractName;
const version = contractOptions && contractOptions.version;
let publisherAddress = contractOptions && contractOptions.publisherAddress;
let metadata = contractOptions && contractOptions.metadata;
invariant(contractName || metadata, "Require contract name or metadata");
@@ -57,9 +64,20 @@ export async function computeDeploymentInfo(
if (!metadata) {
invariant(contractName, "Require contract name");
const uri = await fetchAndCachePublishedContractURI(contractName);
metadata = (await fetchAndCacheDeployMetadata(uri, storage))
.compilerMetadata;
if (!publisherAddress) {
publisherAddress = THIRDWEB_DEPLOYER;
}
const publishedContract = await fetchPublishedContractFromPolygon(
publisherAddress,
contractName,
version,
storage,
clientId,
secretKey,
);
metadata = (
await fetchAndCacheDeployMetadata(publishedContract.metadataUri, storage)
).compilerMetadata;
}
const encodedArgs = await encodeConstructorParamsForImplementation(
@@ -68,6 +86,8 @@ export async function computeDeploymentInfo(
storage,
create2Factory,
contractOptions?.constructorParams,
clientId,
secretKey,
);
const address = computeDeploymentAddress(
metadata.bytecode,
@@ -108,6 +128,8 @@ export async function encodeConstructorParamsForImplementation(
storage: ThirdwebStorage,
create2Factory: string,
constructorParamMap?: ConstructorParamMap,
clientId?: string,
secretKey?: string,
): Promise<BytesLike> {
const constructorParams = extractConstructorParamsFromAbi(
compilerMetadata.abi,
@@ -147,6 +169,8 @@ export async function encodeConstructorParamsForImplementation(
{
contractName: "WETH9",
},
clientId,
secretKey,
);
if (!caches.deploymentPresets["WETH9"]) {
caches.deploymentPresets["WETH9"] = deploymentInfo;
@@ -168,6 +192,8 @@ export async function encodeConstructorParamsForImplementation(
{
contractName: "ForwarderEOAOnly",
},
clientId,
secretKey,
);
if (!caches.deploymentPresets["ForwarderEOAOnly"]) {
caches.deploymentPresets["ForwarderEOAOnly"] = deploymentInfo;
@@ -183,6 +209,8 @@ export async function encodeConstructorParamsForImplementation(
{
contractName: "Forwarder",
},
clientId,
secretKey,
);
if (!caches.deploymentPresets["Forwarder"]) {
caches.deploymentPresets["Forwarder"] = deploymentInfo;
@@ -14,13 +14,23 @@ export async function computeEOAForwarderAddress(
provider: providers.Provider,
storage: ThirdwebStorage,
create2Factory?: string,
clientId?: string,
secretKey?: string,
): Promise<string> {
if (!create2Factory) {
if (!create2Factory || create2Factory === "") {
create2Factory = await getCreate2FactoryAddress(provider);
}
return (
await computeDeploymentInfo("infra", provider, storage, create2Factory, {
contractName: "ForwarderEOAOnly",
})
await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "ForwarderEOAOnly",
},
clientId,
secretKey,
)
).transaction.predictedAddress;
}
@@ -14,13 +14,23 @@ export async function computeForwarderAddress(
provider: providers.Provider,
storage: ThirdwebStorage,
create2Factory?: string,
clientId?: string,
secretKey?: string,
): Promise<string> {
if (!create2Factory) {
if (!create2Factory || create2Factory === "") {
create2Factory = await getCreate2FactoryAddress(provider);
}
return (
await computeDeploymentInfo("infra", provider, storage, create2Factory, {
contractName: "Forwarder",
})
await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "Forwarder",
},
clientId,
secretKey,
)
).transaction.predictedAddress;
}
@@ -14,13 +14,23 @@ export async function computeNativeTokenAddress(
provider: providers.Provider,
storage: ThirdwebStorage,
create2Factory?: string,
clientId?: string,
secretKey?: string,
): Promise<string> {
if (!create2Factory) {
if (!create2Factory || create2Factory === "") {
create2Factory = await getCreate2FactoryAddress(provider);
}
return (
await computeDeploymentInfo("infra", provider, storage, create2Factory, {
contractName: "WETH9",
})
await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "WETH9",
},
clientId,
secretKey,
)
).transaction.predictedAddress;
}
@@ -16,6 +16,7 @@ import { deployCreate2Factory } from "./deployCreate2Factory";
import { convertParamValues } from "./convertParamValues";
import { AbiInput } from "../../schema";
import { getCreate2FactoryAddress } from "./getCreate2FactoryAddress";
import { fetchPublishedContractFromPolygon } from "./fetchPublishedContractFromPolygon";
/**
* Direct deploy a contract at a deterministic address, using Create2 method
@@ -36,7 +37,7 @@ export async function directDeployDeterministic(
constructorArgs: any[],
saltForCreate2?: string,
gasLimit: number = 7000000,
) {
): Promise<string> {
invariant(signer.provider, "Provider is required");
const bytecodePrefixed = bytecode.startsWith("0x")
@@ -97,6 +98,8 @@ export async function directDeployDeterministic(
} else {
throw new Error(`Contract already deployed at ${address}`);
}
return address;
}
/**
@@ -118,13 +121,73 @@ export async function directDeployDeterministicWithUri(
constructorArgs: any[],
saltForCreate2?: string,
gasLimit: number = 7000000,
) {
const { compilerMetadata } = await fetchAndCacheDeployMetadata(
publishMetadataUri,
storage,
): Promise<string> {
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishMetadataUri, storage);
invariant(
extendedMetadata?.deployType === "standard",
"Must be direct deploy",
);
await directDeployDeterministic(
return await directDeployDeterministic(
compilerMetadata.bytecode,
compilerMetadata.abi,
signer,
constructorArgs,
saltForCreate2,
gasLimit,
);
}
/**
* Direct deploy a contract at a deterministic address, using Create2 method
* Address depends on the Create2 factory address and salt (if provided).
*
* @public
*
* @param contractName
* @param publisherAddress
* @param contractVersion
* @param constructorArgs
* @param signer
* @param storage
* @param clientId
* @param secretKey
* @param constructorArgs
* @param saltForCreate2
*/
export async function directDeployDeterministicPublished(
contractName: string,
publisherAddress: string,
contractVersion: string = "latest",
constructorArgs: any[],
signer: Signer,
storage: ThirdwebStorage,
clientId?: string,
secretKey?: string,
saltForCreate2?: string,
gasLimit: number = 7000000,
): Promise<string> {
const publishMetadataUri = (
await fetchPublishedContractFromPolygon(
publisherAddress,
contractName,
contractVersion,
storage,
clientId,
secretKey,
)
).metadataUri;
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishMetadataUri, storage);
invariant(
extendedMetadata?.deployType === "standard",
"Must be direct deploy",
);
return await directDeployDeterministic(
compilerMetadata.bytecode,
compilerMetadata.abi,
signer,
@@ -140,7 +203,7 @@ export async function predictAddressDeterministic(
provider: providers.Provider,
constructorArgs: any[],
saltForCreate2?: string,
) {
): Promise<string> {
const bytecodePrefixed = bytecode.startsWith("0x")
? bytecode
: `0x${bytecode}`;
@@ -182,9 +245,50 @@ export async function predictAddressDeterministicWithUri(
constructorArgs: any[],
saltForCreate2?: string,
): Promise<string> {
const { compilerMetadata } = await fetchAndCacheDeployMetadata(
publishMetadataUri,
storage,
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishMetadataUri, storage);
invariant(
extendedMetadata?.deployType === "standard",
"Must be direct deploy",
);
return await predictAddressDeterministic(
compilerMetadata.bytecode,
compilerMetadata.abi,
provider,
constructorArgs,
saltForCreate2,
);
}
export async function predictAddressDeterministicPublished(
contractName: string,
publisherAddress: string,
contractVersion: string = "latest",
constructorArgs: any[],
provider: providers.Provider,
storage: ThirdwebStorage,
clientId?: string,
secretKey?: string,
saltForCreate2?: string,
): Promise<string> {
const publishMetadataUri = (
await fetchPublishedContractFromPolygon(
publisherAddress,
contractName,
contractVersion,
storage,
clientId,
secretKey,
)
).metadataUri;
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishMetadataUri, storage);
invariant(
extendedMetadata?.deployType === "standard",
"Must be direct deploy",
);
return await predictAddressDeterministic(
@@ -1,39 +0,0 @@
import { Contract } from "ethers";
import ContractPublisherAbi from "@thirdweb-dev/contracts-js/dist/abis/ContractPublisher.json";
import type { ContractPublisher } from "@thirdweb-dev/contracts-js";
import { getContractPublisherAddress } from "../../constants/addresses/getContractPublisherAddress";
import { getChainProvider } from "../../constants/urls";
const uriCache: Record<string, string> = {};
const THIRDWEB_DEPLOYER = "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024";
export async function fetchAndCachePublishedContractURI(
contractName: string,
): Promise<string> {
if (uriCache[contractName]) {
return uriCache[contractName];
}
const contract = new Contract(
getContractPublisherAddress(),
ContractPublisherAbi,
getChainProvider("polygon", {}),
) as ContractPublisher;
const model = await contract.getPublishedContract(
THIRDWEB_DEPLOYER,
contractName,
);
if (!model) {
throw new Error(
`No published contract found for ${contractName} at version by '${THIRDWEB_DEPLOYER}'`,
);
}
const uri = model.publishMetadataUri;
uriCache[contractName] = uri;
return uri;
}
@@ -0,0 +1,84 @@
import { Contract } from "ethers";
import ContractPublisherAbi from "@thirdweb-dev/contracts-js/dist/abis/ContractPublisher.json";
import type { ContractPublisher } from "@thirdweb-dev/contracts-js";
import { getContractPublisherAddress } from "../../constants/addresses/getContractPublisherAddress";
import { getChainProvider } from "../../constants/urls";
import { AddressOrEns, PublishedContractSchema } from "../../schema";
import { resolveAddress } from "../ens/resolveAddress";
import invariant from "tiny-invariant";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { fetchAndCacheDeployMetadata } from "./fetchAndCacheDeployMetadata";
import { getSupportedChains } from "../../constants";
import { Polygon } from "@thirdweb-dev/chains";
export const THIRDWEB_DEPLOYER = "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024";
export async function fetchPublishedContractFromPolygon(
publisherAddress: AddressOrEns,
contractName: string,
version: string = "latest",
storage: ThirdwebStorage,
clientId?: string,
secretKey?: string,
) {
const polygonChain = getSupportedChains().find((c) => c.chainId === 137);
const chain = polygonChain || Polygon;
const publisher = await resolveAddress(publisherAddress);
const contract = new Contract(
getContractPublisherAddress(),
ContractPublisherAbi,
getChainProvider(chain, { clientId, secretKey }),
) as ContractPublisher;
let publishedContract;
if (!version || version === "latest") {
const model = await contract.getPublishedContract(publisher, contractName);
publishedContract = PublishedContractSchema.parse({
id: model.contractId,
timestamp: model.publishTimestamp,
metadataUri: model.publishMetadataUri,
});
} else {
const allVersions = (
await contract.getPublishedContractVersions(publisher, contractName)
).map((c) => {
return PublishedContractSchema.parse({
id: c.contractId,
timestamp: c.publishTimestamp,
metadataUri: c.publishMetadataUri,
});
});
// get the metadata for each version
const versionMetadata = await Promise.all(
allVersions.map(async (c) => {
return {
name: c.id,
publishedTimestamp: c.timestamp,
publishedMetadata: await fetchAndCacheDeployMetadata(
c.metadataUri,
storage,
),
};
}),
);
// find the version that matches the version string
const versionMatch = versionMetadata.find(
(metadata) =>
metadata.publishedMetadata.extendedMetadata?.version === version,
);
invariant(versionMatch, "Contract version not found");
// match the version back to the contract based on the published timestamp
publishedContract = allVersions.find(
(c) => c.timestamp === versionMatch.publishedTimestamp,
);
}
if (!publishedContract) {
throw new Error(
`No published contract found for ${contractName} at version by '${THIRDWEB_DEPLOYER}'`,
);
}
return publishedContract;
}
@@ -13,9 +13,9 @@ import {
generateExtensionFunctions,
generatePluginFunctions,
} from "../plugin/generatePluginFunctions";
import { getMetadataForPlugins } from "../plugin/getMetadataForPlugins";
import { getMetadataForExtensions } from "../plugin/getMetadataForExtensions";
import { Extension } from "../../types/extensions";
import { fetchPublishedContractFromPolygon } from "./fetchPublishedContractFromPolygon";
import invariant from "tiny-invariant";
/**
*
* Returns txn data for keyless deploys as well as signer deploys.
@@ -33,6 +33,8 @@ export async function getDeploymentInfo(
storage: ThirdwebStorage,
provider: providers.Provider,
create2Factory?: string,
clientId?: string,
secretKey?: string,
): Promise<DeploymentPreset[]> {
caches.deploymentPresets = {};
@@ -42,18 +44,33 @@ export async function getDeploymentInfo(
const customParams: ConstructorParamMap = {};
const finalDeploymentInfo: DeploymentPreset[] = [];
const { compilerMetadata } = await fetchAndCacheDeployMetadata(
metadataUri,
storage,
);
const pluginMetadata = await getMetadataForPlugins(metadataUri, storage);
const extensionMetadata = await getMetadataForExtensions(
metadataUri,
storage,
);
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(metadataUri, storage);
const defaultExtensions = extendedMetadata?.defaultExtensions;
if (extendedMetadata?.routerType === "plugin" && defaultExtensions) {
invariant(clientId || secretKey, "Require Client Id / Secret Key");
const publishedExtensions = await Promise.all(
defaultExtensions.map((e) => {
return fetchPublishedContractFromPolygon(
e.publisherAddress,
e.extensionName,
e.extensionVersion,
storage,
clientId,
secretKey,
);
}),
);
const pluginMetadata = (
await Promise.all(
publishedExtensions.map(async (c) => {
return fetchAndCacheDeployMetadata(c.metadataUri, storage);
}),
)
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
// if pluginMetadata is not empty, then it's a plugin-pattern router contract
if (pluginMetadata.length > 0) {
// get deployment info for all plugins
const pluginDeploymentInfo = await Promise.all(
pluginMetadata.map(async (metadata) => {
@@ -63,6 +80,8 @@ export async function getDeploymentInfo(
storage,
create2FactoryAddress,
{ metadata: metadata },
clientId,
secretKey,
);
return info;
}),
@@ -88,6 +107,8 @@ export async function getDeploymentInfo(
contractName: "PluginMap",
constructorParams: { _pluginsToAdd: { value: mapInput } },
},
clientId,
secretKey,
);
// address of PluginMap is input for MarketplaceV3's constructor
@@ -96,7 +117,29 @@ export async function getDeploymentInfo(
};
finalDeploymentInfo.push(...pluginDeploymentInfo, pluginMapTransaction);
} else if (extensionMetadata.length > 0) {
} else if (extendedMetadata?.routerType === "dynamic" && defaultExtensions) {
invariant(clientId || secretKey, "Require Client Id / Secret Key");
const publishedExtensions = await Promise.all(
defaultExtensions.map((e) => {
return fetchPublishedContractFromPolygon(
e.publisherAddress,
e.extensionName,
e.extensionVersion,
storage,
clientId,
secretKey,
);
}),
);
const extensionMetadata = (
await Promise.all(
publishedExtensions.map(async (c) => {
return fetchAndCacheDeployMetadata(c.metadataUri, storage);
}),
)
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
// get deployment info for all extensions
const extensionDeploymentInfo = await Promise.all(
extensionMetadata.map(async (metadata) => {
@@ -106,6 +149,8 @@ export async function getDeploymentInfo(
storage,
create2FactoryAddress,
{ metadata: metadata },
clientId,
secretKey,
);
return info;
}),
@@ -143,6 +188,8 @@ export async function getDeploymentInfo(
metadata: compilerMetadata,
constructorParams: customParams,
},
clientId,
secretKey,
);
// get clone factory
@@ -152,6 +199,8 @@ export async function getDeploymentInfo(
storage,
create2FactoryAddress,
{ contractName: "TWCloneFactory" },
clientId,
secretKey,
);
finalDeploymentInfo.push(factoryInfo);
@@ -3,8 +3,10 @@ import { BytesLike } from "ethers";
import invariant from "tiny-invariant";
import { getChainProvider } from "../../constants/urls";
import { ConstructorParamMap } from "../../types/any-evm/deploy-data";
import { getMetadataForPlugins } from "../plugin/getMetadataForPlugins";
import { fetchAndCachePublishedContractURI } from "./fetchAndCachePublishedContractURI";
import {
THIRDWEB_DEPLOYER,
fetchPublishedContractFromPolygon,
} from "./fetchPublishedContractFromPolygon";
import { fetchAndCacheDeployMetadata } from "./fetchAndCacheDeployMetadata";
import { getCreate2FactoryAddress } from "./getCreate2FactoryAddress";
import { encodeConstructorParamsForImplementation } from "./computeDeploymentInfo";
@@ -21,6 +23,7 @@ export async function getEncodedConstructorParamsForThirdwebContract(
contractName: string,
chainId: number,
storage: ThirdwebStorage,
contractVersion: string = "latest",
clientId?: string,
secretKey?: string,
constructorParamMap?: ConstructorParamMap,
@@ -29,22 +32,38 @@ export async function getEncodedConstructorParamsForThirdwebContract(
clientId,
secretKey,
});
const publishUri = await fetchAndCachePublishedContractURI(contractName);
const publishedContract = await fetchPublishedContractFromPolygon(
THIRDWEB_DEPLOYER,
contractName,
contractVersion,
storage,
clientId,
secretKey,
);
const publishUri = publishedContract.metadataUri;
const metadata = await fetchAndCacheDeployMetadata(publishUri, storage);
const create2Factory = await getCreate2FactoryAddress(provider);
invariant(create2Factory, "Thirdweb stack not found");
const pluginMetadata = await getMetadataForPlugins(publishUri, storage);
const { extendedMetadata } = await fetchAndCacheDeployMetadata(
publishUri,
storage,
);
let encodedArgs;
// if pluginMetadata is not empty, then it's a plugin-pattern router contract
if (pluginMetadata.length > 0) {
if (
extendedMetadata?.routerType === "plugin" ||
extendedMetadata?.routerType === "dynamic"
) {
const deploymentInfo = await getDeploymentInfo(
publishUri,
storage,
provider,
create2Factory,
clientId,
secretKey,
);
encodedArgs = deploymentInfo.find(
(contract) => contract.type === "implementation",
@@ -56,6 +75,8 @@ export async function getEncodedConstructorParamsForThirdwebContract(
storage,
create2Factory,
constructorParamMap,
clientId,
secretKey,
);
}
@@ -15,11 +15,14 @@ export function getInitBytecodeWithSalt(
encodedArgs: BytesLike,
salt?: string,
): string {
const saltHash = salt ? utils.id(salt) : getSaltHash(bytecode);
const bytecodePrefixed = bytecode.startsWith("0x")
? bytecode
: `0x${bytecode}`;
const saltHash = salt ? utils.id(salt) : getSaltHash(bytecodePrefixed);
const initBytecodeWithSalt = utils.solidityPack(
["bytes32", "bytes", "bytes"],
[saltHash, bytecode, encodedArgs],
[saltHash, bytecodePrefixed, encodedArgs],
);
return initBytecodeWithSalt;
@@ -8,7 +8,10 @@ import { utils } from "ethers";
* @param bytecode: Creation bytecode of the contract to deploy
*/
export function getSaltHash(bytecode: string): string {
const bytecodeHash = utils.id(bytecode);
const bytecodePrefixed = bytecode.startsWith("0x")
? bytecode
: `0x${bytecode}`;
const bytecodeHash = utils.id(bytecodePrefixed);
const salt = `tw.${bytecodeHash}`;
const saltHash = utils.id(salt);
@@ -16,6 +16,7 @@ export async function getThirdwebContractAddress(
contractName: string,
chainId: number,
storage: ThirdwebStorage,
contractVersion: string = "latest",
clientId?: string,
secretKey?: string,
): Promise<string> {
@@ -27,6 +28,7 @@ export async function getThirdwebContractAddress(
contractName,
chainId,
storage,
contractVersion,
clientId,
secretKey,
);
@@ -1,11 +1,14 @@
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import invariant from "tiny-invariant";
import { getChainProvider } from "../../constants/urls";
import { getMetadataForPlugins } from "../plugin/getMetadataForPlugins";
import { fetchAndCachePublishedContractURI } from "./fetchAndCachePublishedContractURI";
import {
THIRDWEB_DEPLOYER,
fetchPublishedContractFromPolygon,
} from "./fetchPublishedContractFromPolygon";
import { getCreate2FactoryAddress } from "./getCreate2FactoryAddress";
import { computeDeploymentInfo } from "./computeDeploymentInfo";
import { getDeploymentInfo } from "./getDeploymentInfo";
import { fetchAndCacheDeployMetadata } from "./fetchAndCacheDeployMetadata";
/**
*
@@ -18,6 +21,7 @@ export async function predictThirdwebContractAddress(
contractName: string,
chainId: number,
storage: ThirdwebStorage,
contractVersion: string = "latest",
clientId?: string,
secretKey?: string,
): Promise<string> {
@@ -25,19 +29,34 @@ export async function predictThirdwebContractAddress(
clientId,
secretKey,
});
const publishUri = await fetchAndCachePublishedContractURI(contractName);
const publishedContract = await fetchPublishedContractFromPolygon(
THIRDWEB_DEPLOYER,
contractName,
contractVersion,
storage,
clientId,
secretKey,
);
const publishUri = publishedContract.metadataUri;
const create2Factory = await getCreate2FactoryAddress(provider);
invariant(create2Factory, "Thirdweb stack not found");
const pluginMetadata = await getMetadataForPlugins(publishUri, storage);
const { extendedMetadata } = await fetchAndCacheDeployMetadata(
publishUri,
storage,
);
// if pluginMetadata is not empty, then it's a plugin-pattern router contract
if (pluginMetadata.length > 0) {
if (
extendedMetadata?.routerType === "plugin" ||
extendedMetadata?.routerType === "dynamic"
) {
const deploymentInfo = await getDeploymentInfo(
publishUri,
storage,
provider,
create2Factory,
clientId,
secretKey,
);
const implementation = deploymentInfo.find(
@@ -54,6 +73,8 @@ export async function predictThirdwebContractAddress(
storage,
create2Factory,
{ contractName: contractName },
clientId,
secretKey,
);
return implementation.transaction.predictedAddress;
@@ -1,7 +1,7 @@
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import type { IERC20 } from "@thirdweb-dev/contracts-js";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
import { BigNumber, type BigNumberish, utils } from "ethers";
import { BigNumber, utils, type BigNumberish } from "ethers";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
export async function approveErc20Allowance(
contractToApprove: ContractWrapper<any>,
@@ -20,8 +20,8 @@ export async function approveErc20Allowance(
contractToApprove.storage,
);
const owner = await contractToApprove.getSignerAddress();
const spender = contractToApprove.readContract.address;
const allowance = await erc20.readContract.allowance(owner, spender);
const spender = contractToApprove.address;
const allowance = await erc20.read("allowance", [owner, spender]);
const totalPrice = BigNumber.from(price)
.mul(BigNumber.from(quantity))
.div(utils.parseUnits("1", tokenDecimals));
@@ -1,7 +1,7 @@
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import type { IERC20 } from "@thirdweb-dev/contracts-js";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
import { BigNumber } from "ethers";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
export async function hasERC20Allowance(
contractToApprove: ContractWrapper<any>,
@@ -17,7 +17,7 @@ export async function hasERC20Allowance(
contractToApprove.storage,
);
const owner = await contractToApprove.getSignerAddress();
const spender = contractToApprove.readContract.address;
const allowance = await erc20.readContract.allowance(owner, spender);
const spender = contractToApprove.address;
const allowance = await erc20.read("allowance", [owner, spender]);
return allowance.gte(value);
}
@@ -1,13 +1,13 @@
import { BigNumber, utils } from "ethers";
import { AmountSchema } from "../../../core/schema/shared";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import { Amount } from "../../types/currency";
import { BaseERC20 } from "../../types/eips";
import { BigNumber, utils } from "ethers";
export async function normalizeAmount(
contractWrapper: ContractWrapper<BaseERC20>,
amount: Amount,
): Promise<BigNumber> {
const decimals = await contractWrapper.readContract.decimals();
const decimals = await contractWrapper.read("decimals", []);
return utils.parseUnits(AmountSchema.parse(amount), decimals);
}
@@ -2,7 +2,7 @@ import { FeatureName } from "../../constants/contract-features";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import { AbiSchema } from "../../schema/contracts/custom";
import { BaseContract } from "ethers";
import { isFeatureEnabled } from "./isFeatureEnabled";
import { isExtensionEnabled } from "./isFeatureEnabled";
/**
* Type guard for contractWrappers depending on passed feature name
@@ -14,5 +14,5 @@ export function detectContractFeature<T extends BaseContract>(
contractWrapper: ContractWrapper<BaseContract>,
featureName: FeatureName,
): contractWrapper is ContractWrapper<T> {
return isFeatureEnabled(AbiSchema.parse(contractWrapper.abi), featureName);
return isExtensionEnabled(AbiSchema.parse(contractWrapper.abi), featureName);
}
@@ -4,7 +4,7 @@ import {
SUPPORTED_FEATURES,
} from "../../constants/contract-features";
import { AbiInput } from "../../schema/contracts/custom";
import { hasMatchingAbi } from "./hasMatchingAbi";
import { hasMatchingAbi, matchesAbiFromBytecode } from "./hasMatchingAbi";
/**
* Processes ALL supported features and sets whether the passed in abi supports each individual feature
@@ -31,6 +31,24 @@ export function detectFeatures(
return results;
}
export function detectFeaturesFromBytecode(
bytecode: string,
features: Record<string, Feature> = SUPPORTED_FEATURES,
): Record<string, FeatureWithEnabled> {
const results: Record<string, FeatureWithEnabled> = {};
for (const featureKey in features) {
const feature = features[featureKey];
const enabled = matchesAbiFromBytecode(bytecode, feature.abis);
const childResults = detectFeaturesFromBytecode(bytecode, feature.features);
results[featureKey] = {
...feature,
features: childResults,
enabled,
} as FeatureWithEnabled;
}
return results;
}
/**
* @internal
* @param abi
@@ -3,7 +3,8 @@ import {
FeatureWithEnabled,
} from "../../constants/contract-features";
import { AbiInput } from "../../schema/contracts/custom";
import { detectFeatures } from "./detectFeatures";
import { joinABIs } from "../plugin/joinABIs";
import { detectFeatures, detectFeaturesFromBytecode } from "./detectFeatures";
import { extractFeatures } from "./extractFeatures";
/**
@@ -19,6 +20,24 @@ export function getAllDetectedFeatures(abi: AbiInput): FeatureWithEnabled[] {
return features;
}
export function getAllDetectedExtensionsFromBytecode(
bytecode: string,
): FeatureWithEnabled[] {
const features: FeatureWithEnabled[] = [];
extractFeatures(detectFeaturesFromBytecode(bytecode), features);
return features;
}
export function constructAbiFromBytecode(bytecode: string): AbiInput {
let extensions = getAllDetectedExtensionsFromBytecode(bytecode);
// special deduping for ERC721 and ERC20
if (extensions.find((f) => f.name === "ERC721")) {
extensions = extensions.filter((f) => f.name !== "ERC20");
}
const abi = joinABIs(extensions.map((f) => joinABIs(f.abis as any)));
return abi;
}
/**
* Return all the detected extensions in the abi
* @param abi - parsed array of abi entries
@@ -1,3 +1,4 @@
import { Interface } from "ethers/lib/utils";
import { AbiInput } from "../../schema/contracts/custom";
import { extractFunctionsFromAbi } from "./extractFunctionsFromAbi";
@@ -38,3 +39,20 @@ export function hasMatchingAbi(
});
return intersection.length === interfaceFn.length;
}
export function matchesAbiFromBytecode(
contractBytecode: string,
featureAbis: readonly AbiInput[],
) {
const interfaces = featureAbis.map((abi) => new Interface(abi));
const selectors = interfaces.flatMap((i) => {
return Object.values(i.functions).map((fn) =>
Number(i.getSighash(fn)).toString(16),
);
});
const uniqueSelectors = [...new Set(selectors)];
// checks that all unique selectors are found in the bytecode
return uniqueSelectors.every((selector) =>
contractBytecode.includes(selector),
);
}
@@ -11,6 +11,22 @@ export async function resolveContractUriFromAddress(
address: string,
provider: providers.Provider,
): Promise<string | undefined> {
const bytecode = await resolveImplementationBytecode(address, provider);
return extractIPFSHashFromBytecode(bytecode);
}
export async function resolveContractUriAndBytecode(
address: string,
provider: providers.Provider,
): Promise<{ uri: string | undefined; bytecode: string }> {
const bytecode = await resolveImplementationBytecode(address, provider);
return { uri: extractIPFSHashFromBytecode(bytecode), bytecode };
}
export async function resolveImplementationBytecode(
address: string,
provider: providers.Provider,
): Promise<string> {
let bytecode;
try {
bytecode = await provider.getCode(address);
@@ -26,10 +42,11 @@ export async function resolveContractUriFromAddress(
}
try {
// TODO support other types of proxies
const implementationAddress =
extractMinimalProxyImplementationAddress(bytecode);
if (implementationAddress) {
return await resolveContractUriFromAddress(
return await resolveImplementationBytecode(
implementationAddress,
provider,
);
@@ -51,7 +68,7 @@ export async function resolveContractUriFromAddress(
utils.isAddress(implementationAddress) &&
implementationAddress !== constants.AddressZero
) {
return await resolveContractUriFromAddress(
return await resolveImplementationBytecode(
implementationAddress,
provider,
);
@@ -59,6 +76,8 @@ export async function resolveContractUriFromAddress(
} catch (e) {
// ignore
}
// TODO support other types of proxies
return await extractIPFSHashFromBytecode(bytecode);
if (!bytecode) {
throw new Error(`Error fetching bytecode for ${address}`);
}
return bytecode;
}
@@ -5,17 +5,21 @@ import {
} from "../schema/contracts/custom";
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
const CONTRACT_METADATA_TIMEOUT_SEC = 2;
/**
* @internal
* @param compilerMetadataUri
* @param storage
*/
export async function fetchContractMetadata(
compilerMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PublishedMetadata> {
const metadata = await storage.downloadJSON(compilerMetadataUri);
// short timeout to avoid hanging on unpinned contract metadata CIDs
const metadata = await storage.downloadJSON(compilerMetadataUri, {
timeoutInSeconds: CONTRACT_METADATA_TIMEOUT_SEC,
});
if (!metadata || !metadata.output) {
throw new Error(
`Could not resolve metadata for contract at ${compilerMetadataUri}`,
+2 -1
View File
@@ -3,6 +3,7 @@ export * from "./snapshots";
export * from "./role";
export * from "./metadata-resolver";
export * from "./gas-price";
export * from "./fetchContractMetadata";
// feature detection
export * from "./feature-detection/matchesPrebuiltAbi";
@@ -73,7 +74,7 @@ export * from "./any-evm-utils/deployWithThrowawayDeployer";
export * from "./any-evm-utils/computeDeploymentInfo";
export * from "./any-evm-utils/convertParamValues";
export * from "./any-evm-utils/getCreate2FactoryDeploymentInfo";
export * from "./any-evm-utils/fetchAndCachePublishedContractURI";
export * from "./any-evm-utils/fetchPublishedContractFromPolygon";
export * from "./any-evm-utils/fetchAndCacheDeployMetadata";
export * from "./any-evm-utils/estimateGasForDeploy";
export * from "./any-evm-utils/createTransactionBatches";
@@ -1,6 +1,6 @@
import { Abi, PublishedMetadata } from "../schema/contracts/custom";
import { Address } from "../schema/shared/Address";
import { resolveContractUriFromAddress } from "./feature-detection/resolveContractUriFromAddress";
import { resolveContractUriAndBytecode } from "./feature-detection/resolveContractUriFromAddress";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { Contract, providers } from "ethers";
import { fetchContractMetadata } from "./fetchContractMetadata";
@@ -8,7 +8,9 @@ import TWRegistryABI from "@thirdweb-dev/contracts-js/dist/abis/TWMultichainRegi
import { getMultichainRegistryAddress } from "../constants/addresses/getMultichainRegistryAddress";
import { getChainProvider } from "../constants/urls";
import type { TWMultichainRegistryLogic } from "@thirdweb-dev/contracts-js";
import { constructAbiFromBytecode } from "./feature-detection/getAllDetectedFeatures";
import { SDKOptions } from "../schema";
import { Polygon } from "@thirdweb-dev/chains";
// Internal static cache
const metadataCache: Record<string, PublishedMetadata> = {};
@@ -41,61 +43,92 @@ export async function fetchContractMetadataFromAddress(
provider: providers.Provider,
storage: ThirdwebStorage,
sdkOptions: SDKOptions = {},
) {
const chainId = (await provider.getNetwork()).chainId;
): Promise<PublishedMetadata> {
const chainId = (await provider.getNetwork()).chainId; // TODO resolve from sdk network
const cached = getFromCache(address, chainId);
if (cached) {
return cached;
}
let metadata: PublishedMetadata | undefined;
try {
const compilerMetadataUri = await resolveContractUriFromAddress(
address,
provider,
);
if (!compilerMetadataUri) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
}
metadata = await fetchContractMetadata(compilerMetadataUri, storage);
} catch (e) {
console.debug(
"Contract Metadata not found on IPFS, defaulting to onchain registry. Original error:",
(e as any)?.message,
);
try {
// try from multichain registry
if (!multichainRegistry) {
// TODO enforce always passing sdk options for clientId/secretKey
multichainRegistry = new Contract(
getMultichainRegistryAddress(),
TWRegistryABI,
getChainProvider("polygon", sdkOptions),
) as TWMultichainRegistryLogic;
}
const importedUri = await multichainRegistry.getMetadataUri(
chainId,
address,
// we can't race here, because the contract URI might resolve first with a non pinned URI
const [ipfsData, registryData] = await Promise.all([
resolveContractUriAndBytecode(address, provider).catch(() => undefined),
getMetadataUriFromMultichainRegistry(address, chainId, sdkOptions)
.then((uri) => {
if (!uri) {
return undefined;
}
return {
uri,
bytecode: "",
};
})
.catch(() => undefined),
]);
const bytecode = ipfsData?.bytecode;
const metadataUri = registryData?.uri || ipfsData?.uri;
if (!metadataUri && !bytecode) {
throw new Error(
`Could not fetch bytecode for contract at ${address} on chain ${chainId}, double check that the address and chainId are correct.`,
);
}
try {
metadata = await fetchContractMetadata(metadataUri, storage);
} catch (e) {
// Don't warn here, its common to not have IPFS metadata for a contract, fallback to bytecode
}
if (!metadata && bytecode) {
const abi = constructAbiFromBytecode(bytecode);
if (abi && abi.length > 0) {
console.warn(
`Contract metadata could only be partially resolved, some contract functions might be unavailable. Try importing the contract by visiting: https://thirdweb.com/${chainId}/${address}`,
);
if (!importedUri) {
throw new Error(
`Could not resolve metadata for contract at ${address}`,
);
}
metadata = await fetchContractMetadata(importedUri, storage);
} catch (err) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
// return partial ABI
metadata = {
name: "Unimported Contract",
abi: abi as Abi,
metadata: {},
info: {},
licenses: [],
isPartialAbi: true,
};
// return without caching
return metadata;
}
}
if (!metadata) {
throw new Error(
`No ABI found for this contract. Try importing it by visiting: https://thirdweb.com/${chainId}/${address}`,
`Could not resolve contract. Try importing it by visiting: https://thirdweb.com/${chainId}/${address}`,
);
}
putInCache(address, chainId, metadata);
return metadata;
}
async function getMetadataUriFromMultichainRegistry(
address: string,
chainId: number,
sdkOptions: SDKOptions,
) {
if (!multichainRegistry) {
const polygonChain = sdkOptions?.supportedChains?.find(
(c) => c.chainId === 137,
);
const chain = polygonChain || Polygon;
multichainRegistry = new Contract(
getMultichainRegistryAddress(),
TWRegistryABI,
getChainProvider(chain, sdkOptions),
) as TWMultichainRegistryLogic;
}
const importedUri = await multichainRegistry.getMetadataUri(chainId, address);
return importedUri;
}
/**
* @internal
* @param address
@@ -27,7 +27,9 @@ export function generatePluginFunctions(
const pluginFunctions: Plugin[] = [];
// TODO - filter out common functions like _msgSender(), contractType(), etc.
for (const fnFragment of Object.values(pluginInterface.functions)) {
const fn = pluginInterface.getFunction(fnFragment.name);
const fn = pluginInterface.getFunction(
pluginInterface.getSighash(fnFragment),
);
if (fn.name.includes("_")) {
continue;
}
@@ -29,11 +29,11 @@ export async function getCompositePluginABI(
AbiSchema.parse(abi),
"PluginRouter",
);
const isExtensionRouter: boolean = isFeatureEnabled(
const isbaseRouter: boolean = isFeatureEnabled(
AbiSchema.parse(abi),
"ExtensionRouter",
"DynamicContract",
);
if (isExtensionRouter) {
if (isbaseRouter) {
const contract = new ContractWrapper(
provider,
address,
@@ -1,74 +0,0 @@
import { getAllExtensionsAbi } from "../../constants/thirdweb-features";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import {
AbiSchema,
PreDeployMetadataFetched,
} from "../../schema/contracts/custom";
import { isFeatureEnabled } from "../feature-detection/isFeatureEnabled";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { getChainProvider } from "../../constants/urls";
import { fetchAndCachePublishedContractURI } from "../any-evm-utils/fetchAndCachePublishedContractURI";
import { fetchAndCacheDeployMetadata } from "../any-evm-utils/fetchAndCacheDeployMetadata";
import { Extension } from "../../types/extensions";
export async function getMetadataForExtensions(
publishedMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PreDeployMetadataFetched[]> {
let extensionMetadata: PreDeployMetadataFetched[] = [];
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishedMetadataUri, storage);
// check if contract is extension-pattern
const isExtensionRouter: boolean = isFeatureEnabled(
AbiSchema.parse(compilerMetadata.abi),
"ExtensionRouter",
);
if (isExtensionRouter) {
if (
extendedMetadata &&
extendedMetadata.factoryDeploymentData?.implementationAddresses
) {
const implementationsAddresses = Object.entries(
extendedMetadata.factoryDeploymentData.implementationAddresses,
);
try {
const entry = implementationsAddresses.find(
([, implementation]) => implementation !== "",
);
const [network, implementation] = entry ? entry : [];
if (network && implementation) {
const provider = getChainProvider(parseInt(network), {});
const contract = new ContractWrapper(
provider,
implementation,
getAllExtensionsAbi,
{},
storage,
);
const extensions = await contract.call("getAllExtensions");
const extensionNames: string[] = Array.from(
new Set(extensions.map((item: Extension) => item.metadata.name)),
);
const extensionUris = await Promise.all(
extensionNames.map((name) => {
return fetchAndCachePublishedContractURI(name);
}),
);
extensionMetadata = (
await Promise.all(
extensionUris.map(async (uri) => {
return fetchAndCacheDeployMetadata(uri, storage);
}),
)
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
}
} catch {}
}
}
return extensionMetadata;
}
@@ -1,91 +0,0 @@
import { getAllPluginsAbi } from "../../constants/thirdweb-features";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import {
AbiSchema,
PreDeployMetadataFetched,
} from "../../schema/contracts/custom";
import { isFeatureEnabled } from "../feature-detection/isFeatureEnabled";
import { fetchContractMetadataFromAddress } from "../metadata-resolver";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { Plugin } from "../../types/plugins";
import { getChainProvider } from "../../constants/urls";
import { fetchAndCachePublishedContractURI } from "../any-evm-utils/fetchAndCachePublishedContractURI";
import { fetchAndCacheDeployMetadata } from "../any-evm-utils/fetchAndCacheDeployMetadata";
export async function getMetadataForPlugins(
publishedMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PreDeployMetadataFetched[]> {
let pluginMetadata: PreDeployMetadataFetched[] = [];
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishedMetadataUri, storage);
// check if contract is plugin-pattern
const isPluginRouter: boolean = isFeatureEnabled(
AbiSchema.parse(compilerMetadata.abi),
"PluginRouter",
);
if (isPluginRouter) {
if (
extendedMetadata &&
extendedMetadata.factoryDeploymentData?.implementationAddresses
) {
const implementationsAddresses = Object.entries(
extendedMetadata.factoryDeploymentData.implementationAddresses,
);
try {
const entry = implementationsAddresses.find(
([, implementation]) => implementation !== "",
);
const [network, implementation] = entry ? entry : [];
if (network && implementation) {
const provider = getChainProvider(parseInt(network), {});
const contract = new ContractWrapper(
provider,
implementation,
getAllPluginsAbi,
{},
storage,
);
const pluginMap = await contract.call("getAllPlugins");
// get extension addresses
const allPlugins = pluginMap.map(
(item: Plugin) => item.pluginAddress,
);
const pluginAddresses = Array.from(new Set(allPlugins));
const pluginNames = (
await Promise.all(
pluginAddresses.map(async (address) => {
const metadata = fetchContractMetadataFromAddress(
address as string,
provider,
storage,
);
return metadata;
}),
)
).map((metadata) => metadata.name);
const pluginUris = await Promise.all(
pluginNames.map((name) => {
return fetchAndCachePublishedContractURI(name);
}),
);
pluginMetadata = (
await Promise.all(
pluginUris.map(async (uri) => {
return fetchAndCacheDeployMetadata(uri, storage);
}),
)
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
}
} catch {}
}
}
return pluginMetadata;
}
@@ -6,9 +6,9 @@ export function isRouterContract(abi: Abi) {
AbiSchema.parse(abi),
"PluginRouter",
);
const isExtensionRouter: boolean = isFeatureEnabled(
const isBaseRouter: boolean = isFeatureEnabled(
AbiSchema.parse(abi),
"ExtensionRouter",
"DynamicContract",
);
return isExtensionRouter || isPluginRouter;
return isBaseRouter || isPluginRouter;
}
@@ -61,6 +61,7 @@ export async function verifyThirdwebPrebuiltImplementation(
explorerAPIUrl: string,
explorerAPIKey: string,
storage: ThirdwebStorage,
contractVersion: string = "latest",
clientId?: string,
secretKey?: string,
constructorArgs?: ConstructorParamMap,
@@ -69,6 +70,7 @@ export async function verifyThirdwebPrebuiltImplementation(
contractName,
chainId,
storage,
contractVersion,
clientId,
secretKey,
);
@@ -76,6 +78,7 @@ export async function verifyThirdwebPrebuiltImplementation(
contractName,
chainId,
storage,
contractVersion,
clientId,
secretKey,
constructorArgs,
@@ -48,6 +48,8 @@ import {
FEATURE_EDITION_REVEALABLE,
FEATURE_EDITION_SIGNATURE_MINTABLE,
FEATURE_EDITION_CLAIM_PHASES_V1,
FEATURE_EDITION_UPDATABLE_METADATA,
FEATURE_EDITION_SUPPLY,
} from "./erc1155-features";
import {
FEATURE_METADATA,
@@ -64,7 +66,10 @@ import {
FEATURE_DIRECT_LISTINGS,
FEATURE_ENGLISH_AUCTIONS,
FEATURE_OFFERS,
FEATURE_EXTENSION_ROUTER,
FEATURE_DYNAMIC_CONTRACT,
FEATURE_AIRDROP_ERC20,
FEATURE_AIRDROP_ERC721,
FEATURE_AIRDROP_ERC1155,
FEATURE_ACCOUNT,
FEATURE_ACCOUNT_FACTORY,
FEATURE_ACCOUNT_PERMISSIONS,
@@ -119,6 +124,8 @@ export type Feature =
| typeof FEATURE_EDITION_BATCH_MINTABLE
| typeof FEATURE_EDITION_BURNABLE
| typeof FEATURE_EDITION_SIGNATURE_MINTABLE
| typeof FEATURE_EDITION_UPDATABLE_METADATA
| typeof FEATURE_EDITION_SUPPLY
| typeof FEATURE_ROYALTY
| typeof FEATURE_PLATFORM_FEE
| typeof FEATURE_PRIMARY_SALE
@@ -130,10 +137,13 @@ export type Feature =
| typeof FEATURE_GASLESS
| typeof FEATURE_PACK_VRF
| typeof FEATURE_PLUGIN_ROUTER
| typeof FEATURE_EXTENSION_ROUTER
| typeof FEATURE_DYNAMIC_CONTRACT
| typeof FEATURE_DIRECT_LISTINGS
| typeof FEATURE_ENGLISH_AUCTIONS
| typeof FEATURE_OFFERS
| typeof FEATURE_AIRDROP_ERC20
| typeof FEATURE_AIRDROP_ERC721
| typeof FEATURE_AIRDROP_ERC1155
| typeof FEATURE_ACCOUNT
| typeof FEATURE_ACCOUNT_PERMISSIONS
| typeof FEATURE_ACCOUNT_FACTORY;
@@ -174,10 +184,13 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = /* @__PURE__ */ {
[FEATURE_GASLESS.name]: FEATURE_GASLESS,
[FEATURE_PACK_VRF.name]: FEATURE_PACK_VRF,
[FEATURE_PLUGIN_ROUTER.name]: FEATURE_PLUGIN_ROUTER,
[FEATURE_EXTENSION_ROUTER.name]: FEATURE_EXTENSION_ROUTER,
[FEATURE_DYNAMIC_CONTRACT.name]: FEATURE_DYNAMIC_CONTRACT,
[FEATURE_DIRECT_LISTINGS.name]: FEATURE_DIRECT_LISTINGS,
[FEATURE_ENGLISH_AUCTIONS.name]: FEATURE_ENGLISH_AUCTIONS,
[FEATURE_OFFERS.name]: FEATURE_OFFERS,
[FEATURE_AIRDROP_ERC20.name]: FEATURE_AIRDROP_ERC20,
[FEATURE_AIRDROP_ERC721.name]: FEATURE_AIRDROP_ERC721,
[FEATURE_AIRDROP_ERC1155.name]: FEATURE_AIRDROP_ERC1155,
[FEATURE_ACCOUNT_FACTORY.name]: FEATURE_ACCOUNT_FACTORY,
[FEATURE_ACCOUNT.name]: FEATURE_ACCOUNT,
[FEATURE_NFT_LOYALTY_CARD.name]: FEATURE_NFT_LOYALTY_CARD,
@@ -6,11 +6,44 @@ import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC1155
import IDropSinglePhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155.json";
import IDropSinglePhase1155_V1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155_V1.json";
import Erc1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155.json";
import Erc1155MetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155Metadata.json";
import Erc1155SupplyAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155Supply.json";
import Erc1155EnumerableAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155Enumerable.json";
import ILazyMintAbi from "@thirdweb-dev/contracts-js/dist/abis/ILazyMint.json";
import IMintableERC1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableERC1155.json";
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
import ISignatureMintERC1155Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC1155.json";
import INFTMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/INFTMetadata.json";
// TODO could be part of IERC1155Metadata even though its not in the spec
const NAME_SYMBOL_ABI = [
{
inputs: [],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string",
},
],
stateMutability: "view",
type: "function",
},
];
export const FEATURE_EDITION_BURNABLE = {
name: "ERC1155Burnable",
@@ -172,6 +205,29 @@ export const FEATURE_EDITION_ENUMERABLE = {
features: {},
} as const;
export const FEATURE_EDITION_UPDATABLE_METADATA = {
name: "ERC1155UpdatableMetadata",
namespace: "edition.metadata",
docLinks: {
// TODO
sdk: "",
contracts: "",
},
abis: [Erc1155Abi, INFTMetadataAbi],
features: {},
} as const;
export const FEATURE_EDITION_SUPPLY = {
name: "ERC1155Supply",
namespace: "edition.supply",
docLinks: {
sdk: "",
contracts: "",
},
abis: [Erc1155Abi, Erc1155SupplyAbi],
features: {},
} as const;
export const FEATURE_EDITION = /* @__PURE__ */ {
name: "ERC1155",
namespace: "edition",
@@ -179,8 +235,9 @@ export const FEATURE_EDITION = /* @__PURE__ */ {
sdk: "sdk.erc1155enumerable",
contracts: "erc1155",
},
abis: [Erc1155Abi],
abis: [Erc1155Abi, Erc1155MetadataAbi, NAME_SYMBOL_ABI],
features: {
[FEATURE_EDITION_SUPPLY.name]: FEATURE_EDITION_SUPPLY,
[FEATURE_EDITION_BURNABLE.name]: FEATURE_EDITION_BURNABLE,
[FEATURE_EDITION_ENUMERABLE.name]: FEATURE_EDITION_ENUMERABLE,
[FEATURE_EDITION_MINTABLE.name]: FEATURE_EDITION_MINTABLE,
@@ -195,5 +252,7 @@ export const FEATURE_EDITION = /* @__PURE__ */ {
[FEATURE_EDITION_CLAIM_CONDITIONS_V2.name]:
FEATURE_EDITION_CLAIM_CONDITIONS_V2,
[FEATURE_EDITION_CLAIM_PHASES_V2.name]: FEATURE_EDITION_CLAIM_PHASES_V2,
[FEATURE_EDITION_UPDATABLE_METADATA.name]:
FEATURE_EDITION_UPDATABLE_METADATA,
},
} as const;
@@ -8,6 +8,7 @@ import IERC20PermitAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC20Permit.j
import IMintableERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableERC20.json";
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
import ISignatureMintERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC20.json";
import IERC20MetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC20Metadata.json";
export const FEATURE_TOKEN_CLAIM_CONDITIONS_V1 = {
name: "ERC20ClaimConditionsV1",
@@ -117,7 +118,7 @@ export const FEATURE_TOKEN = /* @__PURE__ */ {
sdk: "sdk.erc20",
contracts: "erc20",
},
abis: [ERC20Abi],
abis: [ERC20Abi, IERC20MetadataAbi],
features: {
[FEATURE_TOKEN_BURNABLE.name]: FEATURE_TOKEN_BURNABLE,
[FEATURE_TOKEN_MINTABLE.name]: FEATURE_TOKEN_MINTABLE,
@@ -19,6 +19,7 @@ import SharedMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/SharedMetada
import zora_IDropERC721 from "@thirdweb-dev/contracts-js/dist/abis/zora_IERC721Drop.json";
import ILoyaltyCardAbi from "@thirdweb-dev/contracts-js/dist/abis/ILoyaltyCard.json";
import INFTMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/INFTMetadata.json";
import IERC721MetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC721Metadata.json";
export const FEATURE_NFT_BURNABLE = {
name: "ERC721Burnable",
@@ -246,7 +247,7 @@ export const FEATURE_NFT_UPDATABLE_METADATA = {
sdk: "",
contracts: "",
},
abis: [INFTMetadataAbi],
abis: [Erc721Abi, INFTMetadataAbi],
features: {},
} as const;
@@ -257,7 +258,7 @@ export const FEATURE_NFT = /* @__PURE__ */ {
sdk: "sdk.erc721",
contracts: "erc721",
},
abis: [Erc721Abi],
abis: [Erc721Abi, IERC721MetadataAbi],
features: {
[FEATURE_NFT_BURNABLE.name]: FEATURE_NFT_BURNABLE,
[FEATURE_NFT_SUPPLY.name]: FEATURE_NFT_SUPPLY,
@@ -1,4 +1,4 @@
import IERC2771ContextAbi from "@thirdweb-dev/contracts-js/dist/abis/ERC2771Context.json";
import IERC2771ContextAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC2771Context.json";
import IAppURI from "@thirdweb-dev/contracts-js/dist/abis/IAppURI.json";
import IContractMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IContractMetadata.json";
import IDirectListingsAbi from "@thirdweb-dev/contracts-js/dist/abis/IDirectListings.json";
@@ -11,6 +11,9 @@ import IThirdwebPlatformFeeAbi from "@thirdweb-dev/contracts-js/dist/abis/IPlatf
import IThirdwebPrimarySaleAbi from "@thirdweb-dev/contracts-js/dist/abis/IPrimarySale.json";
import IThirdwebRoyaltyAbi from "@thirdweb-dev/contracts-js/dist/abis/IRoyalty.json";
import IOwnableAbi from "@thirdweb-dev/contracts-js/dist/abis/Ownable.json";
import IAirdropERC20 from "@thirdweb-dev/contracts-js/dist/abis/IAirdropERC20.json";
import IAirdropERC721 from "@thirdweb-dev/contracts-js/dist/abis/IAirdropERC721.json";
import IAirdropERC1155 from "@thirdweb-dev/contracts-js/dist/abis/IAirdropERC1155.json";
import IAccountFactory from "@thirdweb-dev/contracts-js/dist/abis/IAccountFactory.json";
import IAccountPermissions from "@thirdweb-dev/contracts-js/dist/abis/IAccountPermissions.json";
import IAccount from "@thirdweb-dev/contracts-js/dist/abis/IAccount.json";
@@ -232,9 +235,9 @@ export const FEATURE_PLUGIN_ROUTER = {
features: {},
} as const;
export const FEATURE_EXTENSION_ROUTER = {
name: "ExtensionRouter",
namespace: "extension.router",
export const FEATURE_DYNAMIC_CONTRACT = {
name: "DynamicContract",
namespace: "dynamic.contract",
docLinks: {
sdk: "",
//TODO
@@ -315,3 +318,39 @@ export const FEATURE_ACCOUNT = {
abis: [IAccount],
features: { [FEATURE_ACCOUNT_PERMISSIONS.name]: FEATURE_ACCOUNT_PERMISSIONS },
} as const;
export const FEATURE_AIRDROP_ERC20 = {
name: "AirdropERC20",
namespace: "airdrop20",
docLinks: {
// TODO
sdk: "",
contracts: "",
},
abis: [IAirdropERC20],
features: {},
} as const;
export const FEATURE_AIRDROP_ERC721 = {
name: "AirdropERC721",
namespace: "airdrop721",
docLinks: {
// TODO
sdk: "",
contracts: "",
},
abis: [IAirdropERC721],
features: {},
} as const;
export const FEATURE_AIRDROP_ERC1155 = {
name: "AirdropERC1155",
namespace: "airdrop1155",
docLinks: {
// TODO
sdk: "",
contracts: "",
},
abis: [IAirdropERC1155],
features: {},
} as const;
+31 -3
View File
@@ -41,8 +41,11 @@ export function getChainProvider(
// Add the chain to the supportedChains
const options = SDKOptionsSchema.parse(sdkOptions);
if (isChainConfig(network)) {
// @ts-expect-error - we know this is a chain and it will work to build the map
options.supportedChains = [network, ...options.supportedChains];
options.supportedChains = [
// @ts-expect-error - we know this is a chain and it will work to build the map
network,
...options.supportedChains.filter((c) => c.chainId !== network.chainId),
];
}
// Build a map of chainId -> ChainInfo based on the supportedChains
@@ -105,10 +108,35 @@ export function getChainIdFromNetwork(
);
}
export async function getChainIdOrName(
network: NetworkInput,
): Promise<number | string> {
if (isChainConfig(network)) {
// If it's a chain just return the chain id
return network.chainId;
} else if (typeof network === "number") {
// If it's a number (chainId) return it directly
return network;
} else if (typeof network === "number") {
// If it's a string (chain name) return the chain id from the map
return network;
} else if (isProvider(network)) {
return network.getNetwork().then((n) => n.chainId);
} else if (isSigner(network)) {
if (!network.provider) {
throw new Error("Signer does not have a provider");
}
return network.provider.getNetwork().then((n) => n.chainId);
}
throw new Error(`Cannot resolve chainId from: ${network}.`);
}
/**
* Check whether a NetworkInput value is a Chain config (naively, without parsing)
*/
export function isChainConfig(network: NetworkInput): network is Chain {
export function isChainConfig(
network: NetworkInput,
): network is Chain | ChainInfo {
return (
typeof network !== "string" &&
typeof network !== "number" &&
+15 -3
View File
@@ -1,4 +1,7 @@
import { fetchAndCachePublishedContractURI } from "../common/any-evm-utils/fetchAndCachePublishedContractURI";
import {
THIRDWEB_DEPLOYER,
fetchPublishedContractFromPolygon,
} from "../common/any-evm-utils/fetchPublishedContractFromPolygon";
import { getPrebuiltInfo } from "../common/legacy";
import { fetchAbiFromAddress } from "../common/metadata-resolver";
import { ALL_ROLES } from "../common/role";
@@ -194,7 +197,7 @@ export const MarketplaceV3Initializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
MarketplaceV3Initializer.getAbi(address, provider, storage),
MarketplaceV3Initializer.getAbi(address, provider, storage, options),
import("./prebuilt-implementations/marketplacev3"),
provider.getNetwork(),
]);
@@ -212,6 +215,7 @@ export const MarketplaceV3Initializer = {
address: Address,
provider: providers.Provider,
storage: ThirdwebStorage,
options?: SDKOptions,
) => {
const chainId = (await provider.getNetwork()).chainId;
const isZkSync = chainId === 280 || chainId === 324;
@@ -219,7 +223,15 @@ export const MarketplaceV3Initializer = {
// Can't resolve IPFS hash from plugin bytecode on ZkSync
// Thus, pull the composite ABI from the release page
if (isZkSync) {
const uri = await fetchAndCachePublishedContractURI("MarketplaceV3");
const publishedContract = await fetchPublishedContractFromPolygon(
THIRDWEB_DEPLOYER,
"MarketplaceV3",
"latest",
storage,
options?.clientId,
options?.secretKey,
);
const uri = publishedContract.metadataUri;
const compositeAbi = await getCompositeABIfromRelease(uri, storage);
return compositeAbi;
@@ -48,7 +48,7 @@ export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
private static contractRoles = NFT_BASE_CONTRACT_ROLES;
public abi: Abi;
public sales: ContractPrimarySale<PrebuiltEditionDrop>;
public sales: ContractPrimarySale;
public platformFees: ContractPlatformFee<PrebuiltEditionDrop>;
public encoder: ContractEncoder<PrebuiltEditionDrop>;
public estimator: GasCostEstimator<PrebuiltEditionDrop>;

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