Compare commits

...
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
b4676e1b4e Version Packages (#1279)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-07-04 11:48:14 -07:00
Jonas DanielsandGitHub 0135a7790c [storage] - fix head request schema (#1287) 2023-07-04 18:22:56 +00:00
Jonas DanielsandGitHub 2d088d367c [storage] - fix double / case (#1286) 2023-07-04 17:43:01 +00:00
Jonas DanielsandGitHub 546353a479 [storage] - add additional fallback gateways (#1285) 2023-07-04 17:08:03 +00:00
9daf044926 [STORAGE] Use subdomain-based paths for our IPFS gateway (#1232)
Co-authored-by: Jonas Daniels <[email protected]>
2023-07-04 16:14:05 +00:00
Kien NgoandGitHub 7054f9f016 Fix #1201 (#1282) 2023-07-01 00:48:32 +00:00
nkrishangandGitHub a3bb17cb33 [SDK] Handle ERC4337Signer correctly in signTypedDataInternal (#1281) 2023-06-30 23:30:29 +00:00
d03645aefd Omit marketplacev3 filter parameters that have no effect (#1221)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-30 23:22:24 +00:00
Mariano FuentesandGitHub 53626f8100 Don't rely on package.json to run export (#1280) 2023-06-30 16:59:43 +00:00
Jonas DanielsandGitHub 8a389f1295 [all] - update dependencies (#1278) 2023-06-30 02:55:20 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
4e5eb13b82 Version Packages (#1266)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-29 19:11:03 -07:00
2b11353909 [SDK] remove ethers/lib/utils dependency (#1277)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-30 01:10:47 +00:00
Manan TankandGitHub 5882091eab [chains] Fix RPC override issue (#1276) 2023-06-29 22:27:59 +00:00
Mariano FuentesandGitHub 8fc5f204b0 Fix bugs with cli deploy (#1274) 2023-06-29 18:11:25 +00:00
nkrishangandGitHub c953571588 mass rename smart-wallet -> account (#1271) 2023-06-29 12:26:48 +00:00
Manan TankandGitHub edcd22d612 [react-core] Add autoConnectTimeout (#1273) 2023-06-29 12:19:43 +00:00
iketwandGitHub 0d5503aae9 [RN] Only handle link if coinbase in supportedWallets (#1270) 2023-06-28 21:56:12 +00:00
Manan TankandGitHub 998e521733 [wallets, react] expose advancedOptions in paper (#1269) 2023-06-28 21:08:34 +00:00
FirekeeperandGitHub be606dd3c9 [paper] set signer null on disconnect (#1267) 2023-06-28 17:26:35 +00:00
d794b8f9f4 update: Add zerion to useInstalledWallets (#1210)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-28 16:50:36 +00:00
YashandGitHub 21b29490d4 [SDK] Tests for new publish+deploy flow (#1244) 2023-06-28 16:23:36 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
7b1d62b323 Version Packages (#1262)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-28 08:07:57 -07:00
Manan TankandGitHub e78da6b36c [wallets] Wallet connect v2 corrections (#1265) 2023-06-28 13:34:42 +00:00
ed711c8cb2 [Wallets] Use min number of chains if user passes more than 50 chains (#1263)
Co-authored-by: Manan Tank <[email protected]>
2023-06-28 12:04:28 +00:00
05a7495a13 [Wallets] handle passing RPC urls to SmartWallet config (#1255)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-28 07:20:04 +00:00
127 changed files with 9112 additions and 7011 deletions
+7 -7
View File
@@ -34,19 +34,19 @@
"packageManager": "[email protected]",
"dependencies": {
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.1",
"@changesets/get-dependents-graph": "^1.3.5",
"@changesets/get-release-plan": "^3.0.16",
"@changesets/cli": "^2.26.2",
"@changesets/get-dependents-graph": "^1.3.6",
"@changesets/get-release-plan": "^3.0.17",
"@changesets/parse": "^0.3.16",
"@manypkg/cli": "^0.20.0",
"@manypkg/get-packages": "^1.1.3",
"@playwright/test": "1.31.2",
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@types/node": "^18.15.11",
"eslint": "^8.42.0",
"@types/node": "^18.16.18",
"eslint": "^8.43.0",
"mocha": "^10.2.0",
"prettier": "^2.8.7",
"turbo": "^1.9.8",
"prettier": "^2.8.8",
"turbo": "^1.10.6",
"yalc": "1.0.0-pre.53"
},
"manypkg": {
+23
View File
@@ -1,5 +1,28 @@
# @thirdweb-dev/auth
## 3.2.8
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- Updated dependencies [[`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2)]:
- @thirdweb-dev/wallets@1.0.4
## 3.2.7
### Patch Changes
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
- @thirdweb-dev/wallets@1.0.3
## 3.2.6
### Patch Changes
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
- @thirdweb-dev/wallets@1.0.2
## 3.2.5
### Patch Changes
+19 -19
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.5",
"version": "3.2.8",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
@@ -80,29 +80,29 @@
}
},
"devDependencies": {
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@microsoft/api-documenter": "^7.22.21",
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/tsdoc": "^0.14.1",
"@preconstruct/cli": "^2.2.1",
"@preconstruct/cli": "^2.7.0",
"@solana/web3.js": "^1.62.0",
"@swc-node/register": "^1.5.1",
"@swc/core": "^1.3.23",
"@swc-node/register": "^1.6.6",
"@swc/core": "^1.3.67",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.5",
"@types/cookie": "^0.5.1",
"@types/cookie-parser": "^1.4.3",
"@types/express": "^4.17.13",
"@types/mocha": "^10.0.0",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"chai": "^4.3.6",
"cookie-parser": "^1.4.6",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-inclusive-language": "^2.2.0",
@@ -111,10 +111,10 @@
"ethers": "^5.7.2",
"express": "^4.18.1",
"mocha": "^10.2.0",
"next": "^12.2.0",
"next-auth": "^4.20.1",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
"next": "^12.3.4",
"next-auth": "^4.22.1",
"prettier": "^2.8.8",
"typescript": "^5.1.6"
},
"peerDependencies": {
"@solana/web3.js": "^1.73.0",
+14
View File
@@ -1,5 +1,19 @@
# @thirdweb-dev/chains
## 0.1.27
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- [#1281](https://github.com/thirdweb-dev/js/pull/1281) [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96) Thanks [@nkrishang](https://github.com/nkrishang)! - Handle ERC4337Signer correctly for signTypedData
## 0.1.26
### Patch Changes
- [#1276](https://github.com/thirdweb-dev/js/pull/1276) [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad) Thanks [@MananTank](https://github.com/MananTank)! - Do not change order or RPCs in `getChainRPCs` to Fix RPC override issue
## 0.1.25
### Patch Changes
+1 -1
View File
@@ -10,9 +10,9 @@ export default {
},
"rpc": [
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://mainnet.infura.io/v3/${INFURA_API_KEY}",
"wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}",
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://api.mycryptoapi.com/eth",
"https://cloudflare-eth.com",
"https://ethereum.publicnode.com"
+1 -1
View File
@@ -4,8 +4,8 @@ export default {
"chain": "ETH",
"rpc": [
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://mainnet.optimism.io/"
],
"faucets": [],
+41
View File
@@ -0,0 +1,41 @@
import type { Chain } from "../src/types";
export default {
"name": "Metachain One Mainnet",
"chain": "METAO",
"icon": {
"url": "ipfs://QmTmo2QAtX5PbhX96vewnvH4Vc5H83Ft2DJGi6tAqTcFij",
"width": 1000,
"height": 981,
"format": "png"
},
"rpc": [
"https://metachain-one.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.metachain.one",
"https://rpc2.metachain.one"
],
"faucets": [],
"nativeCurrency": {
"name": "Metao",
"symbol": "METAO",
"decimals": 18
},
"infoURL": "https://metachain.one",
"shortName": "metao",
"chainId": 112358,
"networkId": 112358,
"explorers": [
{
"name": "blockscout",
"url": "https://explorer.metachain.one",
"icon": {
"url": "ipfs://bafybeifu5tpui7dk5cjoo54kde7pmuthvnl7sdykobuarsxgu7t2izurnq",
"width": 512,
"height": 512,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "metachain-one"
} as const satisfies Chain;
+1 -1
View File
@@ -10,8 +10,8 @@ export default {
},
"rpc": [
"https://polygon.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://polygon-rpc.com/",
"https://rpc-mainnet.matic.network",
"https://matic-mainnet.chainstacklabs.com",
+1 -1
View File
@@ -4,8 +4,8 @@ export default {
"chain": "ETH",
"rpc": [
"https://optimism-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://optimism-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://goerli.optimism.io/"
],
"faucets": [
+1 -1
View File
@@ -13,8 +13,8 @@ export default {
},
"rpc": [
"https://arbitrum-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://arbitrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://goerli-rollup.arbitrum.io/rpc/"
],
"faucets": [],
+1 -1
View File
@@ -5,9 +5,9 @@ export default {
"chain": "ETH",
"rpc": [
"https://goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://goerli.infura.io/v3/${INFURA_API_KEY}",
"wss://goerli.infura.io/v3/${INFURA_API_KEY}",
"https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://rpc.goerli.mudit.blog/",
"https://ethereum-goerli.publicnode.com"
],
+1
View File
@@ -5,6 +5,7 @@ export default {
"rpc": [
"https://rollux.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.rollux.com",
"https://rollux.public-rpc.com",
"wss://rpc.rollux.com/wss",
"https://rpc.ankr.com/rollux/${ANKR_API_KEY}"
],
+3 -3
View File
@@ -5,10 +5,10 @@ export default {
"chain": "ETH",
"rpc": [
"https://linea-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.goerli.linea.build",
"wss://rpc.goerli.linea.build",
"https://linea-goerli.infura.io/v3/${INFURA_API_KEY}",
"wss://linea-goerli.infura.io/v3/${INFURA_API_KEY}"
"wss://linea-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://rpc.goerli.linea.build",
"wss://rpc.goerli.linea.build"
],
"faucets": [
"https://faucetlink.to/goerli"
+53
View File
@@ -0,0 +1,53 @@
import type { Chain } from "../src/types";
export default {
"name": "Cascadia Testnet",
"chain": "Cascadia",
"rpc": [
"https://cascadia-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.cascadia.foundation"
],
"faucets": [
"https://www.cascadia.foundation/faucet"
],
"nativeCurrency": {
"name": "CC",
"symbol": "tCC",
"decimals": 18
},
"infoURL": "https://www.cascadia.foundation",
"shortName": "cascadia",
"chainId": 6102,
"networkId": 6102,
"icon": {
"url": "ipfs://QmQtcwxNiJ9D1QDz4k6jZ7qacLcqMk6CeW85TTBWBvNp3z",
"width": 256,
"height": 256,
"format": "png"
},
"explorers": [
{
"name": "Cascadia EVM Explorer",
"url": "https://explorer.cascadia.foundation",
"standard": "none",
"icon": {
"url": "ipfs://QmQtcwxNiJ9D1QDz4k6jZ7qacLcqMk6CeW85TTBWBvNp3z",
"width": 256,
"height": 256,
"format": "png"
}
},
{
"name": "Cascadia Cosmos Explorer",
"url": "https://validator.cascadia.foundation",
"standard": "none",
"icon": {
"url": "ipfs://QmQtcwxNiJ9D1QDz4k6jZ7qacLcqMk6CeW85TTBWBvNp3z",
"width": 256,
"height": 256,
"format": "png"
}
}
],
"testnet": true,
"slug": "cascadia-testnet"
} as const satisfies Chain;
+1 -1
View File
@@ -11,8 +11,8 @@ export default {
},
"rpc": [
"https://mumbai.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://polygon-mumbai.infura.io/v3/${INFURA_API_KEY}",
"https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://matic-mumbai.chainstacklabs.com",
"https://rpc-mumbai.maticvigil.com",
"https://matic-testnet-archive-rpc.bwarelabs.com",
+2 -13
View File
@@ -26,19 +26,8 @@ export default {
},
"explorers": [
{
"name": "Evmos EVM Explorer",
"url": "https://evm.evmos.dev",
"standard": "EIP3091",
"icon": {
"url": "ipfs://QmeZW6VKUFTbz7PPW8PmDR3ZHa6osYPLBFPnW8T5LSU49c",
"width": 400,
"height": 400,
"format": "png"
}
},
{
"name": "Evmos Cosmos Explorer",
"url": "https://explorer.evmos.dev",
"name": "Evmos Explorer (Escan)",
"url": "https://testnet.escan.live",
"standard": "none",
"icon": {
"url": "ipfs://QmeZW6VKUFTbz7PPW8PmDR3ZHa6osYPLBFPnW8T5LSU49c",
+1 -13
View File
@@ -4,7 +4,6 @@ export default {
"chain": "Evmos",
"rpc": [
"https://evmos.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://eth.bd.evmos.org:8545",
"https://evmos-evm.publicnode.com"
],
"faucets": [],
@@ -25,7 +24,7 @@ export default {
},
"explorers": [
{
"name": "Evmos EVM Explorer (Escan)",
"name": "Evmos Explorer (Escan)",
"url": "https://escan.live",
"standard": "none",
"icon": {
@@ -34,17 +33,6 @@ export default {
"height": 400,
"format": "png"
}
},
{
"name": "Evmos Cosmos Explorer (Mintscan)",
"url": "https://www.mintscan.io/evmos",
"standard": "none",
"icon": {
"url": "ipfs://QmeZW6VKUFTbz7PPW8PmDR3ZHa6osYPLBFPnW8T5LSU49c",
"width": 400,
"height": 400,
"format": "png"
}
}
],
"testnet": false,
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.25",
"version": "0.1.27",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
@@ -23,18 +23,18 @@
},
"author": "thirdweb eng <[email protected]>",
"devDependencies": {
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@babel/runtime": "^7.19.0",
"@preconstruct/cli": "^2.2.1",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.5",
"@preconstruct/cli": "^2.7.0",
"@thirdweb-dev/tsconfig": "workspace:*",
"axios": "^1.3.4",
"deepmerge": "^4.3.0",
"axios": "^1.4.0",
"deepmerge": "^4.3.1",
"eslint-config-thirdweb": "workspace:*",
"jest": "^29.4.3",
"plop": "^3.1.2",
"typescript": "^4.7.4"
"typescript": "^5.1.6"
},
"preconstruct": {
"entrypoints": [
@@ -80,6 +80,33 @@ chains = chains
};
});
/**
* Sort RPCs in chain
* @param {Chain} chain
*/
function sortRPCs(chain) {
const thirdwebRPCs = [];
const alchemyRPCs = [];
const infuraRPCs = [];
const otherRPCs = [];
chain.rpc.forEach((rpc) => {
if (rpc.includes("${THIRDWEB_API_KEY}")) {
thirdwebRPCs.push(rpc);
} else if (rpc.includes("${ALCHEMY_API_KEY}")) {
alchemyRPCs.push(rpc);
} else if (rpc.includes("${INFURA_API_KEY}")) {
infuraRPCs.push(rpc);
} else {
otherRPCs.push(rpc);
}
});
chain.rpc = [...thirdwebRPCs, ...infuraRPCs, ...alchemyRPCs, ...otherRPCs];
}
chains.forEach(sortRPCs);
const imports = [];
const exports = [];
const exportNames = [];
File diff suppressed because one or more lines are too long
+30 -44
View File
@@ -28,59 +28,45 @@ export function getChainRPCs(
...options,
};
const modeChains = chain.rpc.filter((rpc) => {
if (rpc.startsWith("http") && mode === "http") {
return true;
}
if (rpc.startsWith("ws") && mode === "ws") {
return true;
const processedRPCs: string[] = [];
chain.rpc.forEach((rpc) => {
// exclude RPC if mode mismatch
if (mode === "http" && !rpc.startsWith("http")) {
return;
}
return false;
if (mode === "ws" && !rpc.startsWith("ws")) {
return;
}
// Replace API_KEY placeholder with value
if (thirdwebApiKey && rpc.includes("${THIRDWEB_API_KEY}")) {
processedRPCs.push(rpc.replace("${THIRDWEB_API_KEY}", thirdwebApiKey));
} else if (infuraApiKey && rpc.includes("${INFURA_API_KEY}")) {
processedRPCs.push(rpc.replace("${INFURA_API_KEY}", infuraApiKey));
} else if (alchemyApiKey && rpc.includes("${ALCHEMY_API_KEY}")) {
processedRPCs.push(rpc.replace("${ALCHEMY_API_KEY}", alchemyApiKey));
}
// exclude RPCs with unknown placeholder
else if (rpc.includes("${")) {
return;
}
// add as is
else {
processedRPCs.push(rpc);
}
});
const thirdwebRPC = modeChains
.filter((rpc) => {
return rpc.includes("${THIRDWEB_API_KEY}") && thirdwebApiKey;
})
.map((rpc) =>
thirdwebApiKey ? rpc.replace("${THIRDWEB_API_KEY}", thirdwebApiKey) : rpc,
);
const alchemyRPC = modeChains
.filter((rpc) => {
return rpc.includes("${ALCHEMY_API_KEY}") && alchemyApiKey;
})
.map((rpc) =>
alchemyApiKey ? rpc.replace("${ALCHEMY_API_KEY}", alchemyApiKey) : rpc,
);
const infuraRPC = modeChains
.filter((rpc) => {
return rpc.includes("${INFURA_API_KEY}") && infuraApiKey;
})
.map((rpc) =>
infuraApiKey ? rpc.replace("${INFURA_API_KEY}", infuraApiKey) : rpc,
);
const allOtherRpcs = modeChains.filter((rpc) => {
return !rpc.includes("${");
});
const orderedRPCs = [
...thirdwebRPC,
...infuraRPC,
...alchemyRPC,
...allOtherRpcs,
];
if (orderedRPCs.length === 0) {
if (processedRPCs.length === 0) {
throw new Error(
`No RPC available for chainId "${chain.chainId}" with mode ${mode}`,
);
}
return orderedRPCs;
return processedRPCs;
}
/**
+23
View File
@@ -1,5 +1,28 @@
# thirdweb
## 0.10.29
### Patch Changes
- [#1280](https://github.com/thirdweb-dev/js/pull/1280) [`53626f81`](https://github.com/thirdweb-dev/js/commit/53626f8100f400c46333617b14bd9fc144a7e801) Thanks [@Marfuen](https://github.com/Marfuen)! - Don't rely on package.json to export app
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- Updated dependencies [[`2d088d36`](https://github.com/thirdweb-dev/js/commit/2d088d367ca54233836dc69712fd411ab7924205), [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2), [`9daf0449`](https://github.com/thirdweb-dev/js/commit/9daf044926bf995ac8998929dbeca548c5eb8561), [`546353a4`](https://github.com/thirdweb-dev/js/commit/546353a479c11533818ef917c0f6b4d6f8f69872), [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96), [`0135a779`](https://github.com/thirdweb-dev/js/commit/0135a7790cf2acde6b701cb41ea10dd311da5ec3)]:
- @thirdweb-dev/storage@1.1.6
- @thirdweb-dev/chains@0.1.27
- @thirdweb-dev/sdk@3.10.28
## 0.10.28
### Patch Changes
- [#1274](https://github.com/thirdweb-dev/js/pull/1274) [`8fc5f204`](https://github.com/thirdweb-dev/js/commit/8fc5f204b00733089c02beee92c86b0f1fcac271) Thanks [@Marfuen](https://github.com/Marfuen)! - Added all detections for deploy command and some minor bug fixes
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad)]:
- @thirdweb-dev/sdk@3.10.27
- @thirdweb-dev/chains@0.1.26
## 0.10.27
### Patch Changes
+1 -1
View File
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
// this creates an app, can take some time that's fine
jest.setTimeout(120_000);
jest.setTimeout(240_000);
describe("npx thirdweb detect", () => {
it("should detect ERC721Base extensions", async () => {
+15 -15
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.10.27",
"version": "0.10.29",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -14,25 +14,25 @@
"@types/async-retry": "^1.3.0",
"@types/cross-spawn": "^6.0.2",
"@types/inquirer": "^8.2.1",
"@types/jest": "^29.2.1",
"@types/jest": "^29.5.2",
"@types/js-yaml": "^4.0.5",
"@types/node": "^18.0.0",
"@types/prompts": "^2.0.14",
"@types/node": "^18.16.18",
"@types/prompts": "^2.4.4",
"@types/rimraf": "^3.0.0",
"@types/tar": "^6.1.2",
"@types/update-notifier": "^6.0.1",
"@types/tar": "^6.1.5",
"@types/update-notifier": "^6.0.4",
"@types/validate-npm-package-name": "^4.0.0",
"chalk": "^5.2.0",
"chalk": "^5.3.0",
"cross-spawn": "^7.0.3",
"eslint-config-thirdweb": "workspace:*",
"hardhat": "^2.9.3",
"hardhat": "^2.16.1",
"jest": "^29.4.3",
"ora": "^6.1.2",
"prettier": "^2.7.1",
"ts-jest": "^29.0.3",
"ora": "^6.3.1",
"prettier": "^2.8.8",
"ts-jest": "^29.1.0",
"ts-node": "^10.7.0",
"tsup": "^6.2.3",
"typescript": "^4.7.4"
"tsup": "^6.7.0",
"typescript": "^5.1.6"
},
"dependencies": {
"@iarna/toml": "^2.2.5",
@@ -53,10 +53,10 @@
"rimraf": "^3.0.2",
"solc": "0.8.17",
"sync-disk-cache": "^2.1.0",
"tar": "^6.1.11",
"tar": "^6.1.15",
"update-notifier": "^6.0.2",
"validate-npm-package-name": "^4.0.0",
"yaml": "^2.1.1"
"yaml": "^2.3.1"
},
"bin": {
"thirdweb": "./dist/cli/index.js"
@@ -1,27 +1,28 @@
import inquirer from "inquirer";
import { info } from "../helpers/logger";
import { FrameworkType, PackageManagerType } from "../types/ProjectType";
import inquirer from "inquirer";
import NextDetector from "./frameworks/next";
import CRADetector from "./frameworks/cra";
import RemixDetector from "./frameworks/remix";
import GatsbyDetector from "./frameworks/gatsby";
import VueDetector from "./frameworks/vue";
import ReactNativeCLIDetector from "./frameworks/reactNativeCli";
import DjangoDetector from "./frameworks/django";
import ExpoDetector from "./frameworks/expo";
import FoundryDetector from "./frameworks/foundry";
import HardhatDetector from "./frameworks/hardhat";
import { FrameworkDetector } from "./detector";
import TruffleDetector from "./frameworks/truffle";
import BrownieDetector from "./frameworks/brownie";
import FastAPIDetector from "./frameworks/fastAPI";
import FlaskDetector from "./frameworks/flask";
import PopulusDetector from "./frameworks/populus";
import FastifyDetector from "./frameworks/fastify";
import CRADetector from "./frameworks/cra";
import DjangoDetector from "./frameworks/django";
import EchoDetector from "./frameworks/echo";
import ExpoDetector from "./frameworks/expo";
import FastAPIDetector from "./frameworks/fastAPI";
import FastifyDetector from "./frameworks/fastify";
import FiberDetector from "./frameworks/fiber";
import FlaskDetector from "./frameworks/flask";
import FoundryDetector from "./frameworks/foundry";
import GatsbyDetector from "./frameworks/gatsby";
import GinDetector from "./frameworks/gin";
import HardhatDetector from "./frameworks/hardhat";
import NextDetector from "./frameworks/next";
import PopulusDetector from "./frameworks/populus";
import ReactNativeCLIDetector from "./frameworks/reactNativeCli";
import RemixDetector from "./frameworks/remix";
import RevelDetector from "./frameworks/revel";
import TruffleDetector from "./frameworks/truffle";
import ViteDetector from "./frameworks/vite";
import VueDetector from "./frameworks/vue";
import ZenjectDetector from "./frameworks/zenject";
export default async function detect(
@@ -50,6 +51,7 @@ export default async function detect(
new RevelDetector(),
new TruffleDetector(),
new VueDetector(),
new ViteDetector(),
new ZenjectDetector(),
];
@@ -1,13 +1,12 @@
import inquirer from "inquirer";
import { info } from "../helpers/logger";
import { LibraryType, PackageManagerType } from "../types/ProjectType";
import { LibraryDetector } from "./detector";
import inquirer from "inquirer";
import ReactDetector from "./libraries/react";
import ExpressDetector from "./libraries/express";
import ReactNativeDetector from "./libraries/reactNative";
import ViteDetector from "./libraries/vite";
import Web3PyDetector from "./libraries/web3py";
import PlayMakerDetector from "./libraries/playmaker";
import ReactDetector from "./libraries/react";
import ReactNativeDetector from "./libraries/reactNative";
import Web3PyDetector from "./libraries/web3py";
export default async function detect(
path: string,
@@ -19,7 +18,6 @@ export default async function detect(
new ExpressDetector(),
new ReactDetector(),
new ReactNativeDetector(),
new ViteDetector(),
new Web3PyDetector(),
new PlayMakerDetector(),
];
@@ -1,10 +1,10 @@
import { LibraryDetector } from "../detector";
import { existsSync, readFileSync } from "fs";
import { LibraryType } from "../../types/ProjectType";
import { parsePackageJson } from "../../../lib/utils";
import { FrameworkType } from "../../types/ProjectType";
import { FrameworkDetector } from "../detector";
export default class ViteDetector implements LibraryDetector {
public libraryType: LibraryType = "vite";
export default class ViteDetector implements FrameworkDetector {
public frameworkType: FrameworkType = "vite";
public matches(path: string): boolean {
const packageJsonPath = path + "/package.json";
@@ -16,7 +16,7 @@ export default class ViteDetector implements LibraryDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const viteDependencyExists =
dependencies["vite"] || devDependencies["vite"] || false;
!!dependencies["vite"] || !!devDependencies["vite"] || false;
return viteDependencyExists;
}
@@ -56,6 +56,7 @@ export type FrameworkType =
| "revel"
| "fiber"
| "zenject"
| "vite"
| "none";
export type LibraryType =
| "react"
+46 -19
View File
@@ -1,30 +1,57 @@
import NPMDetector from "../core/detection/npm";
import ViteDetector from "../core/detection/vite";
import YarnDetector from "../core/detection/yarn";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import detectFramework from "../core/detection/detectFramework";
import detectPackageManager from "../core/detection/detectPackageManager";
import { logger } from "../core/helpers/logger";
import { runCommand } from "../create/helpers/run-command";
import { upload } from "../storage/command";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
export async function deployApp(distPath = "dist", projectPath = ".") {
const storage = new ThirdwebStorage();
const supportedFrameworks = [new ViteDetector()];
const detectedPackageManager = await detectPackageManager(projectPath, {});
const detectedFramework = await detectFramework(projectPath, {}, detectedPackageManager);
const possibleProjects = supportedFrameworks
.filter((detector) => detector.matches(projectPath))
.map((detector) => detector.projectType);
const hasYarn = new YarnDetector().matches(".");
const hasNPM = new NPMDetector().matches(".");
if (possibleProjects.length === 0) {
if (detectedFramework === "none") {
throw new Error("No supported project detected");
}
switch (detectedFramework) {
case "next":
distPath = "out";
break;
case "cra":
distPath = "build";
break;
default:
break;
}
logger.info(`Detected project type: ${detectedFramework}`);
logger.info(`Detected package manager: ${detectedPackageManager}`);
logger.info(`distPath: ${distPath}`);
logger.info(`projectPath: ${projectPath}`);
try {
if (hasYarn) {
await runCommand("yarn", ["build"]);
} else if (hasNPM) {
await runCommand("npm", ["build"]);
switch (detectedPackageManager) {
case "yarn":
await runCommand("yarn", ["build"], true);
if (detectedFramework === "next") {
await runCommand("yarn", ["next", "export"], true);
}
break;
case "npm":
await runCommand("npm", ["run", "build"], true);
if (detectedFramework === "next") {
await runCommand("npx", ["next", "export"], true);
}
break;
case "pnpm":
await runCommand("pnpm", ["build"], true);
if (detectedFramework === "next") {
await runCommand("pnpm", ["next", "export"], true);
}
break;
default:
throw new Error("No supported package manager detected");
}
} catch (err) {
console.error("Can't build project");
@@ -33,9 +60,9 @@ export async function deployApp(distPath = "dist", projectPath = ".") {
try {
const uri = await upload(storage, distPath);
return `https://thirdweb.com/app/deploy/${uri.replace("ipfs://", "")}`;
return `${uri.replace("ipfs://", "https://ipfs-public.thirdwebcdn.com/ipfs/")}`;
} catch (err) {
console.error("Can't upload project");
console.error("Can't upload project", err);
return Promise.reject("Can't upload project");
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
import { spinner } from "../core/helpers/logger";
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
import fs from "fs";
import path from "path";
import { spinner } from "../core/helpers/logger";
function recurseFiles(
uploadPath: string,
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/contracts-js
## 1.3.8
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
## 1.3.7
### Patch Changes
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.3.7",
"version": "1.3.8",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"browser": {
@@ -13,17 +13,17 @@
"@thirdweb-dev/contracts": "3.5.9"
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@babel/preset-env": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@preconstruct/cli": "^2.2.1",
"@preconstruct/cli": "^2.7.0",
"@thirdweb-dev/tsconfig": "workspace:*",
"@typechain/ethers-v5": "10.0.0",
"eslint-config-thirdweb": "workspace:*",
"ethers": "^5.7.2",
"typechain": "^8.1.0",
"typescript": "^4.7.4"
"typechain": "^8.2.0",
"typescript": "^5.1.6"
},
"peerDependencies": {
"ethers": "^5"
@@ -1,5 +1,11 @@
# eslint-config-thirdweb
## 0.1.5
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
## 0.1.4
### Patch Changes
+4 -4
View File
@@ -1,13 +1,13 @@
{
"name": "eslint-config-thirdweb",
"version": "0.1.4",
"version": "0.1.5",
"main": "index.js",
"license": "Apache-2.0",
"dependencies": {
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"eslint-config-next": "13.2.4",
"eslint-config-prettier": "^8.3.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-turbo": "^0.0.8",
"eslint-plugin-react": "^7.28.0"
},
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/pay
## 0.1.2
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
## 0.1.1
### Patch Changes
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/pay",
"version": "0.1.1",
"version": "0.1.2",
"main": "dist/thirdweb-dev-pay.cjs.js",
"module": "dist/thirdweb-dev-pay.esm.js",
"exports": {
@@ -33,13 +33,13 @@
},
"sideEffects": false,
"dependencies": {
"@coinbase/cbpay-js": "^1.6.0"
"@coinbase/cbpay-js": "^1.7.0"
},
"devDependencies": {
"@preconstruct/cli": "^2.2.1",
"typescript": "^4.7.4",
"@preconstruct/cli": "^2.7.0",
"@thirdweb-dev/tsconfig": "workspace:*",
"eslint-config-thirdweb": "workspace:*",
"@thirdweb-dev/tsconfig": "workspace:*"
"typescript": "^5.1.6"
},
"scripts": {
"format": "prettier --write 'src/**/*'",
+32
View File
@@ -1,5 +1,37 @@
# @thirdweb-dev/react-core
## 3.14.8
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- Updated dependencies [[`2d088d36`](https://github.com/thirdweb-dev/js/commit/2d088d367ca54233836dc69712fd411ab7924205), [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2), [`9daf0449`](https://github.com/thirdweb-dev/js/commit/9daf044926bf995ac8998929dbeca548c5eb8561), [`546353a4`](https://github.com/thirdweb-dev/js/commit/546353a479c11533818ef917c0f6b4d6f8f69872), [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96), [`0135a779`](https://github.com/thirdweb-dev/js/commit/0135a7790cf2acde6b701cb41ea10dd311da5ec3)]:
- @thirdweb-dev/storage@1.1.6
- @thirdweb-dev/wallets@1.0.4
- @thirdweb-dev/chains@0.1.27
- @thirdweb-dev/sdk@3.10.28
## 3.14.7
### Patch Changes
- [#1271](https://github.com/thirdweb-dev/js/pull/1271) [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8) Thanks [@nkrishang](https://github.com/nkrishang)! - Rename smart wallets to account
- [#1273](https://github.com/thirdweb-dev/js/pull/1273) [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145) Thanks [@MananTank](https://github.com/MananTank)! - Add `autoConnectTimeout` to `ThirdwebProvider` to timeout wallet autoconnect
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
- @thirdweb-dev/wallets@1.0.3
- @thirdweb-dev/sdk@3.10.27
- @thirdweb-dev/chains@0.1.26
## 3.14.6
### Patch Changes
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
- @thirdweb-dev/wallets@1.0.2
## 3.14.5
### Patch Changes
+17 -17
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.5",
"version": "3.14.8",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -66,26 +66,26 @@
},
"sideEffects:": false,
"devDependencies": {
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/runtime": "^7.19.0",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.5",
"@microsoft/api-documenter": "^7.22.21",
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/tsdoc": "^0.14.1",
"@preconstruct/cli": "^2.2.1",
"@preconstruct/cli": "^2.7.0",
"@solana/wallet-adapter-react": "^0.15.19",
"@solana/web3.js": "^1.62.0",
"@thirdweb-dev/auth": "workspace:*",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/js-cookie": "^3.0.3",
"@types/mime": "3.0.0",
"@types/react": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"@types/react": "^18.2.14",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-better-tree-shaking": "0.0.3",
"eslint-plugin-import": "^2.26.0",
@@ -93,12 +93,12 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.2",
"prettier": "^2.7.1",
"prettier": "^2.8.8",
"react": "^18.2.0",
"typescript": "^4.7.4"
"typescript": "^5.1.6"
},
"dependencies": {
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query": "^4.29.19",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/generated-abis": "workspace:^",
"@thirdweb-dev/sdk": "workspace:*",
@@ -61,6 +61,15 @@ export interface ThirdwebProviderCoreProps<TChains extends Chain[]>
* Whether or not to automatically switch to wallet's network to active chain
*/
autoSwitch?: boolean;
/**
* Timeout for auto-connecting wallet in milliseconds
*
* If wallet fails to connect in this time, it will stop trying to connect and user will have to manually connect
*
* @defaultValue 15000
*/
autoConnectTimeout?: number;
}
export const ThirdwebProviderCore = <TChains extends Chain[]>({
@@ -145,6 +154,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
dAppMeta={dAppMeta}
activeChain={activeChainWithKey}
autoSwitch={props.autoSwitch}
autoConnectTimeout={props.autoConnectTimeout}
>
<ThirdwebSDKProviderWrapper
queryClient={props.queryClient}
@@ -101,12 +101,15 @@ export function ThirdwebWalletProvider(
dAppMeta?: DAppMetaData;
chains: Chain[];
autoSwitch?: boolean;
autoConnectTimeout?: number;
}>,
) {
const [signer, setSigner] = useState<Signer | undefined>(undefined);
const [connectionStatus, setConnectionStatus] =
useState<ConnectionStatus>("unknown");
const autoConnectTimeout = props.autoConnectTimeout || 15000;
const [activeWallet, setActiveWallet] = useState<
WalletInstance | undefined
>();
@@ -311,8 +314,14 @@ export function ThirdwebWalletProvider(
const personalWalletInstance = createWalletInstance(personalWalleObj);
try {
await personalWalletInstance.autoConnect(
personalWalletInfo.connectParams,
await timeoutPromise(
personalWalletInstance.autoConnect(
personalWalletInfo.connectParams,
),
{
ms: autoConnectTimeout,
message: "Failed to Auto connect. Auto connect timed out.",
},
);
} catch (e) {
console.error(e);
@@ -337,7 +346,10 @@ export function ThirdwebWalletProvider(
try {
setConnectionStatus("connecting");
await wallet.autoConnect(walletInfo.connectParams);
await timeoutPromise(wallet.autoConnect(walletInfo.connectParams), {
ms: autoConnectTimeout,
message: "Failed to Auto connect. Auto connect timed out.",
});
setConnectedWallet(wallet, walletInfo.connectParams, true);
} catch (e) {
console.error(e);
@@ -356,6 +368,7 @@ export function ThirdwebWalletProvider(
props.shouldAutoConnect,
activeWallet,
connectionStatus,
autoConnectTimeout,
]);
const connectWallet = useCallback(
@@ -496,3 +509,32 @@ async function saveLastConnectedWalletInfo(
console.error("Error saving the last connected wallet info", e);
}
}
/**
* Timeout a promise with a given Error message if the promise does not resolve in given time
*
* @param promise - Promise to track for timeout
* @param option - timeout options
* @returns
*/
function timeoutPromise<T>(
promise: Promise<T>,
option: { ms: number; message: string },
) {
return new Promise<T>((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error(option.message));
}, option.ms);
promise.then(
(res) => {
clearTimeout(timeoutId);
resolve(res);
},
(err) => {
clearTimeout(timeoutId);
reject(err);
},
);
});
}
@@ -0,0 +1,185 @@
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
import { WalletAddress } from "../../types";
import {
cacheKeys,
invalidateContractAndBalances,
} from "../../utils/cache-keys";
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import {
useMutation,
useQueryClient,
UseQueryResult,
} from "@tanstack/react-query";
import type { AccountEvent, SmartContract } from "@thirdweb-dev/sdk";
import type { BytesLike } from "ethers";
import invariant from "tiny-invariant";
/** **********************/
/** READ HOOKS **/
/** **********************/
/**
* Get all accounts
*
* @example
* ```javascript
* const { data: accounts, isLoading, error } = useAccounts(contract);
* ```
*
* @param contract - an instance of a account factory contract
* @returns a response object that includes an array of all accounts with their associated admin
* @twfeature AccountFactory
* @see {@link https://portal.thirdweb.com/react/react.useaccounts?utm_source=sdk | Documentation}
* @beta
*/
export function useAccounts(
contract: RequiredParam<SmartContract>,
): UseQueryResult<AccountEvent[]> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.accountFactory.getAll(contractAddress),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.accountFactory.getAllAccounts,
"Contract instance does not support contract.accountFactory.getAllAccounts",
);
return contract.accountFactory.getAllAccounts();
},
{ enabled: !!contract },
);
}
/**
* Get all accounts associated with the provided address
*
* @example
* ```javascript
* const { data: accountsForAddress, isLoading, error } = useAccountsForAddress(contract, "{{account_address}}");
* ```
*
* @param contract - an instance of a account factory contract
* @returns a response object that includes an array of all accounts associated with the adress
* @twfeature AccountFactory
* @see {@link https://portal.thirdweb.com/react/react.useaccountsforaddress?utm_source=sdk | Documentation}
* @beta
*/
export function useAccountsForAddress(
contract: RequiredParam<SmartContract>,
address: RequiredParam<WalletAddress>,
): UseQueryResult<string[]> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.accountFactory.getAllForAddress(
contractAddress,
address,
),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.accountFactory.getAssociatedAccounts,
"Contract instance does not support contract.accountFactory.getAssociatedAccounts",
);
return contract.accountFactory.getAssociatedAccounts(address || "");
},
{ enabled: !!contract },
);
}
/**
* Check if a account has been deployed for the given admin
*
* @example
* ```javascript
* const { data: isAccountDeployed, isLoading, error } = useIsAccountDeployed(contract);
* ```
*
* @param contract - an instance of a account factory contract
* @returns a boolean indicating if a account has been deployed for the given admin
* @twfeature AccountFactory
* @see {@link https://portal.thirdweb.com/react/react.useisaccountdeployed?utm_source=sdk | Documentation}
* @beta
*/
export function useIsAccountDeployed(
contract: RequiredParam<SmartContract>,
admin: RequiredParam<WalletAddress>,
extraData?: BytesLike,
): UseQueryResult<boolean> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.accountFactory.isAccountDeployed(contractAddress, admin),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.accountFactory.isAccountDeployed,
"Contract instance does not support contract.accountFactory.getAllAccounts",
);
invariant(admin, "No account address provided");
return contract.accountFactory.isAccountDeployed(admin, extraData);
},
{ enabled: !!contract },
);
}
/** **********************/
/** WRITE HOOKS **/
/** **********************/
/**
* Create a account
*
* @example
* ```jsx
* const Component = () => {
* const { contract } = useContract("{{contract_address}}");
* const {
* mutate: createAccount,
* isLoading,
* error,
* } = useCreateAccount(contract);
*
* if (error) {
* console.error("failed to create account", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => createAccount("0x...")}
* >
* Create Account
* </button>
* );
* };
* ```
*
* @param contract - an instance of a account factory contract
* @returns a mutation object that can be used to create a account
* @twfeature AccountFactory
* @see {@link https://portal.thirdweb.com/react/react.usecreateaccount?utm_source=sdk | Documentation}
* @beta
*/
export function useCreateAccount(contract: RequiredParam<SmartContract>) {
const activeChainId = useSDKChainId();
const contractAddress = contract?.getAddress();
const queryClient = useQueryClient();
return useMutation(
async (admin: string, extraData?: BytesLike) => {
requiredParamInvariant(contract, "contract is undefined");
return contract.accountFactory.createAccount(admin, extraData);
},
{
onSettled: () =>
invalidateContractAndBalances(
queryClient,
contractAddress,
activeChainId,
),
},
);
}
@@ -27,32 +27,32 @@ import invariant from "tiny-invariant";
/** **********************/
/**
* Get all wallets
* Get all accounts
*
* @example
* ```javascript
* const { data: smartWallets, isLoading, error } = useSmartWalletSigners(contract);
* const { data: accounts, isLoading, error } = useAccountSigners(contract);
* ```
*
* @param contract - an instance of a smart wallet
* @returns a response object that includes an array of all signers of the provided smart wallet
* @twfeature SmartWallet
* @see {@link https://portal.thirdweb.com/react/react.usesmartwalletsigners?utm_source=sdk | Documentation}
* @param contract - an instance of a account
* @returns a response object that includes an array of all signers of the provided account
* @twfeature Account
* @see {@link https://portal.thirdweb.com/react/react.useaccountsigners?utm_source=sdk | Documentation}
* @beta
*/
export function useSmartWalletSigners(
export function useAccountSigners(
contract: RequiredParam<SmartContract>,
): UseQueryResult<SignerWithRestrictions[]> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.smartWallet.signers(contractAddress),
cacheKeys.contract.account.signers(contractAddress),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.smartWallet.getSignersWithRestrictions,
"Contract instance does not support contract.smartWallet.getSignersWithRestrictions",
contract.account.getSignersWithRestrictions,
"Contract instance does not support contract.account.getSignersWithRestrictions",
);
return contract.smartWallet.getSignersWithRestrictions();
return contract.account.getSignersWithRestrictions();
},
{ enabled: !!contract },
);
@@ -62,40 +62,40 @@ export function useSmartWalletSigners(
/** WRITE HOOKS **/
/** **********************/
/**
* Set the wallet's entire snapshot of permissions
* Set the account's entire snapshot of permissions
*
* @example
* ```jsx
* const Component = () => {
* const { contract } = useContract("{{contract_address}}");
* const {
* mutate: setSmartWalletSigners,
* mutate: setAccountSigners,
* isLoading,
* error,
* } = useSetSmartWalletSigners(contract);
* } = useSetAccountSigners(contract);
*
* if (error) {
* console.error("failed to set smart wallet signers", error);
* console.error("failed to set account signers", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => setSmartWalletSigners("0x...")}
* onClick={() => setAccountSigners("0x...")}
* >
* Set Smart Wallet Signers
* Set Account Signers
* </button>
* );
* };
* ```
*
* @param contract - an instance of a smart wallet contract
* @returns a mutation object that can be used to set the smart wallet signers
* @twfeature SmartWallet
* @see {@link https://portal.thirdweb.com/react/react.usesetsmartwalletsigners?utm_source=sdk | Documentation}
* @param contract - an instance of a account contract
* @returns a mutation object that can be used to set the account signers
* @twfeature Account
* @see {@link https://portal.thirdweb.com/react/react.usesetaccountsigners?utm_source=sdk | Documentation}
* @beta
*/
export function useSetSmartWalletSigners(
export function useSetAccountSigners(
contract: RequiredParam<SmartContract>,
): UseMutationResult<
{ receipt: providers.TransactionReceipt },
@@ -111,7 +111,7 @@ export function useSetSmartWalletSigners(
async (permissionsSnapshot: SignerWithRestrictionsBatchInput) => {
requiredParamInvariant(contract, "contract is undefined");
return contract.smartWallet.setAccess(permissionsSnapshot);
return contract.account.setAccess(permissionsSnapshot);
},
{
onSettled: () =>
@@ -1,188 +0,0 @@
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
import { WalletAddress } from "../../types";
import {
cacheKeys,
invalidateContractAndBalances,
} from "../../utils/cache-keys";
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import {
useMutation,
useQueryClient,
UseQueryResult,
} from "@tanstack/react-query";
import type { AccountEvent, SmartContract } from "@thirdweb-dev/sdk";
import type { BytesLike } from "ethers";
import invariant from "tiny-invariant";
/** **********************/
/** READ HOOKS **/
/** **********************/
/**
* Get all wallets
*
* @example
* ```javascript
* const { data: smartWallets, isLoading, error } = useSmartWallets(contract);
* ```
*
* @param contract - an instance of a smart wallet factory contract
* @returns a response object that includes an array of all smart wallets with their associated admin
* @twfeature SmartWalletFactory
* @see {@link https://portal.thirdweb.com/react/react.usesmartwallets?utm_source=sdk | Documentation}
* @beta
*/
export function useSmartWallets(
contract: RequiredParam<SmartContract>,
): UseQueryResult<AccountEvent[]> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.smartWalletFactory.getAll(contractAddress),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.smartWalletFactory.getAllAccounts,
"Contract instance does not support contract.smartWalletFactory.getAllAccounts",
);
return contract.smartWalletFactory.getAllAccounts();
},
{ enabled: !!contract },
);
}
/**
* Get all wallets associated with the provided address
*
* @example
* ```javascript
* const { data: smartWalletsForAddress, isLoading, error } = useSmartWalletsForAddress(contract, "{{wallet_address}}");
* ```
*
* @param contract - an instance of a smart wallet factory contract
* @returns a response object that includes an array of all smart wallets associated with the adress
* @twfeature SmartWalletFactory
* @see {@link https://portal.thirdweb.com/react/react.usesmartwalletsforaddress?utm_source=sdk | Documentation}
* @beta
*/
export function useSmartWalletsForAddress(
contract: RequiredParam<SmartContract>,
address: RequiredParam<WalletAddress>,
): UseQueryResult<string[]> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.smartWalletFactory.getAllForAddress(
contractAddress,
address,
),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.smartWalletFactory.getAssociatedWallets,
"Contract instance does not support contract.smartWalletFactory.getAssociatedWallets",
);
return contract.smartWalletFactory.getAssociatedWallets(address || "");
},
{ enabled: !!contract },
);
}
/**
* Check if a smart wallet has been deployed for the given admin
*
* @example
* ```javascript
* const { data: isSmartWalletDeployed, isLoading, error } = useIsSmartWalletDeployed(contract);
* ```
*
* @param contract - an instance of a smart wallet factory contract
* @returns a boolean indicating if a smart wallet has been deployed for the given admin
* @twfeature SmartWalletFactory
* @see {@link https://portal.thirdweb.com/react/react.useissmartwalletdeployed?utm_source=sdk | Documentation}
* @beta
*/
export function useIsSmartWalletDeployed(
contract: RequiredParam<SmartContract>,
admin: RequiredParam<WalletAddress>,
extraData?: BytesLike,
): UseQueryResult<boolean> {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.smartWalletFactory.isSmartWalletDeployed(
contractAddress,
admin,
),
() => {
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract.smartWalletFactory.isWalletDeployed,
"Contract instance does not support contract.smartWalletFactory.getAllWallets",
);
invariant(admin, "No wallet address provided");
return contract.smartWalletFactory.isWalletDeployed(admin, extraData);
},
{ enabled: !!contract },
);
}
/** **********************/
/** WRITE HOOKS **/
/** **********************/
/**
* Create a smart wallet
*
* @example
* ```jsx
* const Component = () => {
* const { contract } = useContract("{{contract_address}}");
* const {
* mutate: createSmartWallet,
* isLoading,
* error,
* } = useCreateSmartWallet(contract);
*
* if (error) {
* console.error("failed to create smart wallet", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => createSmartWallet("0x...")}
* >
* Create Smart Wallet
* </button>
* );
* };
* ```
*
* @param contract - an instance of a smart wallet factory contract
* @returns a mutation object that can be used to create a smart wallet
* @twfeature SmartWalletFactory
* @see {@link https://portal.thirdweb.com/react/react.usecreatesmartwallet?utm_source=sdk | Documentation}
* @beta
*/
export function useCreateSmartWallet(contract: RequiredParam<SmartContract>) {
const activeChainId = useSDKChainId();
const contractAddress = contract?.getAddress();
const queryClient = useQueryClient();
return useMutation(
async (admin: string, extraData?: BytesLike) => {
requiredParamInvariant(contract, "contract is undefined");
return contract.smartWalletFactory.createWallet(admin, extraData);
},
{
onSettled: () =>
invalidateContractAndBalances(
queryClient,
contractAddress,
activeChainId,
),
},
);
}
+8 -11
View File
@@ -194,19 +194,16 @@ export {
useBurnToken,
} from "./hooks/async/token";
// smart wallet factory
// account factory
export {
useIsSmartWalletDeployed,
useSmartWallets,
useCreateSmartWallet,
useSmartWalletsForAddress,
} from "./hooks/async/smart-wallet-factory";
useIsAccountDeployed,
useAccounts,
useCreateAccount,
useAccountsForAddress,
} from "./hooks/async/account-factory";
// smart wallet
export {
useSmartWalletSigners,
useSetSmartWalletSigners,
} from "./hooks/async/smart-wallet";
// account
export { useAccountSigners, useSetAccountSigners } from "./hooks/async/account";
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
+14 -13
View File
@@ -118,18 +118,23 @@ export const cacheKeys = {
overrides,
]),
smartWalletFactory: {
accountFactory: {
getAll: (contractAddress: RequiredParam<ContractAddress>) =>
createContractCacheKey(contractAddress, ["smartWalletFactory"]),
isSmartWalletDeployed: (contractAdress: RequiredParam<ContractAddress>, admin: RequiredParam<string>) =>
createContractCacheKey(contractAdress, ["isSmartWalletDeployed", admin]),
getAllForAddress: (contractAdress: RequiredParam<ContractAddress>, address: RequiredParam<string>) =>
createContractCacheKey(contractAddress, ["accountFactory"]),
isAccountDeployed: (
contractAdress: RequiredParam<ContractAddress>,
admin: RequiredParam<string>,
) => createContractCacheKey(contractAdress, ["isAccountDeployed", admin]),
getAllForAddress: (
contractAdress: RequiredParam<ContractAddress>,
address: RequiredParam<string>,
) =>
createContractCacheKey(contractAdress, ["getAllForAddress", address]),
},
smartWallet: {
account: {
signers: (contractAddress: RequiredParam<ContractAddress>) =>
createContractCacheKey(contractAddress, ["smartWallet", "signers"]),
createContractCacheKey(contractAddress, ["account", "signers"]),
},
app: {
@@ -198,12 +203,8 @@ export const cacheKeys = {
},
},
sharedMetadata: {
get: (
contractAddress: RequiredParam<ContractAddress>,
) =>
createContractCacheKey(
contractAddress
),
get: (contractAddress: RequiredParam<ContractAddress>) =>
createContractCacheKey(contractAddress),
},
drop: {
getAllUnclaimed: (
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-native-compat
## 0.2.27
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
## 0.2.26
## 0.2.25
## 0.2.24
## 0.2.23
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.24",
"version": "0.2.27",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
@@ -22,10 +22,10 @@
},
"dependencies": {
"@ethersproject/shims": "^5.7.0",
"@walletconnect/react-native-compat": "^2.3.3",
"@walletconnect/react-native-compat": "^2.8.6",
"base-64": "^1.0.0",
"big-integer": "^1.6.51",
"react-native-get-random-values": "^1.8.0"
"react-native-get-random-values": "^1.9.0"
},
"peerDependencies": {
"ethers": "^5.5.1",
@@ -34,12 +34,12 @@
},
"devDependencies": {
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/node": "^18.0.0",
"@types/node": "^18.16.18",
"babel-plugin-module-resolver": "^5.0.0",
"eslint-config-thirdweb": "workspace:*",
"ethers": "^5.7.2",
"react": "^18.2.0",
"react-native": "^0.71.0",
"typescript": "^4.7.4"
"react-native": "^0.71.11",
"typescript": "^5.1.6"
}
}
+35
View File
@@ -1,5 +1,40 @@
# @thirdweb-dev/react-native
## 0.2.27
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- Updated dependencies [[`2d088d36`](https://github.com/thirdweb-dev/js/commit/2d088d367ca54233836dc69712fd411ab7924205), [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2), [`9daf0449`](https://github.com/thirdweb-dev/js/commit/9daf044926bf995ac8998929dbeca548c5eb8561), [`546353a4`](https://github.com/thirdweb-dev/js/commit/546353a479c11533818ef917c0f6b4d6f8f69872), [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96), [`0135a779`](https://github.com/thirdweb-dev/js/commit/0135a7790cf2acde6b701cb41ea10dd311da5ec3)]:
- @thirdweb-dev/storage@1.1.6
- @thirdweb-dev/react-core@3.14.8
- @thirdweb-dev/wallets@1.0.4
- @thirdweb-dev/chains@0.1.27
- @thirdweb-dev/sdk@3.10.28
## 0.2.26
### Patch Changes
- [#1270](https://github.com/thirdweb-dev/js/pull/1270) [`0d5503aa`](https://github.com/thirdweb-dev/js/commit/0d5503aae90d9cd7a7adcabad19f7f45d9a37063) Thanks [@iketw](https://github.com/iketw)! - Only handle Coinbase callback URL if Coinbase is added as a supportedWallet
- [#1277](https://github.com/thirdweb-dev/js/pull/1277) [`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - remove ethers/lib/utils dependency
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
- @thirdweb-dev/wallets@1.0.3
- @thirdweb-dev/sdk@3.10.27
- @thirdweb-dev/react-core@3.14.7
- @thirdweb-dev/chains@0.1.26
## 0.2.25
### Patch Changes
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
- @thirdweb-dev/wallets@1.0.2
- @thirdweb-dev/react-core@3.14.6
## 0.2.24
### Patch Changes
+19 -19
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.24",
"version": "0.2.27",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -26,9 +26,9 @@
"dependencies": {
"@coinbase/wallet-mobile-sdk": "1.0.6",
"@magic-sdk/provider": "17.2.0",
"@magic-sdk/react-native-bare": "^18.3.0",
"@shopify/restyle": "^2.4.1",
"@tanstack/react-query": "^4.0.10",
"@magic-sdk/react-native-bare": "^18.5.0",
"@shopify/restyle": "^2.4.2",
"@tanstack/react-query": "^4.29.19",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/sdk": "workspace:*",
@@ -41,38 +41,38 @@
"expo-secure-store": "^12.1.1",
"react-native-mmkv": "2.5.1",
"react-native-modal": "^13.0.1",
"react-native-svg": "^13.8.0",
"react-native-svg": "^13.9.0",
"tiny-invariant": "^1.2.0"
},
"devDependencies": {
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.1.6",
"@react-native-async-storage/async-storage": "*",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@react-native-async-storage/async-storage": "^1.18.2",
"@react-native-community/eslint-config": "^3.0.2",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/jest": "^29.2.1",
"@types/react": "^18.0.5",
"@types/react-native": "^0.71.0",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"@types/jest": "^29.5.2",
"@types/react": "^18.2.14",
"@types/react-native": "^0.71.8",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"babel-jest": "^29.2.1",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-inclusive-language": "^2.2.0",
"eslint-plugin-prettier": "^4.2.1",
"ethers": "^5.7.2",
"expo": "^47.0.0",
"expo": "^47.0.14",
"jest": "^29.4.3",
"prettier": "^2.7.1",
"prettier": "^2.8.8",
"react": "^18.2.0",
"react-native": "^0.71.0",
"react-native": "^0.71.11",
"react-native-camera": "^4.2.1",
"react-native-device-info": "10.6.0",
"react-native-safe-area-context": "4.5.3",
"react-native-webview": "12.1.0",
"typescript": "^4.7.4"
"typescript": "^5.1.6"
},
"optionalDependencies": {
"react-native-camera": "^4.2.1",
@@ -65,7 +65,9 @@ export const ThirdwebProvider = <
theme,
...restProps
}: PropsWithChildren<ThirdwebProviderProps<TChains>>) => {
useCoinbaseWalletListener();
useCoinbaseWalletListener(
!!supportedWallets.find((w) => w.id === walletIds.coinbase),
);
const hasMagicConfig = useMemo(
() => !!supportedWallets.find((wc) => wc.id === walletIds.magicLink),
@@ -17,8 +17,7 @@ import {
WagmiConnector,
} from "@thirdweb-dev/wallets";
import type { Address } from "abitype";
import { providers } from "ethers";
import { getAddress, hexValue } from "ethers/lib/utils.js";
import { providers, utils } from "ethers";
export type CoinbaseWalletConnectorOptions = WalletMobileSDKProviderOptions &
ConfigurationParams & {
@@ -130,7 +129,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
throw new Error("No accounts found");
}
// return checksum address
return getAddress(accounts[0] as string);
return utils.getAddress(accounts[0] as string);
}
async getChainId() {
@@ -193,7 +192,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
async switchChain(chainId: number): Promise<Chain> {
const provider = await this.getProvider();
const id = hexValue(chainId);
const id = utils.hexValue(chainId);
try {
await provider.request({
@@ -279,7 +278,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
if (accounts.length === 0) {
this.emit("disconnect");
} else {
this.emit("change", { account: getAddress(accounts[0] as string) });
this.emit("change", { account: utils.getAddress(accounts[0] as string) });
}
};
@@ -13,7 +13,7 @@ import { useCoinbaseWalletListener } from "./useCoinbaseWalletListener";
*/
export function useCoinbaseWallet(callbackURL: string) {
const connect = useConnect();
useCoinbaseWalletListener();
useCoinbaseWalletListener(true);
return useCallback(
async (connectOptions?: { chainId?: number; callbackURL: string }) => {
@@ -7,12 +7,16 @@ import { Linking } from "react-native";
*
* This hook sets up the UniversalLinks listener.
*/
export function useCoinbaseWalletListener() {
export function useCoinbaseWalletListener(enable: boolean) {
useEffect(() => {
if (!enable) {
return;
}
const sub = Linking.addEventListener("url", ({ url }) => {
// @ts-ignore - Passing a URL object to handleResponse crashes the function
handleResponse(url);
});
return () => sub?.remove();
}, []);
}, [enable]);
}
+38
View File
@@ -1,5 +1,43 @@
# @thirdweb-dev/react
## 3.14.8
### Patch Changes
- [#1282](https://github.com/thirdweb-dev/js/pull/1282) [`7054f9f0`](https://github.com/thirdweb-dev/js/commit/7054f9f01691e1c942ffbec3ee8042218aadd126) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Fix issue #1201 - MediaRenderer HTML MimeType
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- Updated dependencies [[`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2), [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96)]:
- @thirdweb-dev/react-core@3.14.8
- @thirdweb-dev/wallets@1.0.4
- @thirdweb-dev/chains@0.1.27
- @thirdweb-dev/sdk@3.10.28
## 3.14.7
### Patch Changes
- [#1210](https://github.com/thirdweb-dev/js/pull/1210) [`d794b8f9`](https://github.com/thirdweb-dev/js/commit/d794b8f9f41dbd7e461ef07d0808c5b6d2f85515) Thanks [@konojunya](https://github.com/konojunya)! - Add zerion to useInstalledWallets
- [#1269](https://github.com/thirdweb-dev/js/pull/1269) [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae) Thanks [@MananTank](https://github.com/MananTank)! - - Expose `advancedOptions` and `styles` for paper wallet
- Allow using "+" in paper email
- Allow using "+" in magic email
- Update Paper SDK version
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
- @thirdweb-dev/wallets@1.0.3
- @thirdweb-dev/sdk@3.10.27
- @thirdweb-dev/react-core@3.14.7
- @thirdweb-dev/chains@0.1.26
## 3.14.6
### Patch Changes
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
- @thirdweb-dev/wallets@1.0.2
- @thirdweb-dev/react-core@3.14.6
## 3.14.5
### Patch Changes
+28 -28
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.14.5",
"version": "3.14.8",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -81,15 +81,15 @@
},
"sideEffects:": false,
"devDependencies": {
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/runtime": "^7.19.0",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@babel/core": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.5",
"@microsoft/api-documenter": "^7.22.21",
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/tsdoc": "^0.14.1",
"@preconstruct/cli": "^2.2.1",
"@preconstruct/cli": "^2.7.0",
"@solana/wallet-adapter-base": "^0.9.17",
"@solana/wallet-adapter-phantom": "^0.9.17",
"@solana/wallet-adapter-react": "^0.15.19",
@@ -99,13 +99,13 @@
"@thirdweb-dev/sdk": "workspace:*",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/color": "^3.0.3",
"@types/react": "^18.0.5",
"@types/react-dom": "^18.0.6",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-better-tree-shaking": "0.0.3",
"eslint-plugin-import": "^2.26.0",
@@ -113,25 +113,25 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.2",
"prettier": "^2.7.1",
"prettier": "^2.8.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"stream": "npm:stream-browserify@^3.0.0",
"typescript": "^4.7.4"
"typescript": "^5.1.6"
},
"dependencies": {
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@google/model-viewer": "^2.1.1",
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-icons": "^1.1.1",
"@radix-ui/react-popover": "^1.0.5",
"@radix-ui/react-tabs": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.4",
"@radix-ui/colors": "^0.1.9",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-popover": "^1.0.6",
"@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.0.10",
"@tanstack/react-query": "^4.29.19",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/react-core": "workspace:*",
"@thirdweb-dev/wallets": "workspace:*",
@@ -431,7 +431,7 @@ export const MediaRenderer = /* @__PURE__ */ React.forwardRef<
alt={alt}
/>
);
} else if (videoOrImageSrc.mimeType === "text/html") {
} else if (videoOrImageSrc.mimeType.startsWith("text/html")) {
return (
<IframePlayer
style={mergedStyle}
@@ -1,5 +1,9 @@
import { useConnect, useWallet } from "@thirdweb-dev/react-core";
import { PaperWallet, walletIds } from "@thirdweb-dev/wallets";
import {
PaperWallet,
walletIds,
PaperWalletAdditionalOptions,
} from "@thirdweb-dev/wallets";
import { useCallback, useEffect } from "react";
import {
useQuery,
@@ -7,10 +11,12 @@ import {
useQueryClient,
} from "@tanstack/react-query";
type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
export function usePaperWallet() {
const connect = useConnect();
return useCallback(
async (options: { chainId?: number; clientId: string; email?: string }) => {
async (options: { chainId?: number; email?: string } & PaperConfig) => {
const { paperWallet } = await import(
"../../../wallet/wallets/paperWallet"
);
@@ -3,22 +3,23 @@ import { assertWindowEthereum } from "@thirdweb-dev/wallets";
export function useInstalledWallets() {
let isMetamaskInstalled = false;
let isCoinbaseWalletInstalled = false;
let isTrustWalletInstalled: boolean | undefined = false;
let isZerionWalletInstalled = false;
let isTrustWalletInstalled = false;
if (assertWindowEthereum(globalThis.window)) {
isMetamaskInstalled = globalThis.window.ethereum?.isMetaMask;
const window_: Window | undefined = globalThis?.window;
if (assertWindowEthereum(window_)) {
isMetamaskInstalled = !!window_.ethereum?.isMetaMask;
isCoinbaseWalletInstalled =
globalThis.window.ethereum?.isCoinbaseWallet ||
globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet) ||
false;
isTrustWalletInstalled = globalThis.window.ethereum?.isTrust;
!!window_.ethereum?.isCoinbaseWallet ||
!!window_.ethereum?.providers?.some((p) => p.isCoinbaseWallet);
isZerionWalletInstalled = !!window_.ethereum?.isZerion;
isTrustWalletInstalled = !!window_.ethereum?.isTrust;
}
const installedWallets = {
metamask: !!isMetamaskInstalled,
coinbaseWallet: !!isCoinbaseWalletInstalled,
trustWallet: !!isTrustWalletInstalled,
return {
metamask: isMetamaskInstalled,
coinbaseWallet: isCoinbaseWalletInstalled,
trustWallet: isTrustWalletInstalled,
zerionWallet: isZerionWalletInstalled,
};
return installedWallets;
}
@@ -21,12 +21,11 @@ export const coinbaseWallet = (): WalletConfig<CoinbaseWallet> => {
},
connectUI: CoinbaseConnectUI,
isInstalled() {
if (assertWindowEthereum(globalThis.window)) {
const window_: Window | undefined = globalThis?.window;
if (assertWindowEthereum(window_)) {
return (
globalThis.window.ethereum?.isCoinbaseWallet ||
globalThis.window.ethereum?.providers?.some(
(p) => p.isCoinbaseWallet,
) ||
window_.ethereum?.isCoinbaseWallet ||
window_.ethereum?.providers?.some((p) => p.isCoinbaseWallet) ||
false
);
}
@@ -19,10 +19,11 @@ export const frameWallet = (): WalletConfig<FrameWallet> => ({
},
connectUI: FrameConnectUI,
isInstalled() {
if (assertWindowEthereum(globalThis.window)) {
const window_: Window | undefined = globalThis?.window;
if (assertWindowEthereum(window_)) {
return (
globalThis.window.ethereum?.isFrame ||
globalThis.window.ethereum?.providers?.some((p) => p.isFrame) ||
window_.ethereum?.isFrame ||
window_.ethereum?.providers?.some((p) => p.isFrame) ||
false
);
}
@@ -79,7 +79,7 @@ const MagicSelectionUI: React.FC<
if (isEmail && isEmailEnabled) {
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
const isValidEmail = emailRegex.test(input);
const isValidEmail = emailRegex.test(input.replace(/\+/g, ""));
if (!isValidEmail) {
return "Invalid email address";
}
@@ -1,4 +1,7 @@
import { PaperWallet } from "@thirdweb-dev/wallets";
import {
PaperWallet,
PaperWalletAdditionalOptions,
} from "@thirdweb-dev/wallets";
import {
WalletConfig,
WalletOptions,
@@ -11,7 +14,7 @@ import { Spinner } from "../../components/Spinner";
import { Flex } from "../../components/basic";
import { InputSelectionUI } from "./InputSelectionUI";
type PaperConfig = { clientId: string };
type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
export const paperWallet = (config: PaperConfig): WalletConfig<PaperWallet> => {
return {
@@ -32,7 +35,8 @@ const PaperSelectionUI: React.FC<SelectUIProps<PaperWallet>> = (props) => {
placeholder="Enter your email address"
name="email"
type="email"
errorMessage={(input) => {
errorMessage={(_input) => {
const input = _input.replace(/\+/g, "");
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
const isValidEmail = emailRegex.test(input);
if (!isValidEmail) {
+24
View File
@@ -1,5 +1,29 @@
# @thirdweb-dev/sdk
## 3.10.28
### Patch Changes
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- [#1281](https://github.com/thirdweb-dev/js/pull/1281) [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96) Thanks [@nkrishang](https://github.com/nkrishang)! - Handle ERC4337Signer correctly for signTypedData
- Updated dependencies [[`2d088d36`](https://github.com/thirdweb-dev/js/commit/2d088d367ca54233836dc69712fd411ab7924205), [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2), [`9daf0449`](https://github.com/thirdweb-dev/js/commit/9daf044926bf995ac8998929dbeca548c5eb8561), [`546353a4`](https://github.com/thirdweb-dev/js/commit/546353a479c11533818ef917c0f6b4d6f8f69872), [`a3bb17cb`](https://github.com/thirdweb-dev/js/commit/a3bb17cb33f033846fb3b4c8a0a4809ba76cab96), [`0135a779`](https://github.com/thirdweb-dev/js/commit/0135a7790cf2acde6b701cb41ea10dd311da5ec3)]:
- @thirdweb-dev/storage@1.1.6
- @thirdweb-dev/contracts-js@1.3.8
- @thirdweb-dev/chains@0.1.27
## 3.10.27
### Patch Changes
- [#1277](https://github.com/thirdweb-dev/js/pull/1277) [`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - remove ethers/lib/utils dependency
- [#1271](https://github.com/thirdweb-dev/js/pull/1271) [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8) Thanks [@nkrishang](https://github.com/nkrishang)! - Rename smart wallets to account
- Updated dependencies [[`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad)]:
- @thirdweb-dev/chains@0.1.26
## 3.10.26
### Patch Changes
+22 -22
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.10.26",
"version": "3.10.28",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -97,35 +97,35 @@
"push": "yalc push"
},
"devDependencies": {
"@aws-sdk/client-secrets-manager": "^3.256.0",
"@aws-sdk/client-secrets-manager": "^3.363.0",
"@ethersproject/abstract-provider": "^5.7.0",
"@metaplex-foundation/amman": "^0.12.1",
"@metaplex-foundation/amman-client": "^0.2.4",
"@metaplex-foundation/js": "^0.19.2",
"@metaplex-foundation/mpl-token-metadata": "^2.11",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@metaplex-foundation/mpl-token-metadata": "^2.12.0",
"@microsoft/api-documenter": "^7.22.21",
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/tsdoc": "^0.14.1",
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@preconstruct/cli": "^2.2.1",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@preconstruct/cli": "^2.7.0",
"@project-serum/anchor": "^0.25.0",
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.62.0",
"@swc-node/register": "^1.5.1",
"@swc/core": "^1.3.23",
"@swc-node/register": "^1.6.6",
"@swc/core": "^1.3.67",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/bn.js": "^5.1.1",
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.5",
"@types/deep-equal-in-any-order": "^1.0.1",
"@types/mocha": "^10.0.0",
"@types/node": "^18.0.0",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@types/node": "^18.16.18",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"chai": "^4.3.6",
"deep-equal-in-any-order": "^1.1.18",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-better-tree-shaking": "0.0.3",
"eslint-plugin-import": "^2.26.0",
@@ -134,11 +134,11 @@
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.2",
"ethers-aws-kms-signer": "^1.3.2",
"hardhat": "^2.9.3",
"hardhat": "^2.16.1",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4",
"prettier": "^2.8.8",
"typescript": "^5.1.6",
"zksync-web3": "^0.14.3"
},
"peerDependencies": {
@@ -187,14 +187,14 @@
"bn.js": "^5.2.1",
"bs58": "^5.0.0",
"buffer": "^6.0.3",
"cross-fetch": "^3.1.5",
"eventemitter3": "^5.0.0",
"cross-fetch": "^3.1.6",
"eventemitter3": "^5.0.1",
"fast-deep-equal": "^3.1.3",
"merkletreejs": "^0.2.24",
"tiny-invariant": "^1.2.0",
"tweetnacl": "^1.0.3",
"uuid": "^9.0.0",
"yaml": "^2.1.1",
"yaml": "^2.3.1",
"zod": "^3.20.2"
},
"bugs": {
@@ -1,5 +1,4 @@
import { BigNumber, providers, constants } from "ethers";
import { isAddress } from "ethers/lib/utils";
import { BigNumber, providers, constants, utils } from "ethers";
import { extractIPFSHashFromBytecode } from "./extractIPFSHashFromBytecode";
import { extractMinimalProxyImplementationAddress } from "./extractMinimalProxyImplementationAddress";
@@ -49,7 +48,7 @@ export async function resolveContractUriFromAddress(
);
const implementationAddress = `0x${proxyStorage.slice(-40)}`;
if (
isAddress(implementationAddress) &&
utils.isAddress(implementationAddress) &&
implementationAddress !== constants.AddressZero
) {
return await resolveContractUriFromAddress(
+8 -2
View File
@@ -31,11 +31,17 @@ export type EIP712Domain = EIP712StandardDomain | EIP712PolygonDomain;
* @internal
*/
export async function signTypedDataInternal(
signer: Signer,
signerInput: Signer,
domain: EIP712Domain,
types: Record<string, Array<TypedDataField>>,
message: Record<string, any>,
) {
// Handle ERC4337Signer
let signer = signerInput;
if ((signerInput as any).originalSigner) {
signer = (signerInput as any).originalSigner;
}
const provider = signer?.provider as providers.JsonRpcProvider;
if (!provider) {
throw new Error("missing provider");
@@ -60,7 +66,7 @@ export async function signTypedDataInternal(
message,
);
} catch (err: any) {
if (err?.message?.includes("Method eth_signTypedData_v4 not supported")) {
if (err?.message?.includes("eth_signTypedData_v4")) {
signature = await provider.send("eth_signTypedData", [
signerAddress,
JSON.stringify(payload),
@@ -62,8 +62,8 @@ import {
FEATURE_ENGLISH_AUCTIONS,
FEATURE_OFFERS,
FEATURE_EXTENSION_ROUTER,
FEATURE_SMART_WALLET,
FEATURE_SMART_WALLET_FACTORY,
FEATURE_ACCOUNT,
FEATURE_ACCOUNT_FACTORY,
} from "./thirdweb-features";
/**
@@ -127,8 +127,8 @@ export type Feature =
| typeof FEATURE_DIRECT_LISTINGS
| typeof FEATURE_ENGLISH_AUCTIONS
| typeof FEATURE_OFFERS
| typeof FEATURE_SMART_WALLET
| typeof FEATURE_SMART_WALLET_FACTORY;
| typeof FEATURE_ACCOUNT
| typeof FEATURE_ACCOUNT_FACTORY;
export type Extension = Feature;
@@ -170,6 +170,6 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = /* @__PURE__ */ {
[FEATURE_DIRECT_LISTINGS.name]: FEATURE_DIRECT_LISTINGS,
[FEATURE_ENGLISH_AUCTIONS.name]: FEATURE_ENGLISH_AUCTIONS,
[FEATURE_OFFERS.name]: FEATURE_OFFERS,
[FEATURE_SMART_WALLET_FACTORY.name]: FEATURE_SMART_WALLET_FACTORY,
[FEATURE_SMART_WALLET.name]: FEATURE_SMART_WALLET,
[FEATURE_ACCOUNT_FACTORY.name]: FEATURE_ACCOUNT_FACTORY,
[FEATURE_ACCOUNT.name]: FEATURE_ACCOUNT,
};
@@ -279,24 +279,24 @@ export const FEATURE_OFFERS = {
features: {},
} as const;
export const FEATURE_SMART_WALLET_FACTORY = {
name: "SmartWalletFactory",
namespace: "smartwallet.factory",
export const FEATURE_ACCOUNT_FACTORY = {
name: "AccountFactory",
namespace: "accountFactory",
docLinks: {
// TODO
sdk: "sdk.smartWalletFactory",
contracts: "smartWalletFactory",
sdk: "sdk.accountFactory",
contracts: "",
},
abis: [IAccountFactory],
features: {},
} as const;
export const FEATURE_SMART_WALLET = {
name: "SmartWallet",
namespace: "smartwallet",
export const FEATURE_ACCOUNT = {
name: "Account",
namespace: "account",
docLinks: {
// TODO
sdk: "",
sdk: "sdk.account",
contracts: "",
},
abis: [IAccountCore],
@@ -259,7 +259,7 @@ export class Marketplace implements UpdateableNetwork {
(l.type === ListingType.Auction &&
BigNumber.from(l.endTimeInEpochSeconds).gt(now) &&
BigNumber.from(l.startTimeInEpochSeconds).lte(now)) ||
(l.type === ListingType.Direct && l.quantity > 0)
(l.type === ListingType.Direct && BigNumber.from(l.quantity).gt(0))
);
});
}
@@ -14,8 +14,8 @@ import {
FEATURE_PLATFORM_FEE,
FEATURE_PRIMARY_SALE,
FEATURE_ROYALTY,
FEATURE_SMART_WALLET_FACTORY,
FEATURE_SMART_WALLET,
FEATURE_ACCOUNT_FACTORY,
FEATURE_ACCOUNT,
} from "../constants/thirdweb-features";
import { Transaction } from "../core/classes/transactions";
import { ContractAppURI } from "../core/classes/contract-appuri";
@@ -54,7 +54,7 @@ import type {
EnglishAuctionsLogic,
OffersLogic,
IAccountFactory,
IAccountCore
IAccountCore,
} from "@thirdweb-dev/contracts-js";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BaseContract, CallOverrides } from "ethers";
@@ -66,8 +66,8 @@ import { ContractOwner } from "../core/classes/contract-owner";
import { MarketplaceV3DirectListings } from "../core/classes/marketplacev3-direct-listings";
import { MarketplaceV3EnglishAuctions } from "../core/classes/marketplacev3-english-auction";
import { MarketplaceV3Offers } from "../core/classes/marketplacev3-offers";
import { SmartWalletFactory } from "../core/classes/smart-wallet-factory";
import { SmartWallet } from "../core/classes/smart-wallet";
import { AccountFactory } from "../core/classes/account-factory";
import { Account } from "../core/classes/account";
/**
* Custom contract dynamic class with feature detection
@@ -299,46 +299,40 @@ export class SmartContract<
}
/**
* Smart Wallet Factory
* Account Factory
*
* @remarks Create smart wallets and fetch data about them.
* @remarks Create accounts and fetch data about them.
* @example
* ```javascript
*
* // Predict the address of the smart wallet that will be created for an admin.
* const deterministicAddress = await contract.smartWalletFactory.predictWalletAddress(admin, extraData);
* // Predict the address of the account that will be created for an admin.
* const deterministicAddress = await contract.accountFactory.predictAccountAddress(admin, extraData);
*
* // Create smart wallets
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData);
* // Create accounts
* const tx = await contract.accountFactory.createAccount(admin, extraData);
* // the same as `deterministicAddress`
* const smartWalletAddress = tx.address;
* const accountAddress = tx.address;
*
* // Get all smart wallets created by the factory
* const allWallets = await contract.smartWalletFactory.getAllWallets();
* // Get all accounts created by the factory
* const allAccounts = await contract.accountFactory.getAllAccounts();
*
* // Get all smart wallets on which a signer has been given authority.
* const associatedWallets = await contract.smartWalletFactory.getAssociatedWallets(signer);
* // Get all accounts on which a signer has been given authority.
* const associatedAccounts = await contract.accountFactory.getAssociatedAccounts(signer);
*
* // Get all signers who have been given authority on a smart wallet.
* const associatedSigners = await contract.smartWalletFactory.getAssociatedSigners(smartWalletAddress);
* // Get all signers who have been given authority on a account.
* const associatedSigners = await contract.accountFactory.getAssociatedSigners(accountAddress);
*
* // Check whether a smart wallet has already been created for a given admin.
* const isWalletDeployed = await contract.smartWalletFactory.isWalletDeployed(admin, extraData);
* // Check whether a account has already been created for a given admin.
* const isAccountDeployed = await contract.accountFactory.isAccountDeployed(admin, extraData);
* ```
*/
get smartWalletFactory(): SmartWalletFactory<IAccountFactory> {
return assertEnabled(
this.detectSmartWalletFactory(),
FEATURE_SMART_WALLET_FACTORY,
);
get accountFactory(): AccountFactory<IAccountFactory> {
return assertEnabled(this.detectAccountFactory(), FEATURE_ACCOUNT_FACTORY);
}
// TODO documentation
get smartWallet(): SmartWallet<IAccountCore> {
return assertEnabled(
this.detectSmartWallet(),
FEATURE_SMART_WALLET,
)
get account(): Account<IAccountCore> {
return assertEnabled(this.detectAccount(), FEATURE_ACCOUNT);
}
private _chainId: number;
@@ -568,25 +562,28 @@ export class SmartContract<
return undefined;
}
// ========== Smart account features ==========
// ========== Account features ==========
private detectSmartWalletFactory() {
private detectAccountFactory() {
if (
detectContractFeature<IAccountFactory>(
this.contractWrapper,
FEATURE_SMART_WALLET_FACTORY.name,
FEATURE_ACCOUNT_FACTORY.name,
)
) {
return new SmartWalletFactory(this.contractWrapper);
return new AccountFactory(this.contractWrapper);
}
return undefined;
}
private detectSmartWallet() {
private detectAccount() {
if (
detectContractFeature<IAccountCore>(this.contractWrapper, FEATURE_SMART_WALLET.name)
detectContractFeature<IAccountCore>(
this.contractWrapper,
FEATURE_ACCOUNT.name,
)
) {
return new SmartWallet(this.contractWrapper);
return new Account(this.contractWrapper);
}
return undefined;
}
@@ -1,6 +1,6 @@
import type { IAccountFactory } from "@thirdweb-dev/contracts-js";
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { FEATURE_SMART_WALLET_FACTORY } from "../../constants/thirdweb-features";
import { FEATURE_ACCOUNT_FACTORY } from "../../constants/thirdweb-features";
import { ContractEvents } from "./contract-events";
import { ContractWrapper } from "./contract-wrapper";
@@ -9,13 +9,13 @@ import { Transaction } from "./transactions";
import { TransactionResultWithAddress } from "../types";
import { type BytesLike, utils } from "ethers";
import { AccountCreatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/AccountFactory";
import type { AccountEvent } from "../../types/smart-wallet";
import type { AccountEvent } from "../../types/account";
import { isContractDeployed } from "../../common/any-evm-utils/isContractDeployed";
export class SmartWalletFactory<TContract extends IAccountFactory>
export class AccountFactory<TContract extends IAccountFactory>
implements DetectableFeature
{
featureName = FEATURE_SMART_WALLET_FACTORY.name;
featureName = FEATURE_ACCOUNT_FACTORY.name;
private contractWrapper: ContractWrapper<IAccountFactory>;
// utilities
@@ -36,19 +36,19 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
*******************************/
/**
* Get the deterministic address of the smart wallet that will be created
* Get the deterministic address of the account that will be created
*
* @example
* ```javascript
* const walletAddress = await contract.smartWalletFactory.predictWalletAddress(admin);
* const accountAddress = await contract.accountFactory.predictAccountAddress(admin);
* ```
* @param admin - The admin of the smart wallet.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
* @returns the deterministic address of the smart wallet that will be created for the given admin.
* @param admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the account on creation.
* @returns the deterministic address of the account that will be created for the given admin.
*
* @twfeature SmartWalletFactory
* @twfeature AccountFactory
*/
public async predictWalletAddress(
public async predictAccountAddress(
admin: string,
extraData?: BytesLike,
): Promise<string> {
@@ -60,48 +60,48 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
}
/**
* Get all signers who have authority on the given smart wallet
* Get all signers who have authority on the given account
*
* @example
* ```javascript
* const allSigners = await contract.smartWalletFactory.getAssociatedSigners(admin);
* const allSigners = await contract.accountFactory.getAssociatedSigners(admin);
* ```
* @param wallet - The smart wallet address.
* @returns all signers who have authority on the given smart wallet.
* @param account - The account address.
* @returns all signers who have authority on the given account.
*
* @twfeature SmartWalletFactory
* @twfeature AccountFactory
*/
public async getAssociatedSigners(wallet: string): Promise<string[]> {
return this.contractWrapper.readContract.getSignersOfAccount(wallet);
public async getAssociatedSigners(account: string): Promise<string[]> {
return this.contractWrapper.readContract.getSignersOfAccount(account);
}
/**
* Get all wallets on which the given signer has authority
* Get all accounts on which the given signer has authority
*
* @example
* ```javascript
* const allWallets = await contract.smartWalletFactory.getAssociatedWallets(admin);
* const allAccounts = await contract.accountFactory.getAssociatedAccounts(admin);
* ```
* @param signer - The smart wallet address.
* @returns all wallets on which the given signer has authority.
* @param signer - The account address.
* @returns all accounts on which the given signer has authority.
*
* @twfeature SmartWalletFactory
* @twfeature AccountFactory
*/
public async getAssociatedWallets(signer: string): Promise<string[]> {
public async getAssociatedAccounts(signer: string): Promise<string[]> {
return this.contractWrapper.readContract.getAccountsOfSigner(signer);
}
/**
* Get all wallets
* Get all accounts
*
* @example
* ```javascript
* const allWallets = await contract.smartWalletFactory.getAllWallets();
* const allAccounts = await contract.accountFactory.getAllAccounts();
* ```
*
* @returns all wallets created via the smart wallet factory.
* @returns all accounts created via the account factory.
*
* @twfeature SmartWalletFactory
* @twfeature AccountFactory
*/
public async getAllAccounts(): Promise<AccountEvent[]> {
const allAccounts =
@@ -122,17 +122,17 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
}
/**
* Check if a smart wallet has been deployed for the given admin
* Check if a account has been deployed for the given admin
*
* @param admin - The admin of the smart wallet.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
* @returns whether the smart wallet has been deployed for the given admin.
* @param admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the account on creation.
* @returns whether the account has been deployed for the given admin.
*/
public async isWalletDeployed(
public async isAccountDeployed(
admin: string,
extraData?: BytesLike,
): Promise<boolean> {
const addr = await this.predictWalletAddress(admin, extraData);
const addr = await this.predictAccountAddress(admin, extraData);
return isContractDeployed(addr, this.contractWrapper.getProvider());
}
@@ -141,29 +141,29 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
*******************************/
/**
* Create a smart wallet
* Create a account
*
* @remarks Create a smart wallet for an admin. The admin will have complete authority over the smart wallet.
* @remarks Create a account for an admin. The admin will have complete authority over the account.
*
* @param admin - The admin of the smart wallet.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
* @param admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the account on creation.
*
* @example
* ```javascript
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData);
* const tx = await contract.accountFactory.createAccount(admin, extraData);
* const receipt = tx.receipt();
* const smartWalletAddress = tx.address;
* const accountAddress = tx.address;
* ```
*
* @twfeature SmartWalletFactory
* @twfeature AccountFactory
*/
createWallet = /* @__PURE__ */ buildTransactionFunction(
createAccount = /* @__PURE__ */ buildTransactionFunction(
async (
walletAdmin: string,
accountAdmin: string,
extraData?: BytesLike,
): Promise<Transaction<TransactionResultWithAddress>> => {
if (await this.isWalletDeployed(walletAdmin, extraData)) {
throw new Error(`Wallet already deployed for admin: ${walletAdmin}`);
if (await this.isAccountDeployed(accountAdmin, extraData)) {
throw new Error(`Account already deployed for admin: ${accountAdmin}`);
}
let data: BytesLike = utils.toUtf8Bytes("");
@@ -174,7 +174,7 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper,
method: "createAccount",
args: [walletAdmin, data],
args: [accountAdmin, data],
parse: (receipt) => {
const event = this.contractWrapper.parseLogs<AccountCreatedEvent>(
"AccountCreated",
@@ -1,6 +1,6 @@
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { ContractWrapper } from "./contract-wrapper";
import { FEATURE_SMART_WALLET } from "../../constants/thirdweb-features";
import { FEATURE_ACCOUNT } from "../../constants/thirdweb-features";
import { utils, BigNumber } from "ethers";
import { Transaction } from "./transactions";
@@ -27,10 +27,10 @@ import { AddressOrEns } from "../../schema";
import { resolveAddress } from "../../common";
import { Signer } from "ethers";
export class SmartWallet<TContract extends IAccountCore>
export class Account<TContract extends IAccountCore>
implements DetectableFeature
{
featureName = FEATURE_SMART_WALLET.name;
featureName = FEATURE_ACCOUNT.name;
private contractWrapper: ContractWrapper<IAccountCore>;
private emptyRole: string =
@@ -87,7 +87,7 @@ export class SmartWallet<TContract extends IAccountCore>
}
/**
* Generate and sign a payload to grant or revoke a signer's access to the smart wallet.
* Generate and sign a payload to grant or revoke a signer's access to the account.
*
* @param signer - The address of the signer
* @param roleAction - The address of the signer
@@ -137,7 +137,7 @@ export class SmartWallet<TContract extends IAccountCore>
}
/**
* Get the factory contract which deployed the smart wallet
* Get the factory contract which deployed the account
*
* @returns Returns the address of the factory
*
@@ -161,16 +161,16 @@ export class SmartWallet<TContract extends IAccountCore>
********************************/
/**
* Get whether a signer is an admin on the smart wallet.
* Get whether a signer is an admin on the account.
*
* @example
* ```javascript
* const isAdmin = await contract.smartWallet.isAdmin(signer);
* const isAdmin = await contract.account.isAdmin(signer);
* ```
* @param signer - The address of a signer of the smart wallet.
* @returns whether a signer is an admin on the smart wallet.
* @param signer - The address of a signer of the account.
* @returns whether a signer is an admin on the account.
*
* @twfeature SmartWallet
* @twfeature Account
*/
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress);
@@ -180,16 +180,16 @@ export class SmartWallet<TContract extends IAccountCore>
}
/**
* Get the restrictions under which a given signer can use the smart wallet.
* Get the restrictions under which a given signer can use the account.
*
* @example
* ```javascript
* const restrictionsForSigner = await contract.smartWallet.getAccessRestrictions(signer);
* const restrictionsForSigner = await contract.account.getAccessRestrictions(signer);
* ```
* @param signer - The address of a signer of the smart wallet.
* @returns the restrictions under which a given signer can use the smart wallet.
* @param signer - The address of a signer of the account.
* @returns the restrictions under which a given signer can use the account.
*
* @twfeature SmartWallet
* @twfeature Account
*/
public async getAccessRestrictions(
signerAddress: AddressOrEns,
@@ -203,16 +203,16 @@ export class SmartWallet<TContract extends IAccountCore>
}
/**
* Get the deployer of the smart wallet
* @remarks Get the address of the EIP-4337 factory contract which deployed the smart wallet
* Get the deployer of the account
* @remarks Get the address of the EIP-4337 factory contract which deployed the account
*
* @example
* ```javascript
* const factoryAddress = await contract.smartWallet.getFactoryAddress();
* const factoryAddress = await contract.account.getFactoryAddress();
* ```
* @returns the address of the factory which deployed the smart wallet.
* @returns the address of the factory which deployed the account.
*
* @twfeature SmartWallet
* @twfeature Account
*/
public async getFactoryAddress(): Promise<string> {
return this.contractWrapper.readContract.factory();
@@ -223,11 +223,11 @@ export class SmartWallet<TContract extends IAccountCore>
*
* @example
* ```javascript
* const allSigners = await contract.smartWallet.getSignersWithRestrictions();
* const allSigners = await contract.account.getSignersWithRestrictions();
* ```
* @returns all signers (admin or non-admin) of the smart wallet, along with their access restrictions.
* @returns all signers (admin or non-admin) of the account, along with their access restrictions.
*
* @twfeature SmartWallet
* @twfeature Account
*/
public async getSignersWithRestrictions(): Promise<SignerWithRestrictions[]> {
// Get all associated signers.
@@ -250,19 +250,19 @@ export class SmartWallet<TContract extends IAccountCore>
********************************/
/**
* Grant an address admin access to the smart wallet
* Grant an address admin access to the account
*
* @remarks Grants an address admin access to the smart wallet. The admin will have complete authority over the smart wallet.
* @remarks Grants an address admin access to the account. The admin will have complete authority over the account.
*
* @param signer - The address to be granted admin access to the smart wallet.
* @param signer - The address to be granted admin access to the account.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.grantAdminAccess(signer);
* const tx = await contract.account.grantAdminAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
grantAdminAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
@@ -276,19 +276,19 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Revoke an address' admin access to the smart wallet
* Revoke an address' admin access to the account
*
* @remarks Revokes an address' admin access to the smart wallet.
* @remarks Revokes an address' admin access to the account.
*
* @param signer - The address of an admin of the smart wallet.
* @param signer - The address of an admin of the account.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.revokeAdminAccess(signer);
* const tx = await contract.account.revokeAdminAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
revokeAdminAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
@@ -302,20 +302,20 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Grant an address access to the smart wallet with restrictions
* Grant an address access to the account with restrictions
*
* @remarks Grants an address access to the smart wallet with certain restrictions.
* @remarks Grants an address access to the account with certain restrictions.
*
* @param signer - The address to be granted access to the smart wallet.
* @param restrictions - The restrictions to be applied to the signer's use of the smart wallet.
* @param signer - The address to be granted access to the account.
* @param restrictions - The restrictions to be applied to the signer's use of the account.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.grantAccess(signer, restrictions);
* const tx = await contract.account.grantAccess(signer, restrictions);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
grantAccess = /* @__PURE__ */ buildTransactionFunction(
async (
@@ -395,20 +395,20 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Approve an address as a call target for a given signer on the smart wallet
* Approve an address as a call target for a given signer on the account
*
* @remarks Approves an address as a call target for a given signer on the smart wallet.
* @remarks Approves an address as a call target for a given signer on the account.
*
* @param signer - A signer with restricted access to the smart wallet.
* @param signer - A signer with restricted access to the account.
* @param target - The address to approve as a call target for the signer.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.approveTargetForSigner(signer, target);
* const tx = await contract.account.approveTargetForSigner(signer, target);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
@@ -444,20 +444,20 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Disapprove an address as a call target for a given signer on the smart wallet
* Disapprove an address as a call target for a given signer on the account
*
* @remarks Disapprove an address as a call target for a given signer on the smart wallet.
* @remarks Disapprove an address as a call target for a given signer on the account.
*
* @param signer - A signer with restricted access to the smart wallet.
* @param signer - A signer with restricted access to the account.
* @param target - The address to disapprove as a call target for the signer.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.disapproveTargetForSigner(signer, target);
* const tx = await contract.account.disapproveTargetForSigner(signer, target);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async (
@@ -496,20 +496,20 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Update the restrictions of an address for using the smart wallet
* Update the restrictions of an address for using the account
*
* @remarks Updates an address' access to the smart wallet.
* @remarks Updates an address' access to the account.
*
* @param signer - The address whose access to the smart wallet is to be updated.
* @param restrictions - The restrictions to be applied to the signer's use of the smart wallet.
* @param signer - The address whose access to the account is to be updated.
* @param restrictions - The restrictions to be applied to the signer's use of the account.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.updateAccess(signer, restrictions);
* const tx = await contract.account.updateAccess(signer, restrictions);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
updateAccess = /* @__PURE__ */ buildTransactionFunction(
async (
@@ -550,19 +550,19 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Revoke a scoped access address to the smart wallet
* Revoke a scoped access address to the account
*
* @remarks Revokes an address' access to the smart wallet.
* @remarks Revokes an address' access to the account.
*
* @param signer - The address whose access to the smart wallet is to be revoked.
* @param signer - The address whose access to the account is to be revoked.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.revokeAccess(signer);
* const tx = await contract.account.revokeAccess(signer);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
revokeAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => {
@@ -600,19 +600,19 @@ export class SmartWallet<TContract extends IAccountCore>
);
/**
* Set the wallet's entire snapshot of permissions
* Set the account's entire snapshot of permissions
*
* @remarks Sets the wallet's entire snapshot of permissions.
* @remarks Sets the account's entire snapshot of permissions.
*
* @param permissionsSnapshot - the snapshot to set as the wallet's entire permission snapshot.
* @param permissionsSnapshot - the snapshot to set as the account's entire permission snapshot.
*
* @example
* ```javascript
* const tx = await contract.smartWallet.setAccess(permissionsSnapshot);
* const tx = await contract.account.setAccess(permissionsSnapshot);
* const receipt = tx.receipt();
* ```
*
* @twfeature SmartWallet
* @twfeature Account
*/
setAccess = /* @__PURE__ */ buildTransactionFunction(
async (
@@ -1,8 +1,7 @@
import { EventType } from "../../constants/events";
import type { ContractEvent, EventQueryOptions } from "../../types/events";
import { ContractWrapper } from "./contract-wrapper";
import type { BaseContract, Event, providers } from "ethers";
import type { EventFragment } from "ethers/lib/utils.js";
import type { BaseContract, Event, providers, utils } from "ethers";
import type { EventEmitter } from "eventemitter3";
/**
@@ -325,7 +324,7 @@ export class ContractEvents<TContract extends BaseContract> {
}
private toContractEvent<TEvent extends Record<string, any>>(
event: EventFragment,
event: utils.EventFragment,
args: ReadonlyArray<any>,
rawLog: providers.Log,
): ContractEvent<TEvent> {
@@ -44,7 +44,6 @@ import {
type Signer,
constants,
} from "ethers";
import { ConnectionInfo } from "ethers/lib/utils.js";
import invariant from "tiny-invariant";
import { CONTRACT_ADDRESSES } from "../../constants/addresses/CONTRACT_ADDRESSES";
import { getContractAddressByChainId } from "../../constants/addresses/getContractAddressByChainId";
@@ -471,7 +470,7 @@ export class ContractWrapper<
callOverrides: CallOverrides,
) {
const provider = this.getProvider() as providers.Provider & {
connection?: ConnectionInfo;
connection?: utils.ConnectionInfo;
};
// Get metadata for transaction to populate into error
+2 -2
View File
@@ -50,5 +50,5 @@ export * from "./contract-published-metadata";
export * from "./contract-owner";
export * from "./transactions";
export * from "./contract-appuri";
export * from "./smart-wallet";
export * from "./smart-wallet-factory";
export * from "./account";
export * from "./account-factory";
@@ -21,7 +21,7 @@ import {
DirectListingInputParams,
DirectListingInputParamsSchema,
} from "../../schema/marketplacev3/direct-listings";
import type { MarketplaceFilter } from "../../types/marketplace";
import type { MarketplaceFilterWithoutOfferor } from "../../types/marketplace";
import type { DirectListingV3 } from "../../types/marketplacev3";
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { TransactionResultWithId } from "../types";
@@ -116,7 +116,7 @@ export class MarketplaceV3DirectListings<TContract extends DirectListingsLogic>
* @returns the Direct listing object array
* @twfeature DirectListings
*/
public async getAll(filter?: MarketplaceFilter): Promise<DirectListingV3[]> {
public async getAll(filter?: MarketplaceFilterWithoutOfferor): Promise<DirectListingV3[]> {
const totalListings = await this.getTotalCount();
let start = BigNumber.from(filter?.start || 0).toNumber();
@@ -156,7 +156,7 @@ export class MarketplaceV3DirectListings<TContract extends DirectListingsLogic>
* @twfeature DirectListings
*/
public async getAllValid(
filter?: MarketplaceFilter,
filter?: MarketplaceFilterWithoutOfferor,
): Promise<DirectListingV3[]> {
const totalListings = await this.getTotalCount();
@@ -955,7 +955,7 @@ export class MarketplaceV3DirectListings<TContract extends DirectListingsLogic>
private async applyFilter(
listings: IDirectListings.ListingStructOutput[],
filter?: MarketplaceFilter,
filter?: MarketplaceFilterWithoutOfferor,
) {
let rawListings = [...listings];
@@ -11,7 +11,7 @@ import {
EnglishAuctionInputParams,
EnglishAuctionInputParamsSchema,
} from "../../schema/marketplacev3/english-auctions";
import type { MarketplaceFilter } from "../../types/marketplace";
import type { MarketplaceFilterWithoutOfferor } from "../../types/marketplace";
import { CurrencyValue, Price } from "../../types/currency";
import { EnglishAuction, Bid } from "../../types/marketplacev3";
import { DetectableFeature } from "../interfaces/DetectableFeature";
@@ -104,7 +104,7 @@ export class MarketplaceV3EnglishAuctions<
* @returns the Auction object array
* @twfeature EnglishAuctions
*/
public async getAll(filter?: MarketplaceFilter): Promise<EnglishAuction[]> {
public async getAll(filter?: MarketplaceFilterWithoutOfferor): Promise<EnglishAuction[]> {
const totalAuctions = await this.getTotalCount();
let start = BigNumber.from(filter?.start || 0).toNumber();
@@ -142,7 +142,7 @@ export class MarketplaceV3EnglishAuctions<
* @twfeature EnglishAuctions
*/
public async getAllValid(
filter?: MarketplaceFilter,
filter?: MarketplaceFilterWithoutOfferor,
): Promise<EnglishAuction[]> {
const totalAuctions = await this.getTotalCount();
@@ -885,7 +885,7 @@ export class MarketplaceV3EnglishAuctions<
private async applyFilter(
auctions: IEnglishAuctions.AuctionStructOutput[],
filter?: MarketplaceFilter,
filter?: MarketplaceFilterWithoutOfferor,
) {
let rawAuctions = [...auctions];
@@ -14,7 +14,7 @@ import {
OfferInputParams,
OfferInputParamsSchema,
} from "../../schema/marketplacev3/offer";
import type { MarketplaceFilter } from "../../types/marketplace";
import type { MarketplaceFilterWithoutSeller } from "../../types/marketplace";
import { OfferV3 } from "../../types/marketplacev3";
import { DetectableFeature } from "../interfaces/DetectableFeature";
import { TransactionResultWithId } from "../types";
@@ -96,7 +96,7 @@ export class MarketplaceV3Offers<TContract extends OffersLogic>
* @returns the Offer object array
* @twfeature Offers
*/
public async getAll(filter?: MarketplaceFilter): Promise<OfferV3[]> {
public async getAll(filter?: MarketplaceFilterWithoutSeller): Promise<OfferV3[]> {
const totalOffers = await this.getTotalCount();
let start = BigNumber.from(filter?.start || 0).toNumber();
@@ -133,7 +133,7 @@ export class MarketplaceV3Offers<TContract extends OffersLogic>
* @returns the Offer object array
* @twfeature Offers
*/
public async getAllValid(filter?: MarketplaceFilter): Promise<OfferV3[]> {
public async getAllValid(filter?: MarketplaceFilterWithoutSeller): Promise<OfferV3[]> {
const totalOffers = await this.getTotalCount();
let start = BigNumber.from(filter?.start || 0).toNumber();
@@ -457,7 +457,7 @@ export class MarketplaceV3Offers<TContract extends OffersLogic>
private async applyFilter(
offers: IOffers.OfferStructOutput[],
filter?: MarketplaceFilter,
filter?: MarketplaceFilterWithoutSeller,
) {
let rawOffers = [...offers];
@@ -30,8 +30,6 @@ import {
constants,
} from "ethers";
import { BigNumber } from "ethers";
import { FormatTypes } from "ethers/lib/utils.js";
import type { ConnectionInfo } from "ethers/lib/utils.js";
import invariant from "tiny-invariant";
import EventEmitter from "eventemitter3";
import type { DeployEvents } from "../../types/deploy";
@@ -494,7 +492,7 @@ export class Transaction<
try {
// for dynamic contracts, add 30% to the gas limit to account for multiple delegate calls
const abi = JSON.parse(
this.contract.interface.format(FormatTypes.json) as string,
this.contract.interface.format("json") as string,
);
if (isRouterContract(abi)) {
overrides.gasLimit = overrides.gasLimit.mul(110).div(100);
@@ -663,7 +661,7 @@ export class Transaction<
*/
private async transactionError(error: any) {
const provider = this.provider as providers.Provider & {
connection?: ConnectionInfo;
connection?: utils.ConnectionInfo;
};
// Get metadata for transaction to populate into error
@@ -849,7 +847,7 @@ export class DeployTransaction extends TransactionContext {
*/
private async deployError(error: any) {
const provider = this.provider as providers.Provider & {
connection?: ConnectionInfo;
connection?: utils.ConnectionInfo;
};
// Get metadata for transaction to populate into error
+1 -1
View File
@@ -12,4 +12,4 @@ export * from "./multiwrap";
export * from "./registry";
export * from "./transactions";
export * from "./contract";
export * from "./smart-wallet";
export * from "./account";
@@ -11,3 +11,13 @@ export interface MarketplaceFilter extends QueryAllParams {
tokenId?: BigNumberish;
offeror?: AddressOrEns;
}
/**
* English auctions and Direct Listings V3 cannot be retrieved by offeror.
*/
export interface MarketplaceFilterWithoutOfferor extends Omit<MarketplaceFilter, 'offeror'> {}
/**
* Offers V3 cannot be retrieved by seller.
*/
export interface MarketplaceFilterWithoutSeller extends Omit<MarketplaceFilter, 'seller'> {}
@@ -1,7 +1,4 @@
import { Keypair } from "@solana/web3.js";
import fs from "fs";
import os from "os";
import path from "path";
import yaml from "yaml";
/**
@@ -9,14 +6,14 @@ import yaml from "yaml";
*/
function getConfig(): any {
// Path to Solana CLI config file
const CONFIG_FILE_PATH = path.resolve(
os.homedir(),
const CONFIG_FILE_PATH = require("path").resolve(
require("os").homedir(),
".config",
"solana",
"cli",
"config.yml",
);
const configYml = fs.readFileSync(CONFIG_FILE_PATH, {
const configYml = require("fs").readFileSync(CONFIG_FILE_PATH, {
encoding: "utf8",
});
return yaml.parse(configYml);
@@ -62,7 +59,9 @@ export function getPayer(): Keypair {
* Create a Keypair from a secret key stored in file as bytes' array
*/
export function createKeypairFromFile(filePath: string): Keypair {
const secretKeyString = fs.readFileSync(filePath, { encoding: "utf8" });
const secretKeyString = require("fs").readFileSync(filePath, {
encoding: "utf8",
});
const secretKey = Uint8Array.from(JSON.parse(secretKeyString));
return Keypair.fromSecretKey(secretKey);
}
@@ -4,8 +4,8 @@ import { assert, expect } from "chai";
import {
SignerWithRestrictions,
AccessRestrictions,
SmartWallet,
SmartWalletFactory,
Account,
AccountFactory,
SignerWithRestrictionsInput,
SignerWithRestrictionsBatchInput,
} from "../../src/evm";
@@ -23,9 +23,9 @@ import { IAccountCore, IAccountFactory } from "@thirdweb-dev/contracts-js";
global.fetch = /* @__PURE__ */ require("cross-fetch");
/* @__PURE__ */ describe("Smart wallets with wallet factory", function () {
let smartWalletFactory: SmartWalletFactory<IAccountFactory>;
let smartWallet: SmartWallet<IAccountCore>;
/* @__PURE__ */ describe("Accounts with account factory", function () {
let accountFactory: AccountFactory<IAccountFactory>;
let account: Account<IAccountCore>;
let adminWallet: SignerWithAddress;
@@ -66,64 +66,63 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
adminWallet,
[entrypoint.address],
);
smartWalletFactory = (await sdk.getContract(factoryAddress))
.smartWalletFactory;
accountFactory = (await sdk.getContract(factoryAddress)).accountFactory;
});
describe("Test: SmartWalletFactory actions", () => {
it("Should create a new wallet for the admin", async () => {
// Check before creating a smart wallet for `adminWallet`
const isDeployed = await smartWalletFactory.isWalletDeployed(
describe("Test: AccountFactory actions", () => {
it("Should create a new account for the admin", async () => {
// Check before creating a account for `adminWallet`
const isDeployed = await accountFactory.isAccountDeployed(
adminWallet.address,
);
assert.isFalse(
isDeployed,
"Smart wallet is should not be deployed for admin.",
"Account is should not be deployed for admin.",
);
const predictedAccountAddress: string =
await smartWalletFactory.predictWalletAddress(adminWallet.address);
await accountFactory.predictAccountAddress(adminWallet.address);
const allWalletsBefore = (await smartWalletFactory.getAllAccounts()).map(
(wallet) => wallet.account,
const allAccountsBefore = (await accountFactory.getAllAccounts()).map(
(wallet) => account.account,
);
assert.isFalse(
allWalletsBefore.includes(predictedAccountAddress),
allAccountsBefore.includes(predictedAccountAddress),
"Account should not be deployed for admin already.",
);
assert.isTrue(
(await smartWalletFactory.getAssociatedSigners(predictedAccountAddress))
(await accountFactory.getAssociatedSigners(predictedAccountAddress))
.length === 0,
"Wallet should have no associated signers.",
);
assert.isTrue(
(await smartWalletFactory.getAssociatedWallets(adminWallet.address))
(await accountFactory.getAssociatedAccounts(adminWallet.address))
.length === 0,
"Signer should have no associated wallets.",
"Signer should have no associated accounts.",
);
// Create smart wallet for `adminWallet`
const tx = await smartWalletFactory.createWallet(adminWallet.address);
// Create account for `adminWallet`
const tx = await accountFactory.createAccount(adminWallet.address);
// Checks after creating a smart wallet for `adminWallet`
// Checks after creating a account for `adminWallet`
assert.strictEqual(
utils.getAddress(tx.address),
utils.getAddress(predictedAccountAddress),
"Smart wallet address should match predicted address.",
"Account address should match predicted address.",
);
assert.isTrue(
await smartWalletFactory.isWalletDeployed(adminWallet.address),
"Smart wallet is should be deployed for admin.",
await accountFactory.isAccountDeployed(adminWallet.address),
"Account is should be deployed for admin.",
);
const allWalletsAfter = await smartWalletFactory.getAllAccounts();
const allAccountsAfter = await accountFactory.getAllAccounts();
assert.isTrue(
allWalletsAfter.length === 1,
"Only one wallet should be created on the factory.",
allAccountsAfter.length === 1,
"Only one account should be created on the factory.",
);
const { account, admin } = allWalletsAfter.filter(
const { account, admin } = allAccountsAfter.filter(
(wallet) =>
utils.getAddress(wallet.account) ===
utils.getAddress(predictedAccountAddress),
@@ -136,165 +135,161 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
assert.strictEqual(
utils.getAddress(admin),
utils.getAddress(adminWallet.address),
"Correct admin for smart wallet.",
"Correct admin for account.",
);
const associatedWallets = await smartWalletFactory.getAssociatedWallets(
const associatedAccounts = await accountFactory.getAssociatedAccounts(
admin,
);
const associatedSigner = await smartWalletFactory.getAssociatedSigners(
const associatedSigner = await accountFactory.getAssociatedSigners(
account,
);
assert.isTrue(
associatedWallets.length === 1,
associatedAccounts.length === 1,
"Wallet should have only the admin as an associated signer.",
);
assert.strictEqual(
utils.getAddress(account),
utils.getAddress(associatedWallets[0]),
utils.getAddress(associatedAccounts[0]),
"Wallet should have only the admin as an associated signer.",
);
assert.isTrue(
associatedSigner.length === 1,
"Signer should have only the created wallet as an associated wallet.",
"Signer should have only the created account as an associated account.",
);
assert.strictEqual(
utils.getAddress(admin),
utils.getAddress(associatedSigner[0]),
"Signer should have only the created wallet as an associated wallet.",
"Signer should have only the created account as an associated account.",
);
});
it("Should throw if creating wallet for an admin who already has one", async () => {
// Create a wallet for admin
await smartWalletFactory.createWallet(adminWallet.address);
it("Should throw if creating account for an admin who already has one", async () => {
// Create a account for admin
await accountFactory.createAccount(adminWallet.address);
// Try creating another wallet for the same admin
// Try creating another account for the same admin
try {
await smartWalletFactory.createWallet(adminWallet.address);
await accountFactory.createAccount(adminWallet.address);
expect.fail();
} catch (err: any) {
expect(err.message).to.equal(
`Wallet already deployed for admin: ${adminWallet.address}`,
`Account already deployed for admin: ${adminWallet.address}`,
);
}
});
});
describe("Test: SmartWallet actions", () => {
describe("Test: Account actions", () => {
beforeEach(async () => {
// Create a wallet for admin
const tx = await smartWalletFactory.createWallet(adminWallet.address);
const smartWalletAddress = tx.address;
// Create a account for admin
const tx = await accountFactory.createAccount(adminWallet.address);
const accountAddress = tx.address;
sdk.updateSignerOrProvider(adminWallet);
await mockUploadContractMetadata(
"smart-wallet",
smartWalletAddress,
accountAddress,
IAccountCoreAbi,
);
smartWallet = (await sdk.getContract(smartWalletAddress)).smartWallet;
account = (await sdk.getContract(accountAddress)).account;
});
it("Should be able to add another admin to the wallet.", async () => {
it("Should be able to add another admin to the account.", async () => {
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
await smartWallet.grantAdminAccess(signer1Wallet.address);
await account.grantAdminAccess(signer1Wallet.address);
assert.isTrue(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the account.",
);
const isAdmin = (
(await smartWallet.getSignersWithRestrictions()).find(
(await account.getSignersWithRestrictions()).find(
(result) =>
utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address),
) as SignerWithRestrictions
).isAdmin;
assert.isTrue(isAdmin, "New signer1 should be an admin on the wallet.");
assert.isTrue(isAdmin, "New signer1 should be an admin on the account.");
assert.isTrue(
(
await smartWalletFactory.getAssociatedSigners(
smartWallet.getAddress(),
)
await accountFactory.getAssociatedSigners(account.getAddress())
).includes(signer1Wallet.address),
"New signer1 is an associated signer of the wallet.",
"New signer1 is an associated signer of the account.",
);
assert.isTrue(
(
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
).includes(smartWallet.getAddress()),
"Wallet is an associated wallet of the signer.",
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(account.getAddress()),
"Wallet is an associated account of the signer.",
);
});
it("Should be able to remove an admin from the wallet.", async () => {
await smartWallet.grantAdminAccess(signer1Wallet.address);
it("Should be able to remove an admin from the account.", async () => {
await account.grantAdminAccess(signer1Wallet.address);
assert.isTrue(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the account.",
);
await smartWallet.revokeAdminAccess(signer1Wallet.address);
await account.revokeAdminAccess(signer1Wallet.address);
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
assert.isFalse(
(await smartWallet.getSignersWithRestrictions())
(await account.getSignersWithRestrictions())
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer1 should not be an admin on the wallet.",
"New signer1 should not be an admin on the account.",
);
assert.isFalse(
(
await smartWalletFactory.getAssociatedSigners(
smartWallet.getAddress(),
)
await accountFactory.getAssociatedSigners(account.getAddress())
).includes(signer1Wallet.address),
"New signer1 is not an associated signer of the wallet.",
"New signer1 is not an associated signer of the account.",
);
assert.isFalse(
(
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
).includes(smartWallet.getAddress()),
"Wallet is not an associated wallet of the signer.",
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(account.getAddress()),
"Wallet is not an associated account of the signer.",
);
});
it("Should be able to grant restricted access to a new signer.", async () => {
const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
assert.isFalse(
signersWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer should not already have access to the wallet.",
"New signer should not already have access to the account.",
);
// Grant access
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address],
});
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
const newSignerWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
const restrictions = newSignerWithRestrictions.find(
(result) =>
utils.getAddress(result.signer) ===
@@ -304,7 +299,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
newSignerWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.",
"New signer1 should be a signer on the account.",
);
assert.strictEqual(
restrictions.nativeTokenLimitPerTransaction.toString(),
@@ -324,30 +319,28 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
assert.isTrue(
(
await smartWalletFactory.getAssociatedSigners(
smartWallet.getAddress(),
)
await accountFactory.getAssociatedSigners(account.getAddress())
).includes(signer1Wallet.address),
"New signer1 is an associated signer of the wallet.",
"New signer1 is an associated signer of the account.",
);
assert.isTrue(
(
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
).includes(smartWallet.getAddress()),
"Wallet is an associated wallet of the signer.",
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(account.getAddress()),
"Wallet is an associated account of the signer.",
);
});
it("Should not be able to grant restricted access to a signer who already has access.", async () => {
// Grant access to signer1
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address],
});
// Try granting access to signer1 again
try {
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
approvedCallTargets: [adminWallet.address],
});
expect.fail();
@@ -358,57 +351,55 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
it("Should be able to revoke restricted access from an authorized signer.", async () => {
// Grant access to signer1
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address],
});
// Revoke access
await smartWallet.revokeAccess(signer1Wallet.address);
await account.revokeAccess(signer1Wallet.address);
const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
assert.isFalse(
signersWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer should not have access to the wallet.",
"New signer should not have access to the account.",
);
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
assert.isFalse(
(
await smartWalletFactory.getAssociatedSigners(
smartWallet.getAddress(),
)
await accountFactory.getAssociatedSigners(account.getAddress())
).includes(signer1Wallet.address),
"New signer1 is not an associated signer of the wallet.",
"New signer1 is not an associated signer of the account.",
);
assert.isFalse(
(
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
).includes(smartWallet.getAddress()),
"Wallet is not an associated wallet of the signer.",
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(account.getAddress()),
"Wallet is not an associated account of the signer.",
);
});
it("Should not be able to revoke restricted access from a signer who doesn't have access.", async () => {
const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
assert.isFalse(
signersWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer should not already have access to the wallet.",
"New signer should not already have access to the account.",
);
// Try revoking access from signer1
try {
await smartWallet.revokeAccess(signer1Wallet.address);
await account.revokeAccess(signer1Wallet.address);
expect.fail();
} catch (err: any) {
expect(err.message).to.equal(`Signer does not have any access`);
@@ -417,18 +408,17 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
it("Should be able to update access of an authorized signer.", async () => {
// Grant access
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address],
});
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
const signerWithRestrictions =
await smartWallet.getSignersWithRestrictions();
const signerWithRestrictions = await account.getSignersWithRestrictions();
const restrictions = signerWithRestrictions.find(
(result) =>
utils.getAddress(result.signer) ===
@@ -438,7 +428,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signerWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.",
"New signer1 should be a signer on the account.",
);
assert.strictEqual(
restrictions.nativeTokenLimitPerTransaction.toString(),
@@ -457,18 +447,18 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
);
// Update access
await smartWallet.updateAccess(signer1Wallet.address, {
await account.updateAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "3",
approvedCallTargets: [signer2Wallet.address],
});
assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.",
await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the account.",
);
const newSignerWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
const newRestrictions = newSignerWithRestrictions.find(
(result) =>
utils.getAddress(result.signer) ===
@@ -478,7 +468,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
newSignerWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.",
"New signer1 should be a signer on the account.",
);
assert.strictEqual(
newRestrictions.nativeTokenLimitPerTransaction.toString(),
@@ -499,17 +489,17 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
it("Should not be able to update access of a signer who doesn't have access.", async () => {
const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
assert.isFalse(
signersWithRestrictions
.map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address),
"New signer should not already have access to the wallet.",
"New signer should not already have access to the account.",
);
// Try updating access of signer1
try {
await smartWallet.updateAccess(signer1Wallet.address, {
await account.updateAccess(signer1Wallet.address, {
approvedCallTargets: [signer2Wallet.address],
});
expect.fail();
@@ -520,14 +510,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
it("Should be able to append an approved target for an authorized signer.", async () => {
// Grant access
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address],
});
const restrictions = (
await smartWallet.getSignersWithRestrictions()
).find(
const restrictions = (await account.getSignersWithRestrictions()).find(
(result) =>
utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address),
@@ -544,14 +532,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
);
// Append approved target
await smartWallet.approveTargetForSigner(
await account.approveTargetForSigner(
signer1Wallet.address,
signer2Wallet.address,
);
const newRestrictions = (
await smartWallet.getSignersWithRestrictions()
).find(
const newRestrictions = (await account.getSignersWithRestrictions()).find(
(result) =>
utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address),
@@ -575,14 +561,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
it("Should be able to remove an approved target for an authorized signer.", async () => {
// Grant access
await smartWallet.grantAccess(signer1Wallet.address, {
await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address, signer2Wallet.address],
});
const restrictions = (
await smartWallet.getSignersWithRestrictions()
).find(
const restrictions = (await account.getSignersWithRestrictions()).find(
(result) =>
utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address),
@@ -604,14 +588,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
);
// Remove approved target
await smartWallet.disapproveTargetForSigner(
await account.disapproveTargetForSigner(
signer1Wallet.address,
signer2Wallet.address,
);
const newRestrictions = (
await smartWallet.getSignersWithRestrictions()
).find(
const newRestrictions = (await account.getSignersWithRestrictions()).find(
(result) =>
utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address),
@@ -628,7 +610,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
);
});
it("Should be able to set access for the smart wallet in a batch.", async () => {
it("Should be able to set access for the account in a batch.", async () => {
/**
* All cases to test
*
@@ -661,7 +643,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner3);
// Removing existing admin
await smartWallet.grantAdminAccess(signer4Wallet.address);
await account.grantAdminAccess(signer4Wallet.address);
const restrictionsSigner4: SignerWithRestrictionsInput = {
signer: signer4Wallet.address,
@@ -679,7 +661,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner5);
// Removing an existing scoped signer
await smartWallet.grantAccess(signer6Wallet.address, {
await account.grantAccess(signer6Wallet.address, {
approvedCallTargets: [adminWallet.address],
});
@@ -692,7 +674,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
// Updating the restrictions of an existing scoped signer
await smartWallet.grantAccess(signer7Wallet.address, {
await account.grantAccess(signer7Wallet.address, {
approvedCallTargets: [adminWallet.address],
});
@@ -704,7 +686,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner7);
// Existing admin -> new scoped signer (demote)
await smartWallet.grantAdminAccess(signer8Wallet.address);
await account.grantAdminAccess(signer8Wallet.address);
const restrictionsSigner8: SignerWithRestrictionsInput = {
signer: signer8Wallet.address,
@@ -714,7 +696,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner8);
// Existing scoped signer -> new admin (promote)
await smartWallet.grantAccess(signer9Wallet.address, {
await account.grantAccess(signer9Wallet.address, {
approvedCallTargets: [adminWallet.address],
});
@@ -726,11 +708,11 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner9);
// Set access in batch
await smartWallet.setAccess(signersWithRestrictions);
await account.setAccess(signersWithRestrictions);
// Now checking if permissions are set correctly
const signersWithRestrictionsAfter =
await smartWallet.getSignersWithRestrictions();
await account.getSignersWithRestrictions();
for (const restrictions of signersWithRestrictionsAfter) {
switch (restrictions.signer) {
@@ -738,96 +720,96 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
case adminWallet.address:
assert.isTrue(
restrictions.isAdmin,
"Admin wallet should be an admin.",
"Admin account should be an admin.",
);
break;
// `signer3Wallet` should be an admin
case signer3Wallet.address:
assert.isTrue(
restrictions.isAdmin,
"Signer3 wallet should be an admin.",
"Signer3 account should be an admin.",
);
break;
// `signer4Wallet` should not be admin or scoped signer
case signer4Wallet.address:
assert.isFalse(
restrictions.isAdmin,
"Signer4 wallet should not be an admin.",
"Signer4 account should not be an admin.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length,
0,
"Signer4 wallet should not have any approved call targets.",
"Signer4 account should not have any approved call targets.",
);
break;
// `signer5Wallet` should be a scoped signer
case signer5Wallet.address:
assert.isFalse(
restrictions.isAdmin,
"Signer5 wallet should not be an admin.",
"Signer5 account should not be an admin.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length,
1,
"Signer5 wallet should have one approved call target.",
"Signer5 account should have one approved call target.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0],
adminWallet.address,
"Signer5 wallet should have the expected approved call targets.",
"Signer5 account should have the expected approved call targets.",
);
break;
// `signer6Wallet` should not be admin or scoped signer
case signer6Wallet.address:
assert.isFalse(
restrictions.isAdmin,
"Signer6 wallet should not be an admin.",
"Signer6 account should not be an admin.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length,
0,
"Signer6 wallet should not have any approved call targets.",
"Signer6 account should not have any approved call targets.",
);
break;
// `signer7Wallet` should be a scoped signer with its updated restrictions
case signer7Wallet.address:
assert.isFalse(
restrictions.isAdmin,
"Signer7 wallet should not be an admin.",
"Signer7 account should not be an admin.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length,
1,
"Signer7 wallet should have one approved call target.",
"Signer7 account should have one approved call target.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0],
signer1Wallet.address,
"Signer7 wallet should have the expected approved call targets.",
"Signer7 account should have the expected approved call targets.",
);
break;
// `signer8Wallet` should be a scoped signer
case signer8Wallet.address:
assert.isFalse(
restrictions.isAdmin,
"Signer8 wallet should not be an admin.",
"Signer8 account should not be an admin.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length,
1,
"Signer8 wallet should have one approved call target.",
"Signer8 account should have one approved call target.",
);
assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0],
adminWallet.address,
"Signer8 wallet should have the expected approved call targets.",
"Signer8 account should have the expected approved call targets.",
);
break;
// `signer9Wallet` should be an admin
case signer9Wallet.address:
assert.isTrue(
restrictions.isAdmin,
"Signer9 wallet should be an admin.",
"Signer9 account should be an admin.",
);
break;
default:
+3
View File
@@ -82,6 +82,7 @@ let signers: SignerWithAddress[];
let storage: ThirdwebStorage;
let implementations: { [key in ContractType]?: string };
let mock_weth_address: string;
let thirdwebFactory: TWFactory;
const fastForwardTime = async (timeInSeconds: number): Promise<void> => {
const now = Math.floor(Date.now() / 1000);
@@ -133,6 +134,7 @@ export const mochaHooks = {
.connect(signer)
.deploy(trustedForwarderAddress, registry.address)) as TWFactory;
thirdwebFactory = await thirdwebFactoryDeployer.deployed();
const deployTxFactory = thirdwebFactoryDeployer.deployTransaction;
await deployTxFactory.wait();
const thirdwebRegistryAddress = await thirdwebFactoryDeployer.registry();
@@ -391,4 +393,5 @@ export {
storage,
implementations,
hardhatEthers,
thirdwebFactory,
};
+1 -1
View File
@@ -4,7 +4,7 @@ import { expect } from "chai";
import { Wallet } from "ethers";
describe("Error Handling", async () => {
test.skip("should throw proper error on account with no balance", async () => {
it("should throw proper error on account with no balance", async () => {
const newSdk = ThirdwebSDK.fromSigner(
Wallet.createRandom().connect(sdk.getProvider()),
);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,85 @@
// from SplitWallet published at: ipfs://Qmc5cQotuEnCo71ZztJk69wc8kuKbGmuCARL2FyAojoi9r/
const abi = [
{
inputs: [],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [],
name: "Unauthorized",
type: "error",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "split",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "ReceiveETH",
type: "event",
},
{
inputs: [
{
internalType: "contract ERC20",
name: "token",
type: "address",
},
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "sendERC20ToMain",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "sendETHToMain",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [],
name: "splitMain",
outputs: [
{
internalType: "contract ISplitMain",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
];
const bytecode =
"0x60a060405234801561001057600080fd5b5033606081901b60805261035461004c60003960008181604b0152818160bc015281816101080152818161013c015261018601526103546000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea26469706673582212208e095a368bcb2efb2a8afd9b560ad94441e926086a4bc92edf16c33900df798e64736f6c63430008040033";
const deployedBytecode =
"0x6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea26469706673582212208e095a368bcb2efb2a8afd9b560ad94441e926086a4bc92edf16c33900df798e64736f6c63430008040033";
export { abi, bytecode, deployedBytecode };
File diff suppressed because one or more lines are too long
+9 -1
View File
@@ -20,5 +20,13 @@ export async function mockUploadWithCID(
file: FileOrBufferOrString,
options?: IpfsUploadBatchOptions | undefined,
) {
storage[cid] = file;
const [cidMain, id] = cid.split("/");
if (id) {
storage[cidMain] = {
[id]: file,
};
} else {
storage[cid] = file;
}
}
@@ -0,0 +1,360 @@
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { jsonProvider, sdk, signers, thirdwebFactory } from "./before-setup";
import { expect, assert } from "chai";
import {
Forwarder__factory,
DropERC721__factory,
ERC721Base__factory,
} from "@thirdweb-dev/contracts-js";
import {
bytecode as SplitMainBytecode,
deployedBytecode as SplitMainDeployedBytecode,
abi as SplitMainAbi,
} from "./metadata/SplitMain";
import {
bytecode as SplitWalletBytecode,
deployedBytecode as SplitWalletDeployedBytecode,
abi as SplitWalletAbi,
} from "./metadata/SplitWallet";
import {
bytecode as TWCloneFactoryBytecode,
abi as TWCloneFactoryAbi,
} from "./metadata/TWCloneFactory";
import { mockUploadMetadataWithBytecode } from "./utils";
const extendedMetadataMock = {
name: "",
metadataUri: "",
bytecodeUri: "",
analytics: {},
version: "1.0.0",
displayName: "",
description: "",
changelog: "",
isDeployableViaFactory: false,
isDeployableViaProxy: false,
factoryDeploymentData: {
implementationAddresses: {},
implementationInitializerFunction: "initialize",
factoryAddresses: {},
},
constructorParams: {},
publisher: "",
customFactoryInput: {
factoryFunction: "",
customFactoryAddresses: [],
},
};
describe("New Publish Flow", async () => {
let adminWallet: SignerWithAddress,
samWallet: SignerWithAddress,
bobWallet: SignerWithAddress,
w4: SignerWithAddress;
beforeEach(async () => {
await jsonProvider.send("hardhat_reset", []);
[adminWallet, samWallet, bobWallet, , , , , w4] = signers;
});
before("Mock upload infra contracts", async () => {
// mock upload Forwarder
await mockUploadMetadataWithBytecode(
"Forwarder",
Forwarder__factory.abi,
Forwarder__factory.bytecode,
"",
{
...extendedMetadataMock,
deployType: "standard",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
},
"ipfs://Qmcu8FaqerUvQYb4qPg7PwkXa6dRtEe45LedLJPN42Jwqe/0",
// ^ we use actual publish uri as mock uri here, because this contract's uri is fetched from publisher by contractName
);
// mock upload TWCloneFactory
await mockUploadMetadataWithBytecode(
"Forwarder",
TWCloneFactoryAbi,
TWCloneFactoryBytecode,
"",
{
...extendedMetadataMock,
deployType: "standard",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
},
"ipfs://QmYfw13Zykqf9jAmJobNgYrEpatEF9waWcQPUHvJ7sctRb/0",
// ^ we use actual publish uri as mock uri here, because this contract's uri is fetched from publisher by contractName
);
});
describe("Deploy newly published contract", async () => {
it("should deploy regular contract", async () => {
// mock publish as a standard-deploy contract
const mockPublishUri = await mockUploadMetadataWithBytecode(
"ERC721Base",
ERC721Base__factory.abi,
ERC721Base__factory.bytecode,
"",
{
...extendedMetadataMock,
deployType: "standard",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
publisher: await adminWallet.getAddress(),
},
);
// deploy with mock uri
const admin = await adminWallet.getAddress();
const contractAddress = await sdk.deployer.deployContractFromUri(
mockPublishUri,
["Direct Deploy ERC721Base", "DDE", admin, 5],
);
const contract = await sdk.getContract(contractAddress);
const name = await contract.call("name");
const owner = await contract.call("owner");
expect(name).to.equal("Direct Deploy ERC721Base");
expect(owner).to.equal(admin);
});
it("should deploy with custom factory", async () => {
// mock publish SplitMain as a standard-deploy contract
const splitMainMockUri = await mockUploadMetadataWithBytecode(
"SplitMain",
SplitMainAbi,
SplitMainBytecode,
SplitMainDeployedBytecode,
{
...extendedMetadataMock,
deployType: "standard",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
publisher: await adminWallet.getAddress(),
},
);
// deploy custom-factory `SplitMain`, with mock uri
const splitMainAddress = await sdk.deployer.deployContractFromUri(
splitMainMockUri,
[],
);
// mock publish SplitWallet as a custom-factory-deploy contract
const splitWalletMockUri = await mockUploadMetadataWithBytecode(
"SplitWallet",
SplitWalletAbi,
SplitWalletBytecode,
SplitWalletDeployedBytecode,
{
...extendedMetadataMock,
deployType: "customFactory",
factoryDeploymentData: {
...extendedMetadataMock.factoryDeploymentData,
customFactoryInput: {
factoryFunction: "createSplit",
params: [],
customFactoryAddresses: {
"31337": splitMainAddress,
},
},
},
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
publisher: await adminWallet.getAddress(),
},
);
// deploy contract via custom-factory, with mock uri
const splitWalletAddress = await sdk.deployer.deployContractFromUri(
splitWalletMockUri,
[
[await bobWallet.getAddress(), await adminWallet.getAddress()],
[500000, 500000],
0,
await adminWallet.getAddress(),
],
);
const splitContract = await sdk.getContract(splitWalletAddress);
const deployingAddress = await splitContract.call("splitMain");
expect(deployingAddress).to.equal(splitMainAddress);
});
});
describe("Deploy re-published contract", async () => {
it("should deploy with auto factory", async () => {
const mockPublisher = process.env.contractPublisherAddress;
process.env.contractPublisherAddress =
"0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7";
const adminAddress = await adminWallet.getAddress();
// mock publish as a autoFactory-deploy contract
const mockPublishUri = await mockUploadMetadataWithBytecode(
"DropERC721",
DropERC721__factory.abi,
DropERC721__factory.bytecode,
"",
{
...extendedMetadataMock,
deployType: "autoFactory",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
publisher: adminAddress,
},
);
// deploy via autoFactory, with mock uri
const contractAddress = await sdk.deployer.deployContractFromUri(
mockPublishUri,
[
adminAddress,
"DropERC721 Minimal Proxy",
"DME",
"",
[],
adminAddress,
adminAddress,
5,
5,
adminAddress,
],
);
const contract = await sdk.getContract(contractAddress);
const name = await contract.call("name");
const owner = await contract.call("owner");
const code = await sdk.getProvider().getCode(contractAddress);
expect(name).to.equal("DropERC721 Minimal Proxy");
expect(owner).to.equal(adminAddress);
assert(code.startsWith("0x363d3d373d3d3d363d73"));
process.env.contractPublisherAddress = mockPublisher;
});
});
describe("Deploy old contract without re-publishing", async () => {
it("should deploy regular contract", async () => {
// mock publish as old style -- omit deployType, networksForDeployment etc
const mockPublishUri = await mockUploadMetadataWithBytecode(
"ERC721Base",
ERC721Base__factory.abi,
ERC721Base__factory.bytecode,
"",
extendedMetadataMock,
);
// deploy with mock uri
const admin = await adminWallet.getAddress();
const contractAddress = await sdk.deployer.deployContractFromUri(
mockPublishUri,
["Direct Deploy ERC721Base", "DDE", admin, 5],
);
const contract = await sdk.getContract(contractAddress);
const name = await contract.call("name");
const owner = await contract.call("owner");
expect(name).to.equal("Direct Deploy ERC721Base");
expect(owner).to.equal(admin);
});
it("should deploy via old factory", async () => {
const mockPublisher = process.env.contractPublisherAddress;
process.env.contractPublisherAddress =
"0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7";
const adminAddress = await adminWallet.getAddress();
// mock publish as old-style factory deployable -- omit deployType, networksForDeployment etc
const mockPublishUri = await mockUploadMetadataWithBytecode(
"DropERC721",
DropERC721__factory.abi,
DropERC721__factory.bytecode,
"",
{
...extendedMetadataMock,
isDeployableViaFactory: true,
publisher: adminAddress,
},
);
// deploy implementation
const implementationAddress = await sdk.deployer.deployContractFromUri(
mockPublishUri,
[],
{
forceDirectDeploy: true,
},
);
await (
await thirdwebFactory.addImplementation(implementationAddress)
).wait();
// re-upload, with implementation address
const mockPublishUriUpdated = await mockUploadMetadataWithBytecode(
"DropERC721",
DropERC721__factory.abi,
DropERC721__factory.bytecode,
"",
{
...extendedMetadataMock,
isDeployableViaFactory: true,
factoryDeploymentData: {
...extendedMetadataMock?.factoryDeploymentData,
implementationAddresses: {
"31337": implementationAddress,
},
factoryAddresses: {
"31337": process.env.factoryAddress,
},
},
publisher: adminAddress,
},
);
// Deploy proxy DropERC721
const contractAddress = await sdk.deployer.deployContractFromUri(
mockPublishUriUpdated,
[
adminAddress,
"Drop Proxy Old",
"DPA",
"",
[],
adminAddress,
adminAddress,
5,
5,
adminAddress,
],
);
const drop = await sdk.getContract(contractAddress);
const bytecode = await sdk.getProvider().getCode(contractAddress);
const name = await drop.call("name");
expect(name).to.equal("Drop Proxy Old");
assert(bytecode.startsWith("0x363d3d373d3d3d363d73"));
});
});
// TODO: test any-evm vs standard chain deploys with same publish-uri
});
+1 -1
View File
@@ -177,7 +177,7 @@ describe("Tiered Drop Contract", async () => {
expect(nfts[0].metadata.name).to.equal("NFT #5");
});
test.skip("metadata should reveal correctly", async () => {
it("metadata should reveal correctly", async () => {
contract = await deployTieredDrop();
const placeholder = {
+65 -2
View File
@@ -1,4 +1,8 @@
import { resolveContractUriFromAddress } from "../../src/evm";
import {
FullPublishMetadata,
extractIPFSHashFromBytecode,
resolveContractUriFromAddress,
} from "../../src/evm";
import { defaultProvider } from "./before-setup";
import { mockUploadWithCID } from "./mock/MockStorage";
import { ContractInterface, ethers } from "ethers";
@@ -22,6 +26,8 @@ export const mockUploadContractMetadata = async (
contractName: string,
address: string,
abi: any,
extendedMetadata?: FullPublishMetadata | any,
publishUri?: string,
) => {
const ipfsHash = (await resolveContractUriFromAddress(
address,
@@ -57,11 +63,68 @@ export const mockUploadContractMetadata = async (
// mock raw-metadata
const rawMeta = {
...extendedMetadata,
name: contractName,
metadataUri: ipfsHash,
bytecodeUri: bytecodeUri,
};
const rawMetaUri = ipfsHash.concat("rawMeta");
const rawMetaUri = publishUri || ipfsHash.concat("rawMeta");
const rawMetaCID = rawMetaUri.replace("ipfs://", "");
await mockUploadWithCID(rawMetaCID, JSON.stringify(rawMeta));
return rawMetaUri;
};
export const mockUploadMetadataWithBytecode = async (
contractName: string,
abi: any,
bytecode: string,
deployedBytecode?: string,
extendedMetadata?: FullPublishMetadata | any,
publishUri?: string,
): Promise<string> => {
const ipfsHash =
deployedBytecode && deployedBytecode.length > 0
? (extractIPFSHashFromBytecode(deployedBytecode) as string)
: (extractIPFSHashFromBytecode(bytecode) as string);
const metadata = {
compiler: {},
output: {
abi,
devdoc: {},
userdoc: {},
},
settings: {
compilationTarget: {
contract: contractName,
},
evmVersion: {},
metadata: {},
optimizer: {},
remappings: [],
},
sources: {},
version: 1,
};
const metadataCID = ipfsHash.replace("ipfs://", "");
await mockUploadWithCID(metadataCID, JSON.stringify(metadata));
// mock bytecode
const bytecodeUri = ipfsHash.concat("bytecode");
const bytecodeCID = bytecodeUri.replace("ipfs://", "");
await mockUploadWithCID(bytecodeCID, bytecode);
// mock raw-metadata
const rawMeta = {
...extendedMetadata,
name: contractName,
metadataUri: ipfsHash,
bytecodeUri: bytecodeUri,
};
const rawMetaUri = publishUri || ipfsHash.concat("rawMeta");
const rawMetaCID = rawMetaUri.replace("ipfs://", "");
await mockUploadWithCID(rawMetaCID, JSON.stringify(rawMeta));
return rawMetaUri;
};
+16
View File
@@ -1,5 +1,21 @@
# @thirdweb-dev/storage
## 1.1.6
### Patch Changes
- [#1286](https://github.com/thirdweb-dev/js/pull/1286) [`2d088d36`](https://github.com/thirdweb-dev/js/commit/2d088d367ca54233836dc69712fd411ab7924205) Thanks [@jnsdls](https://github.com/jnsdls)! - fix double `//` case
- [#1278](https://github.com/thirdweb-dev/js/pull/1278) [`8a389f12`](https://github.com/thirdweb-dev/js/commit/8a389f1295d2bf726059997ea0ca10cf0424f2a2) Thanks [@jnsdls](https://github.com/jnsdls)! - updated various dependencies
- [#1232](https://github.com/thirdweb-dev/js/pull/1232) [`9daf0449`](https://github.com/thirdweb-dev/js/commit/9daf044926bf995ac8998929dbeca548c5eb8561) Thanks [@nessup](https://github.com/nessup)! - Switch over to the new `ipfs.thirdweb-storage.com` public gateway.
Better fallback logic for if a gateway is down.
Faster loading of files from the default gateway by skipping a roundtrip to redirect.
- [#1285](https://github.com/thirdweb-dev/js/pull/1285) [`546353a4`](https://github.com/thirdweb-dev/js/commit/546353a479c11533818ef917c0f6b4d6f8f69872) Thanks [@jnsdls](https://github.com/jnsdls)! - add additional fallback gateways
- [#1287](https://github.com/thirdweb-dev/js/pull/1287) [`0135a779`](https://github.com/thirdweb-dev/js/commit/0135a7790cf2acde6b701cb41ea10dd311da5ec3) Thanks [@jnsdls](https://github.com/jnsdls)! - fix uploaded-check
## 1.1.5
### Patch Changes
+15 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/storage",
"version": "1.1.5",
"version": "1.1.6",
"main": "dist/thirdweb-dev-storage.cjs.js",
"module": "dist/thirdweb-dev-storage.esm.js",
"browser": {
@@ -43,28 +43,29 @@
}
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@babel/preset-env": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@microsoft/api-documenter": "^7.22.21",
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/tsdoc": "^0.14.1",
"@preconstruct/cli": "^2.2.1",
"@swc-node/register": "^1.5.1",
"@preconstruct/cli": "^2.7.0",
"@swc-node/register": "^1.6.6",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/chai": "^4.3.3",
"@types/chai": "^4.3.5",
"@types/mocha": "^10.0.0",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"chai": "^4.3.6",
"eslint": "^8.42.0",
"eslint": "^8.43.0",
"eslint-config-thirdweb": "workspace:*",
"esm": "^3.2.25",
"mocha": "^10.2.0",
"typescript": "^4.7.4"
"typescript": "^5.1.6"
},
"dependencies": {
"cross-fetch": "^3.1.5",
"cid-tool": "^3.0.0",
"cross-fetch": "^3.1.6",
"form-data": "^4.0.0",
"ipfs-unixfs-importer": "^7.0.1",
"uuid": "^9.0.0"
+3 -2
View File
@@ -1,5 +1,5 @@
import { FileOrBufferOrString } from "../types";
import { DEFAULT_GATEWAY_URLS } from "./urls";
import { DEFAULT_GATEWAY_URLS, getGatewayUrlForCid } from "./urls";
import { isBufferOrStringWithName } from "./utils";
import fetch from "cross-fetch";
import { importer } from "ipfs-unixfs-importer";
@@ -67,7 +67,8 @@ export async function getCID(
}
export async function isUploaded(cid: string) {
const res = await fetch(`${DEFAULT_GATEWAY_URLS["ipfs://"][0]}${cid}`, {
const url = getGatewayUrlForCid(DEFAULT_GATEWAY_URLS["ipfs://"][0], cid);
const res = await fetch(url, {
method: "HEAD",
headers: {
// tell the gateway to skip fetching from origin in order to fail fast on 404s and just re-upload in those cases
+52 -9
View File
@@ -1,4 +1,5 @@
import { GatewayUrls } from "../types";
import CIDTool from "cid-tool";
/**
* @internal
@@ -6,13 +7,12 @@ import { GatewayUrls } from "../types";
export const DEFAULT_GATEWAY_URLS: GatewayUrls = {
// Note: Gateway URLs should have trailing slashes (we clean this on user input)
"ipfs://": [
"https://ipfs-3.thirdwebcdn.com/ipfs/",
"https://ipfs-4.thirdwebcdn.com/ipfs/",
"https://ipfs-5.thirdwebcdn.com/ipfs/",
"https://cloudflare-ipfs.com/ipfs/",
"https://ipfs.io/ipfs/",
// TODO this one can become the default again once it's stable (no more VT issues)
"https://ipfs.thirdwebcdn.com/ipfs/",
"https://{cid}.ipfs.thirdwebstorage.com/{path}",
"https://{cid}.ipfs.thirdwebipfs.com/{path}",
"https://{cid}.ipfs.thirdwebgateway.com/{path}",
"https://{cid}.ipfs-public.thirdwebcdn.com/{path}",
"https://cloudflare-ipfs.com/ipfs/{cid}/{path}",
"https://ipfs.io/ipfs/{cid}/{path}",
],
};
@@ -41,6 +41,33 @@ export function parseGatewayUrls(
return gatewayUrls || {};
}
/**
* @internal
*/
export function getGatewayUrlForCid(gatewayUrl: string, cid: string): string {
const parts = cid.split("/");
const hash = convertCidToV1(parts[0]);
const filePath = parts.slice(1).join("/");
let url = gatewayUrl;
// If the URL contains {cid} or {path} tokens, replace them with the CID and path
// Both tokens must be present for the URL to be valid
if (gatewayUrl.includes("{cid}") && gatewayUrl.includes("{path}")) {
url = url.replace("{cid}", hash).replace("{path}", filePath);
}
// If the URL contains only the {cid} token, replace it with the CID
else if (gatewayUrl.includes("{cid}")) {
url = url.replace("{cid}", hash);
}
// If those tokens don't exist, use the canonical gateway URL format
else {
url += `${hash}/${filePath}`;
}
return url;
}
/**
* @internal
*/
@@ -53,9 +80,11 @@ export function prepareGatewayUrls(gatewayUrls?: GatewayUrls): GatewayUrls {
for (const key of Object.keys(DEFAULT_GATEWAY_URLS)) {
if (gatewayUrls && gatewayUrls[key]) {
// Make sure that all user gateway URLs have trailing slashes
const cleanedGatewayUrls = gatewayUrls[key].map(
(url) => url.replace(/\/$/, "") + "/",
const cleanedGatewayUrls = gatewayUrls[key].map((url) =>
// don't add trailing slash if the URL contains {path} token
url.includes("{path}") ? url : url.replace(/\/$/, "") + "/",
);
allGatewayUrls[key] = [
...cleanedGatewayUrls,
...DEFAULT_GATEWAY_URLS[key],
@@ -65,3 +94,17 @@ export function prepareGatewayUrls(gatewayUrls?: GatewayUrls): GatewayUrls {
return allGatewayUrls;
}
/**
* @internal
*/
export function convertCidToV1(cid: string) {
let normalized: string;
try {
const hash = cid.split("/")[0];
normalized = CIDTool.base32(hash);
} catch (e) {
throw new Error(`The CID ${cid} is not valid.`);
}
return normalized;
}
+41 -4
View File
@@ -1,4 +1,5 @@
import { BufferOrStringWithName, FileOrBuffer, GatewayUrls } from "../types";
import { getGatewayUrlForCid } from "./urls";
/**
* @internal
@@ -85,6 +86,29 @@ export function isFileBufferOrStringEqual(input1: any, input2: any): boolean {
return false;
}
/**
* @internal
*/
function parseCidAndPath(
gatewayUrl: string,
uri: string,
): { hash?: string; path?: string; query?: string } | undefined {
const regexString = gatewayUrl
.replace("{cid}", "(?<hash>[^/]+)")
.replace("{path}", "(?<path>[^?#]+)");
const regex = new RegExp(regexString);
const match = uri.match(regex);
if (match) {
const hash = match.groups?.hash;
const path = match.groups?.path;
const queryString = uri.includes("?") ? uri.substring(uri.indexOf("?") + 1) : "";
return { hash, path, query: queryString };
}
}
/**
* @internal
*/
@@ -93,9 +117,21 @@ export function replaceGatewayUrlWithScheme(
gatewayUrls: GatewayUrls,
): string {
for (const scheme of Object.keys(gatewayUrls)) {
for (const url of gatewayUrls[scheme]) {
if (uri.startsWith(url)) {
return uri.replace(url, scheme);
for (const gatewayUrl of gatewayUrls[scheme]) {
// If the url is a tokenized url, we need to convert it to a canonical url
// Otherwise, we just need to check if the url is a prefix of the uri
if (gatewayUrl.includes("{cid}")) {
// Given the url is a tokenized url, we need to lift the cid and the path from the uri
const parsed = parseCidAndPath(gatewayUrl, uri);
if (parsed?.hash && parsed?.path) {
const queryString = parsed?.query ? `?${parsed?.query}` : "";
return `${scheme}${parsed?.hash}/${parsed?.path}${queryString}`;
} else {
// If we can't lift the cid and path from the uri, we can't replace the gateway url, return the orig string
return uri;
}
} else if (uri.startsWith(gatewayUrl)) {
return uri.replace(gatewayUrl, scheme);
}
}
}
@@ -122,7 +158,8 @@ export function replaceSchemeWithGatewayUrl(
return uri;
}
return uri.replace(scheme, schemeGatewayUrls[index]);
const path = uri.replace(scheme, "");
return getGatewayUrlForCid(schemeGatewayUrls[index], path);
}
/**
@@ -33,18 +33,39 @@ export class StorageDownloader implements IStorageDownloader {
throw new Error(
"[FAILED_TO_DOWNLOAD_ERROR] Unable to download from URI - all gateway URLs failed to respond.",
);
} else if (attempts > 0) {
console.warn(`Retrying download with backup gateway URL: ${resolvedUri}`);
}
const res = await fetch(resolvedUri);
const resOrErr = await fetch(resolvedUri).catch((err) => err);
if (resOrErr.ok) {
return resOrErr;
}
// can't use instanceof "Response" in node...
if ("status" in resOrErr) {
if (resOrErr.status === 410 || resOrErr.status === 403) {
// Don't retry if the content is blocklisted
console.error(
`Request to ${resolvedUri} failed because this content seems to be blocklisted. Search VirusTotal for this URL to confirm: ${resolvedUri} `,
);
return resOrErr;
}
// If request to the current gateway fails, recursively try the next one we know about
if (res.status >= 500 || res.status === 403 || res.status === 408) {
console.warn(
`Request to ${resolvedUri} failed with status ${res.status} - ${res.statusText}`,
`Request to ${resolvedUri} failed with status ${resOrErr.status} - ${resOrErr.statusText}`,
);
return this.download(uri, gatewayUrls, attempts + 1);
// Don't retry if we see 408 or < 500 status codes that are likely to be resolved by trying another gateway
if (resOrErr.status !== 408 && resOrErr.status < 500) {
return resOrErr;
}
} else {
console.warn(`Request to ${resolvedUri} failed with error`, resOrErr);
}
return res;
// Since the current gateway failed, recursively try the next one we know about
return this.download(uri, gatewayUrls, attempts + 1);
}
}

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