@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 +3 -0
- package/README.md +122 -0
- package/package.json +34 -0
- package/project.json +60 -0
- package/src/embedded-wallet.ts +246 -0
- package/src/hub.ts +71 -0
- package/src/index.ts +6 -0
- package/src/relay-route.ts +104 -0
- package/src/types.ts +25 -0
- package/src/utils.ts +35 -0
- package/tsconfig.json +7 -0
package/CHANGELOG.md
ADDED
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,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
|
+
};
|