@tomo-inc/embedded-wallet-providers 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # @tomo-inc/embedded-wallet-providers
2
+
3
+ ## 0.0.1
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # embedded-wallet-providers
2
+
3
+ ```
4
+ pnpm add @tomo-inc/embedded-wallet-providers
5
+ ```
6
+
7
+ ## 1. embedded wallet
8
+
9
+ ### 1.1 init
10
+
11
+ ```typescript
12
+ const config = {
13
+ tomoStage: "dev" as "dev" | "prod",
14
+ name: "******",
15
+ logo: "https://******",
16
+ tomoClientId: "******",
17
+ xClientId: "******",
18
+ googleClientId: "******",
19
+
20
+ walletBaseUrl: "https://******", //embeded-wallet link
21
+ };
22
+
23
+ embeddedWallet = EmbeddedWallet.getInstance();
24
+ const { isAvailable, message, connectedInfo } =
25
+ await embeddedWallet.init(config);
26
+
27
+ if ((isAvailable = false)) {
28
+ //odic auth
29
+ //wallet login
30
+ }
31
+
32
+ embeddedWallet.setWalletZIndex(999); //default
33
+ ```
34
+
35
+ ### 1.2 oidc auth
36
+
37
+ ```typescript
38
+ const oidcToken = await embeddedWallet.loginByGoogle();
39
+ const oidcToken = await embeddedWallet.loginByX();
40
+ const oidcToken = await embeddedWallet.loginByEmail({ email });
41
+ ```
42
+
43
+ ### 1.3 wallet login
44
+
45
+ same response as init
46
+
47
+ ```typescript
48
+ const { isAvailable, connectedInfo } = await embeddedWallet.login(oidcToken);
49
+ connectInfo = {
50
+ evmProvider: {
51
+ connected: true;
52
+ address: string[];
53
+ },
54
+ solanaProvider: {
55
+ connected: false;
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## 2. wallet brand info
61
+
62
+ ```typescript
63
+ embeddedWallet.info = {
64
+ uuid: string;
65
+ name: string;
66
+ icon: string;
67
+ rdns: string;
68
+ iconBackground?: string;
69
+ links?: {
70
+ homepage: string;
71
+ };
72
+ };
73
+ ```
74
+
75
+ ## 3. wallet api
76
+
77
+ ```typescript
78
+ embeddedWallet.open("setting"); //mfa config
79
+ embeddedWallet.open("mnemonicExport");
80
+ embeddedWallet.logout();
81
+ ```
82
+
83
+ ## 4. providers
84
+
85
+ > isAvailable = true
86
+
87
+ ### 4.1 evm
88
+
89
+ ```typescript
90
+ const evmProvider = embeddedWallet.evmProvider;
91
+
92
+ connect;
93
+ disconnect;
94
+ getChainId;
95
+ switchChain;
96
+ signMessage(siweSign);
97
+ signTypedData;
98
+ eth_signTransaction;
99
+ sendTransaction;
100
+ ```
101
+
102
+ api doc: https://qsg07xytt12z.sg.larksuite.com/wiki/XLq9wrNRLiAXANkCj4QlERCxg7f
103
+
104
+ ### 4.2 solana(todo)
105
+
106
+ ```typescript
107
+ const solanaProvider = embeddedWallet.solanaProvider;
108
+ ```
109
+
110
+ api doc: https://qsg07xytt12z.sg.larksuite.com/wiki/LyVnwBkzaibRDEkUfXclabRmg6g
111
+
112
+ ### 4.3 dogecoin(todo)
113
+
114
+ ```typescript
115
+ const dogecoinProvider = embeddedWallet.dogecoinProvider;
116
+ ```
117
+
118
+ api doc: https://qsg07xytt12z.sg.larksuite.com/wiki/FKuOwiSN7iNHHNkA4zjl4S5JgLb
119
+
120
+ ## 5. demo
121
+
122
+ https://github.com/tomo-inc/tomo-wallet/tree/tomo-sdk-design/examples/wallet-sdk-demo/src/embedded-wallet-providers
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@tomo-inc/embedded-wallet-providers",
3
+ "version": "0.0.2",
4
+ "author": "tomo.inc",
5
+ "license": "MIT",
6
+ "private": false,
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "dependencies": {
19
+ "@tomo-inc/oidc-auth": "0.0.2",
20
+ "@tomo-inc/wallet-utils": "0.0.2",
21
+ "@tomo-inc/inject-providers": "0.0.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "@types/supertest": "^2.0.12",
26
+ "supertest": "^6.3.0",
27
+ "tsup": "^8.0.0",
28
+ "tsx": "^4.19.2",
29
+ "typescript": "^5.0.0",
30
+ "@vitest/browser": "^3.2.4",
31
+ "playwright": "^1.44.1",
32
+ "vitest": "^3.2.4"
33
+ }
34
+ }
package/project.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "embedded-wallet-providers",
3
+ "sourceRoot": "packages/embedded-wallet-providers/src",
4
+ "projectType": "library",
5
+ "targets": {
6
+ "build": {
7
+ "executor": "nx:run-commands",
8
+ "outputs": ["{projectRoot}/dist"],
9
+ "dependsOn": ["^build", "inject-providers:build"],
10
+ "options": {
11
+ "command": "tsup src/index.ts --format esm,cjs --dts --treeshake",
12
+ "cwd": "packages/embedded-wallet-providers"
13
+ }
14
+ },
15
+ "dev": {
16
+ "executor": "nx:run-commands",
17
+ "options": {
18
+ "command": "tsup src/index.ts --format esm,cjs --watch --dts",
19
+ "cwd": "packages/embedded-wallet-providers"
20
+ }
21
+ },
22
+ "lint": {
23
+ "executor": "nx:run-commands",
24
+ "options": {
25
+ "command": "eslint src/**/*.ts",
26
+ "cwd": "packages/embedded-wallet-providers"
27
+ }
28
+ },
29
+ "lint:fix": {
30
+ "executor": "nx:run-commands",
31
+ "options": {
32
+ "command": "eslint src/**/*.ts --fix",
33
+ "cwd": "packages/embedded-wallet-providers"
34
+ }
35
+ },
36
+ "format": {
37
+ "executor": "nx:run-commands",
38
+ "options": {
39
+ "command": "prettier --write \"src/**/*.{ts,tsx}\"",
40
+ "cwd": "packages/embedded-wallet-providers"
41
+ }
42
+ },
43
+ "test": {
44
+ "executor": "nx:run-commands",
45
+ "outputs": ["{projectRoot}/coverage"],
46
+ "options": {
47
+ "command": "vitest run",
48
+ "cwd": "packages/embedded-wallet-providers"
49
+ }
50
+ },
51
+ "test:watch": {
52
+ "executor": "nx:run-commands",
53
+ "options": {
54
+ "command": "vitest",
55
+ "cwd": "packages/embedded-wallet-providers"
56
+ }
57
+ }
58
+ },
59
+ "tags": ["npm:private", "scope:embedded-wallet-providers", "type:library"]
60
+ }
@@ -0,0 +1,246 @@
1
+ import { BtcProvider, DogecoinProvider, EvmProvider, SolanaProvider, TronProvider } from "@tomo-inc/inject-providers";
2
+ import { onResponse, sendRequest } from "./hub";
3
+
4
+ import { OidcAuth } from "@tomo-inc/oidc-auth";
5
+ import { InitConfig, WalletInfo, WalletOpenMethod, WalletRequestMethod } from "./types";
6
+
7
+ export class EmbeddedWallet {
8
+ public isAvailable: boolean = false;
9
+ public config: InitConfig | null = null;
10
+ public info: WalletInfo | null = null;
11
+ public btcProvider: BtcProvider | null = null;
12
+ public dogecoinProvider: DogecoinProvider | null = null;
13
+ public evmProvider: EvmProvider | null = null;
14
+ public solanaProvider: SolanaProvider | null = null;
15
+ public tronProvider: TronProvider | null = null;
16
+
17
+ public walletIframe: HTMLIFrameElement | null = null;
18
+ public walletOrigin: string = "";
19
+ public maskZIndex: number = 999;
20
+ private static instance: EmbeddedWallet;
21
+ public loginByGoogle: (() => Promise<string>) | null = null;
22
+ public loginByX: (() => Promise<string>) | null = null;
23
+ public constructor() {}
24
+
25
+ public static getInstance() {
26
+ if (!EmbeddedWallet.instance) {
27
+ EmbeddedWallet.instance = new EmbeddedWallet();
28
+ }
29
+ return EmbeddedWallet.instance;
30
+ }
31
+
32
+ public async init(config: InitConfig) {
33
+ this.config = config;
34
+
35
+ if (!config.tomoClientId) {
36
+ throw new Error("tomoClientId is required.");
37
+ }
38
+ if (!config.walletBaseUrl) {
39
+ throw new Error("walletBaseUrl is required.");
40
+ }
41
+
42
+ const { origin: walletOrigin, hostname, port } = new URL(config.walletBaseUrl);
43
+ this.walletOrigin = walletOrigin;
44
+ const hostArr = hostname.split(".");
45
+ if (port) {
46
+ hostArr.push(port);
47
+ }
48
+ hostArr.reverse();
49
+ const rdns = hostArr.join(".");
50
+
51
+ this.info = {
52
+ uuid: hostArr.join("-"),
53
+ name: config.name,
54
+ icon: config.logo,
55
+ rdns,
56
+ links: {
57
+ homepage: config.walletBaseUrl,
58
+ },
59
+ };
60
+
61
+ const productInfo = {
62
+ name: config.name,
63
+ rdns,
64
+ icon: config.logo,
65
+ };
66
+
67
+ this.btcProvider = new BtcProvider(productInfo, { sendRequest, onResponse });
68
+ this.dogecoinProvider = new DogecoinProvider(productInfo, { sendRequest, onResponse });
69
+ this.evmProvider = new EvmProvider(productInfo, { sendRequest, onResponse });
70
+ this.solanaProvider = new SolanaProvider(productInfo, { sendRequest, onResponse });
71
+ this.tronProvider = new TronProvider(productInfo, { sendRequest, onResponse });
72
+
73
+ const { loginByGoogle, loginByX } = OidcAuth(config);
74
+
75
+ this.loginByGoogle = loginByGoogle;
76
+ this.loginByX = loginByX;
77
+
78
+ const { isAvailable, message, connectedInfo } = await this.login();
79
+ this.isAvailable = isAvailable;
80
+
81
+ const { connected, address = [] } = connectedInfo?.evmProvider || {};
82
+ if (connected && address.length > 0) {
83
+ this.evmProvider?.setConnectedStatus({ connected, address });
84
+ }
85
+ return { isAvailable, message, connectedInfo };
86
+ }
87
+
88
+ public setWalletZIndex(zIndex: number) {
89
+ this.maskZIndex = zIndex;
90
+ }
91
+
92
+ /**
93
+ * loginByCubistV2, create wallet with oidcToken
94
+ */
95
+ public async login(oidcToken?: string): Promise<{ connectedInfo: any; message?: string; isAvailable: boolean }> {
96
+ const config = this.config;
97
+ if (!config) {
98
+ throw new Error("config is not initialized");
99
+ }
100
+
101
+ return new Promise((resolve, reject) => {
102
+ try {
103
+ const { walletBaseUrl, tomoClientId, tomoStage, logo, name } = config || {};
104
+ if (!walletBaseUrl || !tomoClientId) {
105
+ throw new Error("walletBaseUrl + tomoClientId is required");
106
+ }
107
+
108
+ const EMBEDDED_WALLET_ID = tomoClientId;
109
+
110
+ let walletIframe = document.getElementById(EMBEDDED_WALLET_ID) as HTMLIFrameElement | null;
111
+ if (!walletIframe) {
112
+ walletIframe = document.createElement("iframe");
113
+ walletIframe.style.cssText = ` width: 0; height: 0;`;
114
+ walletIframe.id = EMBEDDED_WALLET_ID;
115
+ document.body.appendChild(walletIframe);
116
+ }
117
+
118
+ const dappOrigin = window.location.origin;
119
+ walletIframe.src = `${walletBaseUrl}#dappOrigin=${dappOrigin}&tomoStage=${tomoStage}&tomoClientId=${tomoClientId}&oidcToken=${oidcToken || ""}&logo=${logo || ""}&name=${name || ""}`;
120
+ walletIframe.allow = "publickey-credentials-get; publickey-credentials-create";
121
+ this.walletIframe = walletIframe;
122
+ } catch (error) {
123
+ console.error("login error", error);
124
+ reject(error);
125
+ }
126
+
127
+ const receiveResponse = ({ origin, data }: { origin: string; data: any }) => {
128
+ if (data?.type === "wallet-ready" && origin === this.walletOrigin) {
129
+ this.isAvailable = data?.data?.isAvailable || false;
130
+ resolve(data?.data);
131
+ window.removeEventListener("message", receiveResponse);
132
+ }
133
+ if (data?.type === "wallet-close" && origin === this.walletOrigin) {
134
+ this.close();
135
+ }
136
+ };
137
+ window.addEventListener("message", receiveResponse);
138
+ // add wallet-close listener
139
+ window.addEventListener("message", this.walletCloseHandler);
140
+ });
141
+ }
142
+
143
+ private walletCloseHandler = ({ origin, data }: { origin: string; data: any }) => {
144
+ if (data?.type === "wallet-close" && origin === this.walletOrigin) {
145
+ this.close();
146
+ }
147
+ };
148
+
149
+ public popup() {
150
+ if (!this.walletIframe) {
151
+ return;
152
+ }
153
+ const baseCssText = "position: fixed; top:0; left:0; border: none; width: 100%; height: 100%;";
154
+ const maskZIndex = this.maskZIndex;
155
+ this.walletIframe.style.cssText = `${baseCssText} z-index: ${maskZIndex};`;
156
+ }
157
+
158
+ public close() {
159
+ if (!this.walletIframe) {
160
+ return;
161
+ }
162
+ this.walletIframe.style.width = "0";
163
+ this.walletIframe.style.height = "0";
164
+ }
165
+
166
+ /**
167
+ * call relay for cubist logout, retrieve sessionInfo
168
+ */
169
+ public async logout(): Promise<boolean> {
170
+ // const { tomoClientId = "" } = this.config || {};
171
+ // if (tomoClientId) {
172
+ // const walletIframe = document.getElementById(tomoClientId) as HTMLIFrameElement | null;
173
+ // if (walletIframe) {
174
+ // walletIframe.parentElement?.removeChild(walletIframe);
175
+ // }
176
+ // }
177
+ if (this.walletIframe) {
178
+ this.walletIframe.src = `${this.walletOrigin}#logout=true`;
179
+ }
180
+ window.removeEventListener("message", this.walletCloseHandler);
181
+ this.request("logout");
182
+ return true;
183
+ }
184
+ /**
185
+ * open email login page
186
+ * */
187
+ public async loginByEmail({ email }: { email?: string }): Promise<string> {
188
+ this.popup();
189
+
190
+ return new Promise((resolve, reject) => {
191
+ const emailLoginCloseHandler = (event: MessageEvent) => {
192
+ if (event.data?.type === "wallet-close" && event.origin === this.walletOrigin) {
193
+ window.removeEventListener("message", emailLoginCloseHandler);
194
+ this.close();
195
+ resolve("");
196
+ }
197
+ };
198
+
199
+ window.addEventListener("message", emailLoginCloseHandler);
200
+
201
+ this.request("emailLogin", { email })
202
+ .then(({ oidcToken = "" }) => {
203
+ resolve(oidcToken);
204
+ })
205
+ .catch((error) => {
206
+ reject(error);
207
+ })
208
+ .finally(() => {
209
+ window.removeEventListener("message", emailLoginCloseHandler);
210
+ this.close();
211
+ });
212
+ });
213
+ }
214
+
215
+ /**
216
+ * wallet feature apis
217
+ * wallet action without user approve
218
+ */
219
+ public async request(method: WalletRequestMethod, params?: any): Promise<any> {
220
+ const data = {
221
+ type: "wallet-request",
222
+ data: { method, params },
223
+ };
224
+ (this.walletIframe as any).contentWindow?.postMessage(data, this.walletOrigin);
225
+ return new Promise((resolve, reject) => {
226
+ const receiveResponse = ({ origin, data }: { origin: string; data: any }) => {
227
+ if (data?.type === "wallet-response" && origin === this.walletOrigin) {
228
+ resolve(data?.data);
229
+ }
230
+ };
231
+ window.addEventListener("message", receiveResponse);
232
+ });
233
+ }
234
+
235
+ /**
236
+ * wallet features page
237
+ */
238
+ public async open(method: WalletOpenMethod, params?: any): Promise<any> {
239
+ const data = {
240
+ type: "wallet-request",
241
+ data: { method, params },
242
+ };
243
+ (this.walletIframe as any).contentWindow?.postMessage(data, this.walletOrigin);
244
+ this.popup();
245
+ }
246
+ }
package/src/hub.ts ADDED
@@ -0,0 +1,71 @@
1
+ import { EmbeddedWallet } from "embedded-wallet";
2
+ import { dappPopups } from "./relay-route";
3
+
4
+ export const notPorivderAPIs = {
5
+ keepAlive: true,
6
+ wallet_getProviderState: true,
7
+ wallet_sendDomainMetadata: true,
8
+ };
9
+
10
+ //("0: dapp -> provider -> wallet");
11
+ export const sendRequest = async (
12
+ chainType: string,
13
+ { method, params, dappInfo }: { method: string; params?: any; dappInfo?: any },
14
+ ) => {
15
+ if (!chainType || !method) {
16
+ throw new Error("chainType or method is not allowed to be empty");
17
+ }
18
+
19
+ if (notPorivderAPIs[method as keyof typeof notPorivderAPIs]) {
20
+ return;
21
+ }
22
+
23
+ const embeddedWallet = EmbeddedWallet.getInstance();
24
+ const walletOrigin = embeddedWallet.walletOrigin;
25
+ const walletIframe = embeddedWallet?.walletIframe;
26
+
27
+ if (!walletOrigin || !walletIframe) {
28
+ console.error("walletOrigin is not set", { chainType, method, params, dappInfo });
29
+ return;
30
+ }
31
+
32
+ const popupRoutes = dappPopups[chainType as keyof typeof dappPopups];
33
+ //dapp connect status
34
+ const isNeedApprove = popupRoutes?.[method as keyof (typeof dappPopups)[keyof typeof dappPopups]];
35
+ if (isNeedApprove) {
36
+ embeddedWallet.popup();
37
+ }
38
+
39
+ const data = {
40
+ chainType,
41
+ type: "dapp-request",
42
+ data: { method, params, dappInfo },
43
+ };
44
+ (walletIframe as any).contentWindow?.postMessage(data, walletOrigin);
45
+ console.log("sendRequest", data, walletOrigin);
46
+ };
47
+
48
+ //wallet -> provider -> dapp
49
+ export const onResponse = async (requestParams: { method: string }) => {
50
+ return new Promise((resolve, reject) => {
51
+ const receiveResponse = ({ origin, data }: { origin: string; data: any }) => {
52
+ if (data?.type !== "dapp-response") {
53
+ return;
54
+ }
55
+
56
+ const embeddedWallet = EmbeddedWallet.getInstance();
57
+ if (origin === embeddedWallet.walletOrigin && requestParams.method === data?.method) {
58
+ window.removeEventListener("message", receiveResponse);
59
+
60
+ console.log("onResponse", data);
61
+ if (data?.success) {
62
+ resolve(data);
63
+ } else {
64
+ reject(data.data);
65
+ }
66
+ embeddedWallet.close();
67
+ }
68
+ };
69
+ window.addEventListener("message", receiveResponse);
70
+ });
71
+ };
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { InitConfig } from "./types";
2
+
3
+ export type { InitConfig };
4
+ export { type EmailLoginResult } from "@tomo-inc/oidc-auth";
5
+
6
+ export { EmbeddedWallet } from "./embedded-wallet";
@@ -0,0 +1,104 @@
1
+ import { ChainTypes } from "@tomo-inc/wallet-utils";
2
+
3
+ /*
4
+ popups = {
5
+ method: "/dapp-${chianType}/${fileName}"
6
+ }
7
+ */
8
+ const evmDappPopups = {
9
+ connect: "/dapp/connect",
10
+ eth_requestAccounts: "/dapp/connect",
11
+ wallet_addEthereumChain: "/dapp-evm/network-add",
12
+ wallet_watchAsset: "/dapp-evm/token-add",
13
+ personal_sign: "/dapp-evm/message-sign",
14
+ eth_encrypt: "/dapp-evm/message-sign",
15
+ eth_decrypt: "/dapp-evm/message-unsign",
16
+ eth_signTypedData_v4: "/dapp-evm/message-sign",
17
+ eth_signTransaction: "/dapp-evm/tx-sign",
18
+ eth_sendTransaction: "/dapp-evm/tx-send",
19
+ };
20
+
21
+ const dogeDappPopups = {
22
+ connect: "/dapp/connect",
23
+ requestAccounts: "/dapp/connect",
24
+ getPublicKey: "/dapp-doge/publickey",
25
+
26
+ switchNetwork: "/dapp-doge/network-switch",
27
+ signMessage: "/dapp-doge/message-sign",
28
+ requestSignedMessage: "/dapp-doge/message-sign",
29
+ requestDecryptedMessage: "/dapp-doge/message-unsign",
30
+ signPsbt: "/dapp-doge/psbt-sign",
31
+ requestPsbt: "/dapp-doge/psbt-sign",
32
+ signPsbts: "/dapp-doge/psbts-sign",
33
+ requestPsbts: "/dapp-doge/psbts-sign",
34
+ requestTransaction: "/dapp-doge/tx-send",
35
+ requestAvailableDRC20Transaction: "/dapp-doge/drc20-inscribe",
36
+ requestInscriptionTransaction: "/dapp-doge/drc20-tx",
37
+ requestDunesTransaction: "/dapp-doge/dunes-tx",
38
+ };
39
+
40
+ const solanaDappPopups = {
41
+ connect: "/dapp/connect",
42
+ requestAccounts: "/dapp/connect",
43
+ getPublicKey: "/dapp-solana/publickey",
44
+
45
+ signMessage: "/dapp-solana/message-sign",
46
+ signIn: "/dapp-solana/message-sign",
47
+
48
+ signTransaction: "/dapp-solana/tx-send",
49
+ signAllTransactions: "/dapp-solana/tx-send",
50
+
51
+ signAndSendTransaction: "/dapp-solana/tx-send",
52
+ signAndSendAllTransactions: "/dapp-solana/tx-send",
53
+
54
+ sendSolana: "/dapp-solana/tx-send",
55
+ sendToken: "/dapp-solana/tx-send",
56
+ };
57
+
58
+ const tronDappPopups = {
59
+ connect: "/dapp/connect",
60
+ tron_requestAccounts: "/dapp/connect",
61
+ signMessage: "/dapp-tron/message-sign",
62
+ wallet_watchAsset: "/dapp-tron/token-add",
63
+ signTransaction: "/dapp-tron/tx-send",
64
+ sendRawTransaction: "/dapp-tron/tx-send",
65
+ sendTransaction: "/dapp-tron/tx-send",
66
+ sendToken: "/dapp-tron/tx-send",
67
+ };
68
+
69
+ const btcDappPopups = {
70
+ connect: "/dapp/connect",
71
+ getPublicKey: "/dapp/connect",
72
+ requestAccounts: "/dapp/connect",
73
+ getBalance: "/dapp/connect",
74
+
75
+ switchNetwork: "/dapp-btc/network-switch",
76
+ switchChain: "/dapp-btc/network-switch",
77
+
78
+ signMessage: "/dapp-btc/message-sign",
79
+ requestDecryptedMessage: "/dapp-btc/message-unsign",
80
+
81
+ pushPsbt: "/dapp-btc/psbt-sign",
82
+ signPsbt: "/dapp-btc/psbt-sign",
83
+ signPsbts: "/dapp-btc/psbts-sign",
84
+ sendBitcoin: "/dapp-btc/tx-send",
85
+ };
86
+
87
+ const shopDappPopups = {
88
+ connect: "/dapp-shop/dialog",
89
+ welcomeDialog: "/dapp-shop/dialog",
90
+ addToCartDialog: "/dapp-shop/dialog",
91
+ rewardEstimatedDialog: "/dapp-shop/dialog",
92
+ rewardClaimedDialog: "/dapp-shop/dialog",
93
+ };
94
+
95
+ const dappPopups = {
96
+ [ChainTypes.EVM]: evmDappPopups,
97
+ [ChainTypes.DOGE]: dogeDappPopups,
98
+ [ChainTypes.SOL]: solanaDappPopups,
99
+ [ChainTypes.TRON]: tronDappPopups,
100
+ [ChainTypes.BTC]: btcDappPopups,
101
+ shop: shopDappPopups,
102
+ };
103
+
104
+ export { dappPopups, evmDappPopups, dogeDappPopups, solanaDappPopups, tronDappPopups, shopDappPopups, btcDappPopups };
package/src/types.ts ADDED
@@ -0,0 +1,25 @@
1
+ export interface InitConfig {
2
+ xClientId: string;
3
+ googleClientId: string;
4
+ name: string;
5
+ logo: string;
6
+ tomoStage: "dev" | "prod";
7
+ tomoClientId: string;
8
+ walletBaseUrl: string;
9
+ relayBaseUrl?: string;
10
+ }
11
+
12
+ export interface WalletInfo {
13
+ uuid: string;
14
+ name: string;
15
+ icon: string;
16
+ rdns: string;
17
+ iconBackground?: string;
18
+ links?: {
19
+ homepage: string;
20
+ };
21
+ }
22
+
23
+ export type WalletRequestMethod = "logout" | "token" | "market" | "assets" | "transactions" | "wallet" | "emailLogin";
24
+
25
+ export type WalletOpenMethod = "wallet" | "swap" | "onRamp" | "funding" | "mfaVerify" | "mnemonic" | "setting";
package/src/utils.ts ADDED
@@ -0,0 +1,35 @@
1
+ export const isMobile = () => {
2
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
3
+ };
4
+
5
+ interface OpenWindow {
6
+ url: string;
7
+ name?: string;
8
+ width?: number;
9
+ height?: number;
10
+ }
11
+
12
+ export const openWindow = ({ url, name, width, height }: OpenWindow): Window | null => {
13
+ const top = (window.innerHeight - (height || 400)) / 2 + window.screenY;
14
+ const left = (window.innerWidth - (width || 400)) / 2 + window.screenX;
15
+
16
+ try {
17
+ const relyWindow = window.open(
18
+ url,
19
+ name,
20
+ `dialog=yes,top=${top}px,left=${left},width=${width !== undefined ? width : 400}px,height=${height !== undefined ? height : 600}px`,
21
+ );
22
+
23
+ // Fallback to iframe modal if:
24
+ // 1. window.open is blocked by browser
25
+ // 2. iOS Safari requires user interaction for window.open
26
+ if (!relyWindow) {
27
+ return null;
28
+ }
29
+
30
+ return relyWindow;
31
+ } catch (error) {
32
+ console.error("Failed to open window:", error);
33
+ return null;
34
+ }
35
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "baseUrl": "./src"
5
+ },
6
+ "include": ["src"]
7
+ }