Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
755cffe590 Version Packages (#2589)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-03-29 16:17:16 -07:00
Manan TankandGitHub dd1141f9af fix: Do not open wallet uri when connected using official WC modal (#2595) 2024-03-29 23:00:55 +00:00
Joaquim VergesandGitHub 968fdc3ebe chore: add smart wallet exports for user op types (#2594) 2024-03-29 22:29:21 +00:00
2ef20589b7 chore(chains): update chains (#2593)
Co-authored-by: GitHub Action <[email protected]>
2024-03-29 15:07:03 -07:00
Manan TankandGitHub 6d63920c0a feat: add walletConnect, Fix WC connection issues (#2591) 2024-03-29 21:58:03 +00:00
3ef378659e chore(chains): update chains (#2590)
Co-authored-by: GitHub Action <[email protected]>
2024-03-29 14:24:29 -07:00
Joaquim VergesandGitHub eba8f1c198 fix: 721/1155 claimTo with custom currency (#2588) 2024-03-29 19:45:02 +00:00
63 changed files with 858 additions and 248 deletions
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 4.1.52
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@2.4.30
## 4.1.51
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "4.1.51",
"version": "4.1.52",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/chains
## 0.1.85
### Patch Changes
- [#2590](https://github.com/thirdweb-dev/js/pull/2590) [`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc) Thanks [@github-actions](https://github.com/apps/github-actions)! - Synced Chains Package
## 0.1.84
### Patch Changes
+41
View File
@@ -0,0 +1,41 @@
import type { Chain } from "../src/types";
export default {
"chain": "NetMind",
"chainId": 1100789,
"explorers": [
{
"name": "NetMind Testnet Explorer",
"url": "https://testbrower.protago-dev.com",
"standard": "EIP3091",
"icon": {
"url": "ipfs://QmQNipd6uen7sm7HZXGbqhcSVkUXxu3Tp6c3BoeFpvmywp",
"width": 500,
"height": 500,
"format": "png"
}
}
],
"faucets": [],
"icon": {
"url": "ipfs://QmQNipd6uen7sm7HZXGbqhcSVkUXxu3Tp6c3BoeFpvmywp",
"width": 500,
"height": 500,
"format": "png"
},
"infoURL": "https://netmind.ai",
"name": "Netmind Chain Testnet",
"nativeCurrency": {
"name": "NMT",
"symbol": "NMT",
"decimals": 18
},
"networkId": 1100789,
"rpc": [
"https://1100789.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testblock.protago-dev.com"
],
"shortName": "nmtTest",
"slug": "netmind-chain-testnet",
"testnet": true,
"title": "NetMind Chain Testnet"
} as const satisfies Chain;
+28
View File
@@ -0,0 +1,28 @@
import type { Chain } from "../src/types";
export default {
"chain": "Azra Testnet",
"chainId": 5106,
"explorers": [
{
"name": "blockscout",
"url": "https://explorerl2new-azra-testnet-6hz86owb1n.t.conduit.xyz",
"standard": "EIP3091"
}
],
"faucets": [],
"infoURL": "https://azragames.com",
"name": "Azra Testnet",
"nativeCurrency": {
"name": "ETH",
"symbol": "ETH",
"decimals": 18
},
"networkId": 5106,
"rpc": [
"https://5106.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-azra-testnet-6hz86owb1n.t.conduit.xyz"
],
"shortName": "azra-testnet",
"slug": "azra-testnet",
"testnet": true
} as const satisfies Chain;
+1
View File
@@ -39,6 +39,7 @@ export default {
"shortName": "maticmum",
"slip44": 1,
"slug": "mumbai",
"status": "active",
"testnet": true,
"title": "Polygon Testnet Mumbai"
} as const satisfies Chain;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.84",
"version": "0.1.85",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"exports": {
File diff suppressed because one or more lines are too long
+10
View File
@@ -1,5 +1,15 @@
# thirdweb
## 0.13.60
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/sdk@4.0.54
- @thirdweb-dev/wallets@2.4.30
- @thirdweb-dev/auth@4.1.52
## 0.13.59
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/cli",
"main": "dist/cli/index.js",
"version": "0.13.59",
"version": "0.13.60",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-core
## 4.4.28
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/sdk@4.0.54
- @thirdweb-dev/wallets@2.4.30
- @thirdweb-dev/auth@4.1.52
## 4.4.27
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "4.4.27",
"version": "4.4.28",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.7.25
## 0.7.24
## 0.7.23
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.7.24",
"version": "0.7.25",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-native-compat",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-native
## 0.7.25
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/react-core@4.4.28
- @thirdweb-dev/sdk@4.0.54
- @thirdweb-dev/wallets@2.4.30
## 0.7.24
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.7.24",
"version": "0.7.25",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react
## 4.4.28
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/react-core@4.4.28
- @thirdweb-dev/sdk@4.0.54
- @thirdweb-dev/wallets@2.4.30
## 4.4.27
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "4.4.27",
"version": "4.4.28",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
Binary file not shown.
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/sdk
## 4.0.54
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
## 4.0.53
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "4.0.53",
"version": "4.0.54",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/sdk",
"license": "Apache-2.0",
Binary file not shown.
+8
View File
@@ -1,5 +1,13 @@
# @thirdweb-dev/wallets
## 2.4.30
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/sdk@4.0.54
## 2.4.29
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "2.4.29",
"version": "2.4.30",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"browser": {
+10
View File
@@ -1,5 +1,15 @@
# thirdweb
## 5.0.3
### Patch Changes
- [#2595](https://github.com/thirdweb-dev/js/pull/2595) [`dd1141f`](https://github.com/thirdweb-dev/js/commit/dd1141f9af002817fb4fd4c002f5d77fde4ac950) Thanks [@MananTank](https://github.com/MananTank)! - Do not subscribe to `session_request_sent` event when using `walletConnect` because that is already handled when connecting with official Modal
- [#2591](https://github.com/thirdweb-dev/js/pull/2591) [`6d63920`](https://github.com/thirdweb-dev/js/commit/6d63920c0a25a395fed091f749e6e5438dce0b5d) Thanks [@MananTank](https://github.com/MananTank)! - Add `walletConnect`, fix WC connection issues
- [#2588](https://github.com/thirdweb-dev/js/pull/2588) [`eba8f1c`](https://github.com/thirdweb-dev/js/commit/eba8f1c19839ad89391d03271ef96b51d5f515ed) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix 721/1155 claimTo
## 5.0.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "thirdweb",
"version": "5.0.2",
"version": "5.0.3",
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
+30 -1
View File
@@ -89,6 +89,21 @@ const walletInfos = allSupportedWallets.map((wallet) => {
return { id: wallet.id, name: wallet.name };
});
const customWalletInfos = [
{
id: "smart",
name: "Smart Wallet",
},
{
id: "embedded",
name: "Embedded Wallet",
},
{
id: "walletConnect",
name: "WalletConnect",
},
];
// clean the __geneated__ folder within `src/wallets/` directory
const OUT_PATH = join(__dirname, "../../src/wallets/__generated__");
@@ -141,7 +156,7 @@ export type MinimalWalletInfo = {
/**
* @internal
*/
const ALL_MINIMAL_WALLET_INFOS = <const>${JSON.stringify(walletInfos, null, 2)} satisfies MinimalWalletInfo[];
const ALL_MINIMAL_WALLET_INFOS = <const>${JSON.stringify([...walletInfos, ...customWalletInfos], null, 2)} satisfies MinimalWalletInfo[];
export default ALL_MINIMAL_WALLET_INFOS;
`,
@@ -222,6 +237,19 @@ const walletImports = allSupportedWallets
)
.join("\n");
const customWalletImports = ["smart", "embedded", "walletConnect"]
.map(
(walletId) =>
`case "${walletId}": {
return (
image
? import("../custom/${walletId}/image.js").then((img) => img.default)
: import("../custom/${walletId}/index.js").then((w) => w.wallet)
) as Promise<[TImage] extends [true] ? string : any>;
}`,
)
.join("\n");
await writeFile(
join(OUT_PATH, "getWalletInfo.ts"),
await format(
@@ -238,6 +266,7 @@ import type { WalletId } from "../wallet-types.js";
*/
export async function getWalletInfo<TImage extends boolean>(id: WalletId, image?: TImage): Promise<[TImage] extends [true] ? string : WalletInfo> {
switch (id) {
${customWalletImports}
${walletImports}
default: {
throw new Error(\`Wallet with id \${id} not found\`);
+1
View File
@@ -2,6 +2,7 @@ export {
createWallet,
smartWallet,
embeddedWallet,
walletConnect,
} from "../wallets/create-wallet.js";
export type { Wallet, Account } from "../wallets/interfaces/wallet.js";
@@ -1,3 +1,10 @@
export { smartWallet } from "../../wallets/create-wallet.js";
export type {
SmartWalletConnectionOptions,
SmartWalletOptions,
UserOperation,
PaymasterResult,
} from "../../wallets/smart/types.js";
// TODO: add exports for smart wallet utils here
@@ -3,6 +3,7 @@ import type { BaseTransactionOptions } from "../../../../transaction/types.js";
import { prepareContractCall } from "../../../../transaction/prepare-contract-call.js";
import { getActiveClaimCondition } from "../read/getActiveClaimCondition.js";
import { padHex } from "../../../../utils/encoding/hex.js";
import { NATIVE_TOKEN_ADDRESS } from "../../../../constants/addresses.js";
const CLAIM_ABI = {
inputs: [
@@ -129,7 +130,11 @@ export function claimTo(options: BaseTransactionOptions<ClaimToParams>) {
contract: options.contract,
tokenId: options.tokenId,
});
return cc.pricePerToken * BigInt(options.quantity);
if (cc.currency === NATIVE_TOKEN_ADDRESS) {
return cc.pricePerToken * BigInt(options.quantity);
} else {
return 0n;
}
},
});
}
@@ -3,6 +3,7 @@ import type { BaseTransactionOptions } from "../../../../transaction/types.js";
import { prepareContractCall } from "../../../../transaction/prepare-contract-call.js";
import { getActiveClaimCondition } from "../read/getActiveClaimCondition.js";
import { padHex } from "../../../../utils/encoding/hex.js";
import { NATIVE_TOKEN_ADDRESS } from "../../../../constants/addresses.js";
/**
* Represents the parameters for claiming an ERC721 token.
*/
@@ -117,7 +118,11 @@ export function claimTo(options: BaseTransactionOptions<ClaimToParams>) {
const cc = await getActiveClaimCondition({
contract: options.contract,
});
return cc.pricePerToken * BigInt(options.quantity);
if (cc.currency === NATIVE_TOKEN_ADDRESS) {
return cc.pricePerToken * BigInt(options.quantity);
} else {
return 0n;
}
},
});
}
@@ -17,13 +17,13 @@ import type {
Wallet,
// WalletWithPersonalAccount,
} from "../../../../wallets/interfaces/wallet.js";
import { asyncLocalStorage } from "../../utils/asyncLocalStorage.js";
import type { ThirdwebClient } from "../../../../client/client.js";
import type { AppMetadata } from "../../../../wallets/types.js";
import { timeoutPromise } from "../../utils/timeoutPromise.js";
import type { SmartWalletOptions } from "../../../../wallets/smart/types.js";
import { createWallet } from "../../../../wallets/create-wallet.js";
import { getSavedConnectParamsFromStorage } from "../../../../wallets/storage/walletStorage.js";
import { asyncLocalStorage } from "../../../../wallets/storage/asyncLocalStorage.js";
let autoConnectAttempted = false;
+1 -1
View File
@@ -1,5 +1,5 @@
import type { AsyncStorage } from "../../wallets/storage/AsyncStorage.js";
import { asyncLocalStorage } from "./utils/asyncLocalStorage.js";
import { asyncLocalStorage } from "../../wallets/storage/asyncLocalStorage.js";
let storage: AsyncStorage;
@@ -12,7 +12,10 @@ import type { InjectedWalletLocale } from "../../../wallets/injected/locale/type
import { getInjectedWalletLocale } from "../../../wallets/injected/locale/getInjectedWalletLocale.js";
import { useWalletConnectionCtx } from "../../../../core/hooks/others/useWalletConnectionCtx.js";
import { GetStartedScreen } from "../../../wallets/shared/GetStartedScreen.js";
import { WalletConnectConnection } from "../../../wallets/shared/WalletConnectConnection.js";
import {
WalletConnectConnection,
WalletConnectStandaloneConnection,
} from "../../../wallets/shared/WalletConnectConnection.js";
const CoinbaseSDKWalletConnectUI = /* @__PURE__ */ lazy(
() => import("../../../wallets/shared/CoinbaseSDKConnection.js"),
@@ -28,6 +31,7 @@ export function AnyWalletConnectUI(props: {
wallet: Wallet;
done: () => void;
onBack?: () => void;
setModalVisibility: (value: boolean) => void;
}) {
const [screen, setScreen] = useState<"main" | "get-started">("main");
const walletInfo = useWalletInfo(props.wallet.id);
@@ -114,6 +118,20 @@ export function AnyWalletConnectUI(props: {
);
}
// wallet connect
if (props.wallet.id === "walletConnect") {
return (
<WalletConnectStandaloneConnection
locale={locale}
onBack={props.onBack}
done={props.done}
wallet={props.wallet as Wallet<"walletConnect">}
walletInfo={walletInfo.data}
setModalVisibility={props.setModalVisibility}
/>
);
}
if (props.wallet.id === "embedded") {
return (
<Suspense fallback={<LoadingScreen />}>
@@ -430,10 +430,7 @@ const ConnectEmbedContent = (
onClose={() => {
setScreen(initialScreen);
}}
onHide={() => {
// no op
}}
onShow={() => {
setModalVisibility={() => {
// no op
}}
/>
@@ -74,8 +74,10 @@ const ConnectModal = () => {
}
}, [isWalletModalOpen, setIsWalletModalOpen, screen]);
const onHide = useCallback(() => setHideModal(true), []);
const onShow = useCallback(() => setHideModal(false), []);
const setModalVisibility = useCallback(
(value: boolean) => setHideModal(!value),
[],
);
// if wallet is suddenly disconnected when showing the sign in screen, close the modal and reset the screen
useEffect(() => {
@@ -122,8 +124,7 @@ const ConnectModal = () => {
>
<ConnectModalContent
screenSetup={screenSetup}
onHide={onHide}
onShow={onShow}
setModalVisibility={setModalVisibility}
isOpen={isWalletModalOpen}
onClose={closeModal}
/>
@@ -22,16 +22,16 @@ const AllWalletsUI = /* @__PURE__ */ lazy(() => import("./AllWalletsUI.js"));
*/
export const ConnectModalContent = (props: {
screenSetup: ScreenSetup;
onHide: () => void;
onShow: () => void;
isOpen: boolean;
onClose: () => void;
isOpen: boolean;
setModalVisibility: (value: boolean) => void;
}) => {
const { onShow, onClose } = props;
const { setModalVisibility, onClose } = props;
const { screen, setScreen, initialScreen } = props.screenSetup;
const { wallets, accountAbstraction } = useWalletConnectionCtx();
// const disconnect = useDisconnect();
const modalConfig = useContext(ModalConfigCtx);
// const setModalConfig = useContext(SetModalConfigCtx);
// const activeWalletConnectionStatus = useActiveWalletConnectionStatus();
// const activeWallet = useActiveWallet();
@@ -59,7 +59,7 @@ export const ConnectModalContent = (props: {
// : !!authConfig?.authUrl && !user?.address;
onModalUnmount(() => {
onShow();
setModalVisibility(true);
});
// show sign in screen if required
@@ -77,7 +77,7 @@ export const ConnectModalContent = (props: {
// authConfig?.authUrl,
// user?.address,
setScreen,
onShow,
setModalVisibility,
onClose,
onConnect,
connect,
@@ -138,6 +138,7 @@ export const ConnectModalContent = (props: {
}}
personalWallet={wallet}
onBack={goBack}
setModalVisibility={props.setModalVisibility}
/>
);
}
@@ -150,6 +151,7 @@ export const ConnectModalContent = (props: {
done={() => {
handleConnected(wallet);
}}
setModalVisibility={props.setModalVisibility}
/>
);
};
@@ -90,16 +90,13 @@ function ConnectModalInlineContent(props: {
<>
<ConnectModalContent
screenSetup={screenSetup}
onHide={() => {
// no op
setModalVisibility={() => {
// noop
}}
isOpen={true}
onClose={() => {
// no op
}}
onShow={() => {
// no op
}}
/>
{/* close icon */}
@@ -18,7 +18,7 @@ import { createWallet } from "../../../../../wallets/create-wallet.js";
import { useWalletInfo } from "../../hooks/useWalletInfo.js";
import type { WalletInfo } from "../../../../../wallets/wallet-info.js";
import { saveConnectParamsToStorage } from "../../../../../wallets/storage/walletStorage.js";
import { asyncLocalStorage } from "../../../../core/utils/asyncLocalStorage.js";
import { asyncLocalStorage } from "../../../../../wallets/storage/asyncLocalStorage.js";
/**
* @internal
@@ -28,6 +28,7 @@ export function SmartConnectUI(props: {
done: (smartWallet: Wallet) => void;
onBack?: () => void;
accountAbstraction: SmartWalletOptions;
setModalVisibility: (value: boolean) => void;
}) {
const personalWalletInfo = useWalletInfo(props.personalWallet.id);
const [keyConnected, setKeyConnected] = useState(false);
@@ -45,6 +46,7 @@ export function SmartConnectUI(props: {
setKeyConnected(true);
}}
onBack={props.onBack}
setModalVisibility={props.setModalVisibility}
/>
);
}
@@ -10,98 +10,7 @@ export function useWalletInfo(id: WalletId) {
return useQuery<WalletInfo>({
queryKey: ["wallet-info", id],
queryFn: () => {
switch (id) {
// case "local": {
// return {
// id: "local",
// name: "Local Wallet",
// homepage: "https://thirdweb.com",
// app: {
// browser: null,
// ios: null,
// android: null,
// mac: null,
// windows: null,
// linux: null,
// chrome: null,
// firefox: null,
// safari: null,
// edge: null,
// opera: null,
// },
// rdns: null,
// mobile: {
// native: null,
// universal: null,
// },
// desktop: {
// native: null,
// universal: null,
// },
// } as WalletInfo;
// }
case "embedded": {
return {
id: "embedded",
name: "Social Login",
homepage: "https://thirdweb.com",
app: {
browser: null,
ios: null,
android: null,
mac: null,
windows: null,
linux: null,
chrome: null,
firefox: null,
safari: null,
edge: null,
opera: null,
},
rdns: null,
mobile: {
native: null,
universal: null,
},
desktop: {
native: null,
universal: null,
},
} as WalletInfo;
}
case "smart": {
return {
id: "smart",
name: "SmartWallet",
homepage: "https://thirdweb.com",
app: {
browser: null,
ios: null,
android: null,
mac: null,
windows: null,
linux: null,
chrome: null,
firefox: null,
safari: null,
edge: null,
opera: null,
},
rdns: null,
mobile: {
native: null,
universal: null,
},
desktop: {
native: null,
universal: null,
},
} as WalletInfo;
}
default: {
return getWalletInfo(id, false);
}
}
return getWalletInfo(id, false);
},
retry: false,
});
@@ -114,20 +23,7 @@ export function useWalletImage(id: WalletId) {
return useQuery({
queryKey: ["wallet-image", id],
queryFn: () => {
switch (id) {
// case "local": {
// return "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTIiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xXzY0KSIvPgo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfMV82NCkiPgo8cGF0aCBkPSJNNTguNzUgMTkuMTY2N0gyMS4yNUMxOC45NTgzIDE5LjE2NjcgMTcuMDgzMyAyMS4wNDE3IDE3LjA4MzMgMjMuMzMzNFY0OC4zMzM0QzE3LjA4MzMgNTAuNjI1IDE4Ljk1ODMgNTIuNSAyMS4yNSA1Mi41SDM1LjgzMzNMMzEuNjY2NyA1OC43NVY2MC44MzM0SDQ4LjMzMzNWNTguNzVMNDQuMTY2NyA1Mi41SDU4Ljc1QzYxLjA0MTcgNTIuNSA2Mi45MTY3IDUwLjYyNSA2Mi45MTY3IDQ4LjMzMzRWMjMuMzMzNEM2Mi45MTY3IDIxLjA0MTcgNjEuMDQxNyAxOS4xNjY3IDU4Ljc1IDE5LjE2NjdaTTU4Ljc1IDQ0LjE2NjdIMjEuMjVWMjMuMzMzNEg1OC43NVY0NC4xNjY3WiIgZmlsbD0id2hpdGUiLz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzFfNjQiIHgxPSI0MCIgeTE9IjAiIHgyPSI0MCIgeTI9IjgwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNDRTExQUIiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjOTAwQkI1Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMV82NCI+CjxyZWN0IHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgZmlsbD0id2hpdGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE1IDE1KSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo=";
// }
case "embedded": {
return "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzM1ODlfODY0OSkiPgo8cmVjdCB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHJ4PSI4IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMzU4OV84NjQ5KSIvPgo8cmVjdCB4PSItMSIgeT0iLTEiIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgcng9IjkuOCIgZmlsbD0idXJsKCNwYWludDFfbGluZWFyXzM1ODlfODY0OSkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAxXzM1ODlfODY0OSkiPgo8cGF0aCBkPSJNMjQgMTQuMjVDMTguNjE3MiAxNC4yNSAxNC4yNSAxOC42MTcyIDE0LjI1IDI0QzE0LjI1IDI5LjM4MjggMTguNjE3MiAzMy43NSAyNCAzMy43NUMyNC44OTg4IDMzLjc1IDI1LjYyNSAzNC40NzYyIDI1LjYyNSAzNS4zNzVDMjUuNjI1IDM2LjI3MzggMjQuODk4OCAzNyAyNCAzN0MxNi44MTk1IDM3IDExIDMxLjE4MDUgMTEgMjRDMTEgMTYuODE5NSAxNi44MTk1IDExIDI0IDExQzMxLjE4MDUgMTEgMzcgMTYuODE5NSAzNyAyNFYyNS42MjVDMzcgMjguMzE2NCAzNC44MTY0IDMwLjUgMzIuMTI1IDMwLjVDMzAuNjM3MSAzMC41IDI5LjMwMTYgMjkuODI5NyAyOC40MDc4IDI4Ljc3ODVDMjcuMjUgMjkuODQ0OSAyNS43MDEyIDMwLjUgMjQgMzAuNUMyMC40MDk4IDMwLjUgMTcuNSAyNy41OTAyIDE3LjUgMjRDMTcuNSAyMC40MDk4IDIwLjQwOTggMTcuNSAyNCAxNy41QzI1LjQxNjggMTcuNSAyNi43MjcgMTcuOTUyIDI3Ljc5MzQgMTguNzIzOEMyOC4wODI4IDE4LjQ2OTkgMjguNDU4NiAxOC4zMTI1IDI4Ljg3NSAxOC4zMTI1QzI5Ljc3MzggMTguMzEyNSAzMC41IDE5LjAzODcgMzAuNSAxOS45Mzc1VjI1LjYyNUMzMC41IDI2LjUyMzggMzEuMjI2MiAyNy4yNSAzMi4xMjUgMjcuMjVDMzMuMDIzOCAyNy4yNSAzMy43NSAyNi41MjM4IDMzLjc1IDI1LjYyNVYyNEMzMy43NSAxOC42MTcyIDI5LjM4MjggMTQuMjUgMjQgMTQuMjVaTTI3LjI1IDI0QzI3LjI1IDIzLjEzOCAyNi45MDc2IDIyLjMxMTQgMjYuMjk4MSAyMS43MDE5QzI1LjY4ODYgMjEuMDkyNCAyNC44NjIgMjAuNzUgMjQgMjAuNzVDMjMuMTM4IDIwLjc1IDIyLjMxMTQgMjEuMDkyNCAyMS43MDE5IDIxLjcwMTlDMjEuMDkyNCAyMi4zMTE0IDIwLjc1IDIzLjEzOCAyMC43NSAyNEMyMC43NSAyNC44NjIgMjEuMDkyNCAyNS42ODg2IDIxLjcwMTkgMjYuMjk4MUMyMi4zMTE0IDI2LjkwNzYgMjMuMTM4IDI3LjI1IDI0IDI3LjI1QzI0Ljg2MiAyNy4yNSAyNS42ODg2IDI2LjkwNzYgMjYuMjk4MSAyNi4yOTgxQzI2LjkwNzYgMjUuNjg4NiAyNy4yNSAyNC44NjIgMjcuMjUgMjRaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjwvZz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl8zNTg5Xzg2NDkiIHgxPSIyNS41IiB5MT0iLTYuMjk1NzJlLTA2IiB4Mj0iMzAuMjAxNiIgeTI9IjQ3LjUzNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjODM1OEJBIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzdCMUNGNyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MV9saW5lYXJfMzU4OV84NjQ5IiB4MT0iMjUuNTYyNSIgeTE9Ii0xLjAwMDAxIiB4Mj0iMzAuNDYiIHkyPSI0OC41MTU2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM4MzU4QkEiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN0IxQ0Y3Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMzU4OV84NjQ5Ij4KPHJlY3Qgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4IiByeD0iOCIgZmlsbD0id2hpdGUiLz4KPC9jbGlwUGF0aD4KPGNsaXBQYXRoIGlkPSJjbGlwMV8zNTg5Xzg2NDkiPgo8cmVjdCB3aWR0aD0iMjYiIGhlaWdodD0iMjYiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMSAxMSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K";
}
case "smart": {
return "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTIiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xXzkxKSIvPgo8cGF0aCBkPSJNMzkuOTk2OSAxOEw0MC4yMzMzIDE4LjAxNTZMNDAuMzUxMyAxOC4wMzMzTDQwLjQ3MzYgMTguMDYyMkw0MC42OTU4IDE4LjEzNzhDNDAuODQ5NCAxOC4yMDA2IDQwLjk5NTQgMTguMjg0MiA0MS4xMzA1IDE4LjM4NjdMNDEuMzM4NyAxOC41Njg5TDQxLjg0OTMgMTkuMDUzM0M0NS44ODkxIDIyLjc3NjggNTAuOTk0NyAyNC43NzYyIDU2LjI0NTggMjQuNjkxMUw1Ni45MzA3IDI0LjY2ODlDNTcuMzc4MyAyNC42NDYyIDU3LjgyIDI0Ljc5MDkgNTguMTg0OSAyNS4wNzk4QzU4LjU0OTggMjUuMzY4NyA1OC44MTY3IDI1Ljc4NSA1OC45NDMxIDI2LjI2MjJDNTkuOTI3MSAyOS45NzY5IDYwLjIyODMgMzMuODczMSA1OS44Mjg3IDM3LjcxOTRDNTkuNDI4OSA0MS41NjU4IDU4LjMzNjcgNDUuMjgzNiA1Ni42MTY1IDQ4LjY1MjNDNTQuODk2NSA1Mi4wMjA3IDUyLjU4MzYgNTQuOTcxNCA0OS44MTU2IDU3LjMyODVDNDcuMDQ3NiA1OS42ODU2IDQzLjg4MDkgNjEuNDAxMiA0MC41MDM2IDYyLjM3MzRDNDAuMTc0IDYyLjQ2ODMgMzkuODI4IDYyLjQ2ODMgMzkuNDk4MiA2Mi4zNzM0QzM2LjEyMDkgNjEuNDAxNCAzMi45NTM4IDU5LjY4NiAzMC4xODU2IDU3LjMyODlDMjcuNDE3NiA1NC45NzE4IDI1LjEwNDUgNTIuMDIxNCAyMy4zODQyIDQ4LjY1MjlDMjEuNjYzOCA0NS4yODQzIDIwLjU3MTMgNDEuNTY2MiAyMC4xNzE1IDM3LjcxOThDMTkuNzcxNyAzMy44NzM0IDIwLjA3MjcgMjkuOTc2OSAyMS4wNTY3IDI2LjI2MjJDMjEuMTgzMSAyNS43ODUgMjEuNDUwMSAyNS4zNjg3IDIxLjgxNSAyNS4wNzk4QzIyLjE3OTkgMjQuNzkwOSAyMi42MjE1IDI0LjY0NjIgMjMuMDY5MyAyNC42Njg5QzI4LjU1MTMgMjQuOTQ3IDMzLjkyOTMgMjIuOTQ0NCAzOC4xNTA3IDE5LjA1MzNMMzguNjc3MyAxOC41NTMzTDM4Ljg2OTYgMTguMzg2N0MzOS4wMDQ3IDE4LjI4NDIgMzkuMTUwNSAxOC4yMDA2IDM5LjMwNCAxOC4xMzc4TDM5LjUyODIgMTguMDYyMkMzOS42MDY5IDE4LjA0MTIgMzkuNjg2NSAxOC4wMjU2IDM5Ljc2NjcgMTguMDE1NkwzOS45OTY5IDE4Wk00MC4wMDA5IDMzLjU1NTZDMzguOTkwNSAzMy41NTUxIDM4LjAxNzMgMzMuOTc4NyAzNy4yNzY1IDM0Ljc0MTFDMzYuNTM1NiAzNS41MDM2IDM2LjA4MTYgMzYuNTQ4NSAzNi4wMDU4IDM3LjY2NjdMMzUuOTk1OCAzOEwzNi4wMDU4IDM4LjMzMzRDMzYuMDU1MSAzOS4wNTQ3IDM2LjI2MjUgMzkuNzUxOCAzNi42MDk4IDQwLjM2NEMzNi45NTY5IDQwLjk3NjIgMzcuNDMzNiA0MS40ODUxIDM3Ljk5ODUgNDEuODQ2N1Y0NS43Nzc4TDM4LjAxMjUgNDYuMDM3OEMzOC4wNzI3IDQ2LjYwMDMgMzguMzI0MiA0Ny4xMTU4IDM4LjcxNTYgNDcuNDc5NEMzOS4xMDcxIDQ3Ljg0MjkgMzkuNjA4NyA0OC4wMjY5IDQwLjExODIgNDcuOTkzOEM0MC42Mjc4IDQ3Ljk2MDUgNDEuMTA2NyA0Ny43MTI3IDQxLjQ1NzEgNDcuMzAwOUM0MS44MDc2IDQ2Ljg4ODkgNDIuMDAyOSA0Ni4zNDQzIDQyLjAwMzYgNDUuNzc3OEw0Mi4wMDU2IDQxLjg0ODlDNDIuNzY5MSA0MS4zNTk2IDQzLjM2NiA0MC42MDQyIDQzLjcwMzQgMzkuNzAwMkM0NC4wNDA3IDM4Ljc5NiA0NC4wOTk2IDM3Ljc5MzggNDMuODcxMSAzNi44NDg3QzQzLjY0MjcgMzUuOTAzNiA0My4xMzk2IDM1LjA2ODUgNDIuNDM5OCAzNC40NzMxQzQxLjc0IDMzLjg3NzYgNDAuODgyNyAzMy41NTUxIDQwLjAwMDkgMzMuNTU1NloiIGZpbGw9InVybCgjcGFpbnQxX2xpbmVhcl8xXzkxKSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzFfOTEiIHgxPSI0MCIgeTE9IjAiIHgyPSI0MCIgeTI9IjgwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM4MzU2QkQiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN0MyMEY0Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl8xXzkxIiB4MT0iNDAiIHkxPSIxOCIgeDI9IjQwIiB5Mj0iNjIuNDQ0NSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSJ3aGl0ZSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFMUQ4RkIiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K";
}
default: {
return getWalletInfo(id, true);
}
}
return getWalletInfo(id, true);
},
retry: false,
});
@@ -16,7 +16,7 @@ export const ConnectingScreen: React.FC<{
onBack?: () => void;
walletId: WalletId;
walletName: string;
onGetStarted: () => void;
onGetStarted?: () => void;
errorConnecting: boolean;
onRetry: () => void;
locale: {
@@ -92,14 +92,17 @@ export const ConnectingScreen: React.FC<{
</Container>
</Container>
<Spacer y="xl" />
<Line />
<Container flex="row" center="x" p="lg">
<Button variant="link" onClick={props.onGetStarted}>
{locale.getStartedLink}
</Button>
</Container>
{props.onGetStarted && (
<>
<Spacer y="xl" />
<Line />
<Container flex="row" center="x" p="lg">
<Button variant="link" onClick={props.onGetStarted}>
{locale.getStartedLink}
</Button>
</Container>
</>
)}
</Container>
);
};
@@ -18,7 +18,7 @@ import { WalletImage } from "../../ui/components/WalletImage.js";
*/
export const ScanScreen: React.FC<{
onBack?: () => void;
onGetStarted: () => void;
onGetStarted?: () => void;
qrCodeUri?: string;
walletName: string;
walletId: WalletId;
@@ -62,22 +62,24 @@ export const ScanScreen: React.FC<{
<Spacer y="lg" />
<ScreenBottomContainer
style={{
border: modalConfig.modalSize === "compact" ? undefined : "none",
}}
>
<Button
variant="link"
onClick={props.onGetStarted}
{props.onGetStarted && (
<ScreenBottomContainer
style={{
fontSize: fontSize.sm,
textAlign: "center",
border: modalConfig.modalSize === "compact" ? undefined : "none",
}}
>
{props.getStartedLink}
</Button>
</ScreenBottomContainer>
<Button
variant="link"
onClick={props.onGetStarted}
style={{
fontSize: fontSize.sm,
textAlign: "center",
}}
>
{props.getStartedLink}
</Button>
</ScreenBottomContainer>
)}
</Container>
);
};
@@ -8,6 +8,7 @@ import type { WalletInfo } from "../../../../wallets/wallet-info.js";
import type { WCSupportedWalletIds } from "../../../../wallets/__generated__/wallet-ids.js";
import { isMobile, isAndroid, isIOS } from "../../../../utils/web/isMobile.js";
import { openWindow } from "../../../../utils/web/openWindow.js";
import { wait } from "../../../../utils/promise/wait.js";
/**
* QR Scan UI for connecting a specific wallet on desktop.
@@ -123,3 +124,148 @@ export const WalletConnectConnection: React.FC<{
/>
);
};
/**
* QR Scan UI for connecting a specific wallet on desktop.
* shows a "Connecting" screen and opens the app on mobile.
* @internal
*/
export const WalletConnectStandaloneConnection: React.FC<{
onBack?: () => void;
locale: InjectedWalletLocale;
wallet: Wallet<"walletConnect">;
walletInfo: WalletInfo;
done: () => void;
setModalVisibility: (value: boolean) => void;
}> = (props) => {
const { onBack, wallet, walletInfo, locale, done, setModalVisibility } =
props;
const [qrCodeUri, setQrCodeUri] = useState<string | undefined>();
const [errorConnecting, setErrorConnecting] = useState(false);
const { chain, chains, client, walletConnect } = useWalletConnectionCtx();
const connect = useCallback(() => {
setErrorConnecting(false);
if (isMobile()) {
let wcModalClosed = false;
// show spinner while the wallet connect modal loads in the background
wait(2000).then(() => {
// don't hide the modal if wc closed already
if (!wcModalClosed) {
setModalVisibility(false);
}
});
wallet
.connect({
chain,
client: client,
projectId: walletConnect?.projectId,
showQrModal: true,
optionalChains: chains,
})
.then(() => {
wcModalClosed = true;
setModalVisibility(true);
done();
})
.catch((e) => {
wcModalClosed = true;
setModalVisibility(true);
setErrorConnecting(true);
console.error(e);
});
} else {
wallet
.connect({
chain,
client: client,
projectId: walletConnect?.projectId,
showQrModal: false,
onDisplayUri(uri) {
const platformUris = {
ios: walletInfo.mobile.native || "",
android: walletInfo.mobile.universal || "",
other: walletInfo.mobile.universal || "",
};
setQrCodeUri(uri);
if (isMobile()) {
if (isAndroid()) {
openWindow(
`${platformUris.android}wc?uri=${encodeURIComponent(uri)}`,
);
} else if (isIOS()) {
openWindow(
`${platformUris.ios}wc?uri=${encodeURIComponent(uri)}`,
);
} else {
openWindow(
`${platformUris.other}wc?uri=${encodeURIComponent(uri)}`,
);
}
}
},
optionalChains: chains,
})
.then(() => {
done();
})
.catch((e) => {
setErrorConnecting(true);
console.error(e);
});
}
}, [
walletConnect,
walletInfo.mobile.native,
walletInfo.mobile.universal,
wallet,
chain,
client,
chains,
done,
setModalVisibility,
]);
const scanStarted = useRef(false);
useEffect(() => {
if (scanStarted.current) {
return;
}
scanStarted.current = true;
connect();
}, [connect]);
if (isMobile()) {
return (
<ConnectingScreen
locale={{
getStartedLink: locale.getStartedLink,
instruction: locale.connectionScreen.instruction,
tryAgain: locale.connectionScreen.retry,
inProgress: locale.connectionScreen.inProgress,
failed: locale.connectionScreen.failed,
}}
onBack={onBack}
walletName={walletInfo.name}
walletId={wallet.id}
errorConnecting={errorConnecting}
onRetry={connect}
/>
);
}
return (
<ScanScreen
qrScanInstruction={locale.scanScreen.instruction}
onBack={onBack}
qrCodeUri={qrCodeUri}
walletName={walletInfo.name}
walletId={wallet.id}
getStartedLink={locale.getStartedLink}
/>
);
};
@@ -14,6 +14,29 @@ export async function getWalletInfo<TImage extends boolean>(
image?: TImage,
): Promise<[TImage] extends [true] ? string : WalletInfo> {
switch (id) {
case "smart": {
return (
image
? import("../custom/smart/image.js").then((img) => img.default)
: import("../custom/smart/index.js").then((w) => w.wallet)
) as Promise<[TImage] extends [true] ? string : any>;
}
case "embedded": {
return (
image
? import("../custom/embedded/image.js").then((img) => img.default)
: import("../custom/embedded/index.js").then((w) => w.wallet)
) as Promise<[TImage] extends [true] ? string : any>;
}
case "walletConnect": {
return (
image
? import("../custom/walletConnect/image.js").then(
(img) => img.default,
)
: import("../custom/walletConnect/index.js").then((w) => w.wallet)
) as Promise<[TImage] extends [true] ? string : any>;
}
case "io.metamask": {
return (
image
@@ -1313,6 +1313,18 @@ const ALL_MINIMAL_WALLET_INFOS = (<const>[
id: "app.backpack",
name: "Backpack",
},
{
id: "smart",
name: "Smart Wallet",
},
{
id: "embedded",
name: "Embedded Wallet",
},
{
id: "walletConnect",
name: "WalletConnect",
},
]) satisfies MinimalWalletInfo[];
export default ALL_MINIMAL_WALLET_INFOS;
+60 -15
View File
@@ -13,6 +13,7 @@ import type {
import { createWalletEmitter } from "./wallet-emitter.js";
import { trackConnect } from "../analytics/track.js";
import type { WCConnectOptions } from "./wallet-connect/types.js";
// TODO: figure out how to define the type without tuple args type and using function overloads
@@ -37,11 +38,11 @@ export function createWallet<const ID extends WalletId>(
): Wallet<ID> {
const [id, creationOptions] = args;
switch (true) {
switch (id) {
/**
* SMART WALLET
*/
case id === "smart": {
case "smart": {
return smartWallet(
creationOptions as CreateWalletArgs<"smart">[1],
) as Wallet<ID>;
@@ -49,7 +50,7 @@ export function createWallet<const ID extends WalletId>(
/**
* EMBEDDED WALLET
*/
case id === "embedded": {
case "embedded": {
return embeddedWallet(
creationOptions as CreateWalletArgs<"embedded">[1],
) as Wallet<ID>;
@@ -59,12 +60,12 @@ export function createWallet<const ID extends WalletId>(
* COINBASE WALLET VIA SDK
* -> if no injected coinbase found, we'll use the coinbase SDK
*/
case id === "com.coinbase.wallet": {
case "com.coinbase.wallet": {
return coinbaseWalletSDK() as Wallet<ID>;
}
/**
* WALLET CONNECT AND INJECTED WALLETS
* WALLET CONNECT AND INJECTED WALLETS + walletConnect standalone
*/
default: {
const emitter = createWalletEmitter<ID>();
@@ -90,6 +91,7 @@ export function createWallet<const ID extends WalletId>(
account = undefined;
chain = undefined;
};
const wallet: Wallet<ID> = {
id,
subscribe: emitter.subscribe,
@@ -98,7 +100,7 @@ export function createWallet<const ID extends WalletId>(
getAccount: () => account,
autoConnect: async (options) => {
// injected wallet priority for autoConnect
if (injectedProvider(id)) {
if (id !== "walletConnect" && injectedProvider(id)) {
const { autoConnectInjectedWallet } = await import(
"./injected/index.js"
);
@@ -155,8 +157,7 @@ export function createWallet<const ID extends WalletId>(
throw new Error("Failed to auto connect");
},
connect: async (options) => {
// prefer walletconnect over injected for connect (more explicit)
if (options && "walletConnect" in options) {
async function wcConnect(wcOptions: WCConnectOptions) {
const { connectWC } = await import("./wallet-connect/index.js");
const [
@@ -165,23 +166,44 @@ export function createWallet<const ID extends WalletId>(
doDisconnect,
doSwitchChain,
] = await connectWC(
options,
wcOptions,
emitter,
wallet.id as WCSupportedWalletIds,
wallet.id as WCSupportedWalletIds | "walletConnect",
);
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = doDisconnect;
handleDisconnect = () => {
doDisconnect();
account = undefined;
chain = undefined;
};
handleSwitchChain = doSwitchChain;
trackConnect({
client: options.client,
client: wcOptions.client,
walletType: id,
walletAddress: account.address,
});
// return account
return account;
}
if (id === "walletConnect") {
const { client, chain: _chain, ...walletConnectOptions } = options;
return wcConnect({
client,
chain: _chain,
walletConnect: {
...walletConnectOptions,
},
});
}
// prefer walletconnect over injected for connect (more explicit)
if (options && "walletConnect" in options) {
return wcConnect(options);
}
if (injectedProvider(id)) {
const { connectInjectedWallet } = await import(
"./injected/index.js"
@@ -200,7 +222,11 @@ export function createWallet<const ID extends WalletId>(
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = doDisconnect;
handleDisconnect = () => {
doDisconnect();
account = undefined;
chain = undefined;
};
handleSwitchChain = doSwitchChain;
trackConnect({
client: options.client,
@@ -212,7 +238,7 @@ export function createWallet<const ID extends WalletId>(
}
throw new Error("Failed to connect");
},
// these get overridden in connect and autoconnect
// these get overridden in connect and autoConnect
disconnect: async () => handleDisconnect(),
switchChain: (c) => handleSwitchChain(c),
};
@@ -221,6 +247,25 @@ export function createWallet<const ID extends WalletId>(
}
}
/**
* Creates a wallet that allows connecting to any wallet that supports the WalletConnect protocol.
* @returns The created smart wallet.
* @example
* ```ts
* import { walletConnect } from "thirdweb/wallets";
*
* const wallet = walletConnect();
*
* const account = await wallet.connect({
* client
* });
* ```
* @wallet
*/
export function walletConnect() {
return createWallet("walletConnect");
}
/**
* Creates a smart wallet.
* @param createOptions - The options for creating the wallet.
@@ -0,0 +1,4 @@
const image =
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzM1ODlfODY0OSkiPgo8cmVjdCB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHJ4PSI4IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMzU4OV84NjQ5KSIvPgo8cmVjdCB4PSItMSIgeT0iLTEiIHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgcng9IjkuOCIgZmlsbD0idXJsKCNwYWludDFfbGluZWFyXzM1ODlfODY0OSkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAxXzM1ODlfODY0OSkiPgo8cGF0aCBkPSJNMjQgMTQuMjVDMTguNjE3MiAxNC4yNSAxNC4yNSAxOC42MTcyIDE0LjI1IDI0QzE0LjI1IDI5LjM4MjggMTguNjE3MiAzMy43NSAyNCAzMy43NUMyNC44OTg4IDMzLjc1IDI1LjYyNSAzNC40NzYyIDI1LjYyNSAzNS4zNzVDMjUuNjI1IDM2LjI3MzggMjQuODk4OCAzNyAyNCAzN0MxNi44MTk1IDM3IDExIDMxLjE4MDUgMTEgMjRDMTEgMTYuODE5NSAxNi44MTk1IDExIDI0IDExQzMxLjE4MDUgMTEgMzcgMTYuODE5NSAzNyAyNFYyNS42MjVDMzcgMjguMzE2NCAzNC44MTY0IDMwLjUgMzIuMTI1IDMwLjVDMzAuNjM3MSAzMC41IDI5LjMwMTYgMjkuODI5NyAyOC40MDc4IDI4Ljc3ODVDMjcuMjUgMjkuODQ0OSAyNS43MDEyIDMwLjUgMjQgMzAuNUMyMC40MDk4IDMwLjUgMTcuNSAyNy41OTAyIDE3LjUgMjRDMTcuNSAyMC40MDk4IDIwLjQwOTggMTcuNSAyNCAxNy41QzI1LjQxNjggMTcuNSAyNi43MjcgMTcuOTUyIDI3Ljc5MzQgMTguNzIzOEMyOC4wODI4IDE4LjQ2OTkgMjguNDU4NiAxOC4zMTI1IDI4Ljg3NSAxOC4zMTI1QzI5Ljc3MzggMTguMzEyNSAzMC41IDE5LjAzODcgMzAuNSAxOS45Mzc1VjI1LjYyNUMzMC41IDI2LjUyMzggMzEuMjI2MiAyNy4yNSAzMi4xMjUgMjcuMjVDMzMuMDIzOCAyNy4yNSAzMy43NSAyNi41MjM4IDMzLjc1IDI1LjYyNVYyNEMzMy43NSAxOC42MTcyIDI5LjM4MjggMTQuMjUgMjQgMTQuMjVaTTI3LjI1IDI0QzI3LjI1IDIzLjEzOCAyNi45MDc2IDIyLjMxMTQgMjYuMjk4MSAyMS43MDE5QzI1LjY4ODYgMjEuMDkyNCAyNC44NjIgMjAuNzUgMjQgMjAuNzVDMjMuMTM4IDIwLjc1IDIyLjMxMTQgMjEuMDkyNCAyMS43MDE5IDIxLjcwMTlDMjEuMDkyNCAyMi4zMTE0IDIwLjc1IDIzLjEzOCAyMC43NSAyNEMyMC43NSAyNC44NjIgMjEuMDkyNCAyNS42ODg2IDIxLjcwMTkgMjYuMjk4MUMyMi4zMTE0IDI2LjkwNzYgMjMuMTM4IDI3LjI1IDI0IDI3LjI1QzI0Ljg2MiAyNy4yNSAyNS42ODg2IDI2LjkwNzYgMjYuMjk4MSAyNi4yOTgxQzI2LjkwNzYgMjUuNjg4NiAyNy4yNSAyNC44NjIgMjcuMjUgMjRaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjwvZz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl8zNTg5Xzg2NDkiIHgxPSIyNS41IiB5MT0iLTYuMjk1NzJlLTA2IiB4Mj0iMzAuMjAxNiIgeTI9IjQ3LjUzNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjODM1OEJBIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzdCMUNGNyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MV9saW5lYXJfMzU4OV84NjQ5IiB4MT0iMjUuNTYyNSIgeTE9Ii0xLjAwMDAxIiB4Mj0iMzAuNDYiIHkyPSI0OC41MTU2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM4MzU4QkEiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN0IxQ0Y3Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMzU4OV84NjQ5Ij4KPHJlY3Qgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4IiByeD0iOCIgZmlsbD0id2hpdGUiLz4KPC9jbGlwUGF0aD4KPGNsaXBQYXRoIGlkPSJjbGlwMV8zNTg5Xzg2NDkiPgo8cmVjdCB3aWR0aD0iMjYiIGhlaWdodD0iMjYiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMSAxMSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K";
export default image;
@@ -0,0 +1,27 @@
export const wallet = {
id: "embedded",
name: "Social Login",
homepage: "https://thirdweb.com",
app: {
browser: null,
ios: null,
android: null,
mac: null,
windows: null,
linux: null,
chrome: null,
firefox: null,
safari: null,
edge: null,
opera: null,
},
rdns: null,
mobile: {
native: null,
universal: null,
},
desktop: {
native: null,
universal: null,
},
} as const;
@@ -0,0 +1,4 @@
const image =
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTIiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xXzkxKSIvPgo8cGF0aCBkPSJNMzkuOTk2OSAxOEw0MC4yMzMzIDE4LjAxNTZMNDAuMzUxMyAxOC4wMzMzTDQwLjQ3MzYgMTguMDYyMkw0MC42OTU4IDE4LjEzNzhDNDAuODQ5NCAxOC4yMDA2IDQwLjk5NTQgMTguMjg0MiA0MS4xMzA1IDE4LjM4NjdMNDEuMzM4NyAxOC41Njg5TDQxLjg0OTMgMTkuMDUzM0M0NS44ODkxIDIyLjc3NjggNTAuOTk0NyAyNC43NzYyIDU2LjI0NTggMjQuNjkxMUw1Ni45MzA3IDI0LjY2ODlDNTcuMzc4MyAyNC42NDYyIDU3LjgyIDI0Ljc5MDkgNTguMTg0OSAyNS4wNzk4QzU4LjU0OTggMjUuMzY4NyA1OC44MTY3IDI1Ljc4NSA1OC45NDMxIDI2LjI2MjJDNTkuOTI3MSAyOS45NzY5IDYwLjIyODMgMzMuODczMSA1OS44Mjg3IDM3LjcxOTRDNTkuNDI4OSA0MS41NjU4IDU4LjMzNjcgNDUuMjgzNiA1Ni42MTY1IDQ4LjY1MjNDNTQuODk2NSA1Mi4wMjA3IDUyLjU4MzYgNTQuOTcxNCA0OS44MTU2IDU3LjMyODVDNDcuMDQ3NiA1OS42ODU2IDQzLjg4MDkgNjEuNDAxMiA0MC41MDM2IDYyLjM3MzRDNDAuMTc0IDYyLjQ2ODMgMzkuODI4IDYyLjQ2ODMgMzkuNDk4MiA2Mi4zNzM0QzM2LjEyMDkgNjEuNDAxNCAzMi45NTM4IDU5LjY4NiAzMC4xODU2IDU3LjMyODlDMjcuNDE3NiA1NC45NzE4IDI1LjEwNDUgNTIuMDIxNCAyMy4zODQyIDQ4LjY1MjlDMjEuNjYzOCA0NS4yODQzIDIwLjU3MTMgNDEuNTY2MiAyMC4xNzE1IDM3LjcxOThDMTkuNzcxNyAzMy44NzM0IDIwLjA3MjcgMjkuOTc2OSAyMS4wNTY3IDI2LjI2MjJDMjEuMTgzMSAyNS43ODUgMjEuNDUwMSAyNS4zNjg3IDIxLjgxNSAyNS4wNzk4QzIyLjE3OTkgMjQuNzkwOSAyMi42MjE1IDI0LjY0NjIgMjMuMDY5MyAyNC42Njg5QzI4LjU1MTMgMjQuOTQ3IDMzLjkyOTMgMjIuOTQ0NCAzOC4xNTA3IDE5LjA1MzNMMzguNjc3MyAxOC41NTMzTDM4Ljg2OTYgMTguMzg2N0MzOS4wMDQ3IDE4LjI4NDIgMzkuMTUwNSAxOC4yMDA2IDM5LjMwNCAxOC4xMzc4TDM5LjUyODIgMTguMDYyMkMzOS42MDY5IDE4LjA0MTIgMzkuNjg2NSAxOC4wMjU2IDM5Ljc2NjcgMTguMDE1NkwzOS45OTY5IDE4Wk00MC4wMDA5IDMzLjU1NTZDMzguOTkwNSAzMy41NTUxIDM4LjAxNzMgMzMuOTc4NyAzNy4yNzY1IDM0Ljc0MTFDMzYuNTM1NiAzNS41MDM2IDM2LjA4MTYgMzYuNTQ4NSAzNi4wMDU4IDM3LjY2NjdMMzUuOTk1OCAzOEwzNi4wMDU4IDM4LjMzMzRDMzYuMDU1MSAzOS4wNTQ3IDM2LjI2MjUgMzkuNzUxOCAzNi42MDk4IDQwLjM2NEMzNi45NTY5IDQwLjk3NjIgMzcuNDMzNiA0MS40ODUxIDM3Ljk5ODUgNDEuODQ2N1Y0NS43Nzc4TDM4LjAxMjUgNDYuMDM3OEMzOC4wNzI3IDQ2LjYwMDMgMzguMzI0MiA0Ny4xMTU4IDM4LjcxNTYgNDcuNDc5NEMzOS4xMDcxIDQ3Ljg0MjkgMzkuNjA4NyA0OC4wMjY5IDQwLjExODIgNDcuOTkzOEM0MC42Mjc4IDQ3Ljk2MDUgNDEuMTA2NyA0Ny43MTI3IDQxLjQ1NzEgNDcuMzAwOUM0MS44MDc2IDQ2Ljg4ODkgNDIuMDAyOSA0Ni4zNDQzIDQyLjAwMzYgNDUuNzc3OEw0Mi4wMDU2IDQxLjg0ODlDNDIuNzY5MSA0MS4zNTk2IDQzLjM2NiA0MC42MDQyIDQzLjcwMzQgMzkuNzAwMkM0NC4wNDA3IDM4Ljc5NiA0NC4wOTk2IDM3Ljc5MzggNDMuODcxMSAzNi44NDg3QzQzLjY0MjcgMzUuOTAzNiA0My4xMzk2IDM1LjA2ODUgNDIuNDM5OCAzNC40NzMxQzQxLjc0IDMzLjg3NzYgNDAuODgyNyAzMy41NTUxIDQwLjAwMDkgMzMuNTU1NloiIGZpbGw9InVybCgjcGFpbnQxX2xpbmVhcl8xXzkxKSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzFfOTEiIHgxPSI0MCIgeTE9IjAiIHgyPSI0MCIgeTI9IjgwIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM4MzU2QkQiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjN0MyMEY0Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl8xXzkxIiB4MT0iNDAiIHkxPSIxOCIgeDI9IjQwIiB5Mj0iNjIuNDQ0NSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSJ3aGl0ZSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFMUQ4RkIiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K";
export default image;
@@ -0,0 +1,27 @@
export const wallet = {
id: "smart",
name: "SmartWallet",
homepage: "https://thirdweb.com",
app: {
browser: null,
ios: null,
android: null,
mac: null,
windows: null,
linux: null,
chrome: null,
firefox: null,
safari: null,
edge: null,
opera: null,
},
rdns: null,
mobile: {
native: null,
universal: null,
},
desktop: {
native: null,
universal: null,
},
} as const;
@@ -0,0 +1,4 @@
const image =
"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTIiIGZpbGw9IiMxQzdERkMiLz4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTIiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF8xXzQ2KSIvPgo8cGF0aCBkPSJNMjYuNDIyNyAzMS40NzMxQzMzLjkxNzEgMjQuMTc1NiA0Ni4wODI5IDI0LjE3NTYgNTMuNTc3MyAzMS40NzMxTDU0LjQ3OTYgMzIuMzU4QzU0Ljg1OCAzMi43MjA3IDU0Ljg1OCAzMy4zMTU1IDU0LjQ3OTYgMzMuNjc4Mkw1MS4zOTQ1IDM2LjY4MTNDNTEuMjA1MyAzNi44Njk5IDUwLjg5OTcgMzYuODY5OSA1MC43MTA1IDM2LjY4MTNMNDkuNDczNiAzNS40NzcyQzQ0LjIzNDcgMzAuMzg1IDM1Ljc2NTMgMzAuMzg1IDMwLjUyNjQgMzUuNDc3MkwyOS4yMDIxIDM2Ljc2ODRDMjkuMDEzIDM2Ljk1NyAyOC43MDc0IDM2Ljk1NyAyOC41MTgyIDM2Ljc2ODRMMjUuNDMzMSAzMy43NjUzQzI1LjA1NDcgMzMuNDAyNiAyNS4wNTQ3IDMyLjgwNzggMjUuNDMzMSAzMi40NDUxTDI2LjQyMjcgMzEuNDczMVpNNTkuOTY1OCAzNy42ODI0TDYyLjcxNjIgNDAuMzUxOEM2My4wOTQ2IDQwLjcxNDUgNjMuMDk0NiA0MS4zMDkzIDYyLjcxNjIgNDEuNjcyTDUwLjMzMjIgNTMuNzI4QzQ5Ljk1MzggNTQuMDkwNyA0OS4zNDI2IDU0LjA5MDcgNDguOTc4OCA1My43MjhMNDAuMTg5MiA0NS4xNjg0QzQwLjEwMTkgNDUuMDgxMyAzOS45NDE4IDQ1LjA4MTMgMzkuODU0NSA0NS4xNjg0TDMxLjA2NDkgNTMuNzI4QzMwLjY4NjUgNTQuMDkwNyAzMC4wNzUzIDU0LjA5MDcgMjkuNzExNSA1My43MjhMMTcuMjgzOCA0MS42NzJDMTYuOTA1NCA0MS4zMDkzIDE2LjkwNTQgNDAuNzE0NSAxNy4yODM4IDQwLjM1MThMMjAuMDM0MiAzNy42ODI0QzIwLjQxMjUgMzcuMzE5NyAyMS4wMjM3IDM3LjMxOTcgMjEuMzg3NSAzNy42ODI0TDMwLjE3NzIgNDYuMjQyQzMwLjI2NDUgNDYuMzI5IDMwLjQyNDUgNDYuMzI5IDMwLjUxMTkgNDYuMjQyTDM5LjMwMTUgMzcuNjgyNEMzOS42Nzk5IDM3LjMxOTcgNDAuMjkxIDM3LjMxOTcgNDAuNjU0OSAzNy42ODI0TDQ5LjQ0NDUgNDYuMjQyQzQ5LjUzMTggNDYuMzI5IDQ5LjY5MTkgNDYuMzI5IDQ5Ljc3OTIgNDYuMjQyTDU4LjU2ODggMzcuNjgyNEM1OC45NzYzIDM3LjMxOTcgNTkuNTg3NSAzNy4zMTk3IDU5Ljk2NTggMzcuNjgyNFoiIGZpbGw9IndoaXRlIi8+CjxkZWZzPgo8cmFkaWFsR3JhZGllbnQgaWQ9InBhaW50MF9yYWRpYWxfMV80NiIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgwLjAwMDI0Nzk1NSA0MC4wMDEyKSBzY2FsZSg4MCkiPgo8c3RvcCBzdG9wLWNvbG9yPSIjNUQ5REY2Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNkZGRiIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo=";
export default image;
@@ -0,0 +1,27 @@
export const wallet = {
id: "walletConnect",
name: "WalletConnect",
homepage: "https://walletconnect.com",
app: {
browser: null,
ios: null,
android: null,
mac: null,
windows: null,
linux: null,
chrome: null,
firefox: null,
safari: null,
edge: null,
opera: null,
},
rdns: null,
mobile: {
native: null,
universal: null,
},
desktop: {
native: null,
universal: null,
},
} as const;
@@ -4,6 +4,7 @@ import { effect } from "../../reactive/effect.js";
import { createStore } from "../../reactive/store.js";
import type { Account, Wallet } from "../interfaces/wallet.js";
import type { AsyncStorage } from "../storage/AsyncStorage.js";
import { deleteConnectParamsFromStorage } from "../storage/walletStorage.js";
type WalletIdToConnectedWalletMap = Map<string, Wallet>;
export type ConnectionStatus = "connected" | "disconnected" | "connecting";
@@ -60,6 +61,8 @@ export function createConnectionManager(storage: AsyncStorage) {
const onWalletDisconnect = (wallet: Wallet) => {
const currentMap = walletIdToConnectedWalletMap.getValue();
deleteConnectParamsFromStorage(storage, wallet.id);
const newMap = new Map(currentMap);
newMap.delete(wallet.id);
@@ -1,4 +1,4 @@
import type { AsyncStorage } from "../../../wallets/storage/AsyncStorage.js";
import type { AsyncStorage } from "./AsyncStorage.js";
export const asyncLocalStorage: AsyncStorage = {
async getItem(key: string) {
@@ -28,26 +28,52 @@ import type { WalletEmitter } from "../wallet-emitter.js";
import { isAndroid, isIOS, isMobile } from "../../utils/web/isMobile.js";
import { openWindow } from "../../utils/web/openWindow.js";
import { getWalletInfo } from "../__generated__/getWalletInfo.js";
import { asyncLocalStorage as _asyncLocalStorage } from "../storage/asyncLocalStorage.js";
import {
getSavedConnectParamsFromStorage,
saveConnectParamsToStorage,
} from "../storage/walletStorage.js";
const asyncLocalStorage =
typeof window !== "undefined" ? _asyncLocalStorage : undefined;
type WCProvider = InstanceType<typeof EthereumProvider>;
type SavedConnectParams = {
optionalChains?: Chain[];
chain: Chain;
pairingTopic?: string;
};
const defaultWCProjectId = "08c4b07e3ad25f1a27c14a4e8cecb6f0";
const NAMESPACE = "eip155";
const ADD_ETH_CHAIN_METHOD = "wallet_addEthereumChain";
// const isNewChainsStale = true;
const isNewChainsStale = true;
const defaultShowQrModal = true;
const storageKeys = {
requestedChains: "tw.wc.requestedChains",
lastUsedChainId: "tw.wc.lastUsedChainId",
};
/**
* @internal
*/
export async function connectWC(
options: WCConnectOptions,
emitter: WalletEmitter<WCSupportedWalletIds>,
walletId: WCSupportedWalletIds,
walletId: WCSupportedWalletIds | "walletConnect",
): Promise<ReturnType<typeof onConnect>> {
const provider = await initProvider(options, walletId);
const _isChainsState = await isChainsStale(provider, [
provider.chainId,
...(options?.walletConnect?.optionalChains || []).map((c) => c.id),
]);
const wcOptions = options.walletConnect;
const targetChain = options?.chain || ethereum;
@@ -67,7 +93,7 @@ export async function connectWC(
}
// If there no active session, or the chain is stale, force connect.
if (!provider.session) {
if (!provider.session || _isChainsState) {
await provider.connect({
pairingTopic: wcOptions?.pairingTopic,
chains: [Number(targetChainId)],
@@ -75,6 +101,8 @@ export async function connectWC(
[targetChainId.toString()]: rpc,
},
});
setRequestedChainsIds([targetChainId]);
}
// If session exists and chains are authorized, enable provider for required chain
@@ -86,6 +114,18 @@ export async function connectWC(
const chain = defineChain(normalizeChainId(provider.chainId));
if (options) {
const savedParams: SavedConnectParams = {
optionalChains: options.walletConnect?.optionalChains,
chain: chain,
pairingTopic: options.walletConnect?.pairingTopic,
};
if (asyncLocalStorage) {
saveConnectParamsToStorage(asyncLocalStorage, walletId, savedParams);
}
}
if (wcOptions?.onDisplayUri) {
provider.events.removeListener("display_uri", wcOptions.onDisplayUri);
}
@@ -100,16 +140,20 @@ export async function connectWC(
export async function autoConnectWC(
options: WCAutoConnectOptions,
emitter: WalletEmitter<WCSupportedWalletIds>,
walletId: WCSupportedWalletIds,
walletId: WCSupportedWalletIds | "walletConnect",
): Promise<ReturnType<typeof onConnect>> {
const savedConnectParams: SavedConnectParams | null = asyncLocalStorage
? await getSavedConnectParamsFromStorage(asyncLocalStorage, walletId)
: null;
const provider = await initProvider(
options.savedConnectParams
savedConnectParams
? {
chain: options.savedConnectParams.chain,
chain: savedConnectParams.chain,
client: options.client,
walletConnect: {
pairingTopic: options.savedConnectParams.pairingTopic,
optionalChains: options.savedConnectParams.optionalChains,
pairingTopic: savedConnectParams.pairingTopic,
optionalChains: savedConnectParams.optionalChains,
},
}
: {
@@ -117,6 +161,7 @@ export async function autoConnectWC(
walletConnect: {},
},
walletId,
true, // is auto connect
);
const address = provider.accounts[0];
@@ -151,7 +196,8 @@ export async function autoConnectWC(
async function initProvider(
options: WCConnectOptions,
walletId: WCSupportedWalletIds,
walletId: WCSupportedWalletIds | "walletConnect",
isAutoConnect = false,
) {
const walletInfo = await getWalletInfo(walletId);
const wcOptions = options.walletConnect;
@@ -192,35 +238,74 @@ async function initProvider(
disableProviderPing: true,
});
function handleSessionRequest() {
if (typeof window === "undefined") {
return;
}
provider.events.setMaxListeners(Infinity);
if (!isMobile()) {
return;
}
// disconnect the provider if chains are stale when (if not auto connecting)
if (!isAutoConnect) {
const chains = [
targetChain,
...(options?.walletConnect?.optionalChains || []),
];
const preferUniversal =
walletInfo.mobile.universal || walletInfo.mobile.native || "";
const preferNative =
walletInfo.mobile.native || walletInfo.mobile.universal || "";
const isStale = await isChainsStale(
provider,
chains.map((c) => c.id),
);
if (isAndroid()) {
openWindow(preferUniversal);
} else if (isIOS()) {
openWindow(preferNative);
} else {
openWindow(preferUniversal);
if (isStale && provider.session) {
await provider.disconnect();
}
}
provider.signer.client.on("session_request_sent", handleSessionRequest);
provider.events.addListener("disconnect", () => {
provider.signer.client.off("session_request_sent", handleSessionRequest);
});
if (walletId !== "walletConnect") {
function handleSessionRequest() {
if (typeof window === "undefined") {
return;
}
provider.events.setMaxListeners(Infinity);
if (!isMobile()) {
return;
}
const preferUniversal =
walletInfo.mobile.universal || walletInfo.mobile.native;
const preferNative =
walletInfo.mobile.native || walletInfo.mobile.universal;
if (isAndroid()) {
if (preferUniversal) {
openWindow(preferUniversal);
}
} else if (isIOS()) {
if (preferNative) {
openWindow(preferNative);
}
} else {
if (preferUniversal) {
openWindow(preferUniversal);
}
}
}
provider.signer.client.on("session_request_sent", handleSessionRequest);
provider.events.addListener("disconnect", () => {
provider.signer.client.off("session_request_sent", handleSessionRequest);
});
}
// try switching to correct chain
if (options?.chain && provider.chainId !== options?.chain.id) {
try {
await switchChainWC(provider, options.chain);
} catch (e) {
console.error("Failed to Switch chain to target chain");
console.error(e);
// throw only if not auto connecting
if (!isAutoConnect) {
throw e;
}
}
}
return provider;
}
@@ -293,6 +378,8 @@ function onConnect(
}
function onDisconnect() {
setRequestedChainsIds([]);
asyncLocalStorage?.removeItem(storageKeys.lastUsedChainId);
disconnect();
emitter.emit("disconnect", undefined);
}
@@ -308,11 +395,14 @@ function onConnect(
function onChainChanged(newChainId: string) {
const newChain = defineChain(normalizeChainId(newChainId));
emitter.emit("chainChanged", newChain);
asyncLocalStorage?.setItem(storageKeys.lastUsedChainId, String(newChainId));
}
provider.on("accountsChanged", onAccountsChanged);
provider.on("chainChanged", onChainChanged);
provider.on("disconnect", onDisconnect);
provider.on("session_delete", onDisconnect);
return [
account,
chain,
@@ -363,9 +453,9 @@ async function switchChainWC(provider: WCProvider, chain: Chain) {
},
],
});
// const requestedChains = await getRequestedChainsIds(wallet);
// requestedChains.push(chainId);
// setRequestedChainsIds(wallet, requestedChains);
const requestedChains = await getRequestedChainsIds();
requestedChains.push(chainId);
setRequestedChainsIds(requestedChains);
}
await provider.request({
method: "wallet_switchEthereumChain",
@@ -381,3 +471,53 @@ async function switchChainWC(provider: WCProvider, chain: Chain) {
throw new SwitchChainError(error);
}
}
/**
* if every chain requested were already requested earlier - then they are not stale
* @param connectToChainId
* @internal
*/
async function isChainsStale(provider: WCProvider, chains: number[]) {
const namespaceMethods = getNamespaceMethods(provider);
// if chain adding method is available, then chains are not stale
if (namespaceMethods.includes(ADD_ETH_CHAIN_METHOD)) {
return false;
}
// if new chains are considered stale, then return true
if (!isNewChainsStale) {
return false;
}
const requestedChains = await getRequestedChainsIds();
const namespaceChains = getNamespaceChainsIds(provider);
// if any of the requested chains are not in the namespace chains, then they are stale
if (
namespaceChains.length &&
!namespaceChains.some((id) => chains.includes(id))
) {
return false;
}
// if chain was requested earlier, then they are not stale
return !chains.every((id) => requestedChains.includes(id));
}
/**
* Set the requested chains to the storage.
* @internal
*/
function setRequestedChainsIds(chains: number[]) {
localStorage?.setItem(storageKeys.requestedChains, JSON.stringify(chains));
}
/**
* Get the last requested chains from the storage.
* @internal
*/
async function getRequestedChainsIds(): Promise<number[]> {
const data = localStorage.getItem(storageKeys.requestedChains);
return data ? JSON.parse(data) : [];
}
+46 -31
View File
@@ -20,11 +20,20 @@ import type { CoinbaseSDKWalletConnectionOptions } from "./coinbase/coinbaseSDKW
import type { ThirdwebClient } from "../client/client.js";
export type WalletId =
| "walletConnect"
| "embedded"
| "smart"
| WCSupportedWalletIds
| InjectedSupportedWalletIds;
export type StandaloneWCConnectOptions = WCConnectOptions["walletConnect"] & {
client: ThirdwebClient;
/**
* Optional chain to connect to.
*/
chain?: Chain;
};
// connect options
export type InjectedConnectOptions = {
/**
@@ -52,22 +61,25 @@ export type EmbeddedWalletCreationOptions =
* type X = WalletConnectionOption<'io.metamask'>
* ````
*/
export type WalletConnectionOption<T extends WalletId> = T extends "smart"
? SmartWalletConnectionOptions
: // embedded wallet
T extends "embedded"
? EmbeddedWalletConnectionOptions
: // coinbase wallet (inhected + coinbaseWallet)
T extends "com.coinbase.wallet"
? InjectedConnectOptions | CoinbaseSDKWalletConnectionOptions
: // injected + wc both supported
T extends InjectedSupportedWalletIds & WCSupportedWalletIds
? InjectedConnectOptions | WCConnectOptions
: // injected only
T extends InjectedSupportedWalletIds
? InjectedConnectOptions
: // wc only
WCConnectOptions;
export type WalletConnectionOption<T extends WalletId> =
T extends "walletConnect"
? StandaloneWCConnectOptions
: T extends "smart"
? SmartWalletConnectionOptions
: // embedded wallet
T extends "embedded"
? EmbeddedWalletConnectionOptions
: // coinbase wallet (inhected + coinbaseWallet)
T extends "com.coinbase.wallet"
? InjectedConnectOptions | CoinbaseSDKWalletConnectionOptions
: // injected + wc both supported
T extends InjectedSupportedWalletIds & WCSupportedWalletIds
? InjectedConnectOptions | WCConnectOptions
: // injected only
T extends InjectedSupportedWalletIds
? InjectedConnectOptions
: // wc only
WCConnectOptions;
/**
* Generic type for getting the type of object that the `wallet.autoConnect` method takes as the first argument.
@@ -76,21 +88,24 @@ export type WalletConnectionOption<T extends WalletId> = T extends "smart"
* type X = WalletAutoConnectionOption<'io.metamask'>
* ````
*/
export type WalletAutoConnectionOption<T extends WalletId> = T extends "smart"
? SmartWalletConnectionOptions
: T extends "embedded"
? EmbeddedWalletAutoConnectOptions
: // coinbase wallet (inhected + coinbaseWallet)
T extends "com.coinbase.wallet"
? InjectedConnectOptions | CoinbaseSDKWalletConnectionOptions
: // injected + wc both supported
T extends InjectedSupportedWalletIds & WCSupportedWalletIds
? InjectedConnectOptions | WCAutoConnectOptions
: // injected only
T extends InjectedSupportedWalletIds
? InjectedConnectOptions
: // wc only
WCAutoConnectOptions;
export type WalletAutoConnectionOption<T extends WalletId> =
T extends "walletConnect"
? WCAutoConnectOptions
: T extends "smart"
? SmartWalletConnectionOptions
: T extends "embedded"
? EmbeddedWalletAutoConnectOptions
: // coinbase wallet (inhected + coinbaseWallet)
T extends "com.coinbase.wallet"
? InjectedConnectOptions | CoinbaseSDKWalletConnectionOptions
: // injected + wc both supported
T extends InjectedSupportedWalletIds & WCSupportedWalletIds
? InjectedConnectOptions | WCAutoConnectOptions
: // injected only
T extends InjectedSupportedWalletIds
? InjectedConnectOptions
: // wc only
WCAutoConnectOptions;
/**
* Generic type for getting the type of object that the `createWallet` function takes as the second argument. ( the first argument being the wallet id )
* @example
Binary file not shown.
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/unity-js-bridge
## 0.6.3
### Patch Changes
- Updated dependencies [[`3ef3786`](https://github.com/thirdweb-dev/js/commit/3ef378659e83341663dfaded417e33b5af29bbbc)]:
- @thirdweb-dev/chains@0.1.85
- @thirdweb-dev/sdk@4.0.54
- @thirdweb-dev/wallets@2.4.30
- @thirdweb-dev/auth@4.1.52
## 0.6.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.6.2",
"version": "0.6.3",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",