Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[react, wallets] Add imToken Wallet #2497

Merged
merged 11 commits into from Mar 20, 2024
6 changes: 6 additions & 0 deletions .changeset/tall-moose-add-imToken.md
@@ -0,0 +1,6 @@
---
"@thirdweb-dev/wallets": patch
"@thirdweb-dev/react": patch
---

[Wallets/React] Add imToken Wallet
jnsdls marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions packages/react-core/src/core/hooks/wallet-hooks.ts
Expand Up @@ -8,6 +8,7 @@ import type {
CryptoDefiWallet,
EmbeddedWallet,
FrameWallet,
ImTokenWallets
makoshan marked this conversation as resolved.
Show resolved Hide resolved
LocalWallet,
MagicEdenWallet,
MagicLink,
Expand Down Expand Up @@ -41,6 +42,7 @@ export type WalletIdToWalletTypeMap = {
rainbowWallet: RainbowWallet;
blocto: BloctoWallet;
frame: FrameWallet;
imtoken: ImTokenWallet
localWallet: LocalWallet;
magicLink: MagicLink;
paper: PaperWallet;
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/evm/index.ts
Expand Up @@ -111,4 +111,5 @@ export {
CryptoDefiWallet,
RabbyWallet,
Coin98Wallet,
ImTokenWallet,
} from "@thirdweb-dev/wallets";
1 change: 1 addition & 0 deletions packages/react/src/evm/locales/en.ts
Expand Up @@ -171,6 +171,7 @@ export function enDefault(): ThirdwebLocale {
xdefiWallet: extensionAndQRScanScreens("XDEFI"),
rainbowWallet: extensionAndQRScanScreens("Rainbow"),
trustWallet: extensionAndQRScanScreens("Trust"),
imtokenWallet: extensionAndQRScanScreens("imToken"),
zerionWallet: extensionAndQRScanScreens("Zerion"),
coreWallet: extensionAndQRScanScreens("Core"),
oneKeyWallet: extensionAndQRScanScreens("OneKey"),
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/evm/locales/es.ts
Expand Up @@ -176,6 +176,7 @@ export function esDefault(): ThirdwebLocale {
xdefiWallet: extensionAndQRScanScreens("XDEFI"),
rainbowWallet: extensionAndQRScanScreens("Rainbow"),
trustWallet: extensionAndQRScanScreens("Trust"),
imtokenWallet: extensionAndQRScanScreens("imToken"),
zerionWallet: extensionAndQRScanScreens("Zerion"),
oneKeyWallet: extensionAndQRScanScreens("OneKey"),
cryptoDefiWallet: extensionAndQRScanScreens("Crypto Defi"),
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/evm/locales/ja.ts
Expand Up @@ -176,6 +176,7 @@ export function jaDefault(): ThirdwebLocale {
xdefiWallet: extensionAndQRScanScreens("XDEFI"),
rainbowWallet: extensionAndQRScanScreens("Rainbow"),
trustWallet: extensionAndQRScanScreens("Trust"),
imtokenWallet: extensionAndQRScanScreens("imToken"),
zerionWallet: extensionAndQRScanScreens("Zerion"),
oneKeyWallet: extensionAndQRScanScreens("OneKey"),
cryptoDefiWallet: extensionAndQRScanScreens("Crypto Defi"),
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/evm/locales/tl.ts
Expand Up @@ -176,6 +176,7 @@ export function tlDefault(): ThirdwebLocale {
xdefiWallet: extensionAndQRScanScreens("XDEFI"),
rainbowWallet: extensionAndQRScanScreens("Rainbow"),
trustWallet: extensionAndQRScanScreens("Trust"),
imtokenWallet: extensionAndQRScanScreens("imToken"),
zerionWallet: extensionAndQRScanScreens("Zerion"),
coreWallet: extensionAndQRScanScreens("Core"),
oneKeyWallet: extensionAndQRScanScreens("OneKey"),
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/evm/locales/types.ts
Expand Up @@ -183,6 +183,7 @@ export type ThirdwebLocale = {
getStartedScreen: { instruction: string };
scanScreen: { instruction: string };
};
trustWallet: ExtensionAndQRScreensLocale;
localWallet: {
confirmPasswordLabel: string;
createScreen: {
Expand Down Expand Up @@ -302,7 +303,7 @@ export type ThirdwebLocale = {
title: string;
};
};
trustWallet: ExtensionAndQRScreensLocale;
imtokenWallet: ExtensionAndQRScreensLocale;
walletConnect: { scanInstruction: string };
zerionWallet: ExtensionAndQRScreensLocale;
};
Expand Down
5 changes: 5 additions & 0 deletions packages/react/src/index.ts
Expand Up @@ -107,6 +107,11 @@ export {
type Coin98WalletConfigOptions,
} from "./wallet/wallets/coin98/coin98Wallet";

export {
imTokenWallet,
type ImTokenWalletConfigOptions,
} from "./wallet/wallets/imtoken/imTokenWallet";

// theming
export { darkTheme, lightTheme } from "./design-system/index";
export type { Theme, ThemeOverrides } from "./design-system/index";
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/wallet/hooks/useInstalledWallets.ts
Expand Up @@ -12,19 +12,22 @@ export function useInstalledWallets() {
let isCoinbaseWalletInstalled = false;
let isZerionWalletInstalled = false;
let isTrustWalletInstalled = false;
let isImTokenInstalled = false;

const window_: Window | undefined = globalThis?.window;
if (assertWindowEthereum(window_)) {
isMetamaskInstalled = !!getInjectedMetamaskProvider();
isCoinbaseWalletInstalled = !!getInjectedCoinbaseProvider();
isZerionWalletInstalled = !!window_.ethereum?.isZerion;
isTrustWalletInstalled = !!window_.ethereum?.isTrust;
isImTokenInstalled = !!window_.ethereum?.isImToken;
}

return {
metamask: isMetamaskInstalled,
coinbaseWallet: isCoinbaseWalletInstalled,
trustWallet: isTrustWalletInstalled,
zerionWallet: isZerionWalletInstalled,
imtokenWallet: isImTokenInstalled,
};
}
72 changes: 72 additions & 0 deletions packages/react/src/wallet/wallets/imtoken/imTokenWallet.tsx
@@ -0,0 +1,72 @@
import type {
WalletOptions,
WalletConfig,
ConnectUIProps,
} from "@thirdweb-dev/react-core";
import { ImTokenWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
import { handleWCSessionRequest } from "../handleWCSessionRequest";
import { useTWLocale } from "../../../evm/providers/locale-provider";
import { ExtensionOrWCConnectionUI } from "../_common/ExtensionORWCConnectionUI";

const imTokenWalletUris = {
ios: "imtokenv2://",
makoshan marked this conversation as resolved.
Show resolved Hide resolved
android: "imtokenv2://",
other: "imtokenv2://",
makoshan marked this conversation as resolved.
Show resolved Hide resolved
};

export type ImTokenWalletConfigOptions = {
projectId?: string;
recommended?: boolean;
};

export const imTokenWallet = (
options?: ImTokenWalletConfigOptions,
): WalletConfig<ImTokenWallet> => {
return {
id: ImTokenWallet.id,
recommended: options?.recommended,
meta: {
...ImTokenWallet.meta,
iconURL: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzIyMl80NzgzKSI+CjxtYXNrIGlkPSJtYXNrMF8yMjJfNDc4MyIgc3R5bGU9Im1hc2stdHlwZTpsdW1pbmFuY2UiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjAiIHk9IjAiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCI+CjxwYXRoIGQ9Ik03OS44OTQ4IDBIMC4wNTA3ODEyVjgwSDc5Ljg5NDhWMFoiIGZpbGw9IndoaXRlIi8+CjwvbWFzaz4KPGcgbWFzaz0idXJsKCNtYXNrMF8yMjJfNDc4MykiPgo8cGF0aCBkPSJNNjIuMDI3NSAwSDE4LjA1MDlDOC4xNDYzOSAwIDAuMTE3MTg4IDguMDQ0ODggMC4xMTcxODggMTcuOTY4OFY2Mi4wMzEyQzAuMTE3MTg4IDcxLjk1NTEgOC4xNDYzOSA4MCAxOC4wNTA5IDgwSDYyLjAyNzVDNzEuOTMyIDgwIDc5Ljk2MTIgNzEuOTU1MSA3OS45NjEyIDYyLjAzMTJWMTcuOTY4OEM3OS45NjEyIDguMDQ0ODggNzEuOTMyIDAgNjIuMDI3NSAwWiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzIyMl80NzgzKSIvPgo8cGF0aCBkPSJNNjUuMDk4MSAyNC43MzNDNjYuNzU4NiA0Ny4yNjY3IDUyLjMwMjEgNTcuOTE3MiAzOS4zNDIzIDU5LjA1M0MyNy4yOTM1IDYwLjEwODcgMTUuOTUyIDUyLjY5MDggMTQuOTU3MSA0MS4yOTM2QzE0LjEzNjMgMzEuODc3NiAxOS45NDQ1IDI3Ljg2ODkgMjQuNTA4IDI3LjQ2OTRDMjkuMjAxNSAyNy4wNTcgMzMuMTQ1OCAzMC4zMDAxIDMzLjQ4NzkgMzQuMjI2OUMzMy44MTc1IDM4LjAwMiAzMS40NjY0IDM5LjcyMDUgMjkuODMxMyAzOS44NjM0QzI4LjUzODIgMzkuOTc3IDI2LjkxMTQgMzkuMTkwNSAyNi43NjQ1IDM3LjUwMTZDMjYuNjM4NSAzNi4wNTAzIDI3LjE4ODUgMzUuODUyNiAyNy4wNTQxIDM0LjMxMDlDMjYuODE0OSAzMS41NjYyIDI0LjQyNjEgMzEuMjQ2NiAyMy4xMTgzIDMxLjM2MDFDMjEuNTM1NyAzMS40OTkxIDE4LjY2NDEgMzMuMzQ5OCAxOS4wNjcgMzcuOTZDMTkuNDcyMiA0Mi42MTAxIDIzLjkyMjIgNDYuMjg0NSAyOS43NTU3IDQ1Ljc3MzRDMzYuMDUwOSA0NS4yMjIzIDQwLjQzMzcgNDAuMzExNCA0MC43NjM0IDMzLjQyMzRDNDAuNzYwMyAzMy4wNTg2IDQwLjgzNyAzMi42OTc1IDQwLjk4OCAzMi4zNjU1TDQwLjk5IDMyLjM1NzJDNDEuMDU3OCAzMi4yMTI4IDQxLjEzNzIgMzIuMDc0MiA0MS4yMjcyIDMxLjk0MjhDNDEuMzYxNiAzMS43NDA5IDQxLjUzMzggMzEuNTE4IDQxLjc1NjIgMzEuMjczOUM0MS43NTgzIDMxLjI2NzYgNDEuNzU4MyAzMS4yNjc2IDQxLjc2MjYgMzEuMjY3NkM0MS45MjQxIDMxLjA4NDcgNDIuMTE5NCAzMC44ODcgNDIuMzM5NyAzMC42NzQ1QzQ1LjA4OTcgMjguMDc1IDU0Ljk5MzEgMjEuOTQ0MiA2NC4zNTkyIDIzLjg4NTVDNjQuNTU3MyAyMy45MjggNjQuNzM2MSAyNC4wMzM0IDY0Ljg2OTMgMjQuMTg2MkM2NS4wMDI1IDI0LjMzOTEgNjUuMDgyNiAyNC41MzA4IDY1LjA5ODEgMjQuNzMzWiIgZmlsbD0id2hpdGUiLz4KPC9nPgo8L2c+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMjIyXzQ3ODMiIHgxPSI3My41MDA5IiB5MT0iNS4zMTI1IiB4Mj0iMi44NzI0MSIgeTI9Ijc3LjY3NDciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzExQzREMSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDYyQUQiLz4KPC9saW5lYXJHcmFkaWVudD4KPGNsaXBQYXRoIGlkPSJjbGlwMF8yMjJfNDc4MyI+CjxyZWN0IHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgZmlsbD0id2hpdGUiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4=", // 这里需要替换为imToken的图标数据
},
create: (walletOptions: WalletOptions) => {
const wallet = new ImTokenWallet({
...walletOptions,
projectId: options?.projectId,
qrcode: false,
});

handleWCSessionRequest(wallet, imTokenWalletUris);

return wallet;
},
connectUI: ConnectUI,
isInstalled: isInstalled,
};
};

function isInstalled() {
if (assertWindowEthereum(globalThis.window)) {
return !!globalThis.window.ethereum.isImToken;
}
return false;
}

function ConnectUI(props: ConnectUIProps<ImTokenWallet>) {
const locale = useTWLocale();
return (
<ExtensionOrWCConnectionUI
connect={props.connect}
connected={props.connected}
createWalletInstance={props.createWalletInstance}
goBack={props.goBack}
meta={props.walletConfig.meta}
setConnectedWallet={(w) => props.setConnectedWallet(w as ImTokenWallet)}
setConnectionStatus={props.setConnectionStatus}
supportedWallets={props.supportedWallets}
walletConnectUris={imTokenWalletUris}
walletLocale={locale.wallets.imTokenWallet}
isInstalled={isInstalled}
/>
);
}
7 changes: 7 additions & 0 deletions packages/wallets/evm/connectors/imtoken/package.json
@@ -0,0 +1,7 @@
{
"main": "dist/thirdweb-dev-wallets-evm-connectors-imtoken.cjs.js",
"module": "dist/thirdweb-dev-wallets-evm-connectors-trust.esm.js",
"browser": {
"./dist/thirdweb-dev-wallets-evm-connectors-imtoken.esm.js": "./dist/thirdweb-dev-wallets-evm-connectors-imtoken.browser.esm.js"
}
}
7 changes: 7 additions & 0 deletions packages/wallets/evm/wallets/imtoken/package.json
@@ -0,0 +1,7 @@
{
"main": "dist/thirdweb-dev-wallets-evm-wallets-imtoken.cjs.js",
"module": "dist/thirdweb-dev-wallets-evm-wallets-imtoken.esm.js",
"browser": {
"./dist/thirdweb-dev-wallets-evm-wallets-imtoken.esm.js": "./dist/thirdweb-dev-wallets-evm-wallets-imtoken.browser.esm.js"
}
}
14 changes: 14 additions & 0 deletions packages/wallets/package.json
Expand Up @@ -161,6 +161,13 @@
},
"default": "./evm/wallets/abstract/dist/thirdweb-dev-wallets-evm-wallets-abstract.cjs.js"
},
"./evm/wallets/imtoken": {
"module": {
"browser": "./evm/wallets/imtoken/dist/thirdweb-dev-wallets-evm-wallets-imtoken.browser.esm.js",
"default": "./evm/wallets/imtoken/dist/thirdweb-dev-wallets-evm-wallets-imtoken.esm.js"
},
"default": "./evm/wallets/imtoken/dist/thirdweb-dev-wallets-evm-wallets-imtoken.cjs.js"
},
"./evm/wallets/injected": {
"module": {
"browser": "./evm/wallets/injected/dist/thirdweb-dev-wallets-evm-wallets-injected.browser.esm.js",
Expand Down Expand Up @@ -349,6 +356,13 @@
"default": "./evm/connectors/rainbow/dist/thirdweb-dev-wallets-evm-connectors-rainbow.esm.js"
},
"default": "./evm/connectors/rainbow/dist/thirdweb-dev-wallets-evm-connectors-rainbow.cjs.js"
},
"./evm/connectors/imtoken": {
"module": {
"browser": "./evm/connectors/imtoken/dist/thirdweb-dev-wallets-evm-connectors-imtoken.browser.esm.js",
"default": "./evm/connectors/imtoken/dist/thirdweb-dev-wallets-evm-connectors-imtoken.esm.js"
},
"default": "./evm/connectors/imtoken/dist/thirdweb-dev-wallets-evm-connectors-imtoken.cjs.js"
},
"./evm/connectors/injected": {
"module": {
Expand Down
49 changes: 49 additions & 0 deletions packages/wallets/src/evm/connectors/imtoken/index.ts
@@ -0,0 +1,49 @@
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 ImTokenConnectorConstructorArg = {
chains?: Chain[];
connectorStorage: AsyncStorage;
options?: InjectedConnectorOptions;
};

export class ImTokenConnector extends InjectedConnector {
constructor(arg: ImTokenConnectorConstructorArg) {
const defaultOptions = {
name: "imToken",
getProvider() {
function getReady(ethereum?: Ethereum) {
const isToken = !!ethereum?.isToken;
if (!isToken) {
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 change: 1 addition & 0 deletions packages/wallets/src/evm/constants/walletIds.ts
Expand Up @@ -5,6 +5,7 @@ export const walletIds = {
coreWallet: "coreWallet",
cryptoDefiWallet: "cryptoDefiWallet",
frame: "frame",
imtoken: "imToken",
localWallet: "localWallet",
magicLink: "magicLink",
metamask: "metamask",
Expand Down
1 change: 1 addition & 0 deletions packages/wallets/src/evm/index.ts
Expand Up @@ -32,6 +32,7 @@ export * from "./wallets/coinbase-wallet";
export * from "./wallets/embedded-wallet";
export * from "./wallets/ethers";
export * from "./wallets/frame";
export * from "./wallets/imtoken";
export * from "./wallets/injected";
export * from "./wallets/local-wallet";
export * from "./wallets/signer";
Expand Down