Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a5d2b5bdd | ||
|
|
ac3e019cd1 | ||
|
|
3c5dc4804a | ||
|
|
30ac3aef84 | ||
|
|
ef4cb09219 | ||
|
|
ad7dae3b16 | ||
|
|
0fd8aa04a9 | ||
|
|
620e89dc25 | ||
|
|
86d33c4b3e | ||
|
|
d43f6171d9 | ||
|
|
06ca1c407d | ||
|
|
c578a437cc | ||
|
|
0c5b03b8d6 | ||
|
|
9af346eead | ||
|
|
d9fb134ad4 | ||
|
|
1c7264b403 | ||
|
|
a140ee99b2 | ||
|
|
6e1fe6e582 | ||
|
|
536b0f1240 | ||
|
|
b626782b0e | ||
|
|
1d76334dd3 | ||
|
|
d498c79a91 |
@@ -1,5 +1,21 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1250](https://github.com/thirdweb-dev/js/pull/1250) [`d43f6171`](https://github.com/thirdweb-dev/js/commit/d43f6171d910e31b748b171b012174390aac3fff) Thanks [@adam-maj](https://github.com/adam-maj)! - Allow setting login payload validity duration
|
||||
|
||||
- Updated dependencies [[`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc)]:
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f)]:
|
||||
- @thirdweb-dev/wallets@0.3.3
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.2",
|
||||
"version": "3.2.4",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -25,6 +25,11 @@ export default async function handler(
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
|
||||
@@ -44,6 +44,7 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,11 @@ export default async function handler(
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
|
||||
@@ -55,6 +55,7 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1248](https://github.com/thirdweb-dev/js/pull/1248) [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - update chains
|
||||
|
||||
- [#1243](https://github.com/thirdweb-dev/js/pull/1243) [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19) Thanks [@therealharpaljadeja](https://github.com/therealharpaljadeja)! - update chains
|
||||
|
||||
## 0.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
|
||||
|
||||
## 0.1.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Optimism",
|
||||
"name": "OP Mainnet",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Horizen Yuma Testnet",
|
||||
"shortName": "Yuma",
|
||||
"chain": "Yuma",
|
||||
"icon": {
|
||||
"url": "ipfs://QmSFMBk3rMyu45Sy9KQHjgArFj4HdywANNYrSosLMUdcti",
|
||||
"width": 1213,
|
||||
"height": 1213,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://horizen-yuma-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://yuma-testnet.horizenlabs.io/ethv1"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [
|
||||
"https://yuma-testnet-faucet.horizen.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Testnet Zen",
|
||||
"symbol": "tZEN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://horizen.io/",
|
||||
"chainId": 1662,
|
||||
"networkId": 1662,
|
||||
"slip44": 121,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Yuma Testnet Block Explorer",
|
||||
"url": "https://yuma-explorer.horizen.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmSFMBk3rMyu45Sy9KQHjgArFj4HdywANNYrSosLMUdcti",
|
||||
"width": 1213,
|
||||
"height": 1213,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "horizen-yuma-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Pego Network",
|
||||
"chain": "PEGO",
|
||||
"rpc": [
|
||||
"https://pego-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://pegorpc.com",
|
||||
"https://node1.pegorpc.com",
|
||||
"https://node2.pegorpc.com",
|
||||
"https://node3.pegorpc.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Pego Native Token",
|
||||
"symbol": "PG",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://pego.network",
|
||||
"shortName": "pg",
|
||||
"chainId": 20201022,
|
||||
"networkId": 20201022,
|
||||
"icon": {
|
||||
"url": "ipfs://QmVf1afskRHuZjFSLCZH8397KrVNAoYgyAePX9VMBrPVtx",
|
||||
"width": 246,
|
||||
"height": 247,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Pego Network Explorer",
|
||||
"url": "https://scan.pego.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "pego-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Peperium Chain Testnet",
|
||||
"chain": "PERIUM",
|
||||
"rpc": [
|
||||
"https://peperium-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-testnet.peperium.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Peperium Chain Testnet",
|
||||
"symbol": "PERIUM",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://peperium.io",
|
||||
"shortName": "PERIUM",
|
||||
"chainId": 4001,
|
||||
"networkId": 4001,
|
||||
"icon": {
|
||||
"url": "ipfs://Qmag2hr5DQghRzKPN3oUFBkjWzqd5CndQzZeb5LfoiMCXf",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Peperium Chain Explorer",
|
||||
"url": "https://scan-testnet.peperium.io",
|
||||
"icon": {
|
||||
"url": "ipfs://Qmag2hr5DQghRzKPN3oUFBkjWzqd5CndQzZeb5LfoiMCXf",
|
||||
"width": 160,
|
||||
"height": 160,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "peperium-chain-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -12,15 +12,20 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://celo-alfajores-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://alfajores-forno.celo-testnet.org",
|
||||
"wss://alfajores-forno.celo-testnet.org/ws"
|
||||
"wss://alfajores-forno.celo-testnet.org/ws",
|
||||
"https://alfajores-forno.celo-testnet.org"
|
||||
],
|
||||
"faucets": [
|
||||
"https://celo.org/developers/faucet",
|
||||
"https://cauldron.pretoriaresearchlab.io/alfajores-faucet"
|
||||
"https://cauldron.pretoriaresearchlab.io/alfajores-faucet",
|
||||
"https://celo.org/developers/faucet"
|
||||
],
|
||||
"infoURL": "https://docs.celo.org/",
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Celoscan",
|
||||
"url": "https://alfajores.celoscan.io/",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Celoscan",
|
||||
"url": "https://celoscan.io",
|
||||
|
||||
@@ -5,7 +5,8 @@ export default {
|
||||
"rpc": [
|
||||
"https://rollux.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.rollux.com",
|
||||
"wss://rpc.rollux.com/wss"
|
||||
"wss://rpc.rollux.com/wss",
|
||||
"https://rpc.ankr.com/rollux/${ANKR_API_KEY}"
|
||||
],
|
||||
"faucets": [
|
||||
"https://rollux.id/faucetapp"
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ETC",
|
||||
"rpc": [
|
||||
"https://ethereum-classic.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://www.ethercluster.com/etc"
|
||||
"https://etc.rivet.link"
|
||||
],
|
||||
"faucets": [
|
||||
"https://free-online-app.com/faucet-for-eth-evm-chains/?"
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ETC",
|
||||
"rpc": [
|
||||
"https://ethereum-classic-testnet-mordor.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://www.ethercluster.com/mordor"
|
||||
"https://rpc.mordor.etccooperative.org"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-check
|
||||
/** @typedef { import("../../src/types").Chain } Chain */
|
||||
|
||||
/** @type {Partial<Chain>} */
|
||||
export default {
|
||||
explorers: [
|
||||
{
|
||||
name: "Celoscan",
|
||||
url: "https://alfajores.celoscan.io/",
|
||||
standard: "EIP3091",
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.23",
|
||||
"version": "0.1.25",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -146,6 +146,10 @@ function findSlug(chain) {
|
||||
if (slug === "base-goerli-testnet") {
|
||||
slug = "base-goerli";
|
||||
}
|
||||
// optimisim rename handling
|
||||
if (slug === "op") {
|
||||
slug = "optimism";
|
||||
}
|
||||
// end special cases
|
||||
|
||||
takenSlugs[slug] = true;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,24 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.10.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.10.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1240](https://github.com/thirdweb-dev/js/pull/1240) [`1c7264b4`](https://github.com/thirdweb-dev/js/commit/1c7264b40330d068ece67df537a0f5db0f6aedca) Thanks [@Marfuen](https://github.com/Marfuen)! - Small bug fix for updating packages using --nightly
|
||||
|
||||
- Updated dependencies [[`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/sdk@3.10.25
|
||||
- @thirdweb-dev/storage@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.24
|
||||
|
||||
## 0.10.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.10.25",
|
||||
"version": "0.10.27",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as toml from "@iarna/toml";
|
||||
import { PackageManagerType } from "../core/types/ProjectType";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import path from "path";
|
||||
import { PackageManagerType } from "../core/types/ProjectType";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { IProcessAppTypeArgs, IProcessContractAppTypeArgs } from "./types";
|
||||
|
||||
export function convertDependenciesToStringFormat(dependenciesObject: object) {
|
||||
@@ -174,7 +174,7 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
case "npm":
|
||||
runner = "npm";
|
||||
installCommand = ["install"];
|
||||
updateCommand = ["update"]
|
||||
updateCommand = ["install", "--legacy-peer-deps"]
|
||||
break;
|
||||
case "yarn":
|
||||
runner = "yarn";
|
||||
@@ -223,7 +223,7 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
}
|
||||
|
||||
if (typeOfAction === "install") {
|
||||
if (!dependenciesToAdd.length) {return;}
|
||||
if (!dependenciesToAdd.length) { return; }
|
||||
const commands = [...installCommand, ...dependenciesToAdd];
|
||||
|
||||
await runCommand(runner, commands, printLogs);
|
||||
@@ -233,7 +233,7 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
}
|
||||
}
|
||||
if (typeOfAction === "update") {
|
||||
if (!dependenciesToUpdate.length) {return;}
|
||||
if (!dependenciesToUpdate.length) { return; }
|
||||
const commands = [...updateCommand, ...dependenciesToUpdate];
|
||||
await runCommand(runner, commands, printLogs);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
|
||||
|
||||
## 1.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.3.6",
|
||||
"version": "1.3.7",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"browser": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/contracts": "3.5.8"
|
||||
"@thirdweb-dev/contracts": "3.5.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 3.14.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1227](https://github.com/thirdweb-dev/js/pull/1227) [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b) Thanks [@nkrishang](https://github.com/nkrishang)! - Add react hooks for smart wallet
|
||||
|
||||
- [#1248](https://github.com/thirdweb-dev/js/pull/1248) [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Export account hooks
|
||||
|
||||
- [#1253](https://github.com/thirdweb-dev/js/pull/1253) [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6) Thanks [@rattrayd11](https://github.com/rattrayd11)! - Stop using useActiveChain deprecated hook
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.14.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1235](https://github.com/thirdweb-dev/js/pull/1235) [`1d76334d`](https://github.com/thirdweb-dev/js/commit/1d76334dd3884703629835422f241d2825128f6f) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix required type for address on useSmartWalletsForAddress
|
||||
|
||||
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f), [`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/wallets@0.3.3
|
||||
- @thirdweb-dev/sdk@3.10.25
|
||||
- @thirdweb-dev/storage@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.24
|
||||
|
||||
## 3.14.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.2",
|
||||
"version": "3.14.4",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -113,10 +113,6 @@
|
||||
"ethers": ">=5.5.1",
|
||||
"react": ">=18.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ansi-regex": "^6.0.1",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Chain, defaultChains } from "@thirdweb-dev/chains";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useActiveChain, useChainId } from "../../evm/hooks/wallet";
|
||||
import { useChain, useChainId } from "../../evm/hooks/wallet";
|
||||
import { useSupportedChains } from "../../evm/hooks/useSupportedChains";
|
||||
import { useSwitchChain, useWallet } from "./wallet-hooks";
|
||||
import { assertWindowEthereum, walletIds } from "@thirdweb-dev/wallets";
|
||||
@@ -29,7 +29,7 @@ type NetworkMetadata = {
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated - use `useActiveChain`, `useSwitchChain`, `useChainId` instead
|
||||
* @deprecated - use `useChain`, `useSwitchChain`, `useChainId` instead
|
||||
*
|
||||
* Hook for getting metadata about the network the current wallet is connected to and switching networks
|
||||
*
|
||||
@@ -55,7 +55,7 @@ type NetworkMetadata = {
|
||||
* @public
|
||||
*/
|
||||
export function useNetwork(): [NetworkMetadata, SwitchNetwork | undefined] {
|
||||
const chain = useActiveChain();
|
||||
const chain = useChain();
|
||||
const chainId = useChainId();
|
||||
const switchChain = useSwitchChain();
|
||||
const supportedChains = useSupportedChains();
|
||||
|
||||
@@ -504,7 +504,7 @@ export function useEnglishAuctionWinningBid(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getWinningBid(
|
||||
cacheKeys.contract.marketplace.englishAuctions.getWinningBid(
|
||||
contractAddress,
|
||||
auctionId,
|
||||
),
|
||||
@@ -596,7 +596,7 @@ export function useBidBuffer(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getBidBufferBps(contractAddress),
|
||||
cacheKeys.contract.marketplace.auction.getBidBufferBps(contractAddress, listingId),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
@@ -647,7 +647,7 @@ export function useMinimumNextBid(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getWinner(
|
||||
cacheKeys.contract.marketplace.auction.getMinimumNextBid(
|
||||
contractAddress,
|
||||
listingId,
|
||||
),
|
||||
|
||||
@@ -14,14 +14,10 @@ import {
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
AccountEvent, AddressOrEns, SmartContract,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import type { AccountEvent, SmartContract } from "@thirdweb-dev/sdk";
|
||||
import type { BytesLike } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
@@ -41,7 +37,7 @@ import invariant from "tiny-invariant";
|
||||
* @beta
|
||||
*/
|
||||
export function useSmartWallets(
|
||||
contract: RequiredParam<SmartContract>
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<AccountEvent[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
@@ -49,10 +45,10 @@ export function useSmartWallets(
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.smartWalletFactory.getAllWallets,
|
||||
"Contract instance does not support contract.smartWalletFactory.getAllWallets",
|
||||
contract.smartWalletFactory.getAllAccounts,
|
||||
"Contract instance does not support contract.smartWalletFactory.getAllAccounts",
|
||||
);
|
||||
return contract.smartWalletFactory.getAllWallets();
|
||||
return contract.smartWalletFactory.getAllAccounts();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
@@ -74,18 +70,21 @@ export function useSmartWallets(
|
||||
*/
|
||||
export function useSmartWalletsForAddress(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
address: AddressOrEns,
|
||||
address: RequiredParam<WalletAddress>,
|
||||
): UseQueryResult<string[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWalletFactory.getAllForAddress(contractAddress, address),
|
||||
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);
|
||||
return contract.smartWalletFactory.getAssociatedWallets(address || "");
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
@@ -112,7 +111,10 @@ export function useIsSmartWalletDeployed(
|
||||
): UseQueryResult<boolean> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWalletFactory.isSmartWalletDeployed(contractAddress, admin),
|
||||
cacheKeys.contract.smartWalletFactory.isSmartWalletDeployed(
|
||||
contractAddress,
|
||||
admin,
|
||||
),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
@@ -163,9 +165,7 @@ export function useIsSmartWalletDeployed(
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usecreatesmartwallet?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useCreateSmartWallet(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
) {
|
||||
export function useCreateSmartWallet(contract: RequiredParam<SmartContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
@@ -174,10 +174,7 @@ export function useCreateSmartWallet(
|
||||
async (admin: string, extraData?: BytesLike) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.smartWalletFactory.createWallet(
|
||||
admin,
|
||||
extraData,
|
||||
);
|
||||
return contract.smartWalletFactory.createWallet(admin, extraData);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { providers } from "ethers";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import {
|
||||
useMutation,
|
||||
UseMutationResult,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
SignerWithRestrictions,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
SmartContract,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Get all wallets
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: smartWallets, isLoading, error } = useSmartWalletSigners(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet
|
||||
* @returns a response object that includes an array of all signers of the provided smart wallet
|
||||
* @twfeature SmartWallet
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesmartwalletsigners?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSmartWalletSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<SignerWithRestrictions[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWallet.signers(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.smartWallet.getSignersWithRestrictions,
|
||||
"Contract instance does not support contract.smartWallet.getSignersWithRestrictions",
|
||||
);
|
||||
return contract.smartWallet.getSignersWithRestrictions();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
/**
|
||||
* Set the wallet's entire snapshot of permissions
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract("{{contract_address}}");
|
||||
* const {
|
||||
* mutate: setSmartWalletSigners,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useSetSmartWalletSigners(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to set smart wallet signers", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => setSmartWalletSigners("0x...")}
|
||||
* >
|
||||
* Set Smart Wallet Signers
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet contract
|
||||
* @returns a mutation object that can be used to set the smart wallet signers
|
||||
* @twfeature SmartWallet
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesetsmartwalletsigners?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSetSmartWalletSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseMutationResult<
|
||||
{ receipt: providers.TransactionReceipt },
|
||||
unknown,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
unknown
|
||||
> {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
async (permissionsSnapshot: SignerWithRestrictionsBatchInput) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.smartWallet.setAccess(permissionsSnapshot);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
invalidateContractAndBalances(
|
||||
queryClient,
|
||||
contractAddress,
|
||||
activeChainId,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -202,6 +202,12 @@ export {
|
||||
useSmartWalletsForAddress,
|
||||
} from "./hooks/async/smart-wallet-factory";
|
||||
|
||||
// smart wallet
|
||||
export {
|
||||
useSmartWalletSigners,
|
||||
useSetSmartWalletSigners,
|
||||
} from "./hooks/async/smart-wallet";
|
||||
|
||||
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
|
||||
|
||||
// auth hooks
|
||||
|
||||
@@ -127,6 +127,11 @@ export const cacheKeys = {
|
||||
createContractCacheKey(contractAdress, ["getAllForAddress", address]),
|
||||
},
|
||||
|
||||
smartWallet: {
|
||||
signers: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["smartWallet", "signers"]),
|
||||
},
|
||||
|
||||
app: {
|
||||
get: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["appURI"]),
|
||||
@@ -273,10 +278,16 @@ export const cacheKeys = {
|
||||
contractAddress,
|
||||
params ? ["getActiveListings", params] : ["getActiveListings"],
|
||||
),
|
||||
getBidBufferBps: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["getBidBufferBps"]),
|
||||
|
||||
auction: {
|
||||
getBidBufferBps: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"auction",
|
||||
"getBidBufferBps",
|
||||
{ listingId },
|
||||
]),
|
||||
getWinningBid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
@@ -286,6 +297,15 @@ export const cacheKeys = {
|
||||
"getWinningBid",
|
||||
{ listingId },
|
||||
]),
|
||||
getMinimumNextBid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"auction",
|
||||
"getMinimumNextBid",
|
||||
{ listingId },
|
||||
]),
|
||||
getWinner: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
@@ -305,8 +325,8 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllDirectListings", params]
|
||||
: ["getAllDirectListings"],
|
||||
? ["directListings", "getAll", params]
|
||||
: ["directListings", "getAll"],
|
||||
),
|
||||
getAllValid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
@@ -315,20 +335,22 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllValidDirectListings", params]
|
||||
: ["getAllValidDirectListings"],
|
||||
? ["directListings", "getAllValid", params]
|
||||
: ["directListings", "getAllValid"],
|
||||
),
|
||||
getListing: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"directListings",
|
||||
"getListing",
|
||||
{ listingId },
|
||||
]),
|
||||
getTotalCount: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"getTotalDirectListingsCount",
|
||||
"directListings",
|
||||
"getTotalCount",
|
||||
]),
|
||||
},
|
||||
|
||||
@@ -340,8 +362,8 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllEnglishAuctions", params]
|
||||
: ["getAllEnglishAuctions"],
|
||||
? ["englishAuctions", "getAll", params]
|
||||
: ["englishAuctions", "getAll"],
|
||||
),
|
||||
getAllValid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
@@ -350,14 +372,15 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllEValidEnglishAuctions", params]
|
||||
: ["getAllEValidEnglishAuctions"],
|
||||
? ["englishAuctions", "getAllValid", params]
|
||||
: ["englishAuctions", "getAllValid"],
|
||||
),
|
||||
getAuction: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
auctionId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"englishAuctions",
|
||||
"getAuction",
|
||||
{ auctionId },
|
||||
]),
|
||||
@@ -366,12 +389,14 @@ export const cacheKeys = {
|
||||
auctionId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"englishAuctions",
|
||||
"getWinningBid",
|
||||
{ auctionId },
|
||||
]),
|
||||
getTotalCount: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"getTotalEnglishAuctionsCount",
|
||||
"englishAuctions",
|
||||
"getTotalCount",
|
||||
]),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.23
|
||||
|
||||
## 0.2.22
|
||||
|
||||
## 0.2.21
|
||||
|
||||
## 0.2.20
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.21",
|
||||
"version": "0.2.23",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,62 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.2.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1215](https://github.com/thirdweb-dev/js/pull/1215) [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc) Thanks [@iketw](https://github.com/iketw)! - Migrate wallets to WCV2 and remove WCV1 support.
|
||||
|
||||
Please, check our changelogs for more info: https://blog.thirdweb.com/changelog/
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/react-core@3.14.4
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1245](https://github.com/thirdweb-dev/js/pull/1245) [`d9fb134a`](https://github.com/thirdweb-dev/js/commit/d9fb134ad40ae067416625eb43cf3708f87db7b5) Thanks [@iketw](https://github.com/iketw)! - [RN]
|
||||
|
||||
- Added the option to import a new wallet in guest mode
|
||||
|
||||
- Added a "Request Testnet Funds" option when on testnets
|
||||
|
||||
- [#1245](https://github.com/thirdweb-dev/js/pull/1245) [`d9fb134a`](https://github.com/thirdweb-dev/js/commit/d9fb134ad40ae067416625eb43cf3708f87db7b5) Thanks [@iketw](https://github.com/iketw)! - [ReactNative] Export more components for easy development
|
||||
|
||||
- IconTextButton
|
||||
Component that renders an icon and a text inside a button with border:
|
||||
|
||||
```javascript
|
||||
<IconTextButton
|
||||
mt="xs"
|
||||
text="Switch Accounts"
|
||||
icon={<SwitchIcon height={10} width={10} />}
|
||||
onPress={() => {}}
|
||||
/>
|
||||
```
|
||||
|
||||
- NetworkButton: Used to render a Network
|
||||
|
||||
```javascript
|
||||
<NetworkButton
|
||||
chainIconUrl={chain?.icon?.url || ""}
|
||||
chainName={chain?.name || "Unknown Network"}
|
||||
onPress={onChangeNetworkPress}
|
||||
/>
|
||||
```
|
||||
|
||||
- Exported all icons from the assets folder for external use
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`1d76334d`](https://github.com/thirdweb-dev/js/commit/1d76334dd3884703629835422f241d2825128f6f), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f), [`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.2.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.21",
|
||||
"version": "0.2.23",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -44,10 +44,6 @@
|
||||
"react-native-svg": "^13.8.0",
|
||||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"react-native-mmkv": "2.5.1",
|
||||
"@magic-sdk/provider": "17.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.1.6",
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { ThemeProvider } from "../styles/ThemeProvider";
|
||||
import { WalletDetailsButton } from "./ConnectWalletDetails/WalletDetailsButton";
|
||||
import {
|
||||
ConnectWalletDetailsProps,
|
||||
WalletDetailsButton,
|
||||
} from "./ConnectWalletDetails/WalletDetailsButton";
|
||||
import { useAddress } from "@thirdweb-dev/react-core";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Animated } from "react-native";
|
||||
import { ConnectWalletButton } from "./ConnectWalletFlow/ConnectWalletButton";
|
||||
import { ConnectWalletButtonProps } from "./ConnectWalletFlow/ConnectWalletButton";
|
||||
@@ -10,7 +13,7 @@ export type ConnectWalletProps = {
|
||||
/**
|
||||
* render a custom button to display the connected wallet details instead of the default button
|
||||
*/
|
||||
detailsButton?: React.ReactElement;
|
||||
detailsButton?: ConnectWalletDetailsProps["detailsButton"];
|
||||
} & ConnectWalletButtonProps;
|
||||
|
||||
export const ConnectWallet = ({
|
||||
|
||||
+15
-1
@@ -1,4 +1,4 @@
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { Linking, StyleSheet, View } from "react-native";
|
||||
import Box from "../base/Box";
|
||||
import { Toast } from "../base/Toast";
|
||||
import { ExportLocalWalletModal } from "./ExportLocalWalletModal";
|
||||
@@ -22,6 +22,8 @@ import { useModalState } from "../../providers/ui-context-provider";
|
||||
import { CLOSE_MODAL_STATE, WalletDetailsModal } from "../../utils/modalTypes";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { LocalWalletImportModal } from "../ConnectWalletFlow/LocalWalletImportModal";
|
||||
import { IconTextButton } from "../base/IconTextButton";
|
||||
import MoneyIcon from "../../assets/money";
|
||||
|
||||
export const ConnectWalletDetailsModal = () => {
|
||||
const theme = useAppTheme();
|
||||
@@ -192,6 +194,18 @@ export const ConnectWalletDetailsModal = () => {
|
||||
chainName={chain?.name || "Unknown Network"}
|
||||
onPress={onChangeNetworkPress}
|
||||
/>
|
||||
{chain?.testnet && chain?.faucets?.length ? (
|
||||
<IconTextButton
|
||||
mt="xs"
|
||||
text="Request Testnet Funds"
|
||||
icon={<MoneyIcon height={10} width={10} />}
|
||||
onPress={() => {
|
||||
if (chain?.faucets?.[0]) {
|
||||
Linking.openURL(chain.faucets[0]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{getAdditionalActions()}
|
||||
{addressCopied === true ? (
|
||||
<Toast text={"Address copied to clipboard"} />
|
||||
|
||||
+14
-15
@@ -3,8 +3,7 @@ import BaseButton from "../base/BaseButton";
|
||||
import { ChainIcon } from "../base/ChainIcon";
|
||||
import Text from "../base/Text";
|
||||
import { WalletIcon } from "../base/WalletIcon";
|
||||
import { useWallet, useBalance } from "@thirdweb-dev/react-core";
|
||||
import { useActiveChain } from "@thirdweb-dev/react-core/evm";
|
||||
import { useWallet, useBalance, useChain } from "@thirdweb-dev/react-core";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { LocalWallet } from "@thirdweb-dev/wallets";
|
||||
import { useModalState } from "../../providers/ui-context-provider";
|
||||
@@ -12,7 +11,7 @@ import Box from "../base/Box";
|
||||
|
||||
export type ConnectWalletDetailsProps = {
|
||||
address: string;
|
||||
detailsButton?: React.ReactElement;
|
||||
detailsButton?: React.FC<{ onPress: () => void }>;
|
||||
};
|
||||
|
||||
export const WalletDetailsButton = ({
|
||||
@@ -20,7 +19,7 @@ export const WalletDetailsButton = ({
|
||||
detailsButton,
|
||||
}: ConnectWalletDetailsProps) => {
|
||||
const activeWallet = useWallet();
|
||||
const chain = useActiveChain();
|
||||
const chain = useChain();
|
||||
const balanceQuery = useBalance();
|
||||
const { setModalState } = useModalState();
|
||||
|
||||
@@ -38,15 +37,15 @@ export const WalletDetailsButton = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseButton
|
||||
backgroundColor="background"
|
||||
borderColor="border"
|
||||
style={styles.walletDetails}
|
||||
onPress={onPress}
|
||||
>
|
||||
{detailsButton ? (
|
||||
detailsButton
|
||||
) : (
|
||||
{detailsButton ? (
|
||||
detailsButton({ onPress })
|
||||
) : (
|
||||
<BaseButton
|
||||
backgroundColor="background"
|
||||
borderColor="border"
|
||||
style={styles.walletDetails}
|
||||
onPress={onPress}
|
||||
>
|
||||
<Box flex={1} flexDirection="row" justifyContent="space-between">
|
||||
<ChainIcon size={32} chainIconUrl={chain?.icon?.url} />
|
||||
<Box justifyContent="center" alignItems="flex-start">
|
||||
@@ -70,8 +69,8 @@ export const WalletDetailsButton = ({
|
||||
iconUri={activeWallet?.getMeta().iconURL || ""}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</BaseButton>
|
||||
</BaseButton>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@ export { localWallet } from "./wallets/wallets/local-wallet";
|
||||
export { LocalWallet } from "./wallets/wallets/LocalWallet";
|
||||
export { magicWallet } from "./wallets/wallets/magic-wallet";
|
||||
export { MagicWallet } from "./wallets/wallets/MagicWallet";
|
||||
export * from "./wallets/wallets/WalletConnectV1";
|
||||
export * from "./wallets/wallets/WalletConnectV2";
|
||||
export type { WCMeta } from "./wallets/types/wc";
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import {
|
||||
WalletOptions,
|
||||
WalletConnectV1Options,
|
||||
WalletConnectV1 as WalletConnectV1Wallets,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { formatWalletConnectDisplayUri } from "../../utils/uri";
|
||||
import { Linking } from "react-native";
|
||||
import { ExtraCoreWalletOptions } from "@thirdweb-dev/react-core";
|
||||
import { WCMeta } from "../types/wc";
|
||||
import { createAsyncLocalStorage } from "../../../core/AsyncStorage";
|
||||
|
||||
export type WC1Options = Omit<
|
||||
WalletOptions<WalletConnectV1Options>,
|
||||
"qrcode" | "walletId"
|
||||
> &
|
||||
ExtraCoreWalletOptions & {
|
||||
walletId: NonNullable<WalletOptions["walletId"]>;
|
||||
};
|
||||
|
||||
export abstract class WalletConnectV1 extends WalletConnectV1Wallets {
|
||||
constructor(options: WC1Options) {
|
||||
super({
|
||||
...options,
|
||||
walletId: options.walletId,
|
||||
walletStorage:
|
||||
options.walletStorage || createAsyncLocalStorage(options.walletId),
|
||||
qrcode: false,
|
||||
});
|
||||
|
||||
this.on("open_wallet", this._onWCOpenWallet);
|
||||
|
||||
this.on("disconnect", () => {
|
||||
this.removeListener("open_wallet", this._onWCOpenWallet);
|
||||
});
|
||||
}
|
||||
|
||||
abstract getMeta(): WCMeta;
|
||||
|
||||
_onWCOpenWallet(uri?: string) {
|
||||
const links = this.getMeta().links;
|
||||
|
||||
if (uri) {
|
||||
const fullUrl = formatWalletConnectDisplayUri(uri, links);
|
||||
|
||||
Linking.openURL(fullUrl);
|
||||
} else {
|
||||
const fullUrl = formatWalletConnectDisplayUri("", links);
|
||||
|
||||
Linking.openURL(fullUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnectV1 } from "./WalletConnectV1";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WCMeta } from "../types/wc";
|
||||
|
||||
export class MetaMaskWallet extends WalletConnectV1 {
|
||||
export class MetaMaskWallet extends WalletConnectV2 {
|
||||
static id = walletIds.metamask;
|
||||
static meta = {
|
||||
name: "MetaMask",
|
||||
@@ -20,11 +20,17 @@ export class MetaMaskWallet extends WalletConnectV1 {
|
||||
}
|
||||
}
|
||||
|
||||
export const metamaskWallet = () => {
|
||||
type MetaMaskWalletConfig = { projectId?: string };
|
||||
|
||||
export const metamaskWallet = (config?: MetaMaskWalletConfig) => {
|
||||
return {
|
||||
id: MetaMaskWallet.id,
|
||||
meta: MetaMaskWallet.meta,
|
||||
create: (options: WalletOptions) =>
|
||||
new MetaMaskWallet({ ...options, walletId: walletIds.metamask }),
|
||||
new MetaMaskWallet({
|
||||
...options,
|
||||
walletId: walletIds.metamask,
|
||||
projectId: config?.projectId,
|
||||
}),
|
||||
} satisfies WalletConfig;
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import {
|
||||
WalletOptions as WalletOptionsRC,
|
||||
WalletConfig,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { WalletConnectV1 } from "./WalletConnectV1";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
|
||||
export class RainbowWallet extends WalletConnectV1 {
|
||||
export class RainbowWallet extends WalletConnectV2 {
|
||||
static id = "rainbow" as const;
|
||||
static meta = {
|
||||
name: "Rainbow",
|
||||
@@ -21,11 +21,17 @@ export class RainbowWallet extends WalletConnectV1 {
|
||||
}
|
||||
}
|
||||
|
||||
export const rainbowWallet = () => {
|
||||
type RainbowWalletConfig = { projectId?: string };
|
||||
|
||||
export const rainbowWallet = (config?: RainbowWalletConfig) => {
|
||||
return {
|
||||
id: RainbowWallet.id,
|
||||
meta: RainbowWallet.meta,
|
||||
create: (options: WalletOptionsRC) =>
|
||||
new RainbowWallet({ ...options, walletId: RainbowWallet.id }),
|
||||
new RainbowWallet({
|
||||
...options,
|
||||
walletId: RainbowWallet.id,
|
||||
projectId: config?.projectId,
|
||||
}),
|
||||
} satisfies WalletConfig;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WC2Options, WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WCMeta } from "../types/wc";
|
||||
|
||||
export class TrustWallet extends WalletConnectV2 {
|
||||
@@ -14,10 +14,6 @@ export class TrustWallet extends WalletConnectV2 {
|
||||
},
|
||||
};
|
||||
|
||||
constructor(options: WC2Options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
getMeta(): WCMeta {
|
||||
return TrustWallet.meta;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.14.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1215](https://github.com/thirdweb-dev/js/pull/1215) [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc) Thanks [@iketw](https://github.com/iketw)! - Migrate wallets to WCV2 and remove WCV1 support.
|
||||
|
||||
Please, check our changelogs for more info: https://blog.thirdweb.com/changelog/
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/react-core@3.14.4
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.14.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1238](https://github.com/thirdweb-dev/js/pull/1238) [`6e1fe6e5`](https://github.com/thirdweb-dev/js/commit/6e1fe6e582d4178884fc1793b330a9e477df5b4d) Thanks [@iketw](https://github.com/iketw)! - '[React] Adds Rainbow and Trust wallets hooks'
|
||||
|
||||
```javascript
|
||||
import { useRainbowWallet, useTrustWallet } from "@thirdweb-dev/react";
|
||||
|
||||
const connectWithRainbow = useRainbowWallet();
|
||||
|
||||
const connectWithTrust = useTrustWallet();
|
||||
```
|
||||
|
||||
- [#1237](https://github.com/thirdweb-dev/js/pull/1237) [`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b) Thanks [@iketw](https://github.com/iketw)! - [React] Add Rainbow Wallet (implementing the WalletConnect wallet)
|
||||
|
||||
```javascript
|
||||
import { ThirdwebProvider, rainbowWallet } from "@thirdweb-dev/react";
|
||||
|
||||
const activeChain = "ethereum";
|
||||
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
supportedWallets={[rainbowWallet()]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>;
|
||||
```
|
||||
|
||||
- [#1236](https://github.com/thirdweb-dev/js/pull/1236) [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f) Thanks [@iketw](https://github.com/iketw)! - [Wallets/React] Add Trust Wallet
|
||||
|
||||
```javascript
|
||||
import { ThirdwebProvider, trustWallet } from "@thirdweb-dev/react";
|
||||
|
||||
const activeChain = "mumbai";
|
||||
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
autoSwitch={true}
|
||||
supportedWallets={[trustWallet()]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>;
|
||||
```
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`1d76334d`](https://github.com/thirdweb-dev/js/commit/1d76334dd3884703629835422f241d2825128f6f), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f), [`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 3.14.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.14.2",
|
||||
"version": "3.14.4",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -153,10 +153,6 @@
|
||||
"react": ">=18.0.0",
|
||||
"react-dom": ">=18.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ansi-regex": "^6.0.1",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/wallet-adapter-base": {
|
||||
"optional": true
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useConnect } from "@thirdweb-dev/react-core";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export function useRainbowWallet() {
|
||||
const connect = useConnect();
|
||||
return useCallback(
|
||||
async (connectOptions?: { chainId?: number }) => {
|
||||
const { rainbowWallet } = await import(
|
||||
"../../../wallet/wallets/rainbow/RainbowWallet"
|
||||
);
|
||||
return connect(rainbowWallet(), connectOptions);
|
||||
},
|
||||
[connect],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useConnect } from "@thirdweb-dev/react-core";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export function useTrustWallet() {
|
||||
const connect = useConnect();
|
||||
return useCallback(
|
||||
async (connectOptions?: { chainId?: number }) => {
|
||||
const { trustWallet } = await import(
|
||||
"../../../wallet/wallets/trustWallet/TrustWallet"
|
||||
);
|
||||
return connect(trustWallet(), connectOptions);
|
||||
},
|
||||
[connect],
|
||||
);
|
||||
}
|
||||
@@ -20,6 +20,8 @@ export { ThirdwebProvider } from "./providers/thirdweb-provider";
|
||||
export { useInstalledWallets } from "../wallet/hooks/useInstalledWallets";
|
||||
|
||||
// wallet connection hooks
|
||||
export { useRainbowWallet } from "./hooks/wallets/useRainbowWallet";
|
||||
export { useTrustWallet } from "./hooks/wallets/useTrustWallet";
|
||||
export { useMetamask } from "./hooks/wallets/useMetamask";
|
||||
export { useCoinbaseWallet } from "./hooks/wallets/useCoinbaseWallet";
|
||||
export { useFrameWallet } from "./hooks/wallets/useFrame";
|
||||
|
||||
@@ -18,15 +18,15 @@ interface ThirdwebProviderProps<TChains extends Chain[]>
|
||||
"createWalletStorage" | "supportedWallets"
|
||||
> {
|
||||
/**
|
||||
* Wallets that will be supported by the dApp
|
||||
* @defaultValue [metamaskWallet(), coinbaseWallet(), walletConnectV1()]
|
||||
* Wallets supported by the dApp
|
||||
* @defaultValue `[ metamaskWallet(), coinbaseWallet(), walletConnect() ]`
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { metamaskWallet, coinbaseWallet, walletConnectV1 } from "@thirdweb-dev/react";
|
||||
* import { metamaskWallet, coinbaseWallet, walletConnect } from "@thirdweb-dev/react";
|
||||
*
|
||||
* <ThirdwebProvider
|
||||
* supportedWallets={[metamaskWallet(), coinbaseWallet(), walletConnectV1()]}
|
||||
* supportedWallets={[metamaskWallet(), coinbaseWallet(), walletConnect()]}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,9 @@ export { coinbaseWallet } from "./wallet/wallets/coinbase/coinbaseWallet";
|
||||
export { frameWallet } from "./wallet/wallets/frame/frameWallet";
|
||||
export { metamaskWallet } from "./wallet/wallets/metamask/metamaskWallet";
|
||||
export { paperWallet } from "./wallet/wallets/paperWallet";
|
||||
export { rainbowWallet } from "./wallet/wallets/rainbow/RainbowWallet";
|
||||
export { safeWallet } from "./wallet/wallets/safe/safeWallet";
|
||||
export { trustWallet } from "./wallet/wallets/trustWallet/TrustWallet";
|
||||
export { walletConnect } from "./wallet/wallets/walletConnect";
|
||||
export { walletConnectV1 } from "./wallet/wallets/walletConnectV1";
|
||||
export { smartWallet } from "./wallet/wallets/smartWallet/smartWallet";
|
||||
|
||||
@@ -385,6 +385,17 @@ const NetworkList = /* @__PURE__ */ memo(function NetworkList(props: {
|
||||
const [switchingChainId, setSwitchingChainId] = useState(-1);
|
||||
const [errorSwitchingChainId, setErrorSwitchingChainId] = useState(-1);
|
||||
|
||||
const close = props.close;
|
||||
|
||||
useEffect(() => {
|
||||
// if switching and switched successfully - close modal
|
||||
if (switchingChainId !== -1 && activeChainId === switchingChainId) {
|
||||
if (close) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}, [switchingChainId, close, activeChainId]);
|
||||
|
||||
const handleSwitch = async (chain: Chain) => {
|
||||
setErrorSwitchingChainId(-1);
|
||||
setSwitchingChainId(chain.chainId);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
export function useInstalledWallets() {
|
||||
let isMetamaskInstalled = false;
|
||||
let isCoinbaseWalletInstalled = false;
|
||||
let isTrustWalletInstalled: boolean | undefined = false;
|
||||
|
||||
if (assertWindowEthereum(globalThis.window)) {
|
||||
isMetamaskInstalled = globalThis.window.ethereum?.isMetaMask;
|
||||
@@ -10,11 +11,13 @@ export function useInstalledWallets() {
|
||||
globalThis.window.ethereum?.isCoinbaseWallet ||
|
||||
globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet) ||
|
||||
false;
|
||||
isTrustWalletInstalled = globalThis.window.ethereum?.isTrust;
|
||||
}
|
||||
|
||||
const installedWallets = {
|
||||
metamask: !!isMetamaskInstalled,
|
||||
coinbaseWallet: !!isCoinbaseWalletInstalled,
|
||||
trustWallet: !!isTrustWalletInstalled,
|
||||
};
|
||||
|
||||
return installedWallets;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { coinbaseWallet } from "./coinbase/coinbaseWallet";
|
||||
import { metamaskWallet } from "./metamask/metamaskWallet";
|
||||
import { walletConnectV1 } from "./walletConnectV1";
|
||||
import { walletConnect } from "./walletConnect";
|
||||
|
||||
export const defaultWallets: WalletConfig<any>[] = /* @__PURE__ */ (() => [
|
||||
metamaskWallet(),
|
||||
coinbaseWallet(),
|
||||
walletConnectV1(),
|
||||
walletConnect(),
|
||||
])();
|
||||
|
||||
@@ -2,12 +2,28 @@ import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { MetaMaskWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
import { MetamaskConnectUI } from "./MetamaskConnectUI";
|
||||
|
||||
export const metamaskWallet = (): WalletConfig<MetaMaskWallet> => {
|
||||
type MetamaskWalletOptions = {
|
||||
/**
|
||||
* When connecting MetaMask using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const metamaskWallet = (
|
||||
options?: MetamaskWalletOptions,
|
||||
): WalletConfig<MetaMaskWallet> => {
|
||||
return {
|
||||
id: MetaMaskWallet.id,
|
||||
meta: MetaMaskWallet.meta,
|
||||
create: (options: WalletOptions) => {
|
||||
return new MetaMaskWallet({ ...options, qrcode: false });
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new MetaMaskWallet({
|
||||
...walletOptions,
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: MetamaskConnectUI,
|
||||
isInstalled() {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { ConnectUIProps, useConnect } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { isMobile } from "../../../evm/utils/isMobile";
|
||||
import { ConnectingScreen } from "../../ConnectWallet/screens/ConnectingScreen";
|
||||
import { GetStartedScreen } from "../../ConnectWallet/screens/GetStartedScreen";
|
||||
import { RainbowScan } from "./RainbowScan";
|
||||
|
||||
export const RainbowConnectUI = (props: ConnectUIProps<WalletConnect>) => {
|
||||
const [screen, setScreen] = useState<
|
||||
"connecting" | "scanning" | "get-started"
|
||||
>("connecting");
|
||||
const { walletConfig, close } = props;
|
||||
const connect = useConnect();
|
||||
|
||||
const { goBack } = props;
|
||||
|
||||
const connectPrompted = useRef(false);
|
||||
useEffect(() => {
|
||||
if (connectPrompted.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if loading
|
||||
(async () => {
|
||||
// on mobile, open rainbow app link
|
||||
if (isMobile()) {
|
||||
window.open("https://rnbwapp.com");
|
||||
} else {
|
||||
// on desktop, show the rainbow scan qr code
|
||||
setScreen("scanning");
|
||||
}
|
||||
})();
|
||||
}, [walletConfig, close, connect, goBack]);
|
||||
|
||||
if (screen === "connecting") {
|
||||
return (
|
||||
<ConnectingScreen
|
||||
onBack={props.goBack}
|
||||
walletName={walletConfig.meta.name}
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
supportLink="https://rainbow.me/"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "get-started") {
|
||||
return (
|
||||
<GetStartedScreen
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
walletName={walletConfig.meta.name}
|
||||
chromeExtensionLink={walletConfig.meta.urls?.chrome}
|
||||
googlePlayStoreLink={walletConfig.meta.urls?.android}
|
||||
appleStoreLink={walletConfig.meta.urls?.ios}
|
||||
onBack={props.goBack}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "scanning") {
|
||||
return (
|
||||
<RainbowScan
|
||||
onBack={props.goBack}
|
||||
onConnected={close}
|
||||
onGetStarted={() => {
|
||||
setScreen("get-started");
|
||||
}}
|
||||
walletConfig={walletConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { ScanScreen } from "../../ConnectWallet/screens/ScanScreen";
|
||||
import {
|
||||
useCreateWalletInstance,
|
||||
useWalletContext,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import type { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
|
||||
export const RainbowScan: React.FC<{
|
||||
onBack: () => void;
|
||||
onGetStarted: () => void;
|
||||
onConnected: () => void;
|
||||
walletConfig: WalletConfig<WalletConnect>;
|
||||
}> = ({ onBack, onConnected, onGetStarted, walletConfig }) => {
|
||||
const createInstance = useCreateWalletInstance();
|
||||
const [qrCodeUri, setQrCodeUri] = useState<string | undefined>();
|
||||
const { setConnectedWallet, chainToConnect, setConnectionStatus } =
|
||||
useWalletContext();
|
||||
|
||||
const scanStarted = useRef(false);
|
||||
useEffect(() => {
|
||||
if (scanStarted.current) {
|
||||
return;
|
||||
}
|
||||
scanStarted.current = true;
|
||||
|
||||
const rainbow = createInstance(walletConfig);
|
||||
|
||||
setConnectionStatus("connecting");
|
||||
rainbow.connectWithQrCode({
|
||||
chainId: chainToConnect?.chainId,
|
||||
onQrCodeUri(uri) {
|
||||
setQrCodeUri(uri);
|
||||
},
|
||||
onConnected() {
|
||||
setConnectedWallet(rainbow);
|
||||
onConnected();
|
||||
},
|
||||
});
|
||||
}, [
|
||||
createInstance,
|
||||
setConnectedWallet,
|
||||
chainToConnect,
|
||||
onConnected,
|
||||
walletConfig,
|
||||
setConnectionStatus,
|
||||
]);
|
||||
|
||||
return (
|
||||
<ScanScreen
|
||||
onBack={onBack}
|
||||
onGetStarted={onGetStarted}
|
||||
qrCodeUri={qrCodeUri}
|
||||
walletName={walletConfig.meta.name}
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnect } from "@thirdweb-dev/wallets";
|
||||
import { RainbowConnectUI } from "./RainbowConnectUI";
|
||||
|
||||
type RainbowWalletOptions = {
|
||||
/**
|
||||
* When connecting Rainbow using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const rainbowWallet = (
|
||||
options?: RainbowWalletOptions,
|
||||
): WalletConfig<WalletConnect> => {
|
||||
return {
|
||||
id: "rainbow",
|
||||
meta: {
|
||||
name: "Rainbow Wallet",
|
||||
iconURL:
|
||||
"ipfs://QmSZn47p4DVVBfzvg9BAX2EqwnPxkT1YAE7rUnrtd9CybQ/rainbow-logo.png",
|
||||
},
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new WalletConnect({
|
||||
...walletOptions,
|
||||
walletId: "rainbow",
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: RainbowConnectUI,
|
||||
isInstalled() {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
import { ConnectUIProps, useConnect } from "@thirdweb-dev/react-core";
|
||||
import { TrustWallet } from "@thirdweb-dev/wallets";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { isMobile } from "../../../evm/utils/isMobile";
|
||||
import { ConnectingScreen } from "../../ConnectWallet/screens/ConnectingScreen";
|
||||
import { GetStartedScreen } from "../../ConnectWallet/screens/GetStartedScreen";
|
||||
import { TrustScan } from "./TrustScan";
|
||||
|
||||
export const TrustConnectUI = (props: ConnectUIProps<TrustWallet>) => {
|
||||
const [screen, setScreen] = useState<
|
||||
"connecting" | "scanning" | "get-started"
|
||||
>("connecting");
|
||||
const { walletConfig, close } = props;
|
||||
const connect = useConnect();
|
||||
|
||||
const { goBack } = props;
|
||||
|
||||
const connectPrompted = useRef(false);
|
||||
useEffect(() => {
|
||||
if (connectPrompted.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isInstalled = walletConfig.isInstalled
|
||||
? walletConfig.isInstalled()
|
||||
: false;
|
||||
|
||||
// if loading
|
||||
(async () => {
|
||||
if (isInstalled) {
|
||||
try {
|
||||
connectPrompted.current = true;
|
||||
setScreen("connecting");
|
||||
await connect(walletConfig);
|
||||
close();
|
||||
} catch (e) {
|
||||
goBack();
|
||||
}
|
||||
}
|
||||
|
||||
// if trust is not injected
|
||||
else {
|
||||
// on mobile, open trust app link
|
||||
if (isMobile()) {
|
||||
window.open("https://link.trustwallet.com");
|
||||
} else {
|
||||
// on desktop, show the trust scan qr code
|
||||
setScreen("scanning");
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [walletConfig, close, connect, goBack]);
|
||||
|
||||
if (screen === "connecting") {
|
||||
return (
|
||||
<ConnectingScreen
|
||||
onBack={props.goBack}
|
||||
walletName={walletConfig.meta.name}
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
supportLink="https://community.trustwallet.com/c/helpcenter/8"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "get-started") {
|
||||
return (
|
||||
<GetStartedScreen
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
walletName={walletConfig.meta.name}
|
||||
chromeExtensionLink={walletConfig.meta.urls?.chrome}
|
||||
googlePlayStoreLink={walletConfig.meta.urls?.android}
|
||||
appleStoreLink={walletConfig.meta.urls?.ios}
|
||||
onBack={props.goBack}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "scanning") {
|
||||
return (
|
||||
<TrustScan
|
||||
onBack={props.goBack}
|
||||
onConnected={close}
|
||||
onGetStarted={() => {
|
||||
setScreen("get-started");
|
||||
}}
|
||||
walletConfig={walletConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { ScanScreen } from "../../ConnectWallet/screens/ScanScreen";
|
||||
import {
|
||||
useCreateWalletInstance,
|
||||
useWalletContext,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { TrustWallet } from "@thirdweb-dev/wallets";
|
||||
import type { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
|
||||
export const TrustScan: React.FC<{
|
||||
onBack: () => void;
|
||||
onGetStarted: () => void;
|
||||
onConnected: () => void;
|
||||
walletConfig: WalletConfig<TrustWallet>;
|
||||
}> = ({ onBack, onConnected, onGetStarted, walletConfig }) => {
|
||||
const createInstance = useCreateWalletInstance();
|
||||
const [qrCodeUri, setQrCodeUri] = useState<string | undefined>();
|
||||
const { setConnectedWallet, chainToConnect, setConnectionStatus } =
|
||||
useWalletContext();
|
||||
|
||||
const scanStarted = useRef(false);
|
||||
useEffect(() => {
|
||||
if (scanStarted.current) {
|
||||
return;
|
||||
}
|
||||
scanStarted.current = true;
|
||||
|
||||
const trust = createInstance(walletConfig);
|
||||
|
||||
setConnectionStatus("connecting");
|
||||
trust.connectWithQrCode({
|
||||
chainId: chainToConnect?.chainId,
|
||||
onQrCodeUri(uri) {
|
||||
setQrCodeUri(uri);
|
||||
},
|
||||
onConnected() {
|
||||
setConnectedWallet(trust);
|
||||
onConnected();
|
||||
},
|
||||
});
|
||||
}, [
|
||||
createInstance,
|
||||
setConnectedWallet,
|
||||
chainToConnect,
|
||||
onConnected,
|
||||
walletConfig,
|
||||
setConnectionStatus,
|
||||
]);
|
||||
|
||||
return (
|
||||
<ScanScreen
|
||||
onBack={onBack}
|
||||
onGetStarted={onGetStarted}
|
||||
qrCodeUri={qrCodeUri}
|
||||
walletName={walletConfig.meta.name}
|
||||
walletIconURL={walletConfig.meta.iconURL}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { TrustWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
import { TrustConnectUI } from "./TrustConnectUI";
|
||||
|
||||
type TrustWalletOptions = {
|
||||
/**
|
||||
* When connecting Trust using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const trustWallet = (
|
||||
options?: TrustWalletOptions,
|
||||
): WalletConfig<TrustWallet> => {
|
||||
return {
|
||||
id: TrustWallet.id,
|
||||
meta: TrustWallet.meta,
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new TrustWallet({
|
||||
...walletOptions,
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: TrustConnectUI,
|
||||
isInstalled() {
|
||||
if (assertWindowEthereum(globalThis.window)) {
|
||||
return !!globalThis.window.ethereum.isTrust;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,12 +1,9 @@
|
||||
import { WalletConnectV1 } from "@thirdweb-dev/wallets";
|
||||
import { WalletConfig, WalletOptions } from "@thirdweb-dev/react-core";
|
||||
import { walletConnect } from "./walletConnect";
|
||||
|
||||
export const walletConnectV1 = (): WalletConfig<WalletConnectV1> => {
|
||||
return {
|
||||
id: WalletConnectV1.id,
|
||||
meta: WalletConnectV1.meta,
|
||||
create(options: WalletOptions) {
|
||||
return new WalletConnectV1({ ...options, qrcode: true });
|
||||
},
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @deprecated Use `walletConnect` instead
|
||||
*
|
||||
* The WalletConnect v1.0 protocol has been shut down and no longer works.
|
||||
* To avoid breaking change, `walletConnectV1` is still available but is an alias of `walletConnect`.
|
||||
*/
|
||||
export const walletConnectV1 = walletConnect;
|
||||
|
||||
@@ -2,12 +2,28 @@ import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { ZerionWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
import { ZerionConnectUI } from "./ZerionConnectUI";
|
||||
|
||||
export const zerionWallet = (): WalletConfig<ZerionWallet> => {
|
||||
type ZerionkWalletOptions = {
|
||||
/**
|
||||
* When connecting MetaMask using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const zerionWallet = (
|
||||
options?: ZerionkWalletOptions,
|
||||
): WalletConfig<ZerionWallet> => {
|
||||
return {
|
||||
id: ZerionWallet.id,
|
||||
meta: ZerionWallet.meta,
|
||||
create: (options: WalletOptions) => {
|
||||
return new ZerionWallet(options);
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new ZerionWallet({
|
||||
...walletOptions,
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: ZerionConnectUI,
|
||||
isInstalled() {
|
||||
|
||||
@@ -24,6 +24,7 @@ module.exports = {
|
||||
files: "./test/**/*",
|
||||
rules: {
|
||||
"@typescript-eslint/no-restricted-imports": "off",
|
||||
"better-tree-shaking/no-top-level-side-effects": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.10.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1249](https://github.com/thirdweb-dev/js/pull/1249) [`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update EIP155 error substrings for any evm deployments
|
||||
|
||||
- [#1254](https://github.com/thirdweb-dev/js/pull/1254) [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fetch base64 NFTs
|
||||
|
||||
- Updated dependencies [[`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.10.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1233](https://github.com/thirdweb-dev/js/pull/1233) [`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186) Thanks [@nkrishang](https://github.com/nkrishang)! - Fix smartWalletFactory.getAllEvents
|
||||
|
||||
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
|
||||
|
||||
- Updated dependencies [[`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/storage@1.1.5
|
||||
- @thirdweb-dev/contracts-js@1.3.7
|
||||
- @thirdweb-dev/chains@0.1.24
|
||||
|
||||
## 3.10.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.10.24",
|
||||
"version": "3.10.26",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
@@ -197,12 +197,6 @@
|
||||
"yaml": "^2.1.1",
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"bn.js": "^5.2.1",
|
||||
"nanoid": "^3.1.31",
|
||||
"typescript": "^4.6.2",
|
||||
"@microsoft/tsdoc": "^0.14.1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
|
||||
@@ -10,6 +10,8 @@ export const ERROR_SUBSTRINGS = [
|
||||
"recovered sender mismatch",
|
||||
"transaction hash mismatch",
|
||||
"chainid no support",
|
||||
"chainid (0)",
|
||||
"chainid(0)",
|
||||
];
|
||||
|
||||
export const ERROR_SUBSTRINGS_COMPOSITE = [
|
||||
|
||||
@@ -46,6 +46,22 @@ export async function fetchTokenMetadata(
|
||||
tokenUri: string,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<NFTMetadata> {
|
||||
// check for base64 encoded JSON
|
||||
if (
|
||||
tokenUri.startsWith("data:application/json;base64") &&
|
||||
typeof Buffer !== "undefined"
|
||||
) {
|
||||
const base64 = tokenUri.split(",")[1];
|
||||
const jsonMetadata = JSON.parse(
|
||||
Buffer.from(base64, "base64").toString("utf-8"),
|
||||
);
|
||||
return CommonNFTOutput.parse({
|
||||
...jsonMetadata,
|
||||
id: BigNumber.from(tokenId).toString(),
|
||||
uri: tokenUri,
|
||||
});
|
||||
}
|
||||
// handle dynamic id URIs (2 possible formats)
|
||||
const parsedUri = tokenUri.replace(
|
||||
"{id}",
|
||||
utils.hexZeroPad(BigNumber.from(tokenId).toHexString(), 32).slice(2),
|
||||
|
||||
@@ -669,7 +669,7 @@ export class Erc721<
|
||||
* @param quantity - Quantity of the tokens you want to claim
|
||||
*
|
||||
* @returns - an array of results containing the id of the token claimed, the transaction receipt and a promise to optionally fetch the nft metadata
|
||||
* @twfeature ERC721ClaimCustom | ERC721ClaimPhasesV2 | ERC721ClaimPhasesV1 | ERC721ClaimConditionsV2 | ERC721ClaimConditionsV1
|
||||
* @twfeature ERC721ClaimCustom | ERC721ClaimPhasesV2 | ERC721ClaimPhasesV1 | ERC721ClaimConditionsV2 | ERC721ClaimConditionsV1 | ERC721ClaimZora
|
||||
*/
|
||||
claim = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (quantity: BigNumberish, options?: ClaimOptions) => {
|
||||
@@ -701,7 +701,7 @@ export class Erc721<
|
||||
* @param quantity - Quantity of the tokens you want to claim
|
||||
* @param options
|
||||
* @returns - an array of results containing the id of the token claimed, the transaction receipt and a promise to optionally fetch the nft metadata
|
||||
* @twfeature ERC721ClaimCustom | ERC721ClaimPhasesV2 | ERC721ClaimPhasesV1 | ERC721ClaimConditionsV2 | ERC721ClaimConditionsV1
|
||||
* @twfeature ERC721ClaimCustom | ERC721ClaimPhasesV2 | ERC721ClaimPhasesV1 | ERC721ClaimConditionsV2 | ERC721ClaimConditionsV1 | ERC721ClaimZora
|
||||
*/
|
||||
claimTo = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
|
||||
@@ -103,17 +103,22 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
*/
|
||||
public async getAllWallets(): Promise<AccountEvent[]> {
|
||||
const filter = {
|
||||
fromBlock: 0,
|
||||
toBlock: "latest",
|
||||
};
|
||||
public async getAllAccounts(): Promise<AccountEvent[]> {
|
||||
const allAccounts =
|
||||
await this.contractWrapper.readContract.getAllAccounts();
|
||||
|
||||
const events = await this.events.getEvents("AccountCreated", filter);
|
||||
/**
|
||||
* Note: an account can have multiple admins. In this function, we only return the first signer associated with
|
||||
* the account. This should be the admin that created the account, unless this admin has lost their admin status.
|
||||
*/
|
||||
return await Promise.all(
|
||||
allAccounts.map(async (account) => {
|
||||
const assosiatedSigners = await this.getAssociatedSigners(account);
|
||||
const admin = assosiatedSigners[0];
|
||||
|
||||
return events.map((event) => {
|
||||
return { account: event.data.account, admin: event.data.accountAdmin };
|
||||
});
|
||||
return { account, admin };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,13 +18,14 @@ import {
|
||||
SignerWithRestrictions,
|
||||
AccessRestrictionsInput,
|
||||
AccessRestrictionsSchema,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
} from "../../types";
|
||||
import invariant from "tiny-invariant";
|
||||
import { buildTransactionFunction } from "../../common/transactions";
|
||||
import { SmartWalletFactory } from "./smart-wallet-factory";
|
||||
import { resolveOrGenerateId } from "../../common/signature-minting";
|
||||
import { AddressOrEns } from "../../schema";
|
||||
import { resolveAddress } from "../../common";
|
||||
import { Signer } from "ethers";
|
||||
|
||||
export class SmartWallet<TContract extends IAccountCore>
|
||||
implements DetectableFeature
|
||||
@@ -47,6 +48,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
* HELPER FUNCTIONS
|
||||
********************************/
|
||||
|
||||
private hasDuplicateSigners(
|
||||
signers: SignerWithRestrictionsBatchInput,
|
||||
): boolean {
|
||||
const encounteredSigners = new Set();
|
||||
|
||||
return signers
|
||||
.map((item) => item.signer)
|
||||
.some((signer) => {
|
||||
const isDuplicate = encounteredSigners.has(signer);
|
||||
encounteredSigners.add(signer);
|
||||
return isDuplicate;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the access restrictions for a given role
|
||||
*
|
||||
@@ -127,7 +142,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
* @returns Returns the address of the factory
|
||||
*
|
||||
*/
|
||||
private async getFactory(): Promise<SmartWalletFactory<IAccountFactory>> {
|
||||
private async getFactory(): Promise<ContractWrapper<IAccountFactory>> {
|
||||
// Get factory.
|
||||
const chainId = await this.contractWrapper.getChainID();
|
||||
const factoryAddress = await this.getFactoryAddress();
|
||||
@@ -137,13 +152,33 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
IAccountFactoryAbi,
|
||||
this.contractWrapper.options,
|
||||
);
|
||||
return new SmartWalletFactory(wrapper);
|
||||
wrapper.updateSignerOrProvider(this.contractWrapper.getSigner() as Signer);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* READ FUNCTIONS
|
||||
********************************/
|
||||
|
||||
/**
|
||||
* Get whether a signer is an admin on the smart wallet.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const isAdmin = await contract.smartWallet.isAdmin(signer);
|
||||
* ```
|
||||
* @param signer - The address of a signer of the smart wallet.
|
||||
* @returns whether a signer is an admin on the smart wallet.
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
*/
|
||||
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
|
||||
const resolvedSignerAddress = await resolveAddress(signerAddress);
|
||||
return await this.contractWrapper.readContract.isAdmin(
|
||||
resolvedSignerAddress,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restrictions under which a given signer can use the smart wallet.
|
||||
*
|
||||
@@ -168,7 +203,8 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of the EIP-4337 factory contract which deployed the smart wallet
|
||||
* Get the deployer of the smart wallet
|
||||
* @remarks Get the address of the EIP-4337 factory contract which deployed the smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
@@ -183,7 +219,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all signers (admin or non-admin) of the smart wallet, along with their access restrictions.
|
||||
* Get all signers with their access restrictions
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
@@ -195,8 +231,8 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
*/
|
||||
public async getSignersWithRestrictions(): Promise<SignerWithRestrictions[]> {
|
||||
// Get all associated signers.
|
||||
const factory = await this.getFactory();
|
||||
const signers: string[] = await factory.getAssociatedSigners(
|
||||
const contract = await this.getFactory();
|
||||
const signers: string[] = await contract.readContract.getSignersOfAccount(
|
||||
this.getAddress(),
|
||||
);
|
||||
|
||||
@@ -214,7 +250,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
********************************/
|
||||
|
||||
/**
|
||||
* Grant an address admin access to the smart wallet.
|
||||
* Grant an address admin access to the smart wallet
|
||||
*
|
||||
* @remarks Grants an address admin access to the smart wallet. The admin will have complete authority over the smart wallet.
|
||||
*
|
||||
@@ -240,7 +276,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke an address' admin access to the smart wallet.
|
||||
* Revoke an address' admin access to the smart wallet
|
||||
*
|
||||
* @remarks Revokes an address' admin access to the smart wallet.
|
||||
*
|
||||
@@ -266,7 +302,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Grant an address access to the smart wallet with certain restrictions.
|
||||
* Grant an address access to the smart wallet with restrictions
|
||||
*
|
||||
* @remarks Grants an address access to the smart wallet with certain restrictions.
|
||||
*
|
||||
@@ -312,8 +348,9 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction:
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
@@ -358,7 +395,7 @@ 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 smart wallet
|
||||
*
|
||||
* @remarks Approves an address as a call target for a given signer on the smart wallet.
|
||||
*
|
||||
@@ -407,7 +444,7 @@ 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 smart wallet
|
||||
*
|
||||
* @remarks Disapprove an address as a call target for a given signer on the smart wallet.
|
||||
*
|
||||
@@ -459,7 +496,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Update an address' access to the smart wallet.
|
||||
* Update the restrictions of an address for using the smart wallet
|
||||
*
|
||||
* @remarks Updates an address' access to the smart wallet.
|
||||
*
|
||||
@@ -497,8 +534,9 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role: currentRole,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction:
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
@@ -512,7 +550,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke an address' access to the smart wallet.
|
||||
* Revoke a scoped access address to the smart wallet
|
||||
*
|
||||
* @remarks Revokes an address' access to the smart wallet.
|
||||
*
|
||||
@@ -560,4 +598,204 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the wallet's entire snapshot of permissions
|
||||
*
|
||||
* @remarks Sets the wallet's entire snapshot of permissions.
|
||||
*
|
||||
* @param permissionsSnapshot - the snapshot to set as the wallet's entire permission snapshot.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.setAccess(permissionsSnapshot);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
*/
|
||||
setAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
permissionsSnapshot: SignerWithRestrictionsBatchInput,
|
||||
): Promise<Transaction> => {
|
||||
/**
|
||||
* All cases
|
||||
*
|
||||
* - Add new admin :check:
|
||||
* - Remove current admin :check:
|
||||
* - Add new scoped :check:
|
||||
* - Remove current scoped :check:
|
||||
* - Update current scoped :check:
|
||||
* - Current admin -> new scoped :check:
|
||||
* - Current scoped -> new admin :check:
|
||||
**/
|
||||
|
||||
// No duplicate signers in input!
|
||||
if (this.hasDuplicateSigners(permissionsSnapshot)) {
|
||||
throw new Error("Duplicate signers found in input.");
|
||||
}
|
||||
|
||||
const currentPermissionsSnapshot =
|
||||
await this.getSignersWithRestrictions();
|
||||
|
||||
// Performing a multicall.
|
||||
const encoded: string[] = [];
|
||||
|
||||
// First make all calls related to admin access.
|
||||
const allCurrentAdmins = currentPermissionsSnapshot
|
||||
.filter((result) => result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
const allNewAdmins = permissionsSnapshot
|
||||
.filter((result) => result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
|
||||
// All remove-admin actions.
|
||||
for (const currentAdmin of allCurrentAdmins) {
|
||||
if (!allNewAdmins.includes(currentAdmin)) {
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setAdmin",
|
||||
[currentAdmin, false],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All add-admin actions.
|
||||
const toRemoveAsScoped: Record<string, string> = {};
|
||||
for (const newAdmin of allNewAdmins) {
|
||||
if (!allCurrentAdmins.includes(newAdmin)) {
|
||||
const data =
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setAdmin",
|
||||
[newAdmin, true],
|
||||
);
|
||||
|
||||
// If the new admin is already a scoped account, we need to remove them as a scoped account first.
|
||||
const currentRole = (
|
||||
await this.contractWrapper.readContract.getRoleRestrictionsForAccount(
|
||||
newAdmin,
|
||||
)
|
||||
).role;
|
||||
if (currentRole === this.emptyRole) {
|
||||
encoded.push(data);
|
||||
} else {
|
||||
toRemoveAsScoped[newAdmin] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All scoped actions.
|
||||
const allCurrentScoped = currentPermissionsSnapshot
|
||||
.filter((result) => !result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
const allNewScoped = permissionsSnapshot
|
||||
.filter((result) => !result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
|
||||
// All remove-scoped actions.
|
||||
const newAdminsToRemoveAsScoped = Object.keys(toRemoveAsScoped);
|
||||
for (const currentScoped of allCurrentScoped) {
|
||||
if (!allNewScoped.includes(currentScoped)) {
|
||||
const { payload, signature } = await this.generatePayload(
|
||||
currentScoped,
|
||||
RoleAction.REVOKE,
|
||||
);
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"changeRole",
|
||||
[payload, signature],
|
||||
),
|
||||
);
|
||||
|
||||
if (newAdminsToRemoveAsScoped.includes(currentScoped)) {
|
||||
encoded.push(toRemoveAsScoped[currentScoped]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All add-scoped actions.
|
||||
for (const newScoped of allNewScoped) {
|
||||
if (!allCurrentScoped.includes(newScoped)) {
|
||||
// Derive role for target signer.
|
||||
const role = utils.solidityKeccak256(["string"], [newScoped]);
|
||||
|
||||
const parsedRestrictions = await AccessRestrictionsSchema.parseAsync(
|
||||
permissionsSnapshot.find((result) => result.signer === newScoped)
|
||||
?.restrictions,
|
||||
);
|
||||
|
||||
// Get role restrictions struct.
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setRoleRestrictions",
|
||||
[roleRestrictions],
|
||||
),
|
||||
);
|
||||
|
||||
const { payload, signature } = await this.generatePayload(
|
||||
newScoped,
|
||||
RoleAction.GRANT,
|
||||
);
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"changeRole",
|
||||
[payload, signature],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All update-scoped actions.
|
||||
for (const currentScoped of allCurrentScoped) {
|
||||
if (allNewScoped.includes(currentScoped)) {
|
||||
// Derive role for target signer.
|
||||
const role = utils.solidityKeccak256(["string"], [currentScoped]);
|
||||
|
||||
const parsedRestrictions = await AccessRestrictionsSchema.parseAsync(
|
||||
permissionsSnapshot.find(
|
||||
(result) => result.signer === currentScoped,
|
||||
)?.restrictions,
|
||||
);
|
||||
|
||||
// Get role restrictions struct.
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setRoleRestrictions",
|
||||
[roleRestrictions],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform multicall
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this.contractWrapper,
|
||||
method: "multicall",
|
||||
args: [encoded],
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from "ethers";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
import { BlockTag } from "@ethersproject/abstract-provider";
|
||||
import type { BlockTag } from "@ethersproject/abstract-provider";
|
||||
import { fetchCurrencyValue } from "../../common/currency/fetchCurrencyValue";
|
||||
import { isNativeToken } from "../../common/currency/isNativeToken";
|
||||
import { normalizePriceValue } from "../../common/currency/normalizePriceValue";
|
||||
|
||||
@@ -32,6 +32,17 @@ export type SignerWithRestrictions = {
|
||||
restrictions: AccessRestrictions;
|
||||
}
|
||||
|
||||
export const SignerWithRestrictionsSchema = /* @__PURE__ */ z.object({
|
||||
signer: AddressOrEnsSchema,
|
||||
isAdmin: /* @__PURE__ */ z.boolean(),
|
||||
restrictions: AccessRestrictionsSchema,
|
||||
});
|
||||
|
||||
export type SignerWithRestrictionsInput = z.input<typeof SignerWithRestrictionsSchema>;
|
||||
|
||||
export const SignerWithRestrictionsBatchSchema = /* @__PURE__ */ z.array(SignerWithRestrictionsSchema);
|
||||
export type SignerWithRestrictionsBatchInput = z.input<typeof SignerWithRestrictionsBatchSchema>;
|
||||
|
||||
export type SignedAccountPermissionsPayload = {
|
||||
payload: IAccountPermissions.RoleRequestStruct;
|
||||
signature: BytesLike;
|
||||
|
||||
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,839 @@
|
||||
import { sdk, signers } from "./before-setup";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import { assert, expect } from "chai";
|
||||
import {
|
||||
SignerWithRestrictions,
|
||||
AccessRestrictions,
|
||||
SmartWallet,
|
||||
SmartWalletFactory,
|
||||
SignerWithRestrictionsInput,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
} from "../../src/evm";
|
||||
import { ContractFactory, utils } from "ethers";
|
||||
import EntrypointArtifact from "./mock/EntryPoint.json";
|
||||
import AccountFactoryArtifact from "./mock/AccountFactory.json";
|
||||
|
||||
// Target ABIs
|
||||
import IAccountCoreAbi from "@thirdweb-dev/contracts-js/dist/abis/IAccountCore.json";
|
||||
import {
|
||||
deployContractAndUploadMetadata,
|
||||
mockUploadContractMetadata,
|
||||
} from "./utils";
|
||||
import { IAccountCore, IAccountFactory } from "@thirdweb-dev/contracts-js";
|
||||
|
||||
global.fetch = /* @__PURE__ */ require("cross-fetch");
|
||||
|
||||
/* @__PURE__ */ describe("Smart wallets with wallet factory", function () {
|
||||
let smartWalletFactory: SmartWalletFactory<IAccountFactory>;
|
||||
let smartWallet: SmartWallet<IAccountCore>;
|
||||
|
||||
let adminWallet: SignerWithAddress;
|
||||
|
||||
let signer1Wallet: SignerWithAddress;
|
||||
let signer2Wallet: SignerWithAddress;
|
||||
let signer3Wallet: SignerWithAddress;
|
||||
let signer4Wallet: SignerWithAddress;
|
||||
let signer5Wallet: SignerWithAddress;
|
||||
let signer6Wallet: SignerWithAddress;
|
||||
let signer7Wallet: SignerWithAddress;
|
||||
let signer8Wallet: SignerWithAddress;
|
||||
let signer9Wallet: SignerWithAddress;
|
||||
|
||||
before(async () => {
|
||||
[
|
||||
adminWallet,
|
||||
signer1Wallet,
|
||||
signer2Wallet,
|
||||
signer3Wallet,
|
||||
signer4Wallet,
|
||||
signer5Wallet,
|
||||
signer6Wallet,
|
||||
signer7Wallet,
|
||||
signer8Wallet,
|
||||
signer9Wallet,
|
||||
] = signers;
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const entrypoint = await new ContractFactory(
|
||||
EntrypointArtifact.abi,
|
||||
EntrypointArtifact.bytecode.object,
|
||||
adminWallet,
|
||||
).deploy();
|
||||
const factoryAddress = await deployContractAndUploadMetadata(
|
||||
AccountFactoryArtifact.abi,
|
||||
AccountFactoryArtifact.bytecode.object,
|
||||
adminWallet,
|
||||
[entrypoint.address],
|
||||
);
|
||||
smartWalletFactory = (await sdk.getContract(factoryAddress))
|
||||
.smartWalletFactory;
|
||||
});
|
||||
|
||||
describe("Test: SmartWalletFactory actions", () => {
|
||||
it("Should create a new wallet for the admin", async () => {
|
||||
// Check before creating a smart wallet for `adminWallet`
|
||||
const isDeployed = await smartWalletFactory.isWalletDeployed(
|
||||
adminWallet.address,
|
||||
);
|
||||
assert.isFalse(
|
||||
isDeployed,
|
||||
"Smart wallet is should not be deployed for admin.",
|
||||
);
|
||||
|
||||
const predictedAccountAddress: string =
|
||||
await smartWalletFactory.predictWalletAddress(adminWallet.address);
|
||||
|
||||
const allWalletsBefore = (await smartWalletFactory.getAllAccounts()).map(
|
||||
(wallet) => wallet.account,
|
||||
);
|
||||
assert.isFalse(
|
||||
allWalletsBefore.includes(predictedAccountAddress),
|
||||
"Account should not be deployed for admin already.",
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
(await smartWalletFactory.getAssociatedSigners(predictedAccountAddress))
|
||||
.length === 0,
|
||||
"Wallet should have no associated signers.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(await smartWalletFactory.getAssociatedWallets(adminWallet.address))
|
||||
.length === 0,
|
||||
"Signer should have no associated wallets.",
|
||||
);
|
||||
|
||||
// Create smart wallet for `adminWallet`
|
||||
const tx = await smartWalletFactory.createWallet(adminWallet.address);
|
||||
|
||||
// Checks after creating a smart wallet for `adminWallet`
|
||||
assert.strictEqual(
|
||||
utils.getAddress(tx.address),
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
"Smart wallet address should match predicted address.",
|
||||
);
|
||||
assert.isTrue(
|
||||
await smartWalletFactory.isWalletDeployed(adminWallet.address),
|
||||
"Smart wallet is should be deployed for admin.",
|
||||
);
|
||||
|
||||
const allWalletsAfter = await smartWalletFactory.getAllAccounts();
|
||||
assert.isTrue(
|
||||
allWalletsAfter.length === 1,
|
||||
"Only one wallet should be created on the factory.",
|
||||
);
|
||||
|
||||
const { account, admin } = allWalletsAfter.filter(
|
||||
(wallet) =>
|
||||
utils.getAddress(wallet.account) ===
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
)[0];
|
||||
assert.strictEqual(
|
||||
utils.getAddress(account),
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
"Stored account address should match predicted address.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(admin),
|
||||
utils.getAddress(adminWallet.address),
|
||||
"Correct admin for smart wallet.",
|
||||
);
|
||||
|
||||
const associatedWallets = await smartWalletFactory.getAssociatedWallets(
|
||||
admin,
|
||||
);
|
||||
const associatedSigner = await smartWalletFactory.getAssociatedSigners(
|
||||
account,
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
associatedWallets.length === 1,
|
||||
"Wallet should have only the admin as an associated signer.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(account),
|
||||
utils.getAddress(associatedWallets[0]),
|
||||
"Wallet should have only the admin as an associated signer.",
|
||||
);
|
||||
assert.isTrue(
|
||||
associatedSigner.length === 1,
|
||||
"Signer should have only the created wallet as an associated wallet.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(admin),
|
||||
utils.getAddress(associatedSigner[0]),
|
||||
"Signer should have only the created wallet as an associated wallet.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should throw if creating wallet for an admin who already has one", async () => {
|
||||
// Create a wallet for admin
|
||||
await smartWalletFactory.createWallet(adminWallet.address);
|
||||
|
||||
// Try creating another wallet for the same admin
|
||||
try {
|
||||
await smartWalletFactory.createWallet(adminWallet.address);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
`Wallet already deployed for admin: ${adminWallet.address}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test: SmartWallet actions", () => {
|
||||
beforeEach(async () => {
|
||||
// Create a wallet for admin
|
||||
const tx = await smartWalletFactory.createWallet(adminWallet.address);
|
||||
const smartWalletAddress = tx.address;
|
||||
|
||||
sdk.updateSignerOrProvider(adminWallet);
|
||||
await mockUploadContractMetadata(
|
||||
"smart-wallet",
|
||||
smartWalletAddress,
|
||||
IAccountCoreAbi,
|
||||
);
|
||||
|
||||
smartWallet = (await sdk.getContract(smartWalletAddress)).smartWallet;
|
||||
});
|
||||
|
||||
it("Should be able to add another admin to the wallet.", async () => {
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
await smartWallet.grantAdminAccess(signer1Wallet.address);
|
||||
|
||||
assert.isTrue(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
const isAdmin = (
|
||||
(await smartWallet.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
) as SignerWithRestrictions
|
||||
).isAdmin;
|
||||
assert.isTrue(isAdmin, "New signer1 should be an admin on the wallet.");
|
||||
|
||||
assert.isTrue(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedSigners(
|
||||
smartWallet.getAddress(),
|
||||
)
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is an associated signer of the wallet.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
|
||||
).includes(smartWallet.getAddress()),
|
||||
"Wallet is an associated wallet of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to remove an admin from the wallet.", async () => {
|
||||
await smartWallet.grantAdminAccess(signer1Wallet.address);
|
||||
assert.isTrue(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
await smartWallet.revokeAdminAccess(signer1Wallet.address);
|
||||
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(await smartWallet.getSignersWithRestrictions())
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the wallet.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedSigners(
|
||||
smartWallet.getAddress(),
|
||||
)
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is not an associated signer of the wallet.",
|
||||
);
|
||||
assert.isFalse(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
|
||||
).includes(smartWallet.getAddress()),
|
||||
"Wallet is not an associated wallet of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to grant restricted access to a new signer.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the wallet.",
|
||||
);
|
||||
|
||||
// Grant access
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
const newSignerWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
const restrictions = newSignerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
newSignerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the wallet.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("1").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedSigners(
|
||||
smartWallet.getAddress(),
|
||||
)
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is an associated signer of the wallet.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
|
||||
).includes(smartWallet.getAddress()),
|
||||
"Wallet is an associated wallet of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to grant restricted access to a signer who already has access.", async () => {
|
||||
// Grant access to signer1
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
// Try granting access to signer1 again
|
||||
try {
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer already has access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to revoke restricted access from an authorized signer.", async () => {
|
||||
// Grant access to signer1
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
// Revoke access
|
||||
await smartWallet.revokeAccess(signer1Wallet.address);
|
||||
|
||||
const signersWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not have access to the wallet.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedSigners(
|
||||
smartWallet.getAddress(),
|
||||
)
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is not an associated signer of the wallet.",
|
||||
);
|
||||
assert.isFalse(
|
||||
(
|
||||
await smartWalletFactory.getAssociatedWallets(signer1Wallet.address)
|
||||
).includes(smartWallet.getAddress()),
|
||||
"Wallet is not an associated wallet of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to revoke restricted access from a signer who doesn't have access.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the wallet.",
|
||||
);
|
||||
|
||||
// Try revoking access from signer1
|
||||
try {
|
||||
await smartWallet.revokeAccess(signer1Wallet.address);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer does not have any access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to update access of an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
const signerWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
const restrictions = signerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
signerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the wallet.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("1").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Update access
|
||||
await smartWallet.updateAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "3",
|
||||
approvedCallTargets: [signer2Wallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await smartWallet.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the smart wallet.",
|
||||
);
|
||||
|
||||
const newSignerWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
const newRestrictions = newSignerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
newSignerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the wallet.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("3").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to update access of a signer who doesn't have access.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the wallet.",
|
||||
);
|
||||
|
||||
// Try updating access of signer1
|
||||
try {
|
||||
await smartWallet.updateAccess(signer1Wallet.address, {
|
||||
approvedCallTargets: [signer2Wallet.address],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer does not have any access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to append an approved target for an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictions = (
|
||||
await smartWallet.getSignersWithRestrictions()
|
||||
).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Append approved target
|
||||
await smartWallet.approveTargetForSigner(
|
||||
signer1Wallet.address,
|
||||
signer2Wallet.address,
|
||||
);
|
||||
|
||||
const newRestrictions = (
|
||||
await smartWallet.getSignersWithRestrictions()
|
||||
).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
2,
|
||||
"New signer1 should have two approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[1],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to remove an approved target for an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await smartWallet.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address, signer2Wallet.address],
|
||||
});
|
||||
|
||||
const restrictions = (
|
||||
await smartWallet.getSignersWithRestrictions()
|
||||
).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
2,
|
||||
"New signer1 should have two approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[1],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Remove approved target
|
||||
await smartWallet.disapproveTargetForSigner(
|
||||
signer1Wallet.address,
|
||||
signer2Wallet.address,
|
||||
);
|
||||
|
||||
const newRestrictions = (
|
||||
await smartWallet.getSignersWithRestrictions()
|
||||
).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to set access for the smart wallet in a batch.", async () => {
|
||||
/**
|
||||
* All cases to test
|
||||
*
|
||||
* - 1. Adding a new admin
|
||||
* - 2. Removing existing admin
|
||||
* - 3. Adding a new scoped signer
|
||||
* - 4. Removing an existing scoped signer
|
||||
* - 5. Updating the restrictions of an existing scoped signer
|
||||
* - 6. Existing admin -> new scoped signer (demote)
|
||||
* - 7. Existing scoped signer -> new admin :check: (promote)
|
||||
**/
|
||||
|
||||
const signersWithRestrictions: SignerWithRestrictionsBatchInput = [];
|
||||
|
||||
// Setup
|
||||
|
||||
const restrictionsForAdmin: SignerWithRestrictionsInput = {
|
||||
signer: adminWallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsForAdmin);
|
||||
|
||||
// Adding a new admin: Signer3
|
||||
const restrictionsSigner3: SignerWithRestrictionsInput = {
|
||||
signer: signer3Wallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner3);
|
||||
|
||||
// Removing existing admin
|
||||
await smartWallet.grantAdminAccess(signer4Wallet.address);
|
||||
|
||||
const restrictionsSigner4: SignerWithRestrictionsInput = {
|
||||
signer: signer4Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner4);
|
||||
|
||||
// Adding a new scoped signer
|
||||
const restrictionsSigner5: SignerWithRestrictionsInput = {
|
||||
signer: signer5Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [adminWallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner5);
|
||||
|
||||
// Removing an existing scoped signer
|
||||
await smartWallet.grantAccess(signer6Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner6: SignerWithRestrictionsInput = {
|
||||
signer: signer6Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner6);
|
||||
|
||||
// Updating the restrictions of an existing scoped signer
|
||||
|
||||
await smartWallet.grantAccess(signer7Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner7: SignerWithRestrictionsInput = {
|
||||
signer: signer7Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [signer1Wallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner7);
|
||||
|
||||
// Existing admin -> new scoped signer (demote)
|
||||
await smartWallet.grantAdminAccess(signer8Wallet.address);
|
||||
|
||||
const restrictionsSigner8: SignerWithRestrictionsInput = {
|
||||
signer: signer8Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [adminWallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner8);
|
||||
|
||||
// Existing scoped signer -> new admin (promote)
|
||||
await smartWallet.grantAccess(signer9Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner9: SignerWithRestrictionsInput = {
|
||||
signer: signer9Wallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner9);
|
||||
|
||||
// Set access in batch
|
||||
await smartWallet.setAccess(signersWithRestrictions);
|
||||
|
||||
// Now checking if permissions are set correctly
|
||||
const signersWithRestrictionsAfter =
|
||||
await smartWallet.getSignersWithRestrictions();
|
||||
|
||||
for (const restrictions of signersWithRestrictionsAfter) {
|
||||
switch (restrictions.signer) {
|
||||
// `adminWallet` should be an admin
|
||||
case adminWallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Admin wallet should be an admin.",
|
||||
);
|
||||
break;
|
||||
// `signer3Wallet` should be an admin
|
||||
case signer3Wallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Signer3 wallet should be an admin.",
|
||||
);
|
||||
break;
|
||||
// `signer4Wallet` should not be admin or scoped signer
|
||||
case signer4Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer4 wallet should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
0,
|
||||
"Signer4 wallet should not have any approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer5Wallet` should be a scoped signer
|
||||
case signer5Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer5 wallet should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer5 wallet should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"Signer5 wallet should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer6Wallet` should not be admin or scoped signer
|
||||
case signer6Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer6 wallet should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
0,
|
||||
"Signer6 wallet should not have any approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer7Wallet` should be a scoped signer with its updated restrictions
|
||||
case signer7Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer7 wallet should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer7 wallet should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
signer1Wallet.address,
|
||||
"Signer7 wallet should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer8Wallet` should be a scoped signer
|
||||
case signer8Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer8 wallet should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer8 wallet should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"Signer8 wallet should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer9Wallet` should be an admin
|
||||
case signer9Wallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Signer9 wallet should be an admin.",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
assert.fail("Unexpected signer.");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ export const deployContractAndUploadMetadata = async (
|
||||
return deployed.address;
|
||||
};
|
||||
|
||||
const mockUploadContractMetadata = async (
|
||||
export const mockUploadContractMetadata = async (
|
||||
contractName: string,
|
||||
address: string,
|
||||
abi: any,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/storage
|
||||
|
||||
## 1.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1246](https://github.com/thirdweb-dev/js/pull/1246) [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c) Thanks [@nessup](https://github.com/nessup)! - Remove the ipfs-2 gateway due to connectivity errors that seem to happen with certain ISPs
|
||||
|
||||
## 1.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/storage",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"main": "dist/thirdweb-dev-storage.cjs.js",
|
||||
"module": "dist/thirdweb-dev-storage.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -6,7 +6,6 @@ import { GatewayUrls } from "../types";
|
||||
export const DEFAULT_GATEWAY_URLS: GatewayUrls = {
|
||||
// Note: Gateway URLs should have trailing slashes (we clean this on user input)
|
||||
"ipfs://": [
|
||||
"https://ipfs-2.thirdwebcdn.com/ipfs/",
|
||||
"https://ipfs-3.thirdwebcdn.com/ipfs/",
|
||||
"https://ipfs-4.thirdwebcdn.com/ipfs/",
|
||||
"https://ipfs-5.thirdwebcdn.com/ipfs/",
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @thirdweb-dev/unity-js-bridge
|
||||
|
||||
## 0.2.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1256](https://github.com/thirdweb-dev/js/pull/1256) [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - WCv2 and Paper support for WebGL Unity
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`d43f6171`](https://github.com/thirdweb-dev/js/commit/d43f6171d910e31b748b171b012174390aac3fff), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/auth@3.2.4
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.2.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f), [`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/wallets@0.3.3
|
||||
- @thirdweb-dev/sdk@3.10.25
|
||||
- @thirdweb-dev/storage@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.24
|
||||
- @thirdweb-dev/auth@3.2.3
|
||||
|
||||
## 0.2.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/unity-js-bridge",
|
||||
"version": "0.2.39",
|
||||
"version": "0.2.41",
|
||||
"main": "dist/thirdweb-unity-bridge.js",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -6,7 +6,6 @@ import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import {
|
||||
DAppMetaData,
|
||||
SmartWalletConfig,
|
||||
WalletConnectV1,
|
||||
walletIds,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import type { AbstractClientWallet } from "@thirdweb-dev/wallets/evm/wallets/base";
|
||||
@@ -17,8 +16,10 @@ import { InjectedWallet } from "@thirdweb-dev/wallets/evm/wallets/injected";
|
||||
import { MetaMaskWallet } from "@thirdweb-dev/wallets/evm/wallets/metamask";
|
||||
import { MagicLink } from "@thirdweb-dev/wallets/evm/wallets/magic";
|
||||
import { SmartWallet } from "@thirdweb-dev/wallets/evm/wallets/smart-wallet";
|
||||
import { WalletConnect } from "@thirdweb-dev/wallets/evm/wallets/wallet-connect";
|
||||
import { PaperWallet } from "@thirdweb-dev/wallets/evm/wallets/paper-wallet";
|
||||
import { BigNumber } from "ethers";
|
||||
import { allChains } from "@thirdweb-dev/chains";
|
||||
import { Ethereum, allChains, defaultChains } from "@thirdweb-dev/chains";
|
||||
import type { ContractInterface, Signer } from "ethers";
|
||||
|
||||
declare global {
|
||||
@@ -50,7 +51,8 @@ const bigNumberReplacer = (_key: string, value: any) => {
|
||||
const WALLETS = [
|
||||
MetaMaskWallet,
|
||||
InjectedWallet,
|
||||
WalletConnectV1,
|
||||
WalletConnect,
|
||||
PaperWallet,
|
||||
CoinbaseWallet,
|
||||
LocalWallet,
|
||||
MagicLink,
|
||||
@@ -152,10 +154,11 @@ class ThirdwebBridge implements TWBridge {
|
||||
chains: allChains,
|
||||
});
|
||||
break;
|
||||
case walletIds.walletConnectV1:
|
||||
walletInstance = new WalletConnectV1({
|
||||
case walletIds.walletConnect:
|
||||
walletInstance = new WalletConnect({
|
||||
projectId: sdkOptions.wallet?.walletConnectProjectId,
|
||||
dappMetadata,
|
||||
chains: allChains,
|
||||
chains: defaultChains,
|
||||
});
|
||||
break;
|
||||
case walletIds.coinbase:
|
||||
@@ -172,11 +175,20 @@ class ThirdwebBridge implements TWBridge {
|
||||
break;
|
||||
case walletIds.magicLink:
|
||||
walletInstance = new MagicLink({
|
||||
dappMetadata,
|
||||
apiKey: sdkOptions.wallet?.magicLinkApiKey,
|
||||
emailLogin: true,
|
||||
chains: allChains,
|
||||
});
|
||||
break;
|
||||
case walletIds.paper:
|
||||
walletInstance = new PaperWallet({
|
||||
clientId: sdkOptions.wallet?.paperClientId,
|
||||
chain: Ethereum,
|
||||
dappMetadata,
|
||||
chains: allChains,
|
||||
});
|
||||
break;
|
||||
case walletIds.smartWallet:
|
||||
const config: SmartWalletConfig = {
|
||||
chain: chain,
|
||||
@@ -235,6 +247,12 @@ class ThirdwebBridge implements TWBridge {
|
||||
throw new Error("Email is required for Magic Link Wallet");
|
||||
}
|
||||
await magicLinkWallet.connect({ chainId, email });
|
||||
} else if (walletInstance.walletId === walletIds.paper) {
|
||||
const paperWallet = walletInstance as PaperWallet;
|
||||
if (!email) {
|
||||
throw new Error("Email is required for Paper Wallet");
|
||||
}
|
||||
await paperWallet.connect({ chainId, email });
|
||||
} else if (walletInstance.walletId === walletIds.smartWallet) {
|
||||
const smartWallet = walletInstance as SmartWallet;
|
||||
const eoaWallet = this.walletMap.get(personalWallet);
|
||||
|
||||
@@ -1,5 +1,60 @@
|
||||
# @thirdweb-dev/wallets
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#1215](https://github.com/thirdweb-dev/js/pull/1215) [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc) Thanks [@iketw](https://github.com/iketw)! - Migrate wallets to WCV2 and remove WCV1 support.
|
||||
|
||||
Please, check our changelogs for more info: https://blog.thirdweb.com/changelog/
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1256](https://github.com/thirdweb-dev/js/pull/1256) [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - WCv2 and Paper support for WebGL Unity
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1237](https://github.com/thirdweb-dev/js/pull/1237) [`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b) Thanks [@iketw](https://github.com/iketw)! - [React] Add Rainbow Wallet (implementing the WalletConnect wallet)
|
||||
|
||||
```javascript
|
||||
import { ThirdwebProvider, rainbowWallet } from "@thirdweb-dev/react";
|
||||
|
||||
const activeChain = "ethereum";
|
||||
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
supportedWallets={[rainbowWallet()]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>;
|
||||
```
|
||||
|
||||
- [#1236](https://github.com/thirdweb-dev/js/pull/1236) [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f) Thanks [@iketw](https://github.com/iketw)! - [Wallets/React] Add Trust Wallet
|
||||
|
||||
```javascript
|
||||
import { ThirdwebProvider, trustWallet } from "@thirdweb-dev/react";
|
||||
|
||||
const activeChain = "mumbai";
|
||||
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
autoSwitch={true}
|
||||
supportedWallets={[trustWallet()]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>;
|
||||
```
|
||||
|
||||
- Updated dependencies [[`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-wallets-evm-connectors-trust.cjs.js",
|
||||
"module": "dist/thirdweb-dev-wallets-evm-connectors-trust.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-wallets-evm-connectors-trust.esm.js": "./dist/thirdweb-dev-wallets-evm-connectors-trust.browser.esm.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-wallets-evm-wallets-trust.cjs.js",
|
||||
"module": "dist/thirdweb-dev-wallets-evm-wallets-trust.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-wallets-evm-wallets-trust.esm.js": "./dist/thirdweb-dev-wallets-evm-wallets-trust.browser.esm.js"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/wallets",
|
||||
"version": "0.3.2",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/thirdweb-dev-wallets.cjs.js",
|
||||
"module": "dist/thirdweb-dev-wallets.esm.js",
|
||||
"types": "dist/thirdweb-dev-wallets.cjs.d.ts",
|
||||
@@ -57,6 +57,13 @@
|
||||
},
|
||||
"default": "./evm/wallets/magic/dist/thirdweb-dev-wallets-evm-wallets-magic.cjs.js"
|
||||
},
|
||||
"./evm/wallets/trust": {
|
||||
"module": {
|
||||
"browser": "./evm/wallets/trust/dist/thirdweb-dev-wallets-evm-wallets-trust.browser.esm.js",
|
||||
"default": "./evm/wallets/trust/dist/thirdweb-dev-wallets-evm-wallets-trust.esm.js"
|
||||
},
|
||||
"default": "./evm/wallets/trust/dist/thirdweb-dev-wallets-evm-wallets-trust.cjs.js"
|
||||
},
|
||||
"./evm/wallets/ethers": {
|
||||
"module": {
|
||||
"browser": "./evm/wallets/ethers/dist/thirdweb-dev-wallets-evm-wallets-ethers.browser.esm.js",
|
||||
@@ -176,6 +183,13 @@
|
||||
},
|
||||
"default": "./evm/connectors/paper/dist/thirdweb-dev-wallets-evm-connectors-paper.cjs.js"
|
||||
},
|
||||
"./evm/connectors/trust": {
|
||||
"module": {
|
||||
"browser": "./evm/connectors/trust/dist/thirdweb-dev-wallets-evm-connectors-trust.browser.esm.js",
|
||||
"default": "./evm/connectors/trust/dist/thirdweb-dev-wallets-evm-connectors-trust.esm.js"
|
||||
},
|
||||
"default": "./evm/connectors/trust/dist/thirdweb-dev-wallets-evm-connectors-trust.cjs.js"
|
||||
},
|
||||
"./evm/wallets/wallet-connect": {
|
||||
"module": {
|
||||
"browser": "./evm/wallets/wallet-connect/dist/thirdweb-dev-wallets-evm-wallets-wallet-connect.browser.esm.js",
|
||||
@@ -317,36 +331,21 @@
|
||||
"@safe-global/safe-ethers-lib": "^1.9.2",
|
||||
"@thirdweb-dev/chains": "workspace:*",
|
||||
"@thirdweb-dev/sdk": "workspace:*",
|
||||
"@walletconnect/client": "^1.8.0",
|
||||
"@walletconnect/core": "2.7.3",
|
||||
"@walletconnect/ethereum-provider": "2.6.0",
|
||||
"@walletconnect/jsonrpc-http-connection": "^1.0.0",
|
||||
"@walletconnect/jsonrpc-provider": "^1.0.3",
|
||||
"@walletconnect/jsonrpc-types": "^1.0.1",
|
||||
"@walletconnect/core": "^2.8.4",
|
||||
"@walletconnect/ethereum-provider": "^2.8.4",
|
||||
"@walletconnect/jsonrpc-utils": "^1.0.3",
|
||||
"@walletconnect/legacy-client": "^2.0.0-rc.0",
|
||||
"@walletconnect/legacy-modal": "^2.0.0-rc.0",
|
||||
"@walletconnect/legacy-types": "^2.0.0-rc.0",
|
||||
"@walletconnect/legacy-utils": "^2.0.0-rc.0",
|
||||
"@walletconnect/types": "2.7.3",
|
||||
"@walletconnect/utils": "2.7.3",
|
||||
"@walletconnect/web3wallet": "^1.7.1",
|
||||
"@web3modal/standalone": "^2.4.1",
|
||||
"@walletconnect/modal": "^2.5.4",
|
||||
"@walletconnect/types": "^2.8.4",
|
||||
"@walletconnect/utils": "^2.8.4",
|
||||
"@walletconnect/web3wallet": "^1.8.1",
|
||||
"buffer": "^6.0.3",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"crypto-js": "^4.1.1",
|
||||
"eip1193-provider": "^1.0.1",
|
||||
"eth-provider": "^0.13.6",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"magic-sdk": "^13.6.2",
|
||||
"web3-core": "1.5.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@walletconnect/ethereum-provider": "2.6.0",
|
||||
"@walletconnect/core": "2.7.3",
|
||||
"@walletconnect/types": "2.7.3",
|
||||
"@walletconnect/utils": "2.7.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/client-secrets-manager": "^3.256.0",
|
||||
"@noble/ed25519": "^1.7.1",
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
import {
|
||||
WCSession,
|
||||
WalletConnectHandler,
|
||||
WalletConnectReceiverConfig,
|
||||
WCMetadata,
|
||||
} from "../types/walletConnect";
|
||||
import WalletConnect from "@walletconnect/client";
|
||||
import { EIP155_SIGNING_METHODS } from "../../evm/constants/wc";
|
||||
import { AbstractClientWallet } from "../../evm/wallets/base";
|
||||
import { SyncStorage } from "../SyncStorage";
|
||||
import {
|
||||
ISessionStorage,
|
||||
IWalletConnectSession,
|
||||
} from "@walletconnect/legacy-types";
|
||||
import { ethers, utils } from "ethers";
|
||||
|
||||
type WalletConnectV1WalletConfig = Omit<
|
||||
WalletConnectReceiverConfig,
|
||||
"enableConnectApp"
|
||||
> & {
|
||||
storage: SyncStorage;
|
||||
};
|
||||
|
||||
const STORAGE_URI_KEY = "storage_uri_key";
|
||||
|
||||
export class WalletConnectV1Handler extends WalletConnectHandler {
|
||||
#wcMetadata: WCMetadata;
|
||||
#wcWallet: WalletConnect | undefined;
|
||||
|
||||
#activeSessionPayload: any;
|
||||
#activeCallRequest: any;
|
||||
|
||||
#storage: SyncStorage;
|
||||
#sessionStorage: ISessionStorage;
|
||||
|
||||
constructor(options: WalletConnectV1WalletConfig) {
|
||||
super();
|
||||
|
||||
this.#wcMetadata = options?.walletConnectWalletMetadata || {
|
||||
name: "Thirdweb Smart Wallet",
|
||||
description: "Thirdweb Smart Wallet",
|
||||
url: "https://thirdweb.com",
|
||||
icons: ["https://thirdweb.com/favicon.ico"],
|
||||
};
|
||||
|
||||
this.#storage = options.storage;
|
||||
this.#sessionStorage = new SessionStorage(options.storage);
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
const uri = this.#storage.getItem(STORAGE_URI_KEY);
|
||||
|
||||
if (uri) {
|
||||
this.#init(uri);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async connectApp(uri: string): Promise<void> {
|
||||
if (!this.#wcWallet) {
|
||||
this.#storage.setItem(STORAGE_URI_KEY, uri);
|
||||
|
||||
this.#init(uri);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async approveSession(wallet: AbstractClientWallet): Promise<void> {
|
||||
if (!this.#wcWallet) {
|
||||
throw new Error(
|
||||
"Please, init the wallet before making session requests.",
|
||||
);
|
||||
}
|
||||
|
||||
const address = await wallet.getAddress();
|
||||
const chainId = await wallet.getChainId();
|
||||
await this.#wcWallet.approveSession({
|
||||
accounts: [address],
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
this.emit("session_approved");
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
rejectSession(): Promise<void> {
|
||||
if (!this.#wcWallet) {
|
||||
throw new Error(
|
||||
"Please, init the wallet before making session requests.",
|
||||
);
|
||||
}
|
||||
|
||||
this.#wcWallet.rejectSession();
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
async approveEIP155Request(wallet: AbstractClientWallet): Promise<void> {
|
||||
const { params, method } = this.#activeCallRequest;
|
||||
|
||||
try {
|
||||
let result;
|
||||
switch (method) {
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
const ethMsg = params[1];
|
||||
result = await wallet.signMessage(utils.arrayify(ethMsg));
|
||||
break;
|
||||
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
||||
const message = params[0];
|
||||
result = await wallet.signMessage(utils.arrayify(message));
|
||||
break;
|
||||
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
||||
const chainId = await wallet.getChainId();
|
||||
const signer = await wallet.getSigner();
|
||||
|
||||
const tx = await signer.sendTransaction(
|
||||
this.#parseTxParams(params, chainId),
|
||||
);
|
||||
const { transactionHash } = await tx.wait();
|
||||
result = transactionHash;
|
||||
break;
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
|
||||
const chainIdSign = await wallet.getChainId();
|
||||
const signerSign = await wallet.getSigner();
|
||||
|
||||
const txParams = await signerSign.populateTransaction(
|
||||
this.#parseTxParams(params, chainIdSign),
|
||||
);
|
||||
result = await signerSign.signTransaction(txParams);
|
||||
break;
|
||||
case EIP155_SIGNING_METHODS.SWITCH_CHAIN: {
|
||||
await wallet.switchChain(params[0].chainId);
|
||||
result = params[0].chainId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.#wcWallet?.approveRequest({
|
||||
id: this.#activeCallRequest?.id,
|
||||
result,
|
||||
});
|
||||
} catch (error) {
|
||||
let message;
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else {
|
||||
message = `Error executing the method: ${method}`;
|
||||
}
|
||||
|
||||
this.#wcWallet?.rejectRequest({
|
||||
id: this.#activeCallRequest?.id,
|
||||
error: { message },
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
rejectEIP155Request(): Promise<void> {
|
||||
this.#wcWallet?.rejectRequest({
|
||||
id: 1,
|
||||
error: {
|
||||
message: "Rejected by user",
|
||||
},
|
||||
});
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
getActiveSessions(): WCSession[] {
|
||||
const session = this.#wcWallet?.session;
|
||||
|
||||
if (!session) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result: WCSession[] = [
|
||||
{
|
||||
topic: session?.clientId,
|
||||
peer: {
|
||||
metadata: session.peerMeta
|
||||
? session.peerMeta
|
||||
: {
|
||||
name: "Thirdweb Powered Wallet",
|
||||
description: "Thirdweb Powered Wallet",
|
||||
url: "https://thirdweb.com",
|
||||
icons: ["https://thirdweb.com/favicon.ico"],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return result;
|
||||
}
|
||||
async disconnectSession(): Promise<void> {
|
||||
this.#wcWallet?.killSession();
|
||||
|
||||
this.#wcWallet?.off("session_request");
|
||||
this.#wcWallet?.off("call_request");
|
||||
this.#wcWallet?.off("disconnect");
|
||||
|
||||
this.#storage.removeItem(STORAGE_URI_KEY);
|
||||
this.#wcWallet = undefined;
|
||||
|
||||
this.emit("session_delete");
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
#init(uri: string) {
|
||||
this.#wcWallet = new WalletConnect({
|
||||
uri: uri,
|
||||
clientMeta: this.#wcMetadata,
|
||||
storage: this.#sessionStorage,
|
||||
});
|
||||
|
||||
this.#setupWalletConnectEventsListeners();
|
||||
}
|
||||
|
||||
#parseTxParams(params: any, chainId: number) {
|
||||
let txParams: ethers.providers.TransactionRequest = {
|
||||
from: params[0].from,
|
||||
data: params[0].data,
|
||||
chainId: chainId,
|
||||
};
|
||||
if (params[0].gas) {
|
||||
txParams = {
|
||||
...txParams,
|
||||
gasLimit: params[0].gas,
|
||||
};
|
||||
}
|
||||
if (params[0].to) {
|
||||
txParams = {
|
||||
...txParams,
|
||||
to: params[0].to,
|
||||
};
|
||||
}
|
||||
return txParams;
|
||||
}
|
||||
|
||||
#setupWalletConnectEventsListeners() {
|
||||
if (!this.#wcWallet) {
|
||||
throw new Error(
|
||||
"Please, init the wallet before making session requests.",
|
||||
);
|
||||
}
|
||||
|
||||
// Subscribe to session requests
|
||||
this.#wcWallet.on("session_request", (error, payload) => {
|
||||
if (error) {
|
||||
throw new Error(`WCV1H.session_request error: ${error.message}`);
|
||||
}
|
||||
|
||||
this.#activeSessionPayload = payload;
|
||||
|
||||
this.emit("session_proposal", {
|
||||
proposer: {
|
||||
metadata: payload.params[0].peerMeta,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Subscribe to call requests
|
||||
this.#wcWallet.on("call_request", (error, payload) => {
|
||||
if (error) {
|
||||
throw new Error(`WCV1H.call_request error: ${error.message}`);
|
||||
}
|
||||
|
||||
const { params, method } = payload;
|
||||
this.#activeCallRequest = payload;
|
||||
|
||||
switch (method) {
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
||||
const message = params[0];
|
||||
const decodedMessage = new TextDecoder().decode(
|
||||
utils.arrayify(message),
|
||||
);
|
||||
|
||||
const paramsCopy = [...params];
|
||||
paramsCopy[0] = decodedMessage;
|
||||
|
||||
this.emit("session_request", {
|
||||
topic: params[1],
|
||||
params: paramsCopy,
|
||||
peer: {
|
||||
metadata: this.#activeSessionPayload.params[0].peerMeta,
|
||||
},
|
||||
method: method,
|
||||
});
|
||||
return;
|
||||
case EIP155_SIGNING_METHODS.SWITCH_CHAIN:
|
||||
const chain = params[0]; // {"chainId":"0x13881"}
|
||||
const chainId = parseInt(chain.chainId, 16);
|
||||
chain.chainId = chainId;
|
||||
|
||||
const paramsCopyWithChain = [...params];
|
||||
paramsCopyWithChain[0] = chain;
|
||||
|
||||
this.emit("session_request", {
|
||||
topic: params[1],
|
||||
params: paramsCopyWithChain,
|
||||
peer: {
|
||||
metadata: this.#activeSessionPayload.params[0].peerMeta,
|
||||
},
|
||||
method: method,
|
||||
});
|
||||
return;
|
||||
|
||||
this.emit("session_request", {
|
||||
topic: params[1],
|
||||
params: params,
|
||||
peer: {
|
||||
metadata: this.#activeSessionPayload.params[0].peerMeta,
|
||||
},
|
||||
method: method,
|
||||
});
|
||||
return;
|
||||
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
|
||||
this.emit("session_request", {
|
||||
topic: method,
|
||||
params: params,
|
||||
peer: {
|
||||
metadata: this.#activeSessionPayload.params[0].peerMeta,
|
||||
},
|
||||
method: method,
|
||||
});
|
||||
return;
|
||||
default:
|
||||
throw new Error(
|
||||
`WalletConnectV1Handler.call_request. Method not implemented: ${method}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
this.#wcWallet.on("disconnect", (error) => {
|
||||
if (error) {
|
||||
throw new Error(`WCV1H.disconnect error: ${error.message}`);
|
||||
}
|
||||
|
||||
this.disconnectSession();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SessionStorage implements ISessionStorage {
|
||||
#storage: SyncStorage;
|
||||
|
||||
constructor(storage: SyncStorage) {
|
||||
this.#storage = storage;
|
||||
}
|
||||
|
||||
getSession(): IWalletConnectSession | null {
|
||||
const session = this.#storage.getItem("session");
|
||||
|
||||
if (!session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sessionObj = JSON.parse(session);
|
||||
|
||||
return sessionObj as IWalletConnectSession;
|
||||
}
|
||||
|
||||
setSession(session: IWalletConnectSession): IWalletConnectSession {
|
||||
this.#storage.setItem("session", JSON.stringify(session));
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
removeSession() {
|
||||
this.#storage.removeItem("session");
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,4 @@ export type { DAppMetaData } from "./types/dAppMeta";
|
||||
export { CredentialsStorage } from "./CredentialsStorage";
|
||||
|
||||
export * from "./types/walletConnect";
|
||||
export { WalletConnectV1Handler } from "./WalletConnect/WalletConnectV1Handler";
|
||||
export { WalletConnectV2Handler } from "./WalletConnect/WalletConnectV2Handler";
|
||||
|
||||
@@ -81,6 +81,10 @@ export class PaperWalletConnector extends Connector<PaperWalletConnectionArgs> {
|
||||
throw new Error("Error connecting User");
|
||||
}
|
||||
|
||||
if (options?.chainId) {
|
||||
this.switchChain(options.chainId);
|
||||
}
|
||||
|
||||
this.setupListeners();
|
||||
return this.getAddress();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { InjectedConnector, InjectedConnectorOptions } from "../injected";
|
||||
import { assertWindowEthereum } from "../../utils/assertWindowEthereum";
|
||||
import { Ethereum } from "../injected/types";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import { AsyncStorage } from "../../../core/AsyncStorage";
|
||||
|
||||
type TrustConnectorConstructorArg = {
|
||||
chains?: Chain[];
|
||||
connectorStorage: AsyncStorage;
|
||||
options?: InjectedConnectorOptions;
|
||||
};
|
||||
|
||||
export class TrustConnector extends InjectedConnector {
|
||||
constructor(arg: TrustConnectorConstructorArg) {
|
||||
const defaultOptions = {
|
||||
name: "Trust",
|
||||
getProvider() {
|
||||
function getReady(ethereum?: Ethereum) {
|
||||
const isTrust = !!ethereum?.isTrust;
|
||||
if (!isTrust) {
|
||||
return;
|
||||
}
|
||||
return ethereum;
|
||||
}
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (assertWindowEthereum(globalThis.window)) {
|
||||
if (globalThis.window.ethereum?.providers) {
|
||||
return globalThis.window.ethereum.providers.find(getReady);
|
||||
}
|
||||
|
||||
return getReady(globalThis.window.ethereum);
|
||||
}
|
||||
},
|
||||
};
|
||||
const options = {
|
||||
...defaultOptions,
|
||||
...arg.options,
|
||||
};
|
||||
super({
|
||||
chains: arg.chains,
|
||||
options,
|
||||
connectorStorage: arg.connectorStorage,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,361 +1,9 @@
|
||||
import { AsyncStorage } from "../../../core/AsyncStorage";
|
||||
import {
|
||||
SwitchChainError,
|
||||
UserRejectedRequestError,
|
||||
normalizeChainId,
|
||||
WagmiConnector,
|
||||
ProviderRpcError,
|
||||
} from "../../../lib/wagmi-core";
|
||||
import { walletIds } from "../../constants/walletIds";
|
||||
import type WalletConnectProvider from "./walletconnect-legacy-provider/index";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import { IWalletConnectSession } from "@walletconnect/legacy-types";
|
||||
import { utils, providers } from "ethers";
|
||||
import { WalletConnectConnector } from "../wallet-connect";
|
||||
|
||||
/**
|
||||
* Wallets that support chain switching through WalletConnect
|
||||
* - imToken (token.im)
|
||||
* - MetaMask (metamask.io)
|
||||
* - Rainbow (rainbow.me)
|
||||
* - Trust Wallet (trustwallet.com)
|
||||
* @deprecated Use `WalletConnectConnector` instead
|
||||
*
|
||||
* The WalletConnect v1.0 protocol has been shut down and no longer works.
|
||||
* To avoid breaking change, `WalletConnectV1Connector` is still available but is an alias of `WalletConnectConnector`.
|
||||
*/
|
||||
// const switchChainAllowedRegex = /(imtoken|metamask|rainbow|trust wallet)/i;
|
||||
|
||||
const LAST_USED_CHAIN_ID = "last-used-chain-id";
|
||||
const LAST_SESSION = "last-session";
|
||||
|
||||
type WalletConnectOptions = ConstructorParameters<
|
||||
typeof WalletConnectProvider
|
||||
>[0];
|
||||
|
||||
type WalletConnectSigner = providers.JsonRpcSigner;
|
||||
|
||||
export class WalletConnectV1Connector extends WagmiConnector<
|
||||
WalletConnectProvider,
|
||||
WalletConnectOptions,
|
||||
WalletConnectSigner
|
||||
> {
|
||||
readonly id = walletIds.walletConnectV1;
|
||||
readonly name = "WalletConnectV1";
|
||||
readonly ready = true;
|
||||
|
||||
#provider?: WalletConnectProvider;
|
||||
#storage: AsyncStorage;
|
||||
|
||||
walletName?: string;
|
||||
|
||||
constructor(config: {
|
||||
chains?: Chain[];
|
||||
storage: AsyncStorage;
|
||||
options: WalletConnectOptions;
|
||||
}) {
|
||||
super(config);
|
||||
|
||||
this.#storage = config.storage;
|
||||
}
|
||||
|
||||
async connect({ chainId }: { chainId?: number } = {}) {
|
||||
try {
|
||||
let targetChainId = chainId;
|
||||
if (!targetChainId) {
|
||||
const lastUsedChainIdStr = await this.#storage.getItem(
|
||||
LAST_USED_CHAIN_ID,
|
||||
);
|
||||
const lastUsedChainId = lastUsedChainIdStr
|
||||
? parseInt(lastUsedChainIdStr)
|
||||
: undefined;
|
||||
if (lastUsedChainId && !this.isChainUnsupported(lastUsedChainId)) {
|
||||
targetChainId = lastUsedChainId;
|
||||
}
|
||||
}
|
||||
|
||||
const provider = await this.getProvider({
|
||||
chainId: targetChainId,
|
||||
create: true,
|
||||
});
|
||||
|
||||
this.setupListeners();
|
||||
|
||||
// Defer message to the next tick to ensure wallet connect data (provided by `.enable()`) is available
|
||||
setTimeout(() => this.emit("message", { type: "connecting" }), 0);
|
||||
|
||||
const accounts = await provider.enable();
|
||||
const account = utils.getAddress(accounts[0] as string);
|
||||
let id = await this.getChainId();
|
||||
let unsupported = this.isChainUnsupported(id);
|
||||
|
||||
// Not all WalletConnect options support programmatic chain switching
|
||||
// Only enable for wallet options that do
|
||||
this.walletName = provider.connector?.peerMeta?.name ?? "";
|
||||
|
||||
// switch to target chainId
|
||||
if (chainId) {
|
||||
try {
|
||||
await this.switchChain(chainId);
|
||||
id = chainId;
|
||||
unsupported = this.isChainUnsupported(id);
|
||||
} catch (e) {
|
||||
console.error(`could not switch to desired chain id: ${chainId} `, e);
|
||||
}
|
||||
}
|
||||
|
||||
this.#handleConnected();
|
||||
this.emit("connect", {
|
||||
account,
|
||||
chain: { id, unsupported },
|
||||
provider,
|
||||
});
|
||||
|
||||
return {
|
||||
account,
|
||||
chain: { id, unsupported },
|
||||
provider: new providers.Web3Provider(
|
||||
provider as providers.ExternalProvider,
|
||||
),
|
||||
};
|
||||
} catch (error) {
|
||||
if (/user closed modal/i.test((error as ProviderRpcError).message)) {
|
||||
throw new UserRejectedRequestError(error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
const provider = await this.getProvider();
|
||||
await provider.disconnect();
|
||||
}
|
||||
|
||||
async getAccount() {
|
||||
const provider = await this.getProvider();
|
||||
const accounts = provider.accounts;
|
||||
// return checksum address
|
||||
return utils.getAddress(accounts[0] as string);
|
||||
}
|
||||
|
||||
async getChainId() {
|
||||
const provider = await this.getProvider();
|
||||
const chainId = normalizeChainId(provider.chainId);
|
||||
return chainId;
|
||||
}
|
||||
|
||||
async getProvider({
|
||||
chainId,
|
||||
create,
|
||||
}: { chainId?: number; create?: boolean } = {}) {
|
||||
// Force create new provider
|
||||
if (!this.#provider || chainId || create) {
|
||||
const rpc = !this.options?.infuraId
|
||||
? this.chains.reduce(
|
||||
(rpc_, chain) => ({
|
||||
...rpc_,
|
||||
[chain.chainId]: chain.rpc[0],
|
||||
}),
|
||||
{},
|
||||
)
|
||||
: {};
|
||||
|
||||
const WalletConnectProvider = (
|
||||
await import("./walletconnect-legacy-provider/index")
|
||||
).default;
|
||||
|
||||
const sessionStr = await this.#storage.getItem(LAST_SESSION);
|
||||
const session = sessionStr ? JSON.parse(sessionStr) : undefined;
|
||||
this.walletName = session?.peerMeta?.name || undefined;
|
||||
|
||||
this.#provider = new WalletConnectProvider({
|
||||
...this.options,
|
||||
chainId,
|
||||
rpc: { ...rpc, ...this.options?.rpc },
|
||||
session: session ? (session as IWalletConnectSession) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return this.#provider;
|
||||
}
|
||||
|
||||
async getSigner({ chainId }: { chainId?: number } = {}) {
|
||||
const [provider, account] = await Promise.all([
|
||||
this.getProvider({ chainId }),
|
||||
this.getAccount(),
|
||||
]);
|
||||
return new providers.Web3Provider(
|
||||
provider as providers.ExternalProvider,
|
||||
chainId,
|
||||
).getSigner(account);
|
||||
}
|
||||
|
||||
async isAuthorized() {
|
||||
try {
|
||||
const account = await this.getAccount();
|
||||
return !!account;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async switchChain(chainId: number) {
|
||||
const provider = await this.getProvider();
|
||||
const chainIdHex = utils.hexValue(chainId);
|
||||
|
||||
try {
|
||||
// Set up a race between `wallet_switchEthereumChain` & the `chainChanged` event
|
||||
// to ensure the chain has been switched. This is because there could be a case
|
||||
// where a wallet may not resolve the `wallet_switchEthereumChain` method, or
|
||||
// resolves slower than `chainChanged`.
|
||||
await Promise.race([
|
||||
provider.request({
|
||||
method: "wallet_switchEthereumChain",
|
||||
params: [{ chainId: chainIdHex }],
|
||||
}),
|
||||
new Promise((res) =>
|
||||
this.on("change", ({ chain }) => {
|
||||
if (chain?.id === chainId) {
|
||||
res(chainId);
|
||||
}
|
||||
}),
|
||||
),
|
||||
]);
|
||||
return (
|
||||
this.chains.find((x) => x.chainId === chainId) ??
|
||||
({
|
||||
chainId: chainId,
|
||||
name: `Chain ${chainIdHex}`,
|
||||
network: `${chainIdHex}`,
|
||||
nativeCurrency: { name: "Ether", decimals: 18, symbol: "ETH" },
|
||||
rpc: [""],
|
||||
shortName: "eth",
|
||||
chain: "ETH",
|
||||
slug: "ethereum",
|
||||
testnet: false,
|
||||
} as Chain)
|
||||
);
|
||||
} catch (error) {
|
||||
const message =
|
||||
typeof error === "string"
|
||||
? error
|
||||
: (error as ProviderRpcError)?.message;
|
||||
if (/user rejected request/i.test(message)) {
|
||||
throw new UserRejectedRequestError(error);
|
||||
}
|
||||
|
||||
const chain = this.chains.find((x) => x.chainId === chainId);
|
||||
|
||||
// if chain is not supported
|
||||
if (!chain) {
|
||||
throw new SwitchChainError(
|
||||
`Chain ${chainId} is not added in the list of supported chains`,
|
||||
);
|
||||
}
|
||||
|
||||
// if chain is not configured in the wallet
|
||||
if (/Unrecognized chain ID/i.test(message)) {
|
||||
// configure it
|
||||
this.emit("message", { type: "add_chain" });
|
||||
const blockExplorerUrls = this.getBlockExplorerUrls(chain);
|
||||
|
||||
await provider.request({
|
||||
method: "wallet_addEthereumChain",
|
||||
params: [
|
||||
{
|
||||
chainId: chainIdHex,
|
||||
chainName: chain.name,
|
||||
nativeCurrency: chain.nativeCurrency,
|
||||
rpcUrls: chain.rpc,
|
||||
blockExplorerUrls,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return chain;
|
||||
} else {
|
||||
throw new SwitchChainError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #handleConnected() {
|
||||
const session = this.#provider?.connector.session;
|
||||
this.walletName = session?.peerMeta?.name || "";
|
||||
const sessionStr = JSON.stringify(session);
|
||||
|
||||
this.#storage.setItem(LAST_SESSION, sessionStr);
|
||||
}
|
||||
|
||||
async setupListeners() {
|
||||
if (!this.#provider) {
|
||||
return;
|
||||
}
|
||||
this.#provider.on("accountsChanged", this.onAccountsChanged);
|
||||
this.#provider.on("chainChanged", this.onChainChanged);
|
||||
this.#provider.on("disconnect", this.onDisconnect);
|
||||
this.#provider.on("message", this.onMessage);
|
||||
this.#provider.on("switchChain", this.onSwitchChain);
|
||||
this.#provider.on("display_uri", this.onDisplayUri);
|
||||
this.#provider.on("call_request_sent", this.onRequestSent);
|
||||
}
|
||||
|
||||
#removeListeners() {
|
||||
if (!this.#provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#provider.removeListener("accountsChanged", this.onAccountsChanged);
|
||||
this.#provider.removeListener("chainChanged", this.onChainChanged);
|
||||
this.#provider.removeListener("disconnect", this.onDisconnect);
|
||||
this.#provider.removeListener("message", this.onMessage);
|
||||
this.#provider.removeListener("switchChain", this.onSwitchChain);
|
||||
this.#provider.removeListener("display_uri", this.onDisplayUri);
|
||||
this.#provider.removeListener("call_request_sent", this.onRequestSent);
|
||||
}
|
||||
|
||||
protected onSwitchChain = () => {
|
||||
this.emit("message", { type: "switch_chain" });
|
||||
};
|
||||
|
||||
protected onDisplayUri = async (
|
||||
error: any,
|
||||
payload: { params: string[] },
|
||||
) => {
|
||||
if (error) {
|
||||
this.emit("message", { data: error, type: "display_uri_error" });
|
||||
}
|
||||
this.emit("message", { data: payload.params[0], type: "display_uri" });
|
||||
};
|
||||
|
||||
protected onRequestSent = (error: any, payload: { params: string[] }) => {
|
||||
if (error) {
|
||||
this.emit("message", { data: error, type: "request" });
|
||||
}
|
||||
this.emit("message", { data: payload.params[0], type: "request" });
|
||||
};
|
||||
|
||||
protected onMessage = (message: { type: string; data: unknown }) => {
|
||||
this.emit("message", message);
|
||||
};
|
||||
|
||||
protected onAccountsChanged = (accounts: string[]) => {
|
||||
if (accounts.length === 0) {
|
||||
this.emit("disconnect");
|
||||
} else {
|
||||
this.emit("change", { account: utils.getAddress(accounts[0] as string) });
|
||||
}
|
||||
};
|
||||
|
||||
protected onChainChanged = (chainId: number | string) => {
|
||||
const id = normalizeChainId(chainId);
|
||||
const unsupported = this.isChainUnsupported(id);
|
||||
this.#storage.setItem(LAST_USED_CHAIN_ID, String(chainId));
|
||||
this.emit("change", { chain: { id, unsupported } });
|
||||
};
|
||||
|
||||
protected onDisconnect = async () => {
|
||||
this.walletName = undefined;
|
||||
this.#storage.removeItem(LAST_USED_CHAIN_ID);
|
||||
this.#storage.removeItem(LAST_SESSION);
|
||||
|
||||
this.#removeListeners();
|
||||
|
||||
this.emit("disconnect");
|
||||
};
|
||||
}
|
||||
export const WalletConnectV1Connector = WalletConnectConnector;
|
||||
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
import SignerConnection from "./signer";
|
||||
import { IWCEthRpcConnectionOptionsWithSession } from "./types";
|
||||
import { HttpConnection } from "@walletconnect/jsonrpc-http-connection";
|
||||
import { JsonRpcProvider } from "@walletconnect/jsonrpc-provider";
|
||||
import {
|
||||
IConnector,
|
||||
IRpcConfig,
|
||||
SIGNING_METHODS,
|
||||
} from "@walletconnect/legacy-types";
|
||||
import { getRpcUrl } from "@walletconnect/legacy-utils";
|
||||
import {
|
||||
IEthereumProvider,
|
||||
ProviderAccounts,
|
||||
RequestArguments,
|
||||
} from "eip1193-provider";
|
||||
import EventEmitter from "eventemitter3";
|
||||
|
||||
class WalletConnectProvider implements IEthereumProvider {
|
||||
public events: any = new EventEmitter();
|
||||
|
||||
private rpc: IRpcConfig;
|
||||
private signer: JsonRpcProvider;
|
||||
private http: JsonRpcProvider | undefined;
|
||||
|
||||
constructor(opts?: IWCEthRpcConnectionOptionsWithSession) {
|
||||
this.rpc = { infuraId: opts?.infuraId, custom: opts?.rpc };
|
||||
this.signer = new JsonRpcProvider(new SignerConnection(opts));
|
||||
const chainId =
|
||||
(this.signer.connection as SignerConnection).chainId ||
|
||||
opts?.chainId ||
|
||||
1;
|
||||
this.http = this.setHttpProvider(chainId);
|
||||
this.registerEventListeners();
|
||||
}
|
||||
|
||||
get connected(): boolean {
|
||||
return (this.signer.connection as SignerConnection).connected;
|
||||
}
|
||||
|
||||
get connector(): IConnector {
|
||||
return (this.signer.connection as SignerConnection).connector;
|
||||
}
|
||||
|
||||
get accounts(): string[] {
|
||||
return (this.signer.connection as SignerConnection).accounts;
|
||||
}
|
||||
|
||||
get chainId(): number {
|
||||
return (this.signer.connection as SignerConnection).chainId;
|
||||
}
|
||||
|
||||
get rpcUrl(): string {
|
||||
return (this.http?.connection as HttpConnection).url || "";
|
||||
}
|
||||
|
||||
public async request<T = unknown>(args: RequestArguments): Promise<T> {
|
||||
switch (args.method) {
|
||||
case "eth_requestAccounts":
|
||||
await this.connect();
|
||||
return (this.signer.connection as any).accounts;
|
||||
case "eth_accounts":
|
||||
return (this.signer.connection as any).accounts;
|
||||
case "eth_chainId":
|
||||
return (this.signer.connection as any).chainId;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (SIGNING_METHODS.includes(args.method)) {
|
||||
return this.signer.request(args);
|
||||
}
|
||||
if (typeof this.http === "undefined") {
|
||||
throw new Error(
|
||||
`Cannot request JSON-RPC method (${args.method}) without provided rpc url`,
|
||||
);
|
||||
}
|
||||
return this.http.request(args);
|
||||
}
|
||||
|
||||
public async enable(): Promise<ProviderAccounts> {
|
||||
const accounts = await this.request({ method: "eth_requestAccounts" });
|
||||
return accounts as ProviderAccounts;
|
||||
}
|
||||
|
||||
public async connect(): Promise<void> {
|
||||
if (!this.signer.connection.connected) {
|
||||
await this.signer.connect();
|
||||
}
|
||||
}
|
||||
|
||||
public async disconnect(): Promise<void> {
|
||||
if (this.signer.connection.connected) {
|
||||
await this.signer.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public on(event: any, listener: any): void {
|
||||
this.events.on(event, listener);
|
||||
}
|
||||
public once(event: string, listener: any): void {
|
||||
this.events.once(event, listener);
|
||||
}
|
||||
public removeListener(event: string, listener: any): void {
|
||||
this.events.removeListener(event, listener);
|
||||
}
|
||||
public off(event: string, listener: any): void {
|
||||
this.events.off(event, listener);
|
||||
}
|
||||
|
||||
get isWalletConnect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------- Private ----------------------------------------------- //
|
||||
|
||||
private registerEventListeners() {
|
||||
this.signer.connection.on("accountsChanged", (accounts: string[]) => {
|
||||
this.events.emit("accountsChanged", accounts);
|
||||
});
|
||||
this.signer.connection.on("chainChanged", (chainId: number) => {
|
||||
this.http = this.setHttpProvider(chainId);
|
||||
this.events.emit("chainChanged", chainId);
|
||||
});
|
||||
this.connector.on(
|
||||
"display_uri",
|
||||
(error: any, payload: { params: string[] }) => {
|
||||
this.events.emit("display_uri", error, payload);
|
||||
},
|
||||
);
|
||||
this.connector.on(
|
||||
"call_request_sent",
|
||||
(error: any, payload: { params: string[] }) => {
|
||||
this.events.emit("call_request_sent", error, payload);
|
||||
},
|
||||
);
|
||||
this.signer.on("disconnect", () => {
|
||||
this.events.emit("disconnect");
|
||||
});
|
||||
}
|
||||
|
||||
private setHttpProvider(chainId: number): JsonRpcProvider | undefined {
|
||||
const rpcUrl = getRpcUrl(chainId, this.rpc);
|
||||
if (typeof rpcUrl === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const http = new JsonRpcProvider(new HttpConnection(rpcUrl));
|
||||
return http;
|
||||
}
|
||||
}
|
||||
|
||||
export default WalletConnectProvider;
|
||||
-263
@@ -1,263 +0,0 @@
|
||||
import type { IWCEthRpcConnectionOptionsWithSession } from "./types";
|
||||
import {
|
||||
IJsonRpcConnection,
|
||||
JsonRpcError,
|
||||
JsonRpcResponse,
|
||||
} from "@walletconnect/jsonrpc-types";
|
||||
import { formatJsonRpcError } from "@walletconnect/jsonrpc-utils";
|
||||
import WalletConnect from "@walletconnect/legacy-client";
|
||||
import QRCodeModal from "@walletconnect/legacy-modal";
|
||||
import {
|
||||
IConnector,
|
||||
IJsonRpcResponseError,
|
||||
IJsonRpcResponseSuccess,
|
||||
IQRCodeModalOptions,
|
||||
} from "@walletconnect/legacy-types";
|
||||
import EventEmitter from "eventemitter3";
|
||||
|
||||
export class SignerConnection extends IJsonRpcConnection {
|
||||
public events: any = new EventEmitter();
|
||||
|
||||
public accounts: string[] = [];
|
||||
public chainId = 1;
|
||||
|
||||
private pending = false;
|
||||
private wc: IConnector | undefined;
|
||||
private bridge = "https://bridge.walletconnect.org";
|
||||
private qrcode = true;
|
||||
private qrcodeModalOptions: IQRCodeModalOptions | undefined = undefined;
|
||||
private opts: IWCEthRpcConnectionOptionsWithSession | undefined;
|
||||
|
||||
constructor(opts?: IWCEthRpcConnectionOptionsWithSession) {
|
||||
super();
|
||||
this.opts = opts;
|
||||
this.chainId = opts?.chainId || this.chainId;
|
||||
this.wc = this.register(opts);
|
||||
}
|
||||
|
||||
get connected(): boolean {
|
||||
return typeof this.wc !== "undefined" && this.wc.connected;
|
||||
}
|
||||
|
||||
get connecting(): boolean {
|
||||
return this.pending;
|
||||
}
|
||||
|
||||
get connector(): IConnector {
|
||||
this.wc = this.register(this.opts);
|
||||
return this.wc;
|
||||
}
|
||||
|
||||
public on(event: string, listener: any) {
|
||||
this.events.on(event, listener);
|
||||
}
|
||||
|
||||
public once(event: string, listener: any) {
|
||||
this.events.once(event, listener);
|
||||
}
|
||||
|
||||
public off(event: string, listener: any) {
|
||||
this.events.off(event, listener);
|
||||
}
|
||||
|
||||
public removeListener(event: string, listener: any) {
|
||||
this.events.removeListener(event, listener);
|
||||
}
|
||||
|
||||
public async open(chainId?: number): Promise<void> {
|
||||
if (this.connected) {
|
||||
this.onOpen();
|
||||
return;
|
||||
}
|
||||
return new Promise((resolve, reject): void => {
|
||||
this.on("error", (err: any) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
this.on("open", () => {
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.create(chainId);
|
||||
});
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
if (typeof this.wc === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (this.wc.connected) {
|
||||
this.wc.killSession();
|
||||
}
|
||||
this.onClose();
|
||||
}
|
||||
|
||||
public async send(payload: any) {
|
||||
this.wc = this.register(this.opts);
|
||||
|
||||
if (!this.connected) {
|
||||
await this.open();
|
||||
}
|
||||
this.sendPayload(payload)
|
||||
.then((res: any) => this.events.emit("payload", res))
|
||||
.catch((e) =>
|
||||
this.events.emit("payload", formatJsonRpcError(payload.id, e.message)),
|
||||
);
|
||||
}
|
||||
|
||||
public async sendAsync(payload: any) {
|
||||
// noop
|
||||
console.log("sendAsync", payload);
|
||||
}
|
||||
|
||||
// ---------- Private ----------------------------------------------- //
|
||||
|
||||
private register(opts?: IWCEthRpcConnectionOptionsWithSession): IConnector {
|
||||
if (this.wc) {
|
||||
return this.wc;
|
||||
}
|
||||
this.opts = opts || this.opts;
|
||||
this.bridge = opts?.connector
|
||||
? opts.connector.bridge
|
||||
: opts?.bridge || "https://bridge.walletconnect.org";
|
||||
|
||||
this.qrcode = typeof opts?.qrcode === "undefined" || opts.qrcode !== false;
|
||||
this.chainId =
|
||||
typeof opts?.chainId !== "undefined" ? opts.chainId : this.chainId;
|
||||
this.qrcodeModalOptions = opts?.qrcodeModalOptions;
|
||||
const connectorOpts = {
|
||||
bridge: this.bridge,
|
||||
qrcodeModal: this.qrcode ? QRCodeModal : undefined,
|
||||
qrcodeModalOptions: this.qrcodeModalOptions,
|
||||
storageId: opts?.storageId,
|
||||
signingMethods: opts?.signingMethods,
|
||||
clientMeta: opts?.clientMeta,
|
||||
session: opts?.session,
|
||||
};
|
||||
this.wc =
|
||||
typeof opts?.connector !== "undefined"
|
||||
? opts.connector
|
||||
: new WalletConnect(connectorOpts);
|
||||
if (typeof this.wc === "undefined") {
|
||||
throw new Error("Failed to register WalletConnect connector");
|
||||
}
|
||||
if (this.wc.accounts.length) {
|
||||
this.accounts = this.wc.accounts;
|
||||
}
|
||||
if (this.wc.chainId) {
|
||||
this.chainId = this.wc.chainId;
|
||||
}
|
||||
// this.accounts = this.wc.accounts;
|
||||
// this.chainId = this.wc.chainId;
|
||||
this.registerConnectorEvents();
|
||||
return this.wc;
|
||||
}
|
||||
|
||||
private onOpen(wc?: IConnector) {
|
||||
this.pending = false;
|
||||
if (wc) {
|
||||
this.wc = wc;
|
||||
}
|
||||
this.events.emit("open");
|
||||
}
|
||||
|
||||
private onClose() {
|
||||
this.pending = false;
|
||||
if (this.wc) {
|
||||
this.wc = undefined;
|
||||
}
|
||||
this.events.emit("close");
|
||||
}
|
||||
|
||||
public onError(
|
||||
payload: any,
|
||||
message = "Failed or Rejected Request",
|
||||
code = -32000,
|
||||
): JsonRpcError {
|
||||
const errorPayload = {
|
||||
id: payload.id,
|
||||
jsonrpc: payload.jsonrpc,
|
||||
error: { code, message },
|
||||
};
|
||||
this.events.emit("payload", errorPayload);
|
||||
return errorPayload;
|
||||
}
|
||||
|
||||
private create(chainId?: number): void {
|
||||
this.wc = this.register(this.opts);
|
||||
this.chainId = chainId || this.chainId;
|
||||
if (this.connected || this.pending) {
|
||||
return;
|
||||
}
|
||||
this.pending = true;
|
||||
this.registerConnectorEvents();
|
||||
this.wc
|
||||
.createSession({ chainId: this.chainId })
|
||||
.then(() => this.events.emit("created"))
|
||||
.catch((e: Error) => this.events.emit("error", e));
|
||||
}
|
||||
|
||||
private registerConnectorEvents() {
|
||||
this.wc = this.register(this.opts);
|
||||
|
||||
this.wc.on("connect", (err: Error | null) => {
|
||||
if (err) {
|
||||
this.events.emit("error", err);
|
||||
return;
|
||||
}
|
||||
this.accounts = this.wc?.accounts || [];
|
||||
this.chainId = this.wc?.chainId || this.chainId;
|
||||
|
||||
this.onOpen();
|
||||
});
|
||||
|
||||
this.wc.on("disconnect", (err: Error | null) => {
|
||||
if (err) {
|
||||
this.events.emit("error", err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.onClose();
|
||||
});
|
||||
|
||||
this.wc.on("modal_closed", () => {
|
||||
this.events.emit("error", new Error("User closed modal"));
|
||||
});
|
||||
|
||||
this.wc.on("session_update", (_error, payload) => {
|
||||
const { accounts, chainId } = payload.params[0];
|
||||
if (!this.accounts || (accounts && this.accounts !== accounts)) {
|
||||
this.accounts = accounts;
|
||||
this.events.emit("accountsChanged", accounts);
|
||||
}
|
||||
if (!this.chainId || (chainId && this.chainId !== chainId)) {
|
||||
this.chainId = chainId;
|
||||
this.events.emit("chainChanged", chainId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async sendPayload(payload: any): Promise<JsonRpcResponse> {
|
||||
this.wc = this.register(this.opts);
|
||||
try {
|
||||
const response = await this.wc.unsafeSend(payload);
|
||||
return this.sanitizeResponse(response);
|
||||
} catch (error) {
|
||||
return this.onError(payload, (error as any).message);
|
||||
}
|
||||
}
|
||||
|
||||
private sanitizeResponse(
|
||||
response: IJsonRpcResponseSuccess | IJsonRpcResponseError,
|
||||
): JsonRpcResponse {
|
||||
return typeof (response as IJsonRpcResponseError).error !== "undefined" &&
|
||||
typeof (response as IJsonRpcResponseError).error.code === "undefined"
|
||||
? formatJsonRpcError(
|
||||
response.id,
|
||||
(response as IJsonRpcResponseError).error.message,
|
||||
)
|
||||
: (response as JsonRpcResponse);
|
||||
}
|
||||
}
|
||||
|
||||
export default SignerConnection;
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import {
|
||||
IWCEthRpcConnectionOptions,
|
||||
IWalletConnectSession,
|
||||
} from "@walletconnect/legacy-types";
|
||||
|
||||
export type IWCEthRpcConnectionOptionsWithSession =
|
||||
IWCEthRpcConnectionOptions & { session?: IWalletConnectSession };
|
||||
@@ -120,9 +120,11 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
|
||||
// If there no active session, or the chains are stale, connect.
|
||||
if (!provider.session || isChainsStale) {
|
||||
const optionalChains = this.chains
|
||||
.filter((chain) => chain.chainId !== targetChainId)
|
||||
.map((optionalChain) => optionalChain.chainId);
|
||||
// defaultChains, passing ALL CHAINS hangs the connector
|
||||
const optionalChains = [
|
||||
1, 5, 84531, 137, 80001, 42161, 421613, 10, 420, 56, 97, 250, 4002,
|
||||
43114, 43113, 1337,
|
||||
].filter((chainId) => chainId !== targetChainId);
|
||||
|
||||
this.emit("message", { type: "connecting" });
|
||||
|
||||
@@ -133,7 +135,9 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
optionalChains.length > 0 ? optionalChains : [targetChainId],
|
||||
});
|
||||
|
||||
this.#setRequestedChainsIds(this.chains.map(({ chainId }) => chainId));
|
||||
await this.#setRequestedChainsIds(
|
||||
this.chains.map(({ chainId }) => chainId),
|
||||
);
|
||||
}
|
||||
|
||||
// If session exists and chains are authorized, enable provider for required chain
|
||||
@@ -168,7 +172,7 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
}
|
||||
} finally {
|
||||
this.#removeListeners();
|
||||
this.#setRequestedChainsIds([]);
|
||||
await this.#setRequestedChainsIds([]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +271,7 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
});
|
||||
const requestedChains = await this.#getRequestedChainsIds();
|
||||
requestedChains.push(chainId);
|
||||
this.#setRequestedChainsIds(requestedChains);
|
||||
await this.#setRequestedChainsIds(requestedChains);
|
||||
}
|
||||
await provider.request({
|
||||
method: "wallet_switchEthereumChain",
|
||||
@@ -314,6 +318,7 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
optionalEvents: OPTIONAL_EVENTS,
|
||||
chains: [defaultChain],
|
||||
optionalChains: optionalChains,
|
||||
|
||||
metadata: {
|
||||
name: this.options.dappMetadata.name,
|
||||
description: this.options.dappMetadata.description || "",
|
||||
@@ -324,11 +329,7 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
this.chains.map((chain) => [chain.chainId, chain.rpc[0]]),
|
||||
),
|
||||
|
||||
qrModalOptions: {
|
||||
...this.options.qrModalOptions,
|
||||
explorerAllowList: [],
|
||||
explorerDenyList: [],
|
||||
},
|
||||
qrModalOptions: this.options.qrModalOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -403,8 +404,8 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
this.#provider.removeListener("connect", this.onConnect);
|
||||
}
|
||||
|
||||
#setRequestedChainsIds(chains: number[]) {
|
||||
this.#storage.setItem(REQUESTED_CHAINS_KEY, JSON.stringify(chains));
|
||||
async #setRequestedChainsIds(chains: number[]) {
|
||||
await this.#storage.setItem(REQUESTED_CHAINS_KEY, JSON.stringify(chains));
|
||||
}
|
||||
|
||||
async #getRequestedChainsIds(): Promise<number[]> {
|
||||
@@ -438,16 +439,16 @@ export class WalletConnectConnector extends WagmiConnector<
|
||||
}
|
||||
};
|
||||
|
||||
protected onChainChanged = (chainId: number | string) => {
|
||||
protected onChainChanged = async (chainId: number | string) => {
|
||||
const id = Number(chainId);
|
||||
const unsupported = this.isChainUnsupported(id);
|
||||
this.#storage.setItem(LAST_USED_CHAIN_ID, String(chainId));
|
||||
await this.#storage.setItem(LAST_USED_CHAIN_ID, String(chainId));
|
||||
this.emit("change", { chain: { id, unsupported } });
|
||||
};
|
||||
|
||||
protected onDisconnect = () => {
|
||||
this.#setRequestedChainsIds([]);
|
||||
this.#storage.removeItem(LAST_USED_CHAIN_ID);
|
||||
protected onDisconnect = async () => {
|
||||
await this.#setRequestedChainsIds([]);
|
||||
await this.#storage.removeItem(LAST_USED_CHAIN_ID);
|
||||
this.emit("disconnect");
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { WalletConnectModalConfig } from "@walletconnect/modal";
|
||||
|
||||
export type QRModalOptions = {
|
||||
/**
|
||||
* When using Web3Modal in standalone mode (without wagmi) you can define array of custom chains via this option.
|
||||
@@ -6,7 +8,7 @@ export type QRModalOptions = {
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#standalonechains-optional
|
||||
*/
|
||||
standaloneChains?: string[];
|
||||
standaloneChains?: string[];
|
||||
/**
|
||||
* You can define an array of custom mobile wallets.
|
||||
*
|
||||
@@ -18,7 +20,7 @@ export type QRModalOptions = {
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#mobilewallets-optional
|
||||
*/
|
||||
mobileWallets?: MobileWallet[];
|
||||
mobileWallets?: WalletConnectModalConfig['mobileWallets']
|
||||
/**
|
||||
* You can define an array of custom desktop or web based wallets.
|
||||
*
|
||||
@@ -30,7 +32,7 @@ export type QRModalOptions = {
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#desktopwallets-optional
|
||||
*/
|
||||
desktopWallets?: DesktopWallet[];
|
||||
desktopWallets?: WalletConnectModalConfig['desktopWallets'];
|
||||
/**
|
||||
* Array of wallet id's and their logo mappings.
|
||||
*
|
||||
@@ -149,62 +151,7 @@ export type QRModalOptions = {
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#themevariables-optional
|
||||
*/
|
||||
themeVariables?: {
|
||||
"--w3m-z-index"?: string;
|
||||
"--w3m-accent-color"?: string;
|
||||
"--w3m-accent-fill-color"?: string;
|
||||
"--w3m-background-color"?: string;
|
||||
"--w3m-background-image-url"?: string;
|
||||
"--w3m-logo-image-url"?: string;
|
||||
"--w3m-background-border-radius"?: string;
|
||||
"--w3m-container-border-radius"?: string;
|
||||
"--w3m-wallet-icon-border-radius"?: string;
|
||||
"--w3m-wallet-icon-large-border-radius"?: string;
|
||||
"--w3m-wallet-icon-small-border-radius"?: string;
|
||||
"--w3m-input-border-radius"?: string;
|
||||
"--w3m-notification-border-radius"?: string;
|
||||
"--w3m-button-border-radius"?: string;
|
||||
"--w3m-secondary-button-border-radius"?: string;
|
||||
"--w3m-icon-button-border-radius"?: string;
|
||||
"--w3m-button-hover-highlight-border-radius"?: string;
|
||||
"--w3m-font-family"?: string;
|
||||
"--w3m-text-big-bold-size"?: string;
|
||||
"--w3m-text-big-bold-weight"?: string;
|
||||
"--w3m-text-big-bold-line-height"?: string;
|
||||
"--w3m-text-big-bold-letter-spacing"?: string;
|
||||
"--w3m-text-big-bold-text-transform"?: string;
|
||||
"--w3m-text-big-bold-font-family"?: string;
|
||||
"--w3m-text-medium-regular-size"?: string;
|
||||
"--w3m-text-medium-regular-weight"?: string;
|
||||
"--w3m-text-medium-regular-line-height"?: string;
|
||||
"--w3m-text-medium-regular-letter-spacing"?: string;
|
||||
"--w3m-text-medium-regular-text-transform"?: string;
|
||||
"--w3m-text-medium-regular-font-family"?: string;
|
||||
"--w3m-text-small-regular-size"?: string;
|
||||
"--w3m-text-small-regular-weight"?: string;
|
||||
"--w3m-text-small-regular-line-height"?: string;
|
||||
"--w3m-text-small-regular-letter-spacing"?: string;
|
||||
"--w3m-text-small-regular-text-transform"?: string;
|
||||
"--w3m-text-small-regular-font-family"?: string;
|
||||
"--w3m-text-small-thin-size"?: string;
|
||||
"--w3m-text-small-thin-weight"?: string;
|
||||
"--w3m-text-small-thin-line-height"?: string;
|
||||
"--w3m-text-small-thin-letter-spacing"?: string;
|
||||
"--w3m-text-small-thin-text-transform"?: string;
|
||||
"--w3m-text-small-thin-font-family"?: string;
|
||||
"--w3m-text-xsmall-bold-size"?: string;
|
||||
"--w3m-text-xsmall-bold-weight"?: string;
|
||||
"--w3m-text-xsmall-bold-line-height"?: string;
|
||||
"--w3m-text-xsmall-bold-letter-spacing"?: string;
|
||||
"--w3m-text-xsmall-bold-text-transform"?: string;
|
||||
"--w3m-text-xsmall-bold-font-family"?: string;
|
||||
"--w3m-text-xsmall-regular-size"?: string;
|
||||
"--w3m-text-xsmall-regular-weight"?: string;
|
||||
"--w3m-text-xsmall-regular-line-height"?: string;
|
||||
"--w3m-text-xsmall-regular-letter-spacing"?: string;
|
||||
"--w3m-text-xsmall-regular-text-transform"?: string;
|
||||
"--w3m-text-xsmall-regular-font-family"?: string;
|
||||
};
|
||||
themeVariables?: WalletConnectModalConfig['themeVariables']
|
||||
/**
|
||||
* Puts Web3Modal into dark or light mode. Defaults to user's system preference.
|
||||
*
|
||||
@@ -213,19 +160,3 @@ export type QRModalOptions = {
|
||||
themeMode?: "dark" | "light";
|
||||
};
|
||||
|
||||
export interface MobileWallet {
|
||||
id: string;
|
||||
name: string;
|
||||
links: {
|
||||
universal: string;
|
||||
native?: string;
|
||||
};
|
||||
}
|
||||
export interface DesktopWallet {
|
||||
id: string;
|
||||
name: string;
|
||||
links: {
|
||||
native: string;
|
||||
universal: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ export const walletIds = {
|
||||
localWallet: "localWallet",
|
||||
smartWallet: "smartWallet",
|
||||
safe: "safe",
|
||||
trust: "trust",
|
||||
walletConnectV1: "walletConnectV1",
|
||||
walletConnect: "walletConnect",
|
||||
magicLink: "magicLink",
|
||||
|
||||
@@ -38,6 +38,7 @@ export * from "./wallets/smart-wallet";
|
||||
export * from "./wallets/ethers";
|
||||
export * from "./wallets/private-key";
|
||||
export * from "./wallets/zerion";
|
||||
export * from "./wallets/trust";
|
||||
|
||||
export type { Chain } from "@thirdweb-dev/chains";
|
||||
|
||||
|
||||
@@ -1,15 +1,32 @@
|
||||
import type { WalletConnectV1Connector as WalletConnectV1ConnectorType } from "../connectors/wallet-connect-v1";
|
||||
import type { WalletConnectConnector as WalletConnectConnectorType } from "../connectors/wallet-connect";
|
||||
import type { QRModalOptions } from "../connectors/wallet-connect/qrModalOptions";
|
||||
import { Connector, WagmiAdapter } from "../interfaces/connector";
|
||||
import { assertWindowEthereum } from "../utils/assertWindowEthereum";
|
||||
import { AbstractClientWallet, WalletOptions } from "./base";
|
||||
import type { MetaMaskConnector as MetamaskConnectorType } from "../connectors/metamask";
|
||||
import { walletIds } from "../constants/walletIds";
|
||||
import { TW_WC_PROJECT_ID } from "../constants/wc";
|
||||
|
||||
type MetamaskAdditionalOptions = {
|
||||
/**
|
||||
* Whether to display the Wallet Connect QR code Modal for connecting to MetaMask on mobile if MetaMask is not injected.
|
||||
* Whether to open the default Wallet Connect QR code Modal for connecting to Zerion Wallet on mobile if Zerion is not injected when calling connect().
|
||||
*/
|
||||
qrcode?: boolean;
|
||||
|
||||
/**
|
||||
* When connecting MetaMask using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
|
||||
/**
|
||||
* options to customize the Wallet Connect QR Code Modal ( only relevant when qrcode is true )
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options
|
||||
*/
|
||||
qrModalOptions?: QRModalOptions;
|
||||
};
|
||||
|
||||
export type MetamaskWalletOptions = WalletOptions<MetamaskAdditionalOptions>;
|
||||
@@ -22,7 +39,7 @@ type ConnectWithQrCodeArgs = {
|
||||
|
||||
export class MetaMaskWallet extends AbstractClientWallet<MetamaskAdditionalOptions> {
|
||||
connector?: Connector;
|
||||
walletConnectConnector?: WalletConnectV1ConnectorType;
|
||||
walletConnectConnector?: WalletConnectConnectorType;
|
||||
metamaskConnector?: MetamaskConnectorType;
|
||||
isInjected: boolean;
|
||||
|
||||
@@ -74,21 +91,18 @@ export class MetaMaskWallet extends AbstractClientWallet<MetamaskAdditionalOptio
|
||||
|
||||
this.connector = new WagmiAdapter(metamaskConnector);
|
||||
} else {
|
||||
const { WalletConnectV1Connector } = await import(
|
||||
"../connectors/wallet-connect-v1"
|
||||
const { WalletConnectConnector } = await import(
|
||||
"../connectors/wallet-connect"
|
||||
);
|
||||
|
||||
const walletConnectConnector = new WalletConnectV1Connector({
|
||||
const walletConnectConnector = new WalletConnectConnector({
|
||||
chains: this.chains,
|
||||
storage: this.walletStorage,
|
||||
options: {
|
||||
clientMeta: {
|
||||
name: this.dappMetadata.name,
|
||||
description: this.dappMetadata.description || "",
|
||||
url: this.dappMetadata.url,
|
||||
icons: [this.dappMetadata.logoUrl || ""],
|
||||
},
|
||||
projectId: this.options?.projectId || TW_WC_PROJECT_ID, // TODO,
|
||||
storage: this.walletStorage,
|
||||
qrcode: this.options?.qrcode,
|
||||
dappMetadata: this.dappMetadata,
|
||||
qrModalOptions: this.options?.qrModalOptions,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -128,16 +142,9 @@ export class MetaMaskWallet extends AbstractClientWallet<MetamaskAdditionalOptio
|
||||
const wcProvider = await wcConnector.getProvider();
|
||||
|
||||
// set a listener for display_uri event
|
||||
wcProvider.connector.on(
|
||||
"display_uri",
|
||||
(error, payload: { params: string[] }) => {
|
||||
options.onQrCodeUri(payload.params[0]);
|
||||
},
|
||||
);
|
||||
|
||||
// trigger the display_uri event to get the QR code
|
||||
await wcProvider.enable();
|
||||
// connected to app here
|
||||
wcProvider.on("display_uri", (uri) => {
|
||||
options.onQrCodeUri(uri);
|
||||
});
|
||||
|
||||
// trigger connect flow
|
||||
this.connect({ chainId: options.chainId }).then(options.onConnected);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user