Compare commits

...
Author SHA1 Message Date
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
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
11bb053246 Version Packages (#1261)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-27 22:16:09 -07:00
efb3546ec8 [Wallets] Fix. Respect dev passed chains. (#1259)
Co-authored-by: Manan Tank <[email protected]>
2023-06-28 05:07:24 +00:00
90 changed files with 4676 additions and 3161 deletions
+21
View File
@@ -1,5 +1,26 @@
# @thirdweb-dev/auth # @thirdweb-dev/auth
## 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
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
- @thirdweb-dev/wallets@1.0.1
## 3.2.4 ## 3.2.4
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/auth", "name": "@thirdweb-dev/auth",
"version": "3.2.4", "version": "3.2.7",
"main": "dist/thirdweb-dev-auth.cjs.js", "main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js", "module": "dist/thirdweb-dev-auth.esm.js",
"browser": { "browser": {
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/chains # @thirdweb-dev/chains
## 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 ## 0.1.25
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -10,9 +10,9 @@ export default {
}, },
"rpc": [ "rpc": [
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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}", "https://mainnet.infura.io/v3/${INFURA_API_KEY}",
"wss://mainnet.infura.io/ws/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://api.mycryptoapi.com/eth",
"https://cloudflare-eth.com", "https://cloudflare-eth.com",
"https://ethereum.publicnode.com" "https://ethereum.publicnode.com"
+1 -1
View File
@@ -4,8 +4,8 @@ export default {
"chain": "ETH", "chain": "ETH",
"rpc": [ "rpc": [
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://mainnet.optimism.io/" "https://mainnet.optimism.io/"
], ],
"faucets": [], "faucets": [],
+1 -1
View File
@@ -10,8 +10,8 @@ export default {
}, },
"rpc": [ "rpc": [
"https://polygon.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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.infura.io/v3/${INFURA_API_KEY}",
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://polygon-rpc.com/", "https://polygon-rpc.com/",
"https://rpc-mainnet.matic.network", "https://rpc-mainnet.matic.network",
"https://matic-mainnet.chainstacklabs.com", "https://matic-mainnet.chainstacklabs.com",
+1 -1
View File
@@ -4,8 +4,8 @@ export default {
"chain": "ETH", "chain": "ETH",
"rpc": [ "rpc": [
"https://optimism-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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://optimism-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://goerli.optimism.io/" "https://goerli.optimism.io/"
], ],
"faucets": [ "faucets": [
+1 -1
View File
@@ -13,8 +13,8 @@ export default {
}, },
"rpc": [ "rpc": [
"https://arbitrum-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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://arbitrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://goerli-rollup.arbitrum.io/rpc/" "https://goerli-rollup.arbitrum.io/rpc/"
], ],
"faucets": [], "faucets": [],
+1 -1
View File
@@ -5,9 +5,9 @@ export default {
"chain": "ETH", "chain": "ETH",
"rpc": [ "rpc": [
"https://goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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}", "https://goerli.infura.io/v3/${INFURA_API_KEY}",
"wss://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://rpc.goerli.mudit.blog/",
"https://ethereum-goerli.publicnode.com" "https://ethereum-goerli.publicnode.com"
], ],
+3 -3
View File
@@ -5,10 +5,10 @@ export default {
"chain": "ETH", "chain": "ETH",
"rpc": [ "rpc": [
"https://linea-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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}", "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": [ "faucets": [
"https://faucetlink.to/goerli" "https://faucetlink.to/goerli"
+1 -1
View File
@@ -11,8 +11,8 @@ export default {
}, },
"rpc": [ "rpc": [
"https://mumbai.rpc.thirdweb.com/${THIRDWEB_API_KEY}", "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.infura.io/v3/${INFURA_API_KEY}",
"https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://matic-mumbai.chainstacklabs.com", "https://matic-mumbai.chainstacklabs.com",
"https://rpc-mumbai.maticvigil.com", "https://rpc-mumbai.maticvigil.com",
"https://matic-testnet-archive-rpc.bwarelabs.com", "https://matic-testnet-archive-rpc.bwarelabs.com",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/chains", "name": "@thirdweb-dev/chains",
"version": "0.1.25", "version": "0.1.26",
"main": "dist/thirdweb-dev-chains.cjs.js", "main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js", "module": "dist/thirdweb-dev-chains.esm.js",
"browser": { "browser": {
@@ -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 imports = [];
const exports = []; const exports = [];
const exportNames = []; const exportNames = [];
+30 -44
View File
@@ -28,59 +28,45 @@ export function getChainRPCs(
...options, ...options,
}; };
const modeChains = chain.rpc.filter((rpc) => { const processedRPCs: string[] = [];
if (rpc.startsWith("http") && mode === "http") {
return true; chain.rpc.forEach((rpc) => {
} // exclude RPC if mode mismatch
if (rpc.startsWith("ws") && mode === "ws") { if (mode === "http" && !rpc.startsWith("http")) {
return true; 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 if (processedRPCs.length === 0) {
.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) {
throw new Error( throw new Error(
`No RPC available for chainId "${chain.chainId}" with mode ${mode}`, `No RPC available for chainId "${chain.chainId}" with mode ${mode}`,
); );
} }
return orderedRPCs; return processedRPCs;
} }
/** /**
+10
View File
@@ -1,5 +1,15 @@
# thirdweb # thirdweb
## 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 ## 0.10.27
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
import { prepareEnvironment } from "@gmrchk/cli-testing-library"; import { prepareEnvironment } from "@gmrchk/cli-testing-library";
// this creates an app, can take some time that's fine // this creates an app, can take some time that's fine
jest.setTimeout(120_000); jest.setTimeout(240_000);
describe("npx thirdweb detect", () => { describe("npx thirdweb detect", () => {
it("should detect ERC721Base extensions", async () => { it("should detect ERC721Base extensions", async () => {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "thirdweb", "name": "thirdweb",
"main": "dist/cli/index.js", "main": "dist/cli/index.js",
"version": "0.10.27", "version": "0.10.28",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>", "author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -1,27 +1,28 @@
import inquirer from "inquirer";
import { info } from "../helpers/logger"; import { info } from "../helpers/logger";
import { FrameworkType, PackageManagerType } from "../types/ProjectType"; 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 { FrameworkDetector } from "./detector";
import TruffleDetector from "./frameworks/truffle";
import BrownieDetector from "./frameworks/brownie"; import BrownieDetector from "./frameworks/brownie";
import FastAPIDetector from "./frameworks/fastAPI"; import CRADetector from "./frameworks/cra";
import FlaskDetector from "./frameworks/flask"; import DjangoDetector from "./frameworks/django";
import PopulusDetector from "./frameworks/populus";
import FastifyDetector from "./frameworks/fastify";
import EchoDetector from "./frameworks/echo"; 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 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 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 RevelDetector from "./frameworks/revel";
import TruffleDetector from "./frameworks/truffle";
import ViteDetector from "./frameworks/vite";
import VueDetector from "./frameworks/vue";
import ZenjectDetector from "./frameworks/zenject"; import ZenjectDetector from "./frameworks/zenject";
export default async function detect( export default async function detect(
@@ -50,6 +51,7 @@ export default async function detect(
new RevelDetector(), new RevelDetector(),
new TruffleDetector(), new TruffleDetector(),
new VueDetector(), new VueDetector(),
new ViteDetector(),
new ZenjectDetector(), new ZenjectDetector(),
]; ];
@@ -1,13 +1,12 @@
import inquirer from "inquirer";
import { info } from "../helpers/logger"; import { info } from "../helpers/logger";
import { LibraryType, PackageManagerType } from "../types/ProjectType"; import { LibraryType, PackageManagerType } from "../types/ProjectType";
import { LibraryDetector } from "./detector"; import { LibraryDetector } from "./detector";
import inquirer from "inquirer";
import ReactDetector from "./libraries/react";
import ExpressDetector from "./libraries/express"; 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 PlayMakerDetector from "./libraries/playmaker";
import ReactDetector from "./libraries/react";
import ReactNativeDetector from "./libraries/reactNative";
import Web3PyDetector from "./libraries/web3py";
export default async function detect( export default async function detect(
path: string, path: string,
@@ -19,7 +18,6 @@ export default async function detect(
new ExpressDetector(), new ExpressDetector(),
new ReactDetector(), new ReactDetector(),
new ReactNativeDetector(), new ReactNativeDetector(),
new ViteDetector(),
new Web3PyDetector(), new Web3PyDetector(),
new PlayMakerDetector(), new PlayMakerDetector(),
]; ];
@@ -1,10 +1,10 @@
import { LibraryDetector } from "../detector";
import { existsSync, readFileSync } from "fs"; import { existsSync, readFileSync } from "fs";
import { LibraryType } from "../../types/ProjectType";
import { parsePackageJson } from "../../../lib/utils"; import { parsePackageJson } from "../../../lib/utils";
import { FrameworkType } from "../../types/ProjectType";
import { FrameworkDetector } from "../detector";
export default class ViteDetector implements LibraryDetector { export default class ViteDetector implements FrameworkDetector {
public libraryType: LibraryType = "vite"; public frameworkType: FrameworkType = "vite";
public matches(path: string): boolean { public matches(path: string): boolean {
const packageJsonPath = path + "/package.json"; const packageJsonPath = path + "/package.json";
@@ -16,7 +16,7 @@ export default class ViteDetector implements LibraryDetector {
const packageJson = readFileSync(packageJsonPath); const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson); const { dependencies, devDependencies } = parsePackageJson(packageJson);
const viteDependencyExists = const viteDependencyExists =
dependencies["vite"] || devDependencies["vite"] || false; !!dependencies["vite"] || !!devDependencies["vite"] || false;
return viteDependencyExists; return viteDependencyExists;
} }
@@ -56,6 +56,7 @@ export type FrameworkType =
| "revel" | "revel"
| "fiber" | "fiber"
| "zenject" | "zenject"
| "vite"
| "none"; | "none";
export type LibraryType = export type LibraryType =
| "react" | "react"
+46 -19
View File
@@ -1,30 +1,57 @@
import NPMDetector from "../core/detection/npm"; import { ThirdwebStorage } from "@thirdweb-dev/storage";
import ViteDetector from "../core/detection/vite"; import detectFramework from "../core/detection/detectFramework";
import YarnDetector from "../core/detection/yarn"; import detectPackageManager from "../core/detection/detectPackageManager";
import { logger } from "../core/helpers/logger";
import { runCommand } from "../create/helpers/run-command"; import { runCommand } from "../create/helpers/run-command";
import { upload } from "../storage/command"; import { upload } from "../storage/command";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
export async function deployApp(distPath = "dist", projectPath = ".") { export async function deployApp(distPath = "dist", projectPath = ".") {
const storage = new ThirdwebStorage(); const storage = new ThirdwebStorage();
const supportedFrameworks = [new ViteDetector()]; const detectedPackageManager = await detectPackageManager(projectPath, {});
const detectedFramework = await detectFramework(projectPath, {}, detectedPackageManager);
const possibleProjects = supportedFrameworks if (detectedFramework === "none") {
.filter((detector) => detector.matches(projectPath))
.map((detector) => detector.projectType);
const hasYarn = new YarnDetector().matches(".");
const hasNPM = new NPMDetector().matches(".");
if (possibleProjects.length === 0) {
throw new Error("No supported project detected"); 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 { try {
if (hasYarn) { switch (detectedPackageManager) {
await runCommand("yarn", ["build"]); case "yarn":
} else if (hasNPM) { await runCommand("yarn", ["build"], true);
await runCommand("npm", ["build"]); if (detectedFramework === "next") {
await runCommand("yarn", ["export"], true);
}
break;
case "npm":
await runCommand("npm", ["run", "build"], true);
if (detectedFramework === "next") {
await runCommand("npm", ["run", "export"], true);
}
break;
case "pnpm":
await runCommand("pnpm", ["build"], true);
if (detectedFramework === "next") {
await runCommand("pnpm", ["export"], true);
}
break;
default:
throw new Error("No supported package manager detected");
} }
} catch (err) { } catch (err) {
console.error("Can't build project"); console.error("Can't build project");
@@ -33,9 +60,9 @@ export async function deployApp(distPath = "dist", projectPath = ".") {
try { try {
const uri = await upload(storage, distPath); 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) { } catch (err) {
console.error("Can't upload project"); console.error("Can't upload project", err);
return Promise.reject("Can't upload project"); 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 { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { spinner } from "../core/helpers/logger";
function recurseFiles( function recurseFiles(
uploadPath: string, uploadPath: string,
+27
View File
@@ -1,5 +1,32 @@
# @thirdweb-dev/react-core # @thirdweb-dev/react-core
## 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
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
- @thirdweb-dev/wallets@1.0.1
## 3.14.4 ## 3.14.4
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/react-core", "name": "@thirdweb-dev/react-core",
"version": "3.14.4", "version": "3.14.7",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>", "author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -61,6 +61,15 @@ export interface ThirdwebProviderCoreProps<TChains extends Chain[]>
* Whether or not to automatically switch to wallet's network to active chain * Whether or not to automatically switch to wallet's network to active chain
*/ */
autoSwitch?: boolean; 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[]>({ export const ThirdwebProviderCore = <TChains extends Chain[]>({
@@ -145,6 +154,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
dAppMeta={dAppMeta} dAppMeta={dAppMeta}
activeChain={activeChainWithKey} activeChain={activeChainWithKey}
autoSwitch={props.autoSwitch} autoSwitch={props.autoSwitch}
autoConnectTimeout={props.autoConnectTimeout}
> >
<ThirdwebSDKProviderWrapper <ThirdwebSDKProviderWrapper
queryClient={props.queryClient} queryClient={props.queryClient}
@@ -101,12 +101,15 @@ export function ThirdwebWalletProvider(
dAppMeta?: DAppMetaData; dAppMeta?: DAppMetaData;
chains: Chain[]; chains: Chain[];
autoSwitch?: boolean; autoSwitch?: boolean;
autoConnectTimeout?: number;
}>, }>,
) { ) {
const [signer, setSigner] = useState<Signer | undefined>(undefined); const [signer, setSigner] = useState<Signer | undefined>(undefined);
const [connectionStatus, setConnectionStatus] = const [connectionStatus, setConnectionStatus] =
useState<ConnectionStatus>("unknown"); useState<ConnectionStatus>("unknown");
const autoConnectTimeout = props.autoConnectTimeout || 15000;
const [activeWallet, setActiveWallet] = useState< const [activeWallet, setActiveWallet] = useState<
WalletInstance | undefined WalletInstance | undefined
>(); >();
@@ -311,8 +314,14 @@ export function ThirdwebWalletProvider(
const personalWalletInstance = createWalletInstance(personalWalleObj); const personalWalletInstance = createWalletInstance(personalWalleObj);
try { try {
await personalWalletInstance.autoConnect( await timeoutPromise(
personalWalletInfo.connectParams, personalWalletInstance.autoConnect(
personalWalletInfo.connectParams,
),
{
ms: autoConnectTimeout,
message: "Failed to Auto connect. Auto connect timed out.",
},
); );
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@@ -337,7 +346,10 @@ export function ThirdwebWalletProvider(
try { try {
setConnectionStatus("connecting"); 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); setConnectedWallet(wallet, walletInfo.connectParams, true);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@@ -356,6 +368,7 @@ export function ThirdwebWalletProvider(
props.shouldAutoConnect, props.shouldAutoConnect,
activeWallet, activeWallet,
connectionStatus, connectionStatus,
autoConnectTimeout,
]); ]);
const connectWallet = useCallback( const connectWallet = useCallback(
@@ -496,3 +509,32 @@ async function saveLastConnectedWalletInfo(
console.error("Error saving the last connected wallet info", e); 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 * @example
* ```javascript * ```javascript
* const { data: smartWallets, isLoading, error } = useSmartWalletSigners(contract); * const { data: accounts, isLoading, error } = useAccountSigners(contract);
* ``` * ```
* *
* @param contract - an instance of a smart wallet * @param contract - an instance of a account
* @returns a response object that includes an array of all signers of the provided smart wallet * @returns a response object that includes an array of all signers of the provided account
* @twfeature SmartWallet * @twfeature Account
* @see {@link https://portal.thirdweb.com/react/react.usesmartwalletsigners?utm_source=sdk | Documentation} * @see {@link https://portal.thirdweb.com/react/react.useaccountsigners?utm_source=sdk | Documentation}
* @beta * @beta
*/ */
export function useSmartWalletSigners( export function useAccountSigners(
contract: RequiredParam<SmartContract>, contract: RequiredParam<SmartContract>,
): UseQueryResult<SignerWithRestrictions[]> { ): UseQueryResult<SignerWithRestrictions[]> {
const contractAddress = contract?.getAddress(); const contractAddress = contract?.getAddress();
return useQueryWithNetwork( return useQueryWithNetwork(
cacheKeys.contract.smartWallet.signers(contractAddress), cacheKeys.contract.account.signers(contractAddress),
() => { () => {
requiredParamInvariant(contract, "No Contract instance provided"); requiredParamInvariant(contract, "No Contract instance provided");
invariant( invariant(
contract.smartWallet.getSignersWithRestrictions, contract.account.getSignersWithRestrictions,
"Contract instance does not support contract.smartWallet.getSignersWithRestrictions", "Contract instance does not support contract.account.getSignersWithRestrictions",
); );
return contract.smartWallet.getSignersWithRestrictions(); return contract.account.getSignersWithRestrictions();
}, },
{ enabled: !!contract }, { enabled: !!contract },
); );
@@ -62,40 +62,40 @@ export function useSmartWalletSigners(
/** WRITE HOOKS **/ /** WRITE HOOKS **/
/** **********************/ /** **********************/
/** /**
* Set the wallet's entire snapshot of permissions * Set the account's entire snapshot of permissions
* *
* @example * @example
* ```jsx * ```jsx
* const Component = () => { * const Component = () => {
* const { contract } = useContract("{{contract_address}}"); * const { contract } = useContract("{{contract_address}}");
* const { * const {
* mutate: setSmartWalletSigners, * mutate: setAccountSigners,
* isLoading, * isLoading,
* error, * error,
* } = useSetSmartWalletSigners(contract); * } = useSetAccountSigners(contract);
* *
* if (error) { * if (error) {
* console.error("failed to set smart wallet signers", error); * console.error("failed to set account signers", error);
* } * }
* *
* return ( * return (
* <button * <button
* disabled={isLoading} * disabled={isLoading}
* onClick={() => setSmartWalletSigners("0x...")} * onClick={() => setAccountSigners("0x...")}
* > * >
* Set Smart Wallet Signers * Set Account Signers
* </button> * </button>
* ); * );
* }; * };
* ``` * ```
* *
* @param contract - an instance of a smart wallet contract * @param contract - an instance of a account contract
* @returns a mutation object that can be used to set the smart wallet signers * @returns a mutation object that can be used to set the account signers
* @twfeature SmartWallet * @twfeature Account
* @see {@link https://portal.thirdweb.com/react/react.usesetsmartwalletsigners?utm_source=sdk | Documentation} * @see {@link https://portal.thirdweb.com/react/react.usesetaccountsigners?utm_source=sdk | Documentation}
* @beta * @beta
*/ */
export function useSetSmartWalletSigners( export function useSetAccountSigners(
contract: RequiredParam<SmartContract>, contract: RequiredParam<SmartContract>,
): UseMutationResult< ): UseMutationResult<
{ receipt: providers.TransactionReceipt }, { receipt: providers.TransactionReceipt },
@@ -111,7 +111,7 @@ export function useSetSmartWalletSigners(
async (permissionsSnapshot: SignerWithRestrictionsBatchInput) => { async (permissionsSnapshot: SignerWithRestrictionsBatchInput) => {
requiredParamInvariant(contract, "contract is undefined"); requiredParamInvariant(contract, "contract is undefined");
return contract.smartWallet.setAccess(permissionsSnapshot); return contract.account.setAccess(permissionsSnapshot);
}, },
{ {
onSettled: () => 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, useBurnToken,
} from "./hooks/async/token"; } from "./hooks/async/token";
// smart wallet factory // account factory
export { export {
useIsSmartWalletDeployed, useIsAccountDeployed,
useSmartWallets, useAccounts,
useCreateSmartWallet, useCreateAccount,
useSmartWalletsForAddress, useAccountsForAddress,
} from "./hooks/async/smart-wallet-factory"; } from "./hooks/async/account-factory";
// smart wallet // account
export { export { useAccountSigners, useSetAccountSigners } from "./hooks/async/account";
useSmartWalletSigners,
useSetSmartWalletSigners,
} from "./hooks/async/smart-wallet";
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used) // thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
+14 -13
View File
@@ -118,18 +118,23 @@ export const cacheKeys = {
overrides, overrides,
]), ]),
smartWalletFactory: { accountFactory: {
getAll: (contractAddress: RequiredParam<ContractAddress>) => getAll: (contractAddress: RequiredParam<ContractAddress>) =>
createContractCacheKey(contractAddress, ["smartWalletFactory"]), createContractCacheKey(contractAddress, ["accountFactory"]),
isSmartWalletDeployed: (contractAdress: RequiredParam<ContractAddress>, admin: RequiredParam<string>) => isAccountDeployed: (
createContractCacheKey(contractAdress, ["isSmartWalletDeployed", admin]), contractAdress: RequiredParam<ContractAddress>,
getAllForAddress: (contractAdress: RequiredParam<ContractAddress>, address: RequiredParam<string>) => admin: RequiredParam<string>,
) => createContractCacheKey(contractAdress, ["isAccountDeployed", admin]),
getAllForAddress: (
contractAdress: RequiredParam<ContractAddress>,
address: RequiredParam<string>,
) =>
createContractCacheKey(contractAdress, ["getAllForAddress", address]), createContractCacheKey(contractAdress, ["getAllForAddress", address]),
}, },
smartWallet: { account: {
signers: (contractAddress: RequiredParam<ContractAddress>) => signers: (contractAddress: RequiredParam<ContractAddress>) =>
createContractCacheKey(contractAddress, ["smartWallet", "signers"]), createContractCacheKey(contractAddress, ["account", "signers"]),
}, },
app: { app: {
@@ -198,12 +203,8 @@ export const cacheKeys = {
}, },
}, },
sharedMetadata: { sharedMetadata: {
get: ( get: (contractAddress: RequiredParam<ContractAddress>) =>
contractAddress: RequiredParam<ContractAddress>, createContractCacheKey(contractAddress),
) =>
createContractCacheKey(
contractAddress
),
}, },
drop: { drop: {
getAllUnclaimed: ( getAllUnclaimed: (
@@ -1,5 +1,11 @@
# @thirdweb-dev/react-native-compat # @thirdweb-dev/react-native-compat
## 0.2.26
## 0.2.25
## 0.2.24
## 0.2.23 ## 0.2.23
## 0.2.22 ## 0.2.22
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "@thirdweb-dev/react-native-compat", "name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects", "description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.23", "version": "0.2.26",
"author": "thirdweb eng <[email protected]>", "author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0", "license": "Apache-2.0",
+30
View File
@@ -1,5 +1,35 @@
# @thirdweb-dev/react-native # @thirdweb-dev/react-native
## 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
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
- @thirdweb-dev/wallets@1.0.1
- @thirdweb-dev/react-core@3.14.5
## 0.2.23 ## 0.2.23
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/react-native", "name": "@thirdweb-dev/react-native",
"version": "0.2.23", "version": "0.2.26",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>", "author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -65,7 +65,9 @@ export const ThirdwebProvider = <
theme, theme,
...restProps ...restProps
}: PropsWithChildren<ThirdwebProviderProps<TChains>>) => { }: PropsWithChildren<ThirdwebProviderProps<TChains>>) => {
useCoinbaseWalletListener(); useCoinbaseWalletListener(
!!supportedWallets.find((w) => w.id === walletIds.coinbase),
);
const hasMagicConfig = useMemo( const hasMagicConfig = useMemo(
() => !!supportedWallets.find((wc) => wc.id === walletIds.magicLink), () => !!supportedWallets.find((wc) => wc.id === walletIds.magicLink),
@@ -17,8 +17,7 @@ import {
WagmiConnector, WagmiConnector,
} from "@thirdweb-dev/wallets"; } from "@thirdweb-dev/wallets";
import type { Address } from "abitype"; import type { Address } from "abitype";
import { providers } from "ethers"; import { providers, utils } from "ethers";
import { getAddress, hexValue } from "ethers/lib/utils.js";
export type CoinbaseWalletConnectorOptions = WalletMobileSDKProviderOptions & export type CoinbaseWalletConnectorOptions = WalletMobileSDKProviderOptions &
ConfigurationParams & { ConfigurationParams & {
@@ -130,7 +129,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
throw new Error("No accounts found"); throw new Error("No accounts found");
} }
// return checksum address // return checksum address
return getAddress(accounts[0] as string); return utils.getAddress(accounts[0] as string);
} }
async getChainId() { async getChainId() {
@@ -193,7 +192,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
async switchChain(chainId: number): Promise<Chain> { async switchChain(chainId: number): Promise<Chain> {
const provider = await this.getProvider(); const provider = await this.getProvider();
const id = hexValue(chainId); const id = utils.hexValue(chainId);
try { try {
await provider.request({ await provider.request({
@@ -279,7 +278,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
if (accounts.length === 0) { if (accounts.length === 0) {
this.emit("disconnect"); this.emit("disconnect");
} else { } 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) { export function useCoinbaseWallet(callbackURL: string) {
const connect = useConnect(); const connect = useConnect();
useCoinbaseWalletListener(); useCoinbaseWalletListener(true);
return useCallback( return useCallback(
async (connectOptions?: { chainId?: number; callbackURL: string }) => { async (connectOptions?: { chainId?: number; callbackURL: string }) => {
@@ -7,12 +7,16 @@ import { Linking } from "react-native";
* *
* This hook sets up the UniversalLinks listener. * This hook sets up the UniversalLinks listener.
*/ */
export function useCoinbaseWalletListener() { export function useCoinbaseWalletListener(enable: boolean) {
useEffect(() => { useEffect(() => {
if (!enable) {
return;
}
const sub = Linking.addEventListener("url", ({ url }) => { const sub = Linking.addEventListener("url", ({ url }) => {
// @ts-ignore - Passing a URL object to handleResponse crashes the function // @ts-ignore - Passing a URL object to handleResponse crashes the function
handleResponse(url); handleResponse(url);
}); });
return () => sub?.remove(); return () => sub?.remove();
}, []); }, [enable]);
} }
+32
View File
@@ -1,5 +1,37 @@
# @thirdweb-dev/react # @thirdweb-dev/react
## 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
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
- @thirdweb-dev/wallets@1.0.1
- @thirdweb-dev/react-core@3.14.5
## 3.14.4 ## 3.14.4
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/react", "name": "@thirdweb-dev/react",
"version": "3.14.4", "version": "3.14.7",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>", "author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -1,5 +1,9 @@
import { useConnect, useWallet } from "@thirdweb-dev/react-core"; 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 { useCallback, useEffect } from "react";
import { import {
useQuery, useQuery,
@@ -7,10 +11,12 @@ import {
useQueryClient, useQueryClient,
} from "@tanstack/react-query"; } from "@tanstack/react-query";
type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
export function usePaperWallet() { export function usePaperWallet() {
const connect = useConnect(); const connect = useConnect();
return useCallback( return useCallback(
async (options: { chainId?: number; clientId: string; email?: string }) => { async (options: { chainId?: number; email?: string } & PaperConfig) => {
const { paperWallet } = await import( const { paperWallet } = await import(
"../../../wallet/wallets/paperWallet" "../../../wallet/wallets/paperWallet"
); );
@@ -3,22 +3,22 @@ import { assertWindowEthereum } from "@thirdweb-dev/wallets";
export function useInstalledWallets() { export function useInstalledWallets() {
let isMetamaskInstalled = false; let isMetamaskInstalled = false;
let isCoinbaseWalletInstalled = false; let isCoinbaseWalletInstalled = false;
let isTrustWalletInstalled: boolean | undefined = false; let isZerionWalletInstalled = false;
let isTrustWalletInstalled = false;
if (assertWindowEthereum(globalThis.window)) { if (assertWindowEthereum(globalThis.window)) {
isMetamaskInstalled = globalThis.window.ethereum?.isMetaMask; isMetamaskInstalled = !!globalThis.window.ethereum?.isMetaMask;
isCoinbaseWalletInstalled = isCoinbaseWalletInstalled =
globalThis.window.ethereum?.isCoinbaseWallet || !!globalThis.window.ethereum?.isCoinbaseWallet ||
globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet) || !!globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet);
false; isZerionWalletInstalled = !!globalThis.window.ethereum?.isZerion;
isTrustWalletInstalled = globalThis.window.ethereum?.isTrust; isTrustWalletInstalled = !!globalThis.window.ethereum?.isTrust;
} }
const installedWallets = { return {
metamask: !!isMetamaskInstalled, metamask: isMetamaskInstalled,
coinbaseWallet: !!isCoinbaseWalletInstalled, coinbaseWallet: isCoinbaseWalletInstalled,
trustWallet: !!isTrustWalletInstalled, trustWallet: isTrustWalletInstalled,
zerionWallet: isZerionWalletInstalled,
}; };
return installedWallets;
} }
@@ -79,7 +79,7 @@ const MagicSelectionUI: React.FC<
if (isEmail && isEmailEnabled) { if (isEmail && isEmailEnabled) {
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g; 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) { if (!isValidEmail) {
return "Invalid email address"; return "Invalid email address";
} }
@@ -1,4 +1,7 @@
import { PaperWallet } from "@thirdweb-dev/wallets"; import {
PaperWallet,
PaperWalletAdditionalOptions,
} from "@thirdweb-dev/wallets";
import { import {
WalletConfig, WalletConfig,
WalletOptions, WalletOptions,
@@ -11,7 +14,7 @@ import { Spinner } from "../../components/Spinner";
import { Flex } from "../../components/basic"; import { Flex } from "../../components/basic";
import { InputSelectionUI } from "./InputSelectionUI"; import { InputSelectionUI } from "./InputSelectionUI";
type PaperConfig = { clientId: string }; type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
export const paperWallet = (config: PaperConfig): WalletConfig<PaperWallet> => { export const paperWallet = (config: PaperConfig): WalletConfig<PaperWallet> => {
return { return {
@@ -32,7 +35,8 @@ const PaperSelectionUI: React.FC<SelectUIProps<PaperWallet>> = (props) => {
placeholder="Enter your email address" placeholder="Enter your email address"
name="email" name="email"
type="email" type="email"
errorMessage={(input) => { errorMessage={(_input) => {
const input = _input.replace(/\+/g, "");
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g; const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
const isValidEmail = emailRegex.test(input); const isValidEmail = emailRegex.test(input);
if (!isValidEmail) { if (!isValidEmail) {
+11
View File
@@ -1,5 +1,16 @@
# @thirdweb-dev/sdk # @thirdweb-dev/sdk
## 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 ## 3.10.26
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/sdk", "name": "@thirdweb-dev/sdk",
"version": "3.10.26", "version": "3.10.27",
"description": "The main thirdweb SDK.", "description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -1,5 +1,4 @@
import { BigNumber, providers, constants } from "ethers"; import { BigNumber, providers, constants, utils } from "ethers";
import { isAddress } from "ethers/lib/utils";
import { extractIPFSHashFromBytecode } from "./extractIPFSHashFromBytecode"; import { extractIPFSHashFromBytecode } from "./extractIPFSHashFromBytecode";
import { extractMinimalProxyImplementationAddress } from "./extractMinimalProxyImplementationAddress"; import { extractMinimalProxyImplementationAddress } from "./extractMinimalProxyImplementationAddress";
@@ -49,7 +48,7 @@ export async function resolveContractUriFromAddress(
); );
const implementationAddress = `0x${proxyStorage.slice(-40)}`; const implementationAddress = `0x${proxyStorage.slice(-40)}`;
if ( if (
isAddress(implementationAddress) && utils.isAddress(implementationAddress) &&
implementationAddress !== constants.AddressZero implementationAddress !== constants.AddressZero
) { ) {
return await resolveContractUriFromAddress( return await resolveContractUriFromAddress(
@@ -62,8 +62,8 @@ import {
FEATURE_ENGLISH_AUCTIONS, FEATURE_ENGLISH_AUCTIONS,
FEATURE_OFFERS, FEATURE_OFFERS,
FEATURE_EXTENSION_ROUTER, FEATURE_EXTENSION_ROUTER,
FEATURE_SMART_WALLET, FEATURE_ACCOUNT,
FEATURE_SMART_WALLET_FACTORY, FEATURE_ACCOUNT_FACTORY,
} from "./thirdweb-features"; } from "./thirdweb-features";
/** /**
@@ -127,8 +127,8 @@ export type Feature =
| typeof FEATURE_DIRECT_LISTINGS | typeof FEATURE_DIRECT_LISTINGS
| typeof FEATURE_ENGLISH_AUCTIONS | typeof FEATURE_ENGLISH_AUCTIONS
| typeof FEATURE_OFFERS | typeof FEATURE_OFFERS
| typeof FEATURE_SMART_WALLET | typeof FEATURE_ACCOUNT
| typeof FEATURE_SMART_WALLET_FACTORY; | typeof FEATURE_ACCOUNT_FACTORY;
export type Extension = Feature; export type Extension = Feature;
@@ -170,6 +170,6 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = /* @__PURE__ */ {
[FEATURE_DIRECT_LISTINGS.name]: FEATURE_DIRECT_LISTINGS, [FEATURE_DIRECT_LISTINGS.name]: FEATURE_DIRECT_LISTINGS,
[FEATURE_ENGLISH_AUCTIONS.name]: FEATURE_ENGLISH_AUCTIONS, [FEATURE_ENGLISH_AUCTIONS.name]: FEATURE_ENGLISH_AUCTIONS,
[FEATURE_OFFERS.name]: FEATURE_OFFERS, [FEATURE_OFFERS.name]: FEATURE_OFFERS,
[FEATURE_SMART_WALLET_FACTORY.name]: FEATURE_SMART_WALLET_FACTORY, [FEATURE_ACCOUNT_FACTORY.name]: FEATURE_ACCOUNT_FACTORY,
[FEATURE_SMART_WALLET.name]: FEATURE_SMART_WALLET, [FEATURE_ACCOUNT.name]: FEATURE_ACCOUNT,
}; };
@@ -279,24 +279,24 @@ export const FEATURE_OFFERS = {
features: {}, features: {},
} as const; } as const;
export const FEATURE_SMART_WALLET_FACTORY = { export const FEATURE_ACCOUNT_FACTORY = {
name: "SmartWalletFactory", name: "AccountFactory",
namespace: "smartwallet.factory", namespace: "accountFactory",
docLinks: { docLinks: {
// TODO // TODO
sdk: "sdk.smartWalletFactory", sdk: "sdk.accountFactory",
contracts: "smartWalletFactory", contracts: "",
}, },
abis: [IAccountFactory], abis: [IAccountFactory],
features: {}, features: {},
} as const; } as const;
export const FEATURE_SMART_WALLET = { export const FEATURE_ACCOUNT = {
name: "SmartWallet", name: "Account",
namespace: "smartwallet", namespace: "account",
docLinks: { docLinks: {
// TODO // TODO
sdk: "", sdk: "sdk.account",
contracts: "", contracts: "",
}, },
abis: [IAccountCore], abis: [IAccountCore],
@@ -14,8 +14,8 @@ import {
FEATURE_PLATFORM_FEE, FEATURE_PLATFORM_FEE,
FEATURE_PRIMARY_SALE, FEATURE_PRIMARY_SALE,
FEATURE_ROYALTY, FEATURE_ROYALTY,
FEATURE_SMART_WALLET_FACTORY, FEATURE_ACCOUNT_FACTORY,
FEATURE_SMART_WALLET, FEATURE_ACCOUNT,
} from "../constants/thirdweb-features"; } from "../constants/thirdweb-features";
import { Transaction } from "../core/classes/transactions"; import { Transaction } from "../core/classes/transactions";
import { ContractAppURI } from "../core/classes/contract-appuri"; import { ContractAppURI } from "../core/classes/contract-appuri";
@@ -54,7 +54,7 @@ import type {
EnglishAuctionsLogic, EnglishAuctionsLogic,
OffersLogic, OffersLogic,
IAccountFactory, IAccountFactory,
IAccountCore IAccountCore,
} from "@thirdweb-dev/contracts-js"; } from "@thirdweb-dev/contracts-js";
import { ThirdwebStorage } from "@thirdweb-dev/storage"; import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BaseContract, CallOverrides } from "ethers"; 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 { MarketplaceV3DirectListings } from "../core/classes/marketplacev3-direct-listings";
import { MarketplaceV3EnglishAuctions } from "../core/classes/marketplacev3-english-auction"; import { MarketplaceV3EnglishAuctions } from "../core/classes/marketplacev3-english-auction";
import { MarketplaceV3Offers } from "../core/classes/marketplacev3-offers"; import { MarketplaceV3Offers } from "../core/classes/marketplacev3-offers";
import { SmartWalletFactory } from "../core/classes/smart-wallet-factory"; import { AccountFactory } from "../core/classes/account-factory";
import { SmartWallet } from "../core/classes/smart-wallet"; import { Account } from "../core/classes/account";
/** /**
* Custom contract dynamic class with feature detection * 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 * @example
* ```javascript * ```javascript
* *
* // Predict the address of the smart wallet that will be created for an admin. * // Predict the address of the account that will be created for an admin.
* const deterministicAddress = await contract.smartWalletFactory.predictWalletAddress(admin, extraData); * const deterministicAddress = await contract.accountFactory.predictAccountAddress(admin, extraData);
* *
* // Create smart wallets * // Create accounts
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData); * const tx = await contract.accountFactory.createAccount(admin, extraData);
* // the same as `deterministicAddress` * // the same as `deterministicAddress`
* const smartWalletAddress = tx.address; * const accountAddress = tx.address;
* *
* // Get all smart wallets created by the factory * // Get all accounts created by the factory
* const allWallets = await contract.smartWalletFactory.getAllWallets(); * const allAccounts = await contract.accountFactory.getAllAccounts();
* *
* // Get all smart wallets on which a signer has been given authority. * // Get all accounts on which a signer has been given authority.
* const associatedWallets = await contract.smartWalletFactory.getAssociatedWallets(signer); * const associatedAccounts = await contract.accountFactory.getAssociatedAccounts(signer);
* *
* // Get all signers who have been given authority on a smart wallet. * // Get all signers who have been given authority on a account.
* const associatedSigners = await contract.smartWalletFactory.getAssociatedSigners(smartWalletAddress); * const associatedSigners = await contract.accountFactory.getAssociatedSigners(accountAddress);
* *
* // Check whether a smart wallet has already been created for a given admin. * // Check whether a account has already been created for a given admin.
* const isWalletDeployed = await contract.smartWalletFactory.isWalletDeployed(admin, extraData); * const isAccountDeployed = await contract.accountFactory.isAccountDeployed(admin, extraData);
* ``` * ```
*/ */
get smartWalletFactory(): SmartWalletFactory<IAccountFactory> { get accountFactory(): AccountFactory<IAccountFactory> {
return assertEnabled( return assertEnabled(this.detectAccountFactory(), FEATURE_ACCOUNT_FACTORY);
this.detectSmartWalletFactory(),
FEATURE_SMART_WALLET_FACTORY,
);
} }
// TODO documentation // TODO documentation
get smartWallet(): SmartWallet<IAccountCore> { get account(): Account<IAccountCore> {
return assertEnabled( return assertEnabled(this.detectAccount(), FEATURE_ACCOUNT);
this.detectSmartWallet(),
FEATURE_SMART_WALLET,
)
} }
private _chainId: number; private _chainId: number;
@@ -568,25 +562,28 @@ export class SmartContract<
return undefined; return undefined;
} }
// ========== Smart account features ========== // ========== Account features ==========
private detectSmartWalletFactory() { private detectAccountFactory() {
if ( if (
detectContractFeature<IAccountFactory>( detectContractFeature<IAccountFactory>(
this.contractWrapper, this.contractWrapper,
FEATURE_SMART_WALLET_FACTORY.name, FEATURE_ACCOUNT_FACTORY.name,
) )
) { ) {
return new SmartWalletFactory(this.contractWrapper); return new AccountFactory(this.contractWrapper);
} }
return undefined; return undefined;
} }
private detectSmartWallet() { private detectAccount() {
if ( 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; return undefined;
} }
@@ -1,6 +1,6 @@
import type { IAccountFactory } from "@thirdweb-dev/contracts-js"; import type { IAccountFactory } from "@thirdweb-dev/contracts-js";
import { DetectableFeature } from "../interfaces/DetectableFeature"; 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 { ContractEvents } from "./contract-events";
import { ContractWrapper } from "./contract-wrapper"; import { ContractWrapper } from "./contract-wrapper";
@@ -9,13 +9,13 @@ import { Transaction } from "./transactions";
import { TransactionResultWithAddress } from "../types"; import { TransactionResultWithAddress } from "../types";
import { type BytesLike, utils } from "ethers"; import { type BytesLike, utils } from "ethers";
import { AccountCreatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/AccountFactory"; 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"; import { isContractDeployed } from "../../common/any-evm-utils/isContractDeployed";
export class SmartWalletFactory<TContract extends IAccountFactory> export class AccountFactory<TContract extends IAccountFactory>
implements DetectableFeature implements DetectableFeature
{ {
featureName = FEATURE_SMART_WALLET_FACTORY.name; featureName = FEATURE_ACCOUNT_FACTORY.name;
private contractWrapper: ContractWrapper<IAccountFactory>; private contractWrapper: ContractWrapper<IAccountFactory>;
// utilities // 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 * @example
* ```javascript * ```javascript
* const walletAddress = await contract.smartWalletFactory.predictWalletAddress(admin); * const accountAddress = await contract.accountFactory.predictAccountAddress(admin);
* ``` * ```
* @param admin - The admin of the smart wallet. * @param admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation. * @param extraData - (Optional) Extra data to be passed to the account on creation.
* @returns the deterministic address of the smart wallet that will be created for the given admin. * @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, admin: string,
extraData?: BytesLike, extraData?: BytesLike,
): Promise<string> { ): 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 * @example
* ```javascript * ```javascript
* const allSigners = await contract.smartWalletFactory.getAssociatedSigners(admin); * const allSigners = await contract.accountFactory.getAssociatedSigners(admin);
* ``` * ```
* @param wallet - The smart wallet address. * @param account - The account address.
* @returns all signers who have authority on the given smart wallet. * @returns all signers who have authority on the given account.
* *
* @twfeature SmartWalletFactory * @twfeature AccountFactory
*/ */
public async getAssociatedSigners(wallet: string): Promise<string[]> { public async getAssociatedSigners(account: string): Promise<string[]> {
return this.contractWrapper.readContract.getSignersOfAccount(wallet); 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 * @example
* ```javascript * ```javascript
* const allWallets = await contract.smartWalletFactory.getAssociatedWallets(admin); * const allAccounts = await contract.accountFactory.getAssociatedAccounts(admin);
* ``` * ```
* @param signer - The smart wallet address. * @param signer - The account address.
* @returns all wallets on which the given signer has authority. * @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); return this.contractWrapper.readContract.getAccountsOfSigner(signer);
} }
/** /**
* Get all wallets * Get all accounts
* *
* @example * @example
* ```javascript * ```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[]> { public async getAllAccounts(): Promise<AccountEvent[]> {
const allAccounts = 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 admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation. * @param extraData - (Optional) Extra data to be passed to the account on creation.
* @returns whether the smart wallet has been deployed for the given admin. * @returns whether the account has been deployed for the given admin.
*/ */
public async isWalletDeployed( public async isAccountDeployed(
admin: string, admin: string,
extraData?: BytesLike, extraData?: BytesLike,
): Promise<boolean> { ): Promise<boolean> {
const addr = await this.predictWalletAddress(admin, extraData); const addr = await this.predictAccountAddress(admin, extraData);
return isContractDeployed(addr, this.contractWrapper.getProvider()); 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 admin - The admin of the account.
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation. * @param extraData - (Optional) Extra data to be passed to the account on creation.
* *
* @example * @example
* ```javascript * ```javascript
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData); * const tx = await contract.accountFactory.createAccount(admin, extraData);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* const smartWalletAddress = tx.address; * const accountAddress = tx.address;
* ``` * ```
* *
* @twfeature SmartWalletFactory * @twfeature AccountFactory
*/ */
createWallet = /* @__PURE__ */ buildTransactionFunction( createAccount = /* @__PURE__ */ buildTransactionFunction(
async ( async (
walletAdmin: string, accountAdmin: string,
extraData?: BytesLike, extraData?: BytesLike,
): Promise<Transaction<TransactionResultWithAddress>> => { ): Promise<Transaction<TransactionResultWithAddress>> => {
if (await this.isWalletDeployed(walletAdmin, extraData)) { if (await this.isAccountDeployed(accountAdmin, extraData)) {
throw new Error(`Wallet already deployed for admin: ${walletAdmin}`); throw new Error(`Account already deployed for admin: ${accountAdmin}`);
} }
let data: BytesLike = utils.toUtf8Bytes(""); let data: BytesLike = utils.toUtf8Bytes("");
@@ -174,7 +174,7 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
return Transaction.fromContractWrapper({ return Transaction.fromContractWrapper({
contractWrapper: this.contractWrapper, contractWrapper: this.contractWrapper,
method: "createAccount", method: "createAccount",
args: [walletAdmin, data], args: [accountAdmin, data],
parse: (receipt) => { parse: (receipt) => {
const event = this.contractWrapper.parseLogs<AccountCreatedEvent>( const event = this.contractWrapper.parseLogs<AccountCreatedEvent>(
"AccountCreated", "AccountCreated",
@@ -1,6 +1,6 @@
import { DetectableFeature } from "../interfaces/DetectableFeature"; import { DetectableFeature } from "../interfaces/DetectableFeature";
import { ContractWrapper } from "./contract-wrapper"; 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 { utils, BigNumber } from "ethers";
import { Transaction } from "./transactions"; import { Transaction } from "./transactions";
@@ -27,10 +27,10 @@ import { AddressOrEns } from "../../schema";
import { resolveAddress } from "../../common"; import { resolveAddress } from "../../common";
import { Signer } from "ethers"; import { Signer } from "ethers";
export class SmartWallet<TContract extends IAccountCore> export class Account<TContract extends IAccountCore>
implements DetectableFeature implements DetectableFeature
{ {
featureName = FEATURE_SMART_WALLET.name; featureName = FEATURE_ACCOUNT.name;
private contractWrapper: ContractWrapper<IAccountCore>; private contractWrapper: ContractWrapper<IAccountCore>;
private emptyRole: string = 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 signer - The address of the signer
* @param roleAction - 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 * @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 * @example
* ```javascript * ```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. * @param signer - The address of a signer of the account.
* @returns whether a signer is an admin on the smart wallet. * @returns whether a signer is an admin on the account.
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> { public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
const resolvedSignerAddress = await resolveAddress(signerAddress); 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 * @example
* ```javascript * ```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. * @param signer - The address of a signer of the account.
* @returns the restrictions under which a given signer can use the smart wallet. * @returns the restrictions under which a given signer can use the account.
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
public async getAccessRestrictions( public async getAccessRestrictions(
signerAddress: AddressOrEns, signerAddress: AddressOrEns,
@@ -203,16 +203,16 @@ export class SmartWallet<TContract extends IAccountCore>
} }
/** /**
* Get the deployer of the smart wallet * Get the deployer of the account
* @remarks Get the address of the EIP-4337 factory contract which deployed the smart wallet * @remarks Get the address of the EIP-4337 factory contract which deployed the account
* *
* @example * @example
* ```javascript * ```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> { public async getFactoryAddress(): Promise<string> {
return this.contractWrapper.readContract.factory(); return this.contractWrapper.readContract.factory();
@@ -223,11 +223,11 @@ export class SmartWallet<TContract extends IAccountCore>
* *
* @example * @example
* ```javascript * ```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[]> { public async getSignersWithRestrictions(): Promise<SignerWithRestrictions[]> {
// Get all associated signers. // 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 * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.grantAdminAccess(signer); * const tx = await contract.account.grantAdminAccess(signer);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
grantAdminAccess = /* @__PURE__ */ buildTransactionFunction( grantAdminAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => { 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 * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.revokeAdminAccess(signer); * const tx = await contract.account.revokeAdminAccess(signer);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
revokeAdminAccess = /* @__PURE__ */ buildTransactionFunction( revokeAdminAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => { 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 signer - The address to be granted access to the account.
* @param restrictions - The restrictions to be applied to the signer's use of the smart wallet. * @param restrictions - The restrictions to be applied to the signer's use of the account.
* *
* @example * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.grantAccess(signer, restrictions); * const tx = await contract.account.grantAccess(signer, restrictions);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
grantAccess = /* @__PURE__ */ buildTransactionFunction( grantAccess = /* @__PURE__ */ buildTransactionFunction(
async ( 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. * @param target - The address to approve as a call target for the signer.
* *
* @example * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.approveTargetForSigner(signer, target); * const tx = await contract.account.approveTargetForSigner(signer, target);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction( approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async ( 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. * @param target - The address to disapprove as a call target for the signer.
* *
* @example * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.disapproveTargetForSigner(signer, target); * const tx = await contract.account.disapproveTargetForSigner(signer, target);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction( disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
async ( 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 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 smart wallet. * @param restrictions - The restrictions to be applied to the signer's use of the account.
* *
* @example * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.updateAccess(signer, restrictions); * const tx = await contract.account.updateAccess(signer, restrictions);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
updateAccess = /* @__PURE__ */ buildTransactionFunction( updateAccess = /* @__PURE__ */ buildTransactionFunction(
async ( 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 * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.revokeAccess(signer); * const tx = await contract.account.revokeAccess(signer);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
revokeAccess = /* @__PURE__ */ buildTransactionFunction( revokeAccess = /* @__PURE__ */ buildTransactionFunction(
async (signerAddress: AddressOrEns): Promise<Transaction> => { 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 * @example
* ```javascript * ```javascript
* const tx = await contract.smartWallet.setAccess(permissionsSnapshot); * const tx = await contract.account.setAccess(permissionsSnapshot);
* const receipt = tx.receipt(); * const receipt = tx.receipt();
* ``` * ```
* *
* @twfeature SmartWallet * @twfeature Account
*/ */
setAccess = /* @__PURE__ */ buildTransactionFunction( setAccess = /* @__PURE__ */ buildTransactionFunction(
async ( async (
@@ -1,8 +1,7 @@
import { EventType } from "../../constants/events"; import { EventType } from "../../constants/events";
import type { ContractEvent, EventQueryOptions } from "../../types/events"; import type { ContractEvent, EventQueryOptions } from "../../types/events";
import { ContractWrapper } from "./contract-wrapper"; import { ContractWrapper } from "./contract-wrapper";
import type { BaseContract, Event, providers } from "ethers"; import type { BaseContract, Event, providers, utils } from "ethers";
import type { EventFragment } from "ethers/lib/utils.js";
import type { EventEmitter } from "eventemitter3"; import type { EventEmitter } from "eventemitter3";
/** /**
@@ -325,7 +324,7 @@ export class ContractEvents<TContract extends BaseContract> {
} }
private toContractEvent<TEvent extends Record<string, any>>( private toContractEvent<TEvent extends Record<string, any>>(
event: EventFragment, event: utils.EventFragment,
args: ReadonlyArray<any>, args: ReadonlyArray<any>,
rawLog: providers.Log, rawLog: providers.Log,
): ContractEvent<TEvent> { ): ContractEvent<TEvent> {
@@ -44,7 +44,6 @@ import {
type Signer, type Signer,
constants, constants,
} from "ethers"; } from "ethers";
import { ConnectionInfo } from "ethers/lib/utils.js";
import invariant from "tiny-invariant"; import invariant from "tiny-invariant";
import { CONTRACT_ADDRESSES } from "../../constants/addresses/CONTRACT_ADDRESSES"; import { CONTRACT_ADDRESSES } from "../../constants/addresses/CONTRACT_ADDRESSES";
import { getContractAddressByChainId } from "../../constants/addresses/getContractAddressByChainId"; import { getContractAddressByChainId } from "../../constants/addresses/getContractAddressByChainId";
@@ -471,7 +470,7 @@ export class ContractWrapper<
callOverrides: CallOverrides, callOverrides: CallOverrides,
) { ) {
const provider = this.getProvider() as providers.Provider & { const provider = this.getProvider() as providers.Provider & {
connection?: ConnectionInfo; connection?: utils.ConnectionInfo;
}; };
// Get metadata for transaction to populate into error // 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 "./contract-owner";
export * from "./transactions"; export * from "./transactions";
export * from "./contract-appuri"; export * from "./contract-appuri";
export * from "./smart-wallet"; export * from "./account";
export * from "./smart-wallet-factory"; export * from "./account-factory";
@@ -30,8 +30,6 @@ import {
constants, constants,
} from "ethers"; } from "ethers";
import { BigNumber } 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 invariant from "tiny-invariant";
import EventEmitter from "eventemitter3"; import EventEmitter from "eventemitter3";
import type { DeployEvents } from "../../types/deploy"; import type { DeployEvents } from "../../types/deploy";
@@ -494,7 +492,7 @@ export class Transaction<
try { try {
// for dynamic contracts, add 30% to the gas limit to account for multiple delegate calls // for dynamic contracts, add 30% to the gas limit to account for multiple delegate calls
const abi = JSON.parse( const abi = JSON.parse(
this.contract.interface.format(FormatTypes.json) as string, this.contract.interface.format("json") as string,
); );
if (isRouterContract(abi)) { if (isRouterContract(abi)) {
overrides.gasLimit = overrides.gasLimit.mul(110).div(100); overrides.gasLimit = overrides.gasLimit.mul(110).div(100);
@@ -663,7 +661,7 @@ export class Transaction<
*/ */
private async transactionError(error: any) { private async transactionError(error: any) {
const provider = this.provider as providers.Provider & { const provider = this.provider as providers.Provider & {
connection?: ConnectionInfo; connection?: utils.ConnectionInfo;
}; };
// Get metadata for transaction to populate into error // Get metadata for transaction to populate into error
@@ -849,7 +847,7 @@ export class DeployTransaction extends TransactionContext {
*/ */
private async deployError(error: any) { private async deployError(error: any) {
const provider = this.provider as providers.Provider & { const provider = this.provider as providers.Provider & {
connection?: ConnectionInfo; connection?: utils.ConnectionInfo;
}; };
// Get metadata for transaction to populate into error // Get metadata for transaction to populate into error
+1 -1
View File
@@ -12,4 +12,4 @@ export * from "./multiwrap";
export * from "./registry"; export * from "./registry";
export * from "./transactions"; export * from "./transactions";
export * from "./contract"; export * from "./contract";
export * from "./smart-wallet"; export * from "./account";
@@ -4,8 +4,8 @@ import { assert, expect } from "chai";
import { import {
SignerWithRestrictions, SignerWithRestrictions,
AccessRestrictions, AccessRestrictions,
SmartWallet, Account,
SmartWalletFactory, AccountFactory,
SignerWithRestrictionsInput, SignerWithRestrictionsInput,
SignerWithRestrictionsBatchInput, SignerWithRestrictionsBatchInput,
} from "../../src/evm"; } from "../../src/evm";
@@ -23,9 +23,9 @@ import { IAccountCore, IAccountFactory } from "@thirdweb-dev/contracts-js";
global.fetch = /* @__PURE__ */ require("cross-fetch"); global.fetch = /* @__PURE__ */ require("cross-fetch");
/* @__PURE__ */ describe("Smart wallets with wallet factory", function () { /* @__PURE__ */ describe("Accounts with account factory", function () {
let smartWalletFactory: SmartWalletFactory<IAccountFactory>; let accountFactory: AccountFactory<IAccountFactory>;
let smartWallet: SmartWallet<IAccountCore>; let account: Account<IAccountCore>;
let adminWallet: SignerWithAddress; let adminWallet: SignerWithAddress;
@@ -66,64 +66,63 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
adminWallet, adminWallet,
[entrypoint.address], [entrypoint.address],
); );
smartWalletFactory = (await sdk.getContract(factoryAddress)) accountFactory = (await sdk.getContract(factoryAddress)).accountFactory;
.smartWalletFactory;
}); });
describe("Test: SmartWalletFactory actions", () => { describe("Test: AccountFactory actions", () => {
it("Should create a new wallet for the admin", async () => { it("Should create a new account for the admin", async () => {
// Check before creating a smart wallet for `adminWallet` // Check before creating a account for `adminWallet`
const isDeployed = await smartWalletFactory.isWalletDeployed( const isDeployed = await accountFactory.isAccountDeployed(
adminWallet.address, adminWallet.address,
); );
assert.isFalse( assert.isFalse(
isDeployed, isDeployed,
"Smart wallet is should not be deployed for admin.", "Account is should not be deployed for admin.",
); );
const predictedAccountAddress: string = const predictedAccountAddress: string =
await smartWalletFactory.predictWalletAddress(adminWallet.address); await accountFactory.predictAccountAddress(adminWallet.address);
const allWalletsBefore = (await smartWalletFactory.getAllAccounts()).map( const allAccountsBefore = (await accountFactory.getAllAccounts()).map(
(wallet) => wallet.account, (wallet) => account.account,
); );
assert.isFalse( assert.isFalse(
allWalletsBefore.includes(predictedAccountAddress), allAccountsBefore.includes(predictedAccountAddress),
"Account should not be deployed for admin already.", "Account should not be deployed for admin already.",
); );
assert.isTrue( assert.isTrue(
(await smartWalletFactory.getAssociatedSigners(predictedAccountAddress)) (await accountFactory.getAssociatedSigners(predictedAccountAddress))
.length === 0, .length === 0,
"Wallet should have no associated signers.", "Wallet should have no associated signers.",
); );
assert.isTrue( assert.isTrue(
(await smartWalletFactory.getAssociatedWallets(adminWallet.address)) (await accountFactory.getAssociatedAccounts(adminWallet.address))
.length === 0, .length === 0,
"Signer should have no associated wallets.", "Signer should have no associated accounts.",
); );
// Create smart wallet for `adminWallet` // Create account for `adminWallet`
const tx = await smartWalletFactory.createWallet(adminWallet.address); const tx = await accountFactory.createAccount(adminWallet.address);
// Checks after creating a smart wallet for `adminWallet` // Checks after creating a account for `adminWallet`
assert.strictEqual( assert.strictEqual(
utils.getAddress(tx.address), utils.getAddress(tx.address),
utils.getAddress(predictedAccountAddress), utils.getAddress(predictedAccountAddress),
"Smart wallet address should match predicted address.", "Account address should match predicted address.",
); );
assert.isTrue( assert.isTrue(
await smartWalletFactory.isWalletDeployed(adminWallet.address), await accountFactory.isAccountDeployed(adminWallet.address),
"Smart wallet is should be deployed for admin.", "Account is should be deployed for admin.",
); );
const allWalletsAfter = await smartWalletFactory.getAllAccounts(); const allAccountsAfter = await accountFactory.getAllAccounts();
assert.isTrue( assert.isTrue(
allWalletsAfter.length === 1, allAccountsAfter.length === 1,
"Only one wallet should be created on the factory.", "Only one account should be created on the factory.",
); );
const { account, admin } = allWalletsAfter.filter( const { account, admin } = allAccountsAfter.filter(
(wallet) => (wallet) =>
utils.getAddress(wallet.account) === utils.getAddress(wallet.account) ===
utils.getAddress(predictedAccountAddress), utils.getAddress(predictedAccountAddress),
@@ -136,165 +135,161 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
assert.strictEqual( assert.strictEqual(
utils.getAddress(admin), utils.getAddress(admin),
utils.getAddress(adminWallet.address), utils.getAddress(adminWallet.address),
"Correct admin for smart wallet.", "Correct admin for account.",
); );
const associatedWallets = await smartWalletFactory.getAssociatedWallets( const associatedAccounts = await accountFactory.getAssociatedAccounts(
admin, admin,
); );
const associatedSigner = await smartWalletFactory.getAssociatedSigners( const associatedSigner = await accountFactory.getAssociatedSigners(
account, account,
); );
assert.isTrue( assert.isTrue(
associatedWallets.length === 1, associatedAccounts.length === 1,
"Wallet should have only the admin as an associated signer.", "Wallet should have only the admin as an associated signer.",
); );
assert.strictEqual( assert.strictEqual(
utils.getAddress(account), utils.getAddress(account),
utils.getAddress(associatedWallets[0]), utils.getAddress(associatedAccounts[0]),
"Wallet should have only the admin as an associated signer.", "Wallet should have only the admin as an associated signer.",
); );
assert.isTrue( assert.isTrue(
associatedSigner.length === 1, 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( assert.strictEqual(
utils.getAddress(admin), utils.getAddress(admin),
utils.getAddress(associatedSigner[0]), 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 () => { it("Should throw if creating account for an admin who already has one", async () => {
// Create a wallet for admin // Create a account for admin
await smartWalletFactory.createWallet(adminWallet.address); await accountFactory.createAccount(adminWallet.address);
// Try creating another wallet for the same admin // Try creating another account for the same admin
try { try {
await smartWalletFactory.createWallet(adminWallet.address); await accountFactory.createAccount(adminWallet.address);
expect.fail(); expect.fail();
} catch (err: any) { } catch (err: any) {
expect(err.message).to.equal( 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 () => { beforeEach(async () => {
// Create a wallet for admin // Create a account for admin
const tx = await smartWalletFactory.createWallet(adminWallet.address); const tx = await accountFactory.createAccount(adminWallet.address);
const smartWalletAddress = tx.address; const accountAddress = tx.address;
sdk.updateSignerOrProvider(adminWallet); sdk.updateSignerOrProvider(adminWallet);
await mockUploadContractMetadata( await mockUploadContractMetadata(
"smart-wallet", "smart-wallet",
smartWalletAddress, accountAddress,
IAccountCoreAbi, 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( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
await smartWallet.grantAdminAccess(signer1Wallet.address); await account.grantAdminAccess(signer1Wallet.address);
assert.isTrue( assert.isTrue(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the smart wallet.", "New signer1 should be an admin on the account.",
); );
const isAdmin = ( const isAdmin = (
(await smartWallet.getSignersWithRestrictions()).find( (await account.getSignersWithRestrictions()).find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address), utils.getAddress(signer1Wallet.address),
) as SignerWithRestrictions ) as SignerWithRestrictions
).isAdmin; ).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( assert.isTrue(
( (
await smartWalletFactory.getAssociatedSigners( await accountFactory.getAssociatedSigners(account.getAddress())
smartWallet.getAddress(),
)
).includes(signer1Wallet.address), ).includes(signer1Wallet.address),
"New signer1 is an associated signer of the wallet.", "New signer1 is an associated signer of the account.",
); );
assert.isTrue( assert.isTrue(
( (
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address) await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(smartWallet.getAddress()), ).includes(account.getAddress()),
"Wallet is an associated wallet of the signer.", "Wallet is an associated account of the signer.",
); );
}); });
it("Should be able to remove an admin from the wallet.", async () => { it("Should be able to remove an admin from the account.", async () => {
await smartWallet.grantAdminAccess(signer1Wallet.address); await account.grantAdminAccess(signer1Wallet.address);
assert.isTrue( assert.isTrue(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should be an admin on the smart wallet.", "New signer1 should be an admin on the account.",
); );
await smartWallet.revokeAdminAccess(signer1Wallet.address); await account.revokeAdminAccess(signer1Wallet.address);
assert.isFalse( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
assert.isFalse( assert.isFalse(
(await smartWallet.getSignersWithRestrictions()) (await account.getSignersWithRestrictions())
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .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( assert.isFalse(
( (
await smartWalletFactory.getAssociatedSigners( await accountFactory.getAssociatedSigners(account.getAddress())
smartWallet.getAddress(),
)
).includes(signer1Wallet.address), ).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( assert.isFalse(
( (
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address) await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(smartWallet.getAddress()), ).includes(account.getAddress()),
"Wallet is not an associated wallet of the signer.", "Wallet is not an associated account of the signer.",
); );
}); });
it("Should be able to grant restricted access to a new signer.", async () => { it("Should be able to grant restricted access to a new signer.", async () => {
const signersWithRestrictions = const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
assert.isFalse( assert.isFalse(
signersWithRestrictions signersWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .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 // Grant access
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
assert.isFalse( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
const newSignerWithRestrictions = const newSignerWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
const restrictions = newSignerWithRestrictions.find( const restrictions = newSignerWithRestrictions.find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
@@ -304,7 +299,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
newSignerWithRestrictions newSignerWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.", "New signer1 should be a signer on the account.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.nativeTokenLimitPerTransaction.toString(), restrictions.nativeTokenLimitPerTransaction.toString(),
@@ -324,30 +319,28 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
assert.isTrue( assert.isTrue(
( (
await smartWalletFactory.getAssociatedSigners( await accountFactory.getAssociatedSigners(account.getAddress())
smartWallet.getAddress(),
)
).includes(signer1Wallet.address), ).includes(signer1Wallet.address),
"New signer1 is an associated signer of the wallet.", "New signer1 is an associated signer of the account.",
); );
assert.isTrue( assert.isTrue(
( (
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address) await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(smartWallet.getAddress()), ).includes(account.getAddress()),
"Wallet is an associated wallet of the signer.", "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 () => { it("Should not be able to grant restricted access to a signer who already has access.", async () => {
// Grant access to signer1 // Grant access to signer1
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
// Try granting access to signer1 again // Try granting access to signer1 again
try { try {
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
expect.fail(); 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 () => { it("Should be able to revoke restricted access from an authorized signer.", async () => {
// Grant access to signer1 // Grant access to signer1
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
// Revoke access // Revoke access
await smartWallet.revokeAccess(signer1Wallet.address); await account.revokeAccess(signer1Wallet.address);
const signersWithRestrictions = const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
assert.isFalse( assert.isFalse(
signersWithRestrictions signersWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .includes(signer1Wallet.address),
"New signer should not have access to the wallet.", "New signer should not have access to the account.",
); );
assert.isFalse( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
assert.isFalse( assert.isFalse(
( (
await smartWalletFactory.getAssociatedSigners( await accountFactory.getAssociatedSigners(account.getAddress())
smartWallet.getAddress(),
)
).includes(signer1Wallet.address), ).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( assert.isFalse(
( (
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address) await accountFactory.getAssociatedAccounts(signer1Wallet.address)
).includes(smartWallet.getAddress()), ).includes(account.getAddress()),
"Wallet is not an associated wallet of the signer.", "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 () => { it("Should not be able to revoke restricted access from a signer who doesn't have access.", async () => {
const signersWithRestrictions = const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
assert.isFalse( assert.isFalse(
signersWithRestrictions signersWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .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 revoking access from signer1
try { try {
await smartWallet.revokeAccess(signer1Wallet.address); await account.revokeAccess(signer1Wallet.address);
expect.fail(); expect.fail();
} catch (err: any) { } catch (err: any) {
expect(err.message).to.equal(`Signer does not have any access`); 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 () => { it("Should be able to update access of an authorized signer.", async () => {
// Grant access // Grant access
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
assert.isFalse( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
const signerWithRestrictions = const signerWithRestrictions = await account.getSignersWithRestrictions();
await smartWallet.getSignersWithRestrictions();
const restrictions = signerWithRestrictions.find( const restrictions = signerWithRestrictions.find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
@@ -438,7 +428,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signerWithRestrictions signerWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.", "New signer1 should be a signer on the account.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.nativeTokenLimitPerTransaction.toString(), restrictions.nativeTokenLimitPerTransaction.toString(),
@@ -457,18 +447,18 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
); );
// Update access // Update access
await smartWallet.updateAccess(signer1Wallet.address, { await account.updateAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "3", nativeTokenLimitPerTransaction: "3",
approvedCallTargets: [signer2Wallet.address], approvedCallTargets: [signer2Wallet.address],
}); });
assert.isFalse( assert.isFalse(
await smartWallet.isAdmin(signer1Wallet.address), await account.isAdmin(signer1Wallet.address),
"New signer1 should not be an admin on the smart wallet.", "New signer1 should not be an admin on the account.",
); );
const newSignerWithRestrictions = const newSignerWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
const newRestrictions = newSignerWithRestrictions.find( const newRestrictions = newSignerWithRestrictions.find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
@@ -478,7 +468,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
newSignerWithRestrictions newSignerWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .includes(signer1Wallet.address),
"New signer1 should be a signer on the wallet.", "New signer1 should be a signer on the account.",
); );
assert.strictEqual( assert.strictEqual(
newRestrictions.nativeTokenLimitPerTransaction.toString(), 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 () => { it("Should not be able to update access of a signer who doesn't have access.", async () => {
const signersWithRestrictions = const signersWithRestrictions =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
assert.isFalse( assert.isFalse(
signersWithRestrictions signersWithRestrictions
.map((result) => utils.getAddress(result.signer)) .map((result) => utils.getAddress(result.signer))
.includes(signer1Wallet.address), .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 updating access of signer1
try { try {
await smartWallet.updateAccess(signer1Wallet.address, { await account.updateAccess(signer1Wallet.address, {
approvedCallTargets: [signer2Wallet.address], approvedCallTargets: [signer2Wallet.address],
}); });
expect.fail(); 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 () => { it("Should be able to append an approved target for an authorized signer.", async () => {
// Grant access // Grant access
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
const restrictions = ( const restrictions = (await account.getSignersWithRestrictions()).find(
await smartWallet.getSignersWithRestrictions()
).find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address), utils.getAddress(signer1Wallet.address),
@@ -544,14 +532,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
); );
// Append approved target // Append approved target
await smartWallet.approveTargetForSigner( await account.approveTargetForSigner(
signer1Wallet.address, signer1Wallet.address,
signer2Wallet.address, signer2Wallet.address,
); );
const newRestrictions = ( const newRestrictions = (await account.getSignersWithRestrictions()).find(
await smartWallet.getSignersWithRestrictions()
).find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address), 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 () => { it("Should be able to remove an approved target for an authorized signer.", async () => {
// Grant access // Grant access
await smartWallet.grantAccess(signer1Wallet.address, { await account.grantAccess(signer1Wallet.address, {
nativeTokenLimitPerTransaction: "1", nativeTokenLimitPerTransaction: "1",
approvedCallTargets: [adminWallet.address, signer2Wallet.address], approvedCallTargets: [adminWallet.address, signer2Wallet.address],
}); });
const restrictions = ( const restrictions = (await account.getSignersWithRestrictions()).find(
await smartWallet.getSignersWithRestrictions()
).find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address), utils.getAddress(signer1Wallet.address),
@@ -604,14 +588,12 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
); );
// Remove approved target // Remove approved target
await smartWallet.disapproveTargetForSigner( await account.disapproveTargetForSigner(
signer1Wallet.address, signer1Wallet.address,
signer2Wallet.address, signer2Wallet.address,
); );
const newRestrictions = ( const newRestrictions = (await account.getSignersWithRestrictions()).find(
await smartWallet.getSignersWithRestrictions()
).find(
(result) => (result) =>
utils.getAddress(result.signer) === utils.getAddress(result.signer) ===
utils.getAddress(signer1Wallet.address), 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 * All cases to test
* *
@@ -661,7 +643,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner3); signersWithRestrictions.push(restrictionsSigner3);
// Removing existing admin // Removing existing admin
await smartWallet.grantAdminAccess(signer4Wallet.address); await account.grantAdminAccess(signer4Wallet.address);
const restrictionsSigner4: SignerWithRestrictionsInput = { const restrictionsSigner4: SignerWithRestrictionsInput = {
signer: signer4Wallet.address, signer: signer4Wallet.address,
@@ -679,7 +661,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner5); signersWithRestrictions.push(restrictionsSigner5);
// Removing an existing scoped signer // Removing an existing scoped signer
await smartWallet.grantAccess(signer6Wallet.address, { await account.grantAccess(signer6Wallet.address, {
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
@@ -692,7 +674,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
// Updating the restrictions of an existing scoped signer // Updating the restrictions of an existing scoped signer
await smartWallet.grantAccess(signer7Wallet.address, { await account.grantAccess(signer7Wallet.address, {
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
@@ -704,7 +686,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner7); signersWithRestrictions.push(restrictionsSigner7);
// Existing admin -> new scoped signer (demote) // Existing admin -> new scoped signer (demote)
await smartWallet.grantAdminAccess(signer8Wallet.address); await account.grantAdminAccess(signer8Wallet.address);
const restrictionsSigner8: SignerWithRestrictionsInput = { const restrictionsSigner8: SignerWithRestrictionsInput = {
signer: signer8Wallet.address, signer: signer8Wallet.address,
@@ -714,7 +696,7 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner8); signersWithRestrictions.push(restrictionsSigner8);
// Existing scoped signer -> new admin (promote) // Existing scoped signer -> new admin (promote)
await smartWallet.grantAccess(signer9Wallet.address, { await account.grantAccess(signer9Wallet.address, {
approvedCallTargets: [adminWallet.address], approvedCallTargets: [adminWallet.address],
}); });
@@ -726,11 +708,11 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
signersWithRestrictions.push(restrictionsSigner9); signersWithRestrictions.push(restrictionsSigner9);
// Set access in batch // Set access in batch
await smartWallet.setAccess(signersWithRestrictions); await account.setAccess(signersWithRestrictions);
// Now checking if permissions are set correctly // Now checking if permissions are set correctly
const signersWithRestrictionsAfter = const signersWithRestrictionsAfter =
await smartWallet.getSignersWithRestrictions(); await account.getSignersWithRestrictions();
for (const restrictions of signersWithRestrictionsAfter) { for (const restrictions of signersWithRestrictionsAfter) {
switch (restrictions.signer) { switch (restrictions.signer) {
@@ -738,96 +720,96 @@ global.fetch = /* @__PURE__ */ require("cross-fetch");
case adminWallet.address: case adminWallet.address:
assert.isTrue( assert.isTrue(
restrictions.isAdmin, restrictions.isAdmin,
"Admin wallet should be an admin.", "Admin account should be an admin.",
); );
break; break;
// `signer3Wallet` should be an admin // `signer3Wallet` should be an admin
case signer3Wallet.address: case signer3Wallet.address:
assert.isTrue( assert.isTrue(
restrictions.isAdmin, restrictions.isAdmin,
"Signer3 wallet should be an admin.", "Signer3 account should be an admin.",
); );
break; break;
// `signer4Wallet` should not be admin or scoped signer // `signer4Wallet` should not be admin or scoped signer
case signer4Wallet.address: case signer4Wallet.address:
assert.isFalse( assert.isFalse(
restrictions.isAdmin, restrictions.isAdmin,
"Signer4 wallet should not be an admin.", "Signer4 account should not be an admin.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length, restrictions.restrictions.approvedCallTargets.length,
0, 0,
"Signer4 wallet should not have any approved call targets.", "Signer4 account should not have any approved call targets.",
); );
break; break;
// `signer5Wallet` should be a scoped signer // `signer5Wallet` should be a scoped signer
case signer5Wallet.address: case signer5Wallet.address:
assert.isFalse( assert.isFalse(
restrictions.isAdmin, restrictions.isAdmin,
"Signer5 wallet should not be an admin.", "Signer5 account should not be an admin.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length, restrictions.restrictions.approvedCallTargets.length,
1, 1,
"Signer5 wallet should have one approved call target.", "Signer5 account should have one approved call target.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0], restrictions.restrictions.approvedCallTargets[0],
adminWallet.address, adminWallet.address,
"Signer5 wallet should have the expected approved call targets.", "Signer5 account should have the expected approved call targets.",
); );
break; break;
// `signer6Wallet` should not be admin or scoped signer // `signer6Wallet` should not be admin or scoped signer
case signer6Wallet.address: case signer6Wallet.address:
assert.isFalse( assert.isFalse(
restrictions.isAdmin, restrictions.isAdmin,
"Signer6 wallet should not be an admin.", "Signer6 account should not be an admin.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length, restrictions.restrictions.approvedCallTargets.length,
0, 0,
"Signer6 wallet should not have any approved call targets.", "Signer6 account should not have any approved call targets.",
); );
break; break;
// `signer7Wallet` should be a scoped signer with its updated restrictions // `signer7Wallet` should be a scoped signer with its updated restrictions
case signer7Wallet.address: case signer7Wallet.address:
assert.isFalse( assert.isFalse(
restrictions.isAdmin, restrictions.isAdmin,
"Signer7 wallet should not be an admin.", "Signer7 account should not be an admin.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length, restrictions.restrictions.approvedCallTargets.length,
1, 1,
"Signer7 wallet should have one approved call target.", "Signer7 account should have one approved call target.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0], restrictions.restrictions.approvedCallTargets[0],
signer1Wallet.address, signer1Wallet.address,
"Signer7 wallet should have the expected approved call targets.", "Signer7 account should have the expected approved call targets.",
); );
break; break;
// `signer8Wallet` should be a scoped signer // `signer8Wallet` should be a scoped signer
case signer8Wallet.address: case signer8Wallet.address:
assert.isFalse( assert.isFalse(
restrictions.isAdmin, restrictions.isAdmin,
"Signer8 wallet should not be an admin.", "Signer8 account should not be an admin.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets.length, restrictions.restrictions.approvedCallTargets.length,
1, 1,
"Signer8 wallet should have one approved call target.", "Signer8 account should have one approved call target.",
); );
assert.strictEqual( assert.strictEqual(
restrictions.restrictions.approvedCallTargets[0], restrictions.restrictions.approvedCallTargets[0],
adminWallet.address, adminWallet.address,
"Signer8 wallet should have the expected approved call targets.", "Signer8 account should have the expected approved call targets.",
); );
break; break;
// `signer9Wallet` should be an admin // `signer9Wallet` should be an admin
case signer9Wallet.address: case signer9Wallet.address:
assert.isTrue( assert.isTrue(
restrictions.isAdmin, restrictions.isAdmin,
"Signer9 wallet should be an admin.", "Signer9 account should be an admin.",
); );
break; break;
default: default:
+3
View File
@@ -82,6 +82,7 @@ let signers: SignerWithAddress[];
let storage: ThirdwebStorage; let storage: ThirdwebStorage;
let implementations: { [key in ContractType]?: string }; let implementations: { [key in ContractType]?: string };
let mock_weth_address: string; let mock_weth_address: string;
let thirdwebFactory: TWFactory;
const fastForwardTime = async (timeInSeconds: number): Promise<void> => { const fastForwardTime = async (timeInSeconds: number): Promise<void> => {
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
@@ -133,6 +134,7 @@ export const mochaHooks = {
.connect(signer) .connect(signer)
.deploy(trustedForwarderAddress, registry.address)) as TWFactory; .deploy(trustedForwarderAddress, registry.address)) as TWFactory;
thirdwebFactory = await thirdwebFactoryDeployer.deployed();
const deployTxFactory = thirdwebFactoryDeployer.deployTransaction; const deployTxFactory = thirdwebFactoryDeployer.deployTransaction;
await deployTxFactory.wait(); await deployTxFactory.wait();
const thirdwebRegistryAddress = await thirdwebFactoryDeployer.registry(); const thirdwebRegistryAddress = await thirdwebFactoryDeployer.registry();
@@ -391,4 +393,5 @@ export {
storage, storage,
implementations, implementations,
hardhatEthers, hardhatEthers,
thirdwebFactory,
}; };
+2 -2
View File
@@ -1,12 +1,12 @@
import { ThirdwebSDK } from "../../src/evm"; import { ThirdwebSDK } from "../../src/evm";
import { expectError, sdk } from "./before-setup"; import { expectError, sdk } from "./before-setup";
import { expect } from "chai"; import { expect } from "chai";
import { ethers } from "ethers"; import { Wallet } from "ethers";
describe("Error Handling", async () => { describe("Error Handling", async () => {
it("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( const newSdk = ThirdwebSDK.fromSigner(
ethers.Wallet.createRandom().connect(sdk.getProvider()), Wallet.createRandom().connect(sdk.getProvider()),
); );
try { try {
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, file: FileOrBufferOrString,
options?: IpfsUploadBatchOptions | undefined, 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
});
+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 { defaultProvider } from "./before-setup";
import { mockUploadWithCID } from "./mock/MockStorage"; import { mockUploadWithCID } from "./mock/MockStorage";
import { ContractInterface, ethers } from "ethers"; import { ContractInterface, ethers } from "ethers";
@@ -22,6 +26,8 @@ export const mockUploadContractMetadata = async (
contractName: string, contractName: string,
address: string, address: string,
abi: any, abi: any,
extendedMetadata?: FullPublishMetadata | any,
publishUri?: string,
) => { ) => {
const ipfsHash = (await resolveContractUriFromAddress( const ipfsHash = (await resolveContractUriFromAddress(
address, address,
@@ -57,11 +63,68 @@ export const mockUploadContractMetadata = async (
// mock raw-metadata // mock raw-metadata
const rawMeta = { const rawMeta = {
...extendedMetadata,
name: contractName, name: contractName,
metadataUri: ipfsHash, metadataUri: ipfsHash,
bytecodeUri: bytecodeUri, bytecodeUri: bytecodeUri,
}; };
const rawMetaUri = ipfsHash.concat("rawMeta"); const rawMetaUri = publishUri || ipfsHash.concat("rawMeta");
const rawMetaCID = rawMetaUri.replace("ipfs://", ""); const rawMetaCID = rawMetaUri.replace("ipfs://", "");
await mockUploadWithCID(rawMetaCID, JSON.stringify(rawMeta)); 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;
}; };
+26
View File
@@ -1,5 +1,31 @@
# @thirdweb-dev/unity-js-bridge # @thirdweb-dev/unity-js-bridge
## 0.2.44
### Patch Changes
- 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
- @thirdweb-dev/auth@3.2.7
## 0.2.43
### 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/auth@3.2.6
## 0.2.42
### Patch Changes
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
- @thirdweb-dev/wallets@1.0.1
- @thirdweb-dev/auth@3.2.5
## 0.2.41 ## 0.2.41
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/unity-js-bridge", "name": "@thirdweb-dev/unity-js-bridge",
"version": "0.2.41", "version": "0.2.44",
"main": "dist/thirdweb-unity-bridge.js", "main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge", "repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0", "license": "Apache-2.0",
+32
View File
@@ -1,5 +1,37 @@
# @thirdweb-dev/wallets # @thirdweb-dev/wallets
## 1.0.3
### 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
- [#1267](https://github.com/thirdweb-dev/js/pull/1267) [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - set signer null when disconnecting paper to avoid exceptions on event callbacks
- [#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), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad)]:
- @thirdweb-dev/sdk@3.10.27
- @thirdweb-dev/chains@0.1.26
## 1.0.2
### Patch Changes
- [#1263](https://github.com/thirdweb-dev/js/pull/1263) [`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8) Thanks [@iketw](https://github.com/iketw)! - Pass a min set of chains if user passes more than 50 chains. We'll rely on "adding chains" for new chains
- [#1255](https://github.com/thirdweb-dev/js/pull/1255) [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Handle passing RPC urls as chain in SmartWallet config
- [#1265](https://github.com/thirdweb-dev/js/pull/1265) [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1) Thanks [@MananTank](https://github.com/MananTank)! - Wallet Connect v2 Corrections
## 1.0.1
### Patch Changes
- [#1259](https://github.com/thirdweb-dev/js/pull/1259) [`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08) Thanks [@iketw](https://github.com/iketw)! - Fix. Respecting passed wallets if less then 50, otherwhise use defaults chains.
## 1.0.0 ## 1.0.0
### Major Changes ### Major Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@thirdweb-dev/wallets", "name": "@thirdweb-dev/wallets",
"version": "1.0.0", "version": "1.0.3",
"main": "dist/thirdweb-dev-wallets.cjs.js", "main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js", "module": "dist/thirdweb-dev-wallets.esm.js",
"types": "dist/thirdweb-dev-wallets.cjs.d.ts", "types": "dist/thirdweb-dev-wallets.cjs.d.ts",
@@ -325,7 +325,7 @@
"@magic-ext/connect": "^6.7.0", "@magic-ext/connect": "^6.7.0",
"@magic-ext/oauth": "^7.6.2", "@magic-ext/oauth": "^7.6.2",
"@magic-sdk/provider": "^13.6.2", "@magic-sdk/provider": "^13.6.2",
"@paperxyz/embedded-wallet-service-sdk": "^1.0.0", "@paperxyz/embedded-wallet-service-sdk": "^1.1.0",
"@safe-global/safe-core-sdk": "^3.3.2", "@safe-global/safe-core-sdk": "^3.3.2",
"@safe-global/safe-ethers-adapters": "^0.1.0-alpha.16", "@safe-global/safe-ethers-adapters": "^0.1.0-alpha.16",
"@safe-global/safe-ethers-lib": "^1.9.2", "@safe-global/safe-ethers-lib": "^1.9.2",
@@ -13,8 +13,7 @@ import type {
} from "@coinbase/wallet-sdk"; } from "@coinbase/wallet-sdk";
import type { CoinbaseWalletSDKOptions } from "@coinbase/wallet-sdk/dist/CoinbaseWalletSDK"; import type { CoinbaseWalletSDKOptions } from "@coinbase/wallet-sdk/dist/CoinbaseWalletSDK";
import type { Chain } from "@thirdweb-dev/chains"; import type { Chain } from "@thirdweb-dev/chains";
import { providers } from "ethers"; import { providers, utils } from "ethers";
import { getAddress, hexValue } from "ethers/lib/utils.js";
import { walletIds } from "../../constants/walletIds"; import { walletIds } from "../../constants/walletIds";
type Options = CoinbaseWalletSDKOptions & { type Options = CoinbaseWalletSDKOptions & {
@@ -61,7 +60,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
this.emit("message", { type: "connecting" }); this.emit("message", { type: "connecting" });
const accounts = await provider.enable(); const accounts = await provider.enable();
const account = getAddress(accounts[0] as string); const account = utils.getAddress(accounts[0] as string);
// Switch to chain if provided // Switch to chain if provided
let id = await this.getChainId(); let id = await this.getChainId();
let unsupported = this.isChainUnsupported(id); let unsupported = this.isChainUnsupported(id);
@@ -120,7 +119,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
throw new Error("No accounts found"); throw new Error("No accounts found");
} }
// return checksum address // return checksum address
return getAddress(accounts[0] as string); return utils.getAddress(accounts[0] as string);
} }
async getChainId() { async getChainId() {
@@ -197,7 +196,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
async switchChain(chainId: number): Promise<Chain> { async switchChain(chainId: number): Promise<Chain> {
const provider = await this.getProvider(); const provider = await this.getProvider();
const id = hexValue(chainId); const id = utils.hexValue(chainId);
try { try {
await provider.request({ await provider.request({
@@ -257,7 +256,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
if (accounts.length === 0) { if (accounts.length === 0) {
this.emit("disconnect"); this.emit("disconnect");
} else { } else {
this.emit("change", { account: getAddress(accounts[0] as string) }); this.emit("change", { account: utils.getAddress(accounts[0] as string) });
} }
}; };
@@ -1,5 +1,4 @@
import { providers } from "ethers"; import { providers, utils } from "ethers";
import { getAddress, hexValue } from "ethers/lib/utils.js";
import type Provider from "ethereum-provider"; import type Provider from "ethereum-provider";
import type { Address } from "abitype"; import type { Address } from "abitype";
import type { Chain } from "@thirdweb-dev/chains"; import type { Chain } from "@thirdweb-dev/chains";
@@ -76,7 +75,7 @@ export class FrameConnector extends WagmiConnector<
const accounts: string[] = await provider.request({ const accounts: string[] = await provider.request({
method: "eth_requestAccounts", method: "eth_requestAccounts",
}); });
const account = getAddress(accounts[0] as string); const account = utils.getAddress(accounts[0] as string);
// Switch to chain if provided // Switch to chain if provided
let id = await this.getChainId(); let id = await this.getChainId();
let unsupported = this.isChainUnsupported(id); let unsupported = this.isChainUnsupported(id);
@@ -132,7 +131,7 @@ export class FrameConnector extends WagmiConnector<
method: "eth_accounts", method: "eth_accounts",
})) as string[]; })) as string[];
// return checksum address // return checksum address
return getAddress(accounts[0] as string); return utils.getAddress(accounts[0] as string);
} }
async getChainId() { async getChainId() {
@@ -195,7 +194,7 @@ export class FrameConnector extends WagmiConnector<
if (!provider) { if (!provider) {
throw new ConnectorNotFoundError(); throw new ConnectorNotFoundError();
} }
const chainIdHex = hexValue(chainId); const chainIdHex = utils.hexValue(chainId);
try { try {
await Promise.all([ await Promise.all([
@@ -320,7 +319,7 @@ export class FrameConnector extends WagmiConnector<
this.emit("disconnect"); this.emit("disconnect");
} else { } else {
this.emit("change", { this.emit("change", {
account: getAddress(accounts[0] as string), account: utils.getAddress(accounts[0] as string),
}); });
} }
}; };
@@ -5,7 +5,7 @@ import {
MagicOptions, MagicOptions,
} from "./types"; } from "./types";
import type { Chain } from "@thirdweb-dev/chains"; import type { Chain } from "@thirdweb-dev/chains";
import { ethers, Signer } from "ethers"; import { ethers, Signer, utils } from "ethers";
import { import {
// OAuthProvider, // OAuthProvider,
OAuthExtension, OAuthExtension,
@@ -17,7 +17,6 @@ import {
SDKBase, SDKBase,
} from "@magic-sdk/provider"; } from "@magic-sdk/provider";
import { Address } from "@thirdweb-dev/sdk"; import { Address } from "@thirdweb-dev/sdk";
import { getAddress } from "ethers/lib/utils";
import { Magic } from "magic-sdk"; import { Magic } from "magic-sdk";
import type { AbstractProvider } from "web3-core"; import type { AbstractProvider } from "web3-core";
import { RPCProviderModule } from "@magic-sdk/provider/dist/types/modules/rpc-provider"; import { RPCProviderModule } from "@magic-sdk/provider/dist/types/modules/rpc-provider";
@@ -102,7 +101,7 @@ export abstract class MagicBaseConnector extends WagmiConnector<
if (accounts.length === 0) { if (accounts.length === 0) {
this.emit("disconnect"); this.emit("disconnect");
} else { } else {
this.emit("change", { account: getAddress(accounts[0]) }); this.emit("change", { account: utils.getAddress(accounts[0]) });
} }
} }
@@ -8,6 +8,7 @@ import type {
AuthLoginReturnType, AuthLoginReturnType,
InitializedUser, InitializedUser,
PaperEmbeddedWalletSdk, PaperEmbeddedWalletSdk,
RecoveryShareManagement,
} from "@paperxyz/embedded-wallet-service-sdk"; } from "@paperxyz/embedded-wallet-service-sdk";
import { UserStatus } from "@paperxyz/embedded-wallet-service-sdk"; import { UserStatus } from "@paperxyz/embedded-wallet-service-sdk";
import type { Chain } from "@thirdweb-dev/chains"; import type { Chain } from "@thirdweb-dev/chains";
@@ -39,9 +40,15 @@ export class PaperWalletConnector extends Connector<PaperWalletConnectionArgs> {
"@paperxyz/embedded-wallet-service-sdk" "@paperxyz/embedded-wallet-service-sdk"
); );
resolve( resolve(
new PaperEmbeddedWalletSdk({ new PaperEmbeddedWalletSdk<RecoveryShareManagement.USER_MANAGED>({
advancedOptions: {
// @ts-expect-error - Allow passing string instead of forcing enum
recoveryShareManagement:
this.options.advancedOptions?.recoveryShareManagement,
},
clientId: this.options.clientId, clientId: this.options.clientId,
chain: "Ethereum", // just pass Ethereum no matter what chain we are going to connect chain: "Ethereum",
styles: this.options.styles,
}), }),
); );
} catch (err) { } catch (err) {
@@ -92,6 +99,7 @@ export class PaperWalletConnector extends Connector<PaperWalletConnectionArgs> {
async disconnect(): Promise<void> { async disconnect(): Promise<void> {
const paper = await this.#paper; const paper = await this.#paper;
await paper?.auth.logout(); await paper?.auth.logout();
this.#signer = undefined;
this.user = null; this.user = null;
} }
@@ -1,14 +1,26 @@
import type { Chain } from "@thirdweb-dev/chains"; import type { Chain } from "@thirdweb-dev/chains";
import type {
RecoveryShareManagement,
PaperConstructorType,
} from "@paperxyz/embedded-wallet-service-sdk";
type PaperAdvanceOptions = {
recoveryShareManagement?: "USER_MANAGED" | "AWS_MANAGED";
};
export type PaperWalletAdditionalOptions = { export type PaperWalletAdditionalOptions = {
clientId: string; clientId: string;
chain: Pick<Chain, "chainId" | "rpc">; chain: Pick<Chain, "chainId" | "rpc">;
advancedOptions?: PaperAdvanceOptions;
styles?: PaperConstructorType<RecoveryShareManagement>["styles"];
}; };
export interface PaperWalletConnectorOptions { export interface PaperWalletConnectorOptions {
clientId: string; clientId: string;
chain: Pick<Chain, "chainId" | "rpc">; chain: Pick<Chain, "chainId" | "rpc">;
chains: Chain[]; chains: Chain[];
advancedOptions?: PaperAdvanceOptions;
styles?: PaperConstructorType<RecoveryShareManagement>["styles"];
} }
export interface PaperWalletConnectionArgs { export interface PaperWalletConnectionArgs {
@@ -1,4 +1,4 @@
import { Chain } from "@thirdweb-dev/chains"; import { Chain, getChainByChainId } from "@thirdweb-dev/chains";
import { ConnectParams, Connector } from "../../interfaces/connector"; import { ConnectParams, Connector } from "../../interfaces/connector";
import { ERC4337EthersProvider } from "./lib/erc4337-provider"; import { ERC4337EthersProvider } from "./lib/erc4337-provider";
import { getVerifyingPaymaster } from "./lib/paymaster"; import { getVerifyingPaymaster } from "./lib/paymaster";
@@ -15,6 +15,7 @@ import { EVMWallet } from "../../interfaces";
import { ERC4337EthersSigner } from "./lib/erc4337-signer"; import { ERC4337EthersSigner } from "./lib/erc4337-signer";
import { BigNumber, ethers, providers } from "ethers"; import { BigNumber, ethers, providers } from "ethers";
import { import {
ChainOrRpcUrl,
getChainProvider, getChainProvider,
SmartContract, SmartContract,
Transaction, Transaction,
@@ -36,14 +37,14 @@ export class SmartWalletConnector extends Connector<SmartWalletConnectionArgs> {
async initialize(personalWallet: EVMWallet) { async initialize(personalWallet: EVMWallet) {
const config = this.config; const config = this.config;
const chain = const originalProvider = getChainProvider(config.chain, {
typeof config.chain === "string" thirdwebApiKey: config.thirdwebApiKey || DEFAULT_WALLET_API_KEY,
? config.chain }) as providers.BaseProvider;
: (config.chain as Chain).slug; const chainSlug = await this.getChainSlug(config.chain, originalProvider);
const bundlerUrl = const bundlerUrl =
this.config.bundlerUrl || `https://${chain}.bundler.thirdweb.com`; this.config.bundlerUrl || `https://${chainSlug}.bundler.thirdweb.com`;
const paymasterUrl = const paymasterUrl =
this.config.paymasterUrl || `https://${chain}.bundler.thirdweb.com`; this.config.paymasterUrl || `https://${chainSlug}.bundler.thirdweb.com`;
const entryPointAddress = config.entryPointAddress || ENTRYPOINT_ADDRESS; const entryPointAddress = config.entryPointAddress || ENTRYPOINT_ADDRESS;
const localSigner = await personalWallet.getSigner(); const localSigner = await personalWallet.getSigner();
const providerConfig: ProviderConfig = { const providerConfig: ProviderConfig = {
@@ -65,9 +66,6 @@ export class SmartWalletConnector extends Connector<SmartWalletConnectionArgs> {
accountInfo: config.accountInfo || this.defaultAccountInfo(), accountInfo: config.accountInfo || this.defaultAccountInfo(),
thirdwebApiKey: config.thirdwebApiKey, thirdwebApiKey: config.thirdwebApiKey,
}; };
const originalProvider = getChainProvider(config.chain, {
thirdwebApiKey: config.thirdwebApiKey || DEFAULT_WALLET_API_KEY,
}) as providers.BaseProvider;
this.personalWallet = personalWallet; this.personalWallet = personalWallet;
const accountApi = new AccountAPI(providerConfig, originalProvider); const accountApi = new AccountAPI(providerConfig, originalProvider);
this.aaProvider = await create4337Provider( this.aaProvider = await create4337Provider(
@@ -251,4 +249,29 @@ export class SmartWalletConnector extends Connector<SmartWalletConnectionArgs> {
}, },
}; };
} }
private async getChainSlug(
chainOrRpc: ChainOrRpcUrl,
provider: ethers.providers.Provider,
): Promise<string> {
if (typeof chainOrRpc === "object") {
return chainOrRpc.slug;
}
if (typeof chainOrRpc === "number") {
const chain = getChainByChainId(chainOrRpc);
return chain.slug;
}
if (typeof chainOrRpc === "string") {
if (chainOrRpc.startsWith("http") || chainOrRpc.startsWith("ws")) {
// if it's a url, try to get the chain id from the provider
const chainId = (await provider.getNetwork()).chainId;
const chain = getChainByChainId(chainId);
return chain.slug;
}
// otherwise its the network name
return chainOrRpc;
} else {
throw new Error(`Invalid network: ${chainOrRpc}`);
}
}
} }
@@ -1,6 +1,5 @@
import { LOCAL_NODE_PKEY, SmartContract, ThirdwebSDK } from "@thirdweb-dev/sdk"; import { LOCAL_NODE_PKEY, SmartContract, ThirdwebSDK } from "@thirdweb-dev/sdk";
import { BigNumberish, BigNumber, ethers } from "ethers"; import { BigNumberish, BigNumber, ethers, utils } from "ethers";
import { arrayify, hexConcat } from "ethers/lib/utils";
import { AccountApiParams } from "../types"; import { AccountApiParams } from "../types";
import { BaseAccountAPI } from "./base-api"; import { BaseAccountAPI } from "./base-api";
import { MINIMAL_ACCOUNT_ABI } from "./constants"; import { MINIMAL_ACCOUNT_ABI } from "./constants";
@@ -64,7 +63,7 @@ export class AccountAPI extends BaseAccountAPI {
} catch (e) { } catch (e) {
console.error("Cost to deploy smart wallet: unknown", e); console.error("Cost to deploy smart wallet: unknown", e);
} }
return hexConcat([factory.getAddress(), tx.encode()]); return utils.hexConcat([factory.getAddress(), tx.encode()]);
} }
async getFactoryContract() { async getFactoryContract() {
@@ -131,7 +130,9 @@ export class AccountAPI extends BaseAccountAPI {
} }
async signUserOpHash(userOpHash: string): Promise<string> { async signUserOpHash(userOpHash: string): Promise<string> {
return await this.params.localSigner.signMessage(arrayify(userOpHash)); return await this.params.localSigner.signMessage(
utils.arrayify(userOpHash),
);
} }
async isAcountDeployed() { async isAcountDeployed() {
@@ -1,11 +1,10 @@
import { ethers, BigNumber, BigNumberish, providers } from "ethers"; import { ethers, BigNumber, BigNumberish, providers, utils } from "ethers";
import { import {
EntryPoint, EntryPoint,
EntryPoint__factory, EntryPoint__factory,
UserOperationStruct, UserOperationStruct,
} from "@account-abstraction/contracts"; } from "@account-abstraction/contracts";
import { resolveProperties } from "ethers/lib/utils";
import { NotPromise, packUserOp } from "@account-abstraction/utils"; import { NotPromise, packUserOp } from "@account-abstraction/utils";
import { import {
GasOverheads, GasOverheads,
@@ -15,7 +14,11 @@ import {
import { TransactionDetailsForUserOp } from "./transaction-details"; import { TransactionDetailsForUserOp } from "./transaction-details";
import { getUserOpHashV06 } from "./utils"; import { getUserOpHashV06 } from "./utils";
import { DUMMY_PAYMASTER_AND_DATA, SIG_SIZE } from "./paymaster"; import { DUMMY_PAYMASTER_AND_DATA, SIG_SIZE } from "./paymaster";
import { CeloAlfajoresTestnet, CeloBaklavaTestnet, Celo } from "@thirdweb-dev/chains" import {
CeloAlfajoresTestnet,
CeloBaklavaTestnet,
Celo,
} from "@thirdweb-dev/chains";
export interface BaseApiParams { export interface BaseApiParams {
provider: providers.Provider; provider: providers.Provider;
@@ -169,7 +172,7 @@ export abstract class BaseAccountAPI {
async getPreVerificationGas( async getPreVerificationGas(
userOp: Partial<UserOperationStruct>, userOp: Partial<UserOperationStruct>,
): Promise<number> { ): Promise<number> {
const p = await resolveProperties(userOp); const p = await utils.resolveProperties(userOp);
return calcPreVerificationGas(p, this.overheads); return calcPreVerificationGas(p, this.overheads);
} }
@@ -286,7 +289,11 @@ export abstract class BaseAccountAPI {
const network = await this.provider.getNetwork(); const network = await this.provider.getNetwork();
const chainId = network.chainId; const chainId = network.chainId;
if (chainId === Celo.chainId || chainId === CeloAlfajoresTestnet.chainId || chainId === CeloBaklavaTestnet.chainId) { if (
chainId === Celo.chainId ||
chainId === CeloAlfajoresTestnet.chainId ||
chainId === CeloBaklavaTestnet.chainId
) {
maxPriorityFeePerGas = maxFeePerGas; maxPriorityFeePerGas = maxFeePerGas;
} }
} }
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-parameter-properties */ /* eslint-disable @typescript-eslint/no-parameter-properties */
import { BigNumber, providers, Signer } from "ethers"; import { BigNumber, providers, Signer, utils } from "ethers";
import { hexValue, resolveProperties } from "ethers/lib/utils";
import { import {
EntryPoint, EntryPoint,
@@ -134,7 +133,7 @@ export class ERC4337EthersProvider extends providers.BaseProvider {
async constructUserOpTransactionResponse( async constructUserOpTransactionResponse(
userOp1: UserOperationStruct, userOp1: UserOperationStruct,
): Promise<providers.TransactionResponse> { ): Promise<providers.TransactionResponse> {
const userOp = await resolveProperties(userOp1); const userOp = await utils.resolveProperties(userOp1);
const userOpHash = await this.smartAccountAPI.getUserOpHash(userOp); const userOpHash = await this.smartAccountAPI.getUserOpHash(userOp);
const waitForUserOp = async (): Promise<providers.TransactionReceipt> => const waitForUserOp = async (): Promise<providers.TransactionReceipt> =>
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
@@ -154,7 +153,7 @@ export class ERC4337EthersProvider extends providers.BaseProvider {
nonce: BigNumber.from(userOp.nonce).toNumber(), nonce: BigNumber.from(userOp.nonce).toNumber(),
gasLimit: BigNumber.from(userOp.callGasLimit), // ?? gasLimit: BigNumber.from(userOp.callGasLimit), // ??
value: BigNumber.from(0), value: BigNumber.from(0),
data: hexValue(userOp.callData), // should extract the actual called method from this "execFromEntryPoint()" call data: utils.hexValue(userOp.callData), // should extract the actual called method from this "execFromEntryPoint()" call
chainId: this.chainId, chainId: this.chainId,
wait: async ( wait: async (
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1,10 +1,9 @@
import { ethers, providers } from "ethers"; import { ethers, providers, utils } from "ethers";
import { Bytes, Signer } from "ethers"; import { Bytes, Signer } from "ethers";
import { ClientConfig } from "@account-abstraction/sdk"; import { ClientConfig } from "@account-abstraction/sdk";
import { BaseAccountAPI } from "./base-api"; import { BaseAccountAPI } from "./base-api";
import type { ERC4337EthersProvider } from "./erc4337-provider"; import type { ERC4337EthersProvider } from "./erc4337-provider";
import { defineReadOnly, Deferrable } from "ethers/lib/utils";
import { HttpRpcClient } from "./http-rpc-client"; import { HttpRpcClient } from "./http-rpc-client";
export class ERC4337EthersSigner extends Signer { export class ERC4337EthersSigner extends Signer {
@@ -23,7 +22,7 @@ export class ERC4337EthersSigner extends Signer {
smartAccountAPI: BaseAccountAPI, smartAccountAPI: BaseAccountAPI,
) { ) {
super(); super();
defineReadOnly(this, "provider", erc4337provider); utils.defineReadOnly(this, "provider", erc4337provider);
this.config = config; this.config = config;
this.originalSigner = originalSigner; this.originalSigner = originalSigner;
this.erc4337provider = erc4337provider; this.erc4337provider = erc4337provider;
@@ -35,7 +34,7 @@ export class ERC4337EthersSigner extends Signer {
// This one is called by Contract. It signs the request and passes in to Provider to be sent. // This one is called by Contract. It signs the request and passes in to Provider to be sent.
async sendTransaction( async sendTransaction(
transaction: Deferrable<providers.TransactionRequest>, transaction: utils.Deferrable<providers.TransactionRequest>,
batched: boolean = false, batched: boolean = false,
): Promise<providers.TransactionResponse> { ): Promise<providers.TransactionResponse> {
const tx = await ethers.utils.resolveProperties(transaction); const tx = await ethers.utils.resolveProperties(transaction);
@@ -138,7 +137,7 @@ export class ERC4337EthersSigner extends Signer {
async signTransaction( async signTransaction(
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
transaction: Deferrable<providers.TransactionRequest>, transaction: utils.Deferrable<providers.TransactionRequest>,
): Promise<string> { ): Promise<string> {
throw new Error("not implemented"); throw new Error("not implemented");
} }
@@ -1,5 +1,4 @@
import { providers } from "ethers"; import { providers, utils } from "ethers";
import { resolveProperties } from "ethers/lib/utils";
import { UserOperationStruct } from "@account-abstraction/contracts"; import { UserOperationStruct } from "@account-abstraction/contracts";
import { deepHexlify } from "@account-abstraction/utils"; import { deepHexlify } from "@account-abstraction/utils";
@@ -55,7 +54,7 @@ export class HttpRpcClient {
*/ */
async sendUserOpToBundler(userOp1: UserOperationStruct): Promise<string> { async sendUserOpToBundler(userOp1: UserOperationStruct): Promise<string> {
await this.initializing; await this.initializing;
const hexifiedUserOp = deepHexlify(await resolveProperties(userOp1)); const hexifiedUserOp = deepHexlify(await utils.resolveProperties(userOp1));
const jsonRequestData: [UserOperationStruct, string] = [ const jsonRequestData: [UserOperationStruct, string] = [
hexifiedUserOp, hexifiedUserOp,
this.entryPointAddress, this.entryPointAddress,
@@ -71,7 +70,7 @@ export class HttpRpcClient {
userOp1: Partial<UserOperationStruct>, userOp1: Partial<UserOperationStruct>,
): Promise<string> { ): Promise<string> {
await this.initializing; await this.initializing;
const hexifiedUserOp = deepHexlify(await resolveProperties(userOp1)); const hexifiedUserOp = deepHexlify(await utils.resolveProperties(userOp1));
const jsonRequestData: [UserOperationStruct, string] = [ const jsonRequestData: [UserOperationStruct, string] = [
hexifiedUserOp, hexifiedUserOp,
this.entryPointAddress, this.entryPointAddress,
@@ -93,7 +92,7 @@ export class HttpRpcClient {
if (!DEBUG) { if (!DEBUG) {
return; return;
} }
const userOp = await resolveProperties(userOp1); const userOp = await utils.resolveProperties(userOp1);
console.debug( console.debug(
"sending", "sending",
method, method,
@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-parameter-properties */ /* eslint-disable @typescript-eslint/no-parameter-properties */
import { BigNumberish, Event, providers } from "ethers"; import { BigNumberish, Event, providers, utils } from "ethers";
import { EntryPoint } from "@account-abstraction/contracts"; import { EntryPoint } from "@account-abstraction/contracts";
import { defaultAbiCoder } from "ethers/lib/utils";
/** /**
* This class encapsulates Ethers.js listener function and necessary UserOperation details to * This class encapsulates Ethers.js listener function and necessary UserOperation details to
@@ -92,7 +91,7 @@ export class UserOperationEventListener {
let message = revertReasonEvents[0].args.revertReason; let message = revertReasonEvents[0].args.revertReason;
if (message.startsWith("0x08c379a0")) { if (message.startsWith("0x08c379a0")) {
// Error(string) // Error(string)
message = defaultAbiCoder message = utils.defaultAbiCoder
.decode(["string"], "0x" + message.substring(10)) .decode(["string"], "0x" + message.substring(10))
.toString(); .toString();
} }
@@ -1,10 +1,5 @@
import { ethers } from "ethers"; import { ethers, utils } from "ethers";
import { UserOperationStruct } from "@account-abstraction/contracts"; import { UserOperationStruct } from "@account-abstraction/contracts";
import {
resolveProperties,
keccak256,
defaultAbiCoder,
} from "ethers/lib/utils";
export function toJSON(op: Partial<UserOperationStruct>): Promise<any> { export function toJSON(op: Partial<UserOperationStruct>): Promise<any> {
return ethers.utils.resolveProperties(op).then((userOp) => return ethers.utils.resolveProperties(op).then((userOp) =>
@@ -38,18 +33,18 @@ export async function getUserOpHashV06(
entryPoint: string, entryPoint: string,
chainId: number, chainId: number,
): Promise<Promise<string>> { ): Promise<Promise<string>> {
const op = await resolveProperties(userOp); const op = await utils.resolveProperties(userOp);
const hashedUserOp = { const hashedUserOp = {
sender: op.sender, sender: op.sender,
nonce: op.nonce, nonce: op.nonce,
initCodeHash: keccak256(op.initCode), initCodeHash: utils.keccak256(op.initCode),
callDataHash: keccak256(op.callData), callDataHash: utils.keccak256(op.callData),
callGasLimit: op.callGasLimit, callGasLimit: op.callGasLimit,
verificationGasLimit: op.verificationGasLimit, verificationGasLimit: op.verificationGasLimit,
preVerificationGas: op.preVerificationGas, preVerificationGas: op.preVerificationGas,
maxFeePerGas: op.maxFeePerGas, maxFeePerGas: op.maxFeePerGas,
maxPriorityFeePerGas: op.maxPriorityFeePerGas, maxPriorityFeePerGas: op.maxPriorityFeePerGas,
paymasterAndDataHash: keccak256(op.paymasterAndData), paymasterAndDataHash: utils.keccak256(op.paymasterAndData),
}; };
const userOpType = { const userOpType = {
@@ -68,16 +63,16 @@ export async function getUserOpHashV06(
name: "hashedUserOp", name: "hashedUserOp",
type: "tuple", type: "tuple",
}; };
let encoded = defaultAbiCoder.encode( let encoded = utils.defaultAbiCoder.encode(
[userOpType as any], [userOpType as any],
[{ ...hashedUserOp }], [{ ...hashedUserOp }],
); );
// remove leading word (total length) and trailing word (zero-length signature) // remove leading word (total length) and trailing word (zero-length signature)
const userOpHash = keccak256(encoded); const userOpHash = utils.keccak256(encoded);
const enc = defaultAbiCoder.encode( const enc = utils.defaultAbiCoder.encode(
["bytes32", "address", "uint256"], ["bytes32", "address", "uint256"],
[userOpHash, entryPoint, chainId], [userOpHash, entryPoint, chainId],
); );
return keccak256(enc); return utils.keccak256(enc);
} }
@@ -12,6 +12,8 @@ import { providers, utils } from "ethers";
import { walletIds } from "../../constants/walletIds"; import { walletIds } from "../../constants/walletIds";
import { QRModalOptions } from "./qrModalOptions"; import { QRModalOptions } from "./qrModalOptions";
const chainsToRequest = new Set([1, 137, 10, 42161, 56]);
type WalletConnectOptions = { type WalletConnectOptions = {
qrModalOptions?: QRModalOptions; qrModalOptions?: QRModalOptions;
projectId: string; projectId: string;
@@ -78,6 +80,7 @@ export class WalletConnectConnector extends WagmiConnector<
#provider?: WalletConnectProvider; #provider?: WalletConnectProvider;
#initProviderPromise?: Promise<void>; #initProviderPromise?: Promise<void>;
#storage: AsyncStorage; #storage: AsyncStorage;
filteredChains: Chain[];
constructor(config: { chains?: Chain[]; options: WalletConnectOptions }) { constructor(config: { chains?: Chain[]; options: WalletConnectOptions }) {
super({ super({
@@ -86,6 +89,13 @@ export class WalletConnectConnector extends WagmiConnector<
}); });
this.#storage = config.options.storage; this.#storage = config.options.storage;
this.#createProvider(); this.#createProvider();
this.filteredChains =
this.chains.length > 50
? this.chains.filter((c) => {
return chainsToRequest.has(c.chainId);
})
: this.chains;
} }
async connect({ chainId: chainIdP, pairingTopic }: ConnectConfig = {}) { async connect({ chainId: chainIdP, pairingTopic }: ConnectConfig = {}) {
@@ -101,7 +111,7 @@ export class WalletConnectConnector extends WagmiConnector<
if (lastUsedChainId && !this.isChainUnsupported(lastUsedChainId)) { if (lastUsedChainId && !this.isChainUnsupported(lastUsedChainId)) {
targetChainId = lastUsedChainId; targetChainId = lastUsedChainId;
} else { } else {
targetChainId = this.chains[0]?.chainId; targetChainId = this.filteredChains[0]?.chainId;
} }
} }
if (!targetChainId) { if (!targetChainId) {
@@ -120,11 +130,9 @@ export class WalletConnectConnector extends WagmiConnector<
// If there no active session, or the chains are stale, connect. // If there no active session, or the chains are stale, connect.
if (!provider.session || isChainsStale) { if (!provider.session || isChainsStale) {
// defaultChains, passing ALL CHAINS hangs the connector const optionalChains = this.filteredChains
const optionalChains = [ .filter((chain) => chain.chainId !== targetChainId)
1, 5, 84531, 137, 80001, 42161, 421613, 10, 420, 56, 97, 250, 4002, .map((optionalChain) => optionalChain.chainId);
43114, 43113, 1337,
].filter((chainId) => chainId !== targetChainId);
this.emit("message", { type: "connecting" }); this.emit("message", { type: "connecting" });
@@ -136,7 +144,7 @@ export class WalletConnectConnector extends WagmiConnector<
}); });
await this.#setRequestedChainsIds( await this.#setRequestedChainsIds(
this.chains.map(({ chainId }) => chainId), this.filteredChains.map(({ chainId }) => chainId),
); );
} }
@@ -305,7 +313,7 @@ export class WalletConnectConnector extends WagmiConnector<
OPTIONAL_EVENTS, OPTIONAL_EVENTS,
OPTIONAL_METHODS, OPTIONAL_METHODS,
} = await import("@walletconnect/ethereum-provider"); } = await import("@walletconnect/ethereum-provider");
const [defaultChain, ...optionalChains] = this.chains.map( const [defaultChain, ...optionalChains] = this.filteredChains.map(
({ chainId }) => chainId, ({ chainId }) => chainId,
); );
@@ -326,7 +334,7 @@ export class WalletConnectConnector extends WagmiConnector<
icons: [this.options.dappMetadata.logoUrl || ""], icons: [this.options.dappMetadata.logoUrl || ""],
}, },
rpcMap: Object.fromEntries( rpcMap: Object.fromEntries(
this.chains.map((chain) => [chain.chainId, chain.rpc[0]]), this.filteredChains.map((chain) => [chain.chainId, chain.rpc[0]]),
), ),
qrModalOptions: this.options.qrModalOptions, qrModalOptions: this.options.qrModalOptions,
@@ -366,7 +374,7 @@ export class WalletConnectConnector extends WagmiConnector<
} }
const requestedChains = await this.#getRequestedChainsIds(); const requestedChains = await this.#getRequestedChainsIds();
const connectorChains = this.chains.map(({ chainId }) => chainId); const connectorChains = this.filteredChains.map(({ chainId }) => chainId);
const namespaceChains = this.#getNamespaceChainsIds(); const namespaceChains = this.#getNamespaceChainsIds();
if ( if (
@@ -1,6 +1,6 @@
import { import {
PaperWalletConnectionArgs, PaperWalletConnectionArgs,
PaperWalletAdditionalOptions, PaperWalletAdditionalOptions as PaperWalletAdditionalOptions_,
} from "../connectors/paper/types"; } from "../connectors/paper/types";
import { Connector } from "../interfaces/connector"; import { Connector } from "../interfaces/connector";
import { AbstractClientWallet, WalletOptions } from "./base"; import { AbstractClientWallet, WalletOptions } from "./base";
@@ -8,10 +8,12 @@ import type { Chain } from "@thirdweb-dev/chains";
import type { PaperWalletConnector } from "../connectors/paper"; import type { PaperWalletConnector } from "../connectors/paper";
import { walletIds } from "../constants/walletIds"; import { walletIds } from "../constants/walletIds";
export type PaperWalletOptions = WalletOptions<PaperWalletAdditionalOptions>; export type { PaperWalletAdditionalOptions } from "../connectors/paper/types";
export type PaperWalletOptions = WalletOptions<PaperWalletAdditionalOptions_>;
export class PaperWallet extends AbstractClientWallet< export class PaperWallet extends AbstractClientWallet<
PaperWalletAdditionalOptions, PaperWalletAdditionalOptions_,
PaperWalletConnectionArgs PaperWalletConnectionArgs
> { > {
connector?: Connector; connector?: Connector;
@@ -28,8 +30,8 @@ export class PaperWallet extends AbstractClientWallet<
return "Paper Wallet" as const; return "Paper Wallet" as const;
} }
clientId: PaperWalletAdditionalOptions["clientId"]; clientId: PaperWalletAdditionalOptions_["clientId"];
chain: PaperWalletAdditionalOptions["chain"]; chain: PaperWalletAdditionalOptions_["chain"];
constructor(options: PaperWalletOptions) { constructor(options: PaperWalletOptions) {
super(PaperWallet.id, { super(PaperWallet.id, {
@@ -47,6 +49,11 @@ export class PaperWallet extends AbstractClientWallet<
clientId: this.clientId, clientId: this.clientId,
chain: this.chain, chain: this.chain,
chains: this.chains, chains: this.chains,
advancedOptions: {
recoveryShareManagement:
this.options?.advancedOptions?.recoveryShareManagement,
},
styles: this.options?.styles,
}); });
} }
return this.connector; return this.connector;
+236 -2352
View File
File diff suppressed because it is too large Load Diff