@layerswap/wallet-fuel 1.0.0
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/dist/esm/FuelProvider.js +27 -0
- package/dist/esm/connectors/bako-safe/Bako.js +29 -0
- package/dist/esm/connectors/bako-safe/BakoSafeConnector.js +268 -0
- package/dist/esm/connectors/bako-safe/BakoSafeStorage.js +20 -0
- package/dist/esm/connectors/bako-safe/DAPPWindow.js +130 -0
- package/dist/esm/connectors/bako-safe/SocketClient.js +74 -0
- package/dist/esm/connectors/bako-safe/constants.js +16 -0
- package/dist/esm/connectors/bako-safe/index.js +1 -0
- package/dist/esm/connectors/bako-safe/request.js +15 -0
- package/dist/esm/connectors/bako-safe/types.js +25 -0
- package/dist/esm/connectors/fuel-wallet/FuelWalletConnector.js +234 -0
- package/dist/esm/connectors/fuel-wallet/constants.js +4 -0
- package/dist/esm/connectors/fuel-wallet/index.js +3 -0
- package/dist/esm/connectors/fuel-wallet/types.js +9 -0
- package/dist/esm/connectors/fuelet-wallet/FueletWalletConnector.js +19 -0
- package/dist/esm/connectors/fuelet-wallet/constants.js +2 -0
- package/dist/esm/connectors/fuelet-wallet/index.js +1 -0
- package/dist/esm/fuelAddressUtilsProvider.js +19 -0
- package/dist/esm/fuelBalanceProvider.js +61 -0
- package/dist/esm/fuelGasProvider.js +38 -0
- package/dist/esm/index.js +13 -0
- package/dist/esm/jsons/FUELWATCHDOG.json +96 -0
- package/dist/esm/services/transferService/transactionBuilder.js +11 -0
- package/dist/esm/useFuelConnection.js +232 -0
- package/dist/esm/utils/KnownFuelConnectors.js +24 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/resolveIcon.js +9 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/FuelProvider.d.ts +5 -0
- package/dist/types/FuelProvider.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/Bako.d.ts +16 -0
- package/dist/types/connectors/bako-safe/Bako.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/BakoSafeConnector.d.ts +65 -0
- package/dist/types/connectors/bako-safe/BakoSafeConnector.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/BakoSafeStorage.d.ts +11 -0
- package/dist/types/connectors/bako-safe/BakoSafeStorage.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/DAPPWindow.d.ts +26 -0
- package/dist/types/connectors/bako-safe/DAPPWindow.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/SocketClient.d.ts +17 -0
- package/dist/types/connectors/bako-safe/SocketClient.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/constants.d.ts +14 -0
- package/dist/types/connectors/bako-safe/constants.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/index.d.ts +2 -0
- package/dist/types/connectors/bako-safe/index.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/request.d.ts +7 -0
- package/dist/types/connectors/bako-safe/request.d.ts.map +1 -0
- package/dist/types/connectors/bako-safe/types.d.ts +55 -0
- package/dist/types/connectors/bako-safe/types.d.ts.map +1 -0
- package/dist/types/connectors/fuel-wallet/FuelWalletConnector.d.ts +52 -0
- package/dist/types/connectors/fuel-wallet/FuelWalletConnector.d.ts.map +1 -0
- package/dist/types/connectors/fuel-wallet/constants.d.ts +5 -0
- package/dist/types/connectors/fuel-wallet/constants.d.ts.map +1 -0
- package/dist/types/connectors/fuel-wallet/index.d.ts +4 -0
- package/dist/types/connectors/fuel-wallet/index.d.ts.map +1 -0
- package/dist/types/connectors/fuel-wallet/types.d.ts +51 -0
- package/dist/types/connectors/fuel-wallet/types.d.ts.map +1 -0
- package/dist/types/connectors/fuelet-wallet/FueletWalletConnector.d.ts +8 -0
- package/dist/types/connectors/fuelet-wallet/FueletWalletConnector.d.ts.map +1 -0
- package/dist/types/connectors/fuelet-wallet/constants.d.ts +3 -0
- package/dist/types/connectors/fuelet-wallet/constants.d.ts.map +1 -0
- package/dist/types/connectors/fuelet-wallet/index.d.ts +2 -0
- package/dist/types/connectors/fuelet-wallet/index.d.ts.map +1 -0
- package/dist/types/fuelAddressUtilsProvider.d.ts +6 -0
- package/dist/types/fuelAddressUtilsProvider.d.ts.map +1 -0
- package/dist/types/fuelBalanceProvider.d.ts +6 -0
- package/dist/types/fuelBalanceProvider.d.ts.map +1 -0
- package/dist/types/fuelGasProvider.d.ts +6 -0
- package/dist/types/fuelGasProvider.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/services/transferService/transactionBuilder.d.ts +7 -0
- package/dist/types/services/transferService/transactionBuilder.d.ts.map +1 -0
- package/dist/types/useFuelConnection.d.ts +3 -0
- package/dist/types/useFuelConnection.d.ts.map +1 -0
- package/dist/types/utils/KnownFuelConnectors.d.ts +6 -0
- package/dist/types/utils/KnownFuelConnectors.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +3 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/resolveIcon.d.ts +6 -0
- package/dist/types/utils/resolveIcon.d.ts.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BakoRequestAPI } from './connectors/bako-safe/Bako';
|
|
3
|
+
import { BakoSafeConnector } from './connectors/bako-safe';
|
|
4
|
+
import { FuelProvider } from '@fuels/react';
|
|
5
|
+
import { FueletWalletConnector } from './connectors/fuelet-wallet';
|
|
6
|
+
import { FuelWalletConnector } from './connectors/fuel-wallet';
|
|
7
|
+
import { useSettingsState } from '@layerswap/widget/internal';
|
|
8
|
+
import { NetworkType } from '@layerswap/widget/types';
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
const HOST_URL = 'https://api.bako.global';
|
|
11
|
+
const FuelProviderWrapper = ({ children }) => {
|
|
12
|
+
const { networks } = useSettingsState();
|
|
13
|
+
const fuelConfig = {
|
|
14
|
+
connectors: [
|
|
15
|
+
new FuelWalletConnector(),
|
|
16
|
+
new BakoSafeConnector({
|
|
17
|
+
api: new BakoRequestAPI(HOST_URL)
|
|
18
|
+
}),
|
|
19
|
+
new FueletWalletConnector(),
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
const fuelNetworks = useMemo(() => networks.filter(n => n.type == NetworkType.Fuel).map((network) => ({
|
|
23
|
+
chainId: Number(network.chain_id)
|
|
24
|
+
})), [networks]);
|
|
25
|
+
return (_jsx(FuelProvider, { uiConfig: { suggestBridge: false }, theme: 'dark', fuelConfig: fuelConfig, networks: fuelNetworks, children: children }));
|
|
26
|
+
};
|
|
27
|
+
export default FuelProviderWrapper;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { urlJoin } from "@fuel-ts/account";
|
|
2
|
+
export class BAKO_STATE {
|
|
3
|
+
}
|
|
4
|
+
BAKO_STATE.state = { data: false, req_count: 0 };
|
|
5
|
+
BAKO_STATE.period_durtion = 10000;
|
|
6
|
+
export class BakoRequestAPI {
|
|
7
|
+
constructor(baseUrl) {
|
|
8
|
+
this.baseUrl = baseUrl;
|
|
9
|
+
}
|
|
10
|
+
async get(pathname) {
|
|
11
|
+
if (!pathname.includes('/state')) {
|
|
12
|
+
const data = await fetch(urlJoin(this.baseUrl, pathname)).then((res) => res.json());
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
const period_elapsed = BAKO_STATE.state?.period_start && new Date().getTime() - BAKO_STATE.state?.period_start?.getTime() > BAKO_STATE.period_durtion;
|
|
16
|
+
const skip = BAKO_STATE.state?.last_req && new Date().getTime() - BAKO_STATE.state?.last_req?.getTime() < 1000 * 60 * 2 && period_elapsed;
|
|
17
|
+
if (skip)
|
|
18
|
+
return BAKO_STATE.state?.data;
|
|
19
|
+
const data = await fetch(urlJoin(this.baseUrl, pathname)).then((res) => res.json());
|
|
20
|
+
const count = BAKO_STATE.state?.req_count || 0;
|
|
21
|
+
BAKO_STATE.state = { last_req: new Date(), data, req_count: count + 1, period_start: period_elapsed ? new Date() : BAKO_STATE.state?.period_start || new Date() };
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
async delete(pathname) {
|
|
25
|
+
await fetch(urlJoin(this.baseUrl, pathname), {
|
|
26
|
+
method: 'DELETE',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { FuelConnector, FuelConnectorEventTypes, Provider, } from 'fuels';
|
|
2
|
+
import { BakoStorage } from './BakoSafeStorage';
|
|
3
|
+
import { DAppWindow } from './DAPPWindow';
|
|
4
|
+
import { SocketClient } from './SocketClient';
|
|
5
|
+
import { APP_DESCRIPTION, APP_IMAGE_DARK, APP_IMAGE_LIGHT, APP_NAME, APP_NETWORK, APP_URL, APP_VERSION, HAS_WINDOW, HOST_URL, IS_SAFARI, SESSION_ID, WINDOW, } from './constants';
|
|
6
|
+
import { RequestAPI } from './request';
|
|
7
|
+
import { BakoSafeConnectorEvents, } from './types';
|
|
8
|
+
export class BakoSafeConnector extends FuelConnector {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
super();
|
|
11
|
+
this.name = APP_NAME;
|
|
12
|
+
this.metadata = {
|
|
13
|
+
image: {
|
|
14
|
+
light: APP_IMAGE_LIGHT,
|
|
15
|
+
dark: APP_IMAGE_DARK,
|
|
16
|
+
},
|
|
17
|
+
install: {
|
|
18
|
+
action: APP_URL,
|
|
19
|
+
link: APP_URL,
|
|
20
|
+
description: APP_DESCRIPTION,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
this.installed = !IS_SAFARI;
|
|
24
|
+
this.connected = false;
|
|
25
|
+
this.external = false;
|
|
26
|
+
this.host = config?.host ?? HOST_URL;
|
|
27
|
+
this.appUrl = config?.appUrl ?? APP_URL;
|
|
28
|
+
this.api = config?.api ?? new RequestAPI(this.host);
|
|
29
|
+
this.storage = this.getStorage(config?.storage);
|
|
30
|
+
this.setupReady = false;
|
|
31
|
+
}
|
|
32
|
+
// ============================================================
|
|
33
|
+
// Bako Safe application specific methods
|
|
34
|
+
// ============================================================
|
|
35
|
+
getStorage(storage) {
|
|
36
|
+
const _storage = storage ?? WINDOW.localStorage ?? new BakoStorage();
|
|
37
|
+
if (!_storage) {
|
|
38
|
+
throw new Error('No storage provided');
|
|
39
|
+
}
|
|
40
|
+
return _storage;
|
|
41
|
+
}
|
|
42
|
+
async getSessionId() {
|
|
43
|
+
let sessionId = (await this.storage?.getItem(SESSION_ID)) || '';
|
|
44
|
+
if (!sessionId) {
|
|
45
|
+
sessionId = crypto.randomUUID();
|
|
46
|
+
await this.storage?.setItem(SESSION_ID, sessionId);
|
|
47
|
+
}
|
|
48
|
+
return sessionId;
|
|
49
|
+
}
|
|
50
|
+
checkWindow() {
|
|
51
|
+
// timeout to open
|
|
52
|
+
const openInterval = setInterval(() => {
|
|
53
|
+
const isOpen = this.dAppWindow?.isOpen;
|
|
54
|
+
if (!isOpen) {
|
|
55
|
+
this.emit(BakoSafeConnectorEvents.CLIENT_DISCONNECTED, {});
|
|
56
|
+
clearInterval(openInterval);
|
|
57
|
+
}
|
|
58
|
+
}, 2000);
|
|
59
|
+
// timeout to close
|
|
60
|
+
const interval = setInterval(() => {
|
|
61
|
+
const isOpen = this.dAppWindow?.opned?.closed;
|
|
62
|
+
if (isOpen) {
|
|
63
|
+
this.emit(BakoSafeConnectorEvents.CLIENT_DISCONNECTED, {});
|
|
64
|
+
clearInterval(interval);
|
|
65
|
+
}
|
|
66
|
+
}, 300);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* [important]
|
|
70
|
+
* this.socket.emit -> emit message to the server
|
|
71
|
+
* this.emit -> emit message to the dApp client
|
|
72
|
+
*/
|
|
73
|
+
async setup() {
|
|
74
|
+
if (!HAS_WINDOW)
|
|
75
|
+
return;
|
|
76
|
+
if (this.socket)
|
|
77
|
+
this.socket.checkConnection();
|
|
78
|
+
if (this.setupReady)
|
|
79
|
+
return;
|
|
80
|
+
this.setupReady = true;
|
|
81
|
+
const sessionId = await this.getSessionId();
|
|
82
|
+
this.sessionId = sessionId;
|
|
83
|
+
this.socket = SocketClient.create({
|
|
84
|
+
sessionId,
|
|
85
|
+
events: this,
|
|
86
|
+
});
|
|
87
|
+
this.dAppWindow = new DAppWindow({
|
|
88
|
+
sessionId,
|
|
89
|
+
height: 800,
|
|
90
|
+
width: 450,
|
|
91
|
+
appUrl: this.appUrl,
|
|
92
|
+
request_id: this.socket.request_id,
|
|
93
|
+
});
|
|
94
|
+
await this.requestConnectionState();
|
|
95
|
+
}
|
|
96
|
+
async requestConnectionState() {
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
if (!this.socket)
|
|
99
|
+
return;
|
|
100
|
+
this.socket.server.emit(BakoSafeConnectorEvents.CONNECTION_STATE);
|
|
101
|
+
this.socket.server.once(BakoSafeConnectorEvents.CONNECTION_STATE, async ({ data }) => {
|
|
102
|
+
this.connected = data;
|
|
103
|
+
this.emit(this.events.connection, data);
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// ============================================================
|
|
109
|
+
// Connector methods
|
|
110
|
+
// ============================================================
|
|
111
|
+
async connect() {
|
|
112
|
+
await this.setup();
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
if (this.connected) {
|
|
115
|
+
resolve(true);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.dAppWindow?.open('/', reject);
|
|
119
|
+
this.checkWindow();
|
|
120
|
+
this.once(BakoSafeConnectorEvents.CLIENT_DISCONNECTED, () => {
|
|
121
|
+
this.dAppWindow?.close();
|
|
122
|
+
reject(false);
|
|
123
|
+
});
|
|
124
|
+
this.once(BakoSafeConnectorEvents.AUTH_CONFIRMED, async ({ data }) => {
|
|
125
|
+
await this.requestConnectionState();
|
|
126
|
+
this.emit(this.events.accounts, await this.accounts());
|
|
127
|
+
this.emit(this.events.currentAccount, await this.currentAccount());
|
|
128
|
+
this.dAppWindow?.close();
|
|
129
|
+
resolve(data.connected);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/*
|
|
134
|
+
* @param {string} address - The address to sign the transaction
|
|
135
|
+
* @param {Transaction} transaction - The transaction to send
|
|
136
|
+
*
|
|
137
|
+
* @returns {string} - The transaction id
|
|
138
|
+
*/
|
|
139
|
+
async sendTransaction(_address, _transaction) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
this.dAppWindow?.open('/dapp/transaction', reject);
|
|
142
|
+
this.checkWindow();
|
|
143
|
+
const onClientConnected = () => {
|
|
144
|
+
this.socket?.server.emit(BakoSafeConnectorEvents.TX_PENDING, {
|
|
145
|
+
_transaction,
|
|
146
|
+
_address,
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
this.on(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
151
|
+
this.once(BakoSafeConnectorEvents.CLIENT_DISCONNECTED, () => {
|
|
152
|
+
this.dAppWindow?.close();
|
|
153
|
+
this.removeListener(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
154
|
+
reject(new Error('Client disconnected'));
|
|
155
|
+
});
|
|
156
|
+
this.once(BakoSafeConnectorEvents.TX_TIMEOUT, () => {
|
|
157
|
+
this.dAppWindow?.close();
|
|
158
|
+
this.removeListener(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
159
|
+
reject(new Error('Transaction timeout'));
|
|
160
|
+
});
|
|
161
|
+
this.once(BakoSafeConnectorEvents.TX_CONFIRMED, ({ data }) => {
|
|
162
|
+
this.removeListener(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
163
|
+
resolve(`0x${data.id}`);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async selectNetwork(_network) {
|
|
168
|
+
return new Promise((resolve, reject) => {
|
|
169
|
+
this.dAppWindow?.open('/dapp/network', reject);
|
|
170
|
+
this.checkWindow();
|
|
171
|
+
const onClientConnected = () => {
|
|
172
|
+
this.socket?.server.emit(BakoSafeConnectorEvents.CHANGE_NETWORK, {
|
|
173
|
+
_network,
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
// @ts-ignore
|
|
177
|
+
this.on(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
178
|
+
this.once(BakoSafeConnectorEvents.CLIENT_DISCONNECTED, () => {
|
|
179
|
+
this.dAppWindow?.close();
|
|
180
|
+
this.removeListener(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
181
|
+
reject(new Error('Client disconnected'));
|
|
182
|
+
});
|
|
183
|
+
this.once(BakoSafeConnectorEvents.NETWORK_CHANGED, async () => {
|
|
184
|
+
const network = await this.currentNetwork();
|
|
185
|
+
this.emit(this.events.networks, [network]);
|
|
186
|
+
this.emit(this.events.currentNetwork, network);
|
|
187
|
+
this.dAppWindow?.close();
|
|
188
|
+
this.removeListener(BakoSafeConnectorEvents.CLIENT_CONNECTED, onClientConnected);
|
|
189
|
+
resolve(true);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
async ping() {
|
|
194
|
+
if (IS_SAFARI) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
await this.setup();
|
|
198
|
+
return this.setupReady ?? false;
|
|
199
|
+
}
|
|
200
|
+
async version() {
|
|
201
|
+
return {
|
|
202
|
+
app: APP_VERSION,
|
|
203
|
+
network: APP_NETWORK,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async isConnected() {
|
|
207
|
+
await this.setup();
|
|
208
|
+
return this.connected;
|
|
209
|
+
}
|
|
210
|
+
async accounts() {
|
|
211
|
+
const data = await this.api.get(`/connections/${this.sessionId}/accounts`);
|
|
212
|
+
const acc = Array.isArray(data) ? data : [];
|
|
213
|
+
return acc;
|
|
214
|
+
}
|
|
215
|
+
async currentAccount() {
|
|
216
|
+
const data = await this.api.get(`/connections/${this.sessionId}/currentAccount`);
|
|
217
|
+
const isInvalid = data && JSON.stringify(data) === JSON.stringify({});
|
|
218
|
+
return isInvalid ? null : data;
|
|
219
|
+
}
|
|
220
|
+
async disconnect() {
|
|
221
|
+
await this.api.delete(`/connections/${this.sessionId}`);
|
|
222
|
+
await this.requestConnectionState();
|
|
223
|
+
this.emit(this.events.accounts, []);
|
|
224
|
+
this.emit(this.events.currentAccount, null);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
async currentNetwork() {
|
|
228
|
+
const data = await this.api.get(`/connections/${this.sessionId}/currentNetwork`);
|
|
229
|
+
const provider = new Provider(data);
|
|
230
|
+
return {
|
|
231
|
+
url: provider.url,
|
|
232
|
+
chainId: await provider.getChainId(),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async networks() {
|
|
236
|
+
return [await this.currentNetwork()];
|
|
237
|
+
}
|
|
238
|
+
async assets() {
|
|
239
|
+
return [];
|
|
240
|
+
}
|
|
241
|
+
async signMessage(_address, _message) {
|
|
242
|
+
throw new Error('Method not implemented.');
|
|
243
|
+
}
|
|
244
|
+
async addAssets(_assets) {
|
|
245
|
+
throw new Error('Method not implemented.');
|
|
246
|
+
}
|
|
247
|
+
async addAsset(_assets) {
|
|
248
|
+
throw new Error('Method not implemented.');
|
|
249
|
+
}
|
|
250
|
+
async addNetwork(_networkUrl) {
|
|
251
|
+
throw new Error('Method not implemented.');
|
|
252
|
+
}
|
|
253
|
+
async addABI(_contractId, _abi) {
|
|
254
|
+
throw new Error('Method not implemented.');
|
|
255
|
+
}
|
|
256
|
+
async getABI(_id) {
|
|
257
|
+
throw new Error('Method not implemented.');
|
|
258
|
+
}
|
|
259
|
+
async hasABI(_id) {
|
|
260
|
+
throw new Error('Method not implemented.');
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* @inheritdoc
|
|
264
|
+
*/
|
|
265
|
+
async startConsolidation(opts) {
|
|
266
|
+
this.emit(FuelConnectorEventTypes.consolidateCoins, opts);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { StorageAbstract } from 'fuels';
|
|
2
|
+
export class BakoStorage extends StorageAbstract {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.data = {};
|
|
6
|
+
}
|
|
7
|
+
async getItem(key) {
|
|
8
|
+
return this.data[key];
|
|
9
|
+
}
|
|
10
|
+
async setItem(key, value) {
|
|
11
|
+
this.data[key] = value;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
async removeItem(key) {
|
|
15
|
+
delete this.data[key];
|
|
16
|
+
}
|
|
17
|
+
async clear() {
|
|
18
|
+
this.data = {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { WINDOW } from './constants';
|
|
2
|
+
export class DAppWindow {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.config = config;
|
|
5
|
+
this.isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
6
|
+
this.isSafariBrowser = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
7
|
+
this.isOpen = false;
|
|
8
|
+
this.opned = null;
|
|
9
|
+
this.request_id = config.request_id;
|
|
10
|
+
}
|
|
11
|
+
get popupConfig() {
|
|
12
|
+
const { height, width } = this.config;
|
|
13
|
+
return {
|
|
14
|
+
top: WINDOW.innerHeight / 2 - height / 2,
|
|
15
|
+
left: WINDOW.innerWidth / 2 - width / 2,
|
|
16
|
+
width,
|
|
17
|
+
height: !this.isMobile && WINDOW.innerHeight >= height
|
|
18
|
+
? height
|
|
19
|
+
: WINDOW.innerHeight,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
open(method, reject) {
|
|
23
|
+
if (this.isOpen)
|
|
24
|
+
reject(new Error('Window is already open'));
|
|
25
|
+
if (!this.isSafariBrowser) {
|
|
26
|
+
// if is not safari, we can use popup for both cases
|
|
27
|
+
this.makePopup(method);
|
|
28
|
+
}
|
|
29
|
+
// if (this.isSafariBrowser && isConnection) {
|
|
30
|
+
// // to use webauthn, we need a new WINDOW
|
|
31
|
+
// this.makeLink(method);
|
|
32
|
+
// }
|
|
33
|
+
if (this.isSafariBrowser) {
|
|
34
|
+
// && !isConnection) {
|
|
35
|
+
// to confirm tx, we need a new popup
|
|
36
|
+
this.makeFrame(method, true);
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
close() {
|
|
41
|
+
const frame = document.getElementById(`${this.config.sessionId}-iframe`);
|
|
42
|
+
const backdrop = document.getElementById(`${this.config.sessionId}-backdrop`);
|
|
43
|
+
if (frame)
|
|
44
|
+
document.body.removeChild(frame);
|
|
45
|
+
if (backdrop)
|
|
46
|
+
document.body.removeChild(backdrop);
|
|
47
|
+
if (this.opned)
|
|
48
|
+
this.opned.close();
|
|
49
|
+
this.isOpen = false;
|
|
50
|
+
}
|
|
51
|
+
makeLink(method) {
|
|
52
|
+
const link = `${this.config.appUrl}${method}${this.queryString}`;
|
|
53
|
+
const a = document.createElement('a');
|
|
54
|
+
a.setAttribute('href', link);
|
|
55
|
+
a.setAttribute('target', '_blank');
|
|
56
|
+
a.click();
|
|
57
|
+
this.isOpen = true;
|
|
58
|
+
}
|
|
59
|
+
makeFrame(method, isSafari = false) {
|
|
60
|
+
const w = this.small;
|
|
61
|
+
//bako frame
|
|
62
|
+
const frame = document.createElement('iframe');
|
|
63
|
+
frame.id = `${this.config.sessionId}-iframe`;
|
|
64
|
+
frame.src = `${this.config.appUrl}${method}${this.queryString}${isSafari ? '&byConnector=true' : ''}`;
|
|
65
|
+
frame.style.position = 'fixed';
|
|
66
|
+
frame.style.zIndex = '99999999';
|
|
67
|
+
frame.style.top = `${w.top}`;
|
|
68
|
+
frame.style.left = `${w.left}`;
|
|
69
|
+
frame.style.width = w.width;
|
|
70
|
+
frame.style.height = w.height;
|
|
71
|
+
frame.style.borderRadius = '16px';
|
|
72
|
+
//backdrop
|
|
73
|
+
const backdrop = document.createElement('div');
|
|
74
|
+
backdrop.id = `${this.config.sessionId}-backdrop`;
|
|
75
|
+
backdrop.style.position = 'fixed';
|
|
76
|
+
backdrop.style.top = '0';
|
|
77
|
+
backdrop.style.left = '0';
|
|
78
|
+
backdrop.style.width = '100%';
|
|
79
|
+
backdrop.style.height = '100%';
|
|
80
|
+
backdrop.style.backgroundColor = 'rgba(0,0,0,0.5)';
|
|
81
|
+
backdrop.style.zIndex = '99999998';
|
|
82
|
+
backdrop.addEventListener('click', () => this.close()); // if user click on backdrop, close the frame
|
|
83
|
+
document.body.appendChild(backdrop);
|
|
84
|
+
document.body.appendChild(frame);
|
|
85
|
+
this.isOpen = true;
|
|
86
|
+
}
|
|
87
|
+
makePopup(method) {
|
|
88
|
+
const link = `${this.config.appUrl}${method}${this.queryString}`;
|
|
89
|
+
const popup = WINDOW.open(link, 'popup', `width=${this.popupConfig.width}, height=${this.popupConfig.height}, top=${this.popupConfig.top}, left=${this.popupConfig.left}`);
|
|
90
|
+
if (popup)
|
|
91
|
+
this.opned = popup;
|
|
92
|
+
this.isOpen = true;
|
|
93
|
+
return popup;
|
|
94
|
+
}
|
|
95
|
+
get queryString() {
|
|
96
|
+
const { sessionId } = this.config;
|
|
97
|
+
return `?sessionId=${sessionId}&origin=${WINDOW.location.origin}&name=${WINDOW.document.title}&request_id=${this.request_id}`;
|
|
98
|
+
}
|
|
99
|
+
get small() {
|
|
100
|
+
// todo: update this to calculate by screen size changes
|
|
101
|
+
const breakponint = {
|
|
102
|
+
md: {
|
|
103
|
+
top: 0,
|
|
104
|
+
left: 0,
|
|
105
|
+
limit: 650,
|
|
106
|
+
width: '100%',
|
|
107
|
+
height: '100%',
|
|
108
|
+
}, // 100%
|
|
109
|
+
lg: {
|
|
110
|
+
top: `${(WINDOW.innerHeight - WINDOW.innerHeight * 0.7) / 2}px`,
|
|
111
|
+
left: `${(WINDOW.innerWidth - WINDOW.innerWidth * 0.5) / 2}px`,
|
|
112
|
+
limit: 1024,
|
|
113
|
+
width: '50%',
|
|
114
|
+
height: '70%',
|
|
115
|
+
}, // 75%
|
|
116
|
+
xl: {
|
|
117
|
+
top: `${(WINDOW.innerHeight - 650) / 2}px`,
|
|
118
|
+
left: `${(WINDOW.innerWidth - 500) / 2}px`,
|
|
119
|
+
limit: 1440,
|
|
120
|
+
height: '650px',
|
|
121
|
+
width: '500px',
|
|
122
|
+
}, // 400px
|
|
123
|
+
};
|
|
124
|
+
return WINDOW.innerWidth < breakponint.md.limit
|
|
125
|
+
? breakponint.md
|
|
126
|
+
: WINDOW.innerWidth < breakponint.lg.limit
|
|
127
|
+
? breakponint.lg
|
|
128
|
+
: breakponint.xl;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
import { APP_URL, SOCKET_URL } from './constants';
|
|
3
|
+
import { WINDOW } from './constants';
|
|
4
|
+
import { BakoSafeConnectorEvents, BakoSafeUsernames, } from './types';
|
|
5
|
+
const DEFAULT_SOCKET_AUTH = {
|
|
6
|
+
username: BakoSafeUsernames.CONNECTOR,
|
|
7
|
+
data: new Date(),
|
|
8
|
+
origin: WINDOW.origin ?? APP_URL,
|
|
9
|
+
};
|
|
10
|
+
export class SocketClient {
|
|
11
|
+
constructor({ sessionId, events }) {
|
|
12
|
+
this.connecting = false;
|
|
13
|
+
this.request_id = crypto.randomUUID();
|
|
14
|
+
this.server = io(SOCKET_URL, {
|
|
15
|
+
auth: {
|
|
16
|
+
...DEFAULT_SOCKET_AUTH,
|
|
17
|
+
sessionId,
|
|
18
|
+
request_id: this.request_id,
|
|
19
|
+
},
|
|
20
|
+
autoConnect: false,
|
|
21
|
+
reconnection: true,
|
|
22
|
+
reconnectionAttempts: 5,
|
|
23
|
+
reconnectionDelay: 1000,
|
|
24
|
+
});
|
|
25
|
+
this.server?.on(BakoSafeConnectorEvents.DEFAULT, (data) => {
|
|
26
|
+
if (data.to === DEFAULT_SOCKET_AUTH.username) {
|
|
27
|
+
this.events.emit(data.type, {
|
|
28
|
+
from: data.username,
|
|
29
|
+
data: data.data,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
this.events = events;
|
|
34
|
+
this.setupEventListeners();
|
|
35
|
+
this.connect();
|
|
36
|
+
}
|
|
37
|
+
setupEventListeners() {
|
|
38
|
+
this.server.on('connect', () => {
|
|
39
|
+
this.connecting = false;
|
|
40
|
+
});
|
|
41
|
+
this.server.on('connect_error', () => {
|
|
42
|
+
this.connecting = false;
|
|
43
|
+
});
|
|
44
|
+
this.server.on(BakoSafeConnectorEvents.DEFAULT, (data) => {
|
|
45
|
+
if (data.to === DEFAULT_SOCKET_AUTH.username) {
|
|
46
|
+
this.events.emit(data.type, {
|
|
47
|
+
from: data.username,
|
|
48
|
+
data: data.data,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
static create(options) {
|
|
54
|
+
if (!SocketClient.instance) {
|
|
55
|
+
SocketClient.instance = new SocketClient(options);
|
|
56
|
+
}
|
|
57
|
+
return SocketClient.instance;
|
|
58
|
+
}
|
|
59
|
+
connect() {
|
|
60
|
+
if (this.isConnected || this.connecting)
|
|
61
|
+
return;
|
|
62
|
+
this.connecting = true;
|
|
63
|
+
this.server.connect();
|
|
64
|
+
}
|
|
65
|
+
get isConnected() {
|
|
66
|
+
return this.server.connected;
|
|
67
|
+
}
|
|
68
|
+
checkConnection() {
|
|
69
|
+
if (this.isConnected || this.connecting)
|
|
70
|
+
return;
|
|
71
|
+
this.connect();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
SocketClient.instance = null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const APP_VERSION = '0.0.0';
|
|
2
|
+
export const APP_NETWORK = '0.0.0';
|
|
3
|
+
export const APP_NAME = 'Bako Safe';
|
|
4
|
+
export const APP_DESCRIPTION = 'Bako Safe is a connector to safe.bako.global, a non-custodial vault for your crypto assets.';
|
|
5
|
+
export const APP_IMAGE_DARK = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiByeD0iOCIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzEzMjQ5XzE2MjI4MCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzEzMjQ5XzE2MjI4MCkiPgo8cGF0aCBkPSJNMTMgMjUuOTE2N0wzNyAzNy44NjcxTDI1LjAwMjQgMTguOTg5M0wxMyAyNS45MTY3WiIgZmlsbD0iI0Y1RjVGNSIvPgo8cGF0aCBkPSJNMzMuODg2NCAyMi4yMTgyTDI0Ljk5NzYgMTcuMDg2NVY1LjEzNTc0TDEzIDEyLjA2MjhWMjUuOTE2TDI0Ljk5NzYgMTguOTg4OVYzMC45Mzk2TDEzIDM3Ljg2NjhMMjQuOTk3NiA0NC43OTM4TDM2Ljk5NTIgMzcuODY2OFYyNy42MDMzQzM2Ljk5NTIgMjUuMzgxNiAzNS44MDk4IDIzLjMyOTEgMzMuODg2NCAyMi4yMTgyWiIgZmlsbD0iIzFFMUYyMiIvPgo8L2c+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMTMyNDlfMTYyMjgwIiB4MT0iMCIgeTE9IjAiIHgyPSI1Mi4zMjg1IiB5Mj0iNDcuNDMxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkMwMTAiLz4KPHN0b3Agb2Zmc2V0PSIwLjQ4IiBzdG9wLWNvbG9yPSIjRUJBMzEyIi8+CjxzdG9wIG9mZnNldD0iMC43MSIgc3RvcC1jb2xvcj0iI0QzODAxNSIvPgo8c3RvcCBvZmZzZXQ9IjAuOTkiIHN0b3AtY29sb3I9IiNCMjRGMTgiLz4KPC9saW5lYXJHcmFkaWVudD4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMzI0OV8xNjIyODAiPgo8cmVjdCB3aWR0aD0iMjQiIGhlaWdodD0iNDAiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMyA1KSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo=';
|
|
6
|
+
export const APP_IMAGE_LIGHT = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiByeD0iOCIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzEzMjQ5XzE2MjI4MCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzEzMjQ5XzE2MjI4MCkiPgo8cGF0aCBkPSJNMTMgMjUuOTE2N0wzNyAzNy44NjcxTDI1LjAwMjQgMTguOTg5M0wxMyAyNS45MTY3WiIgZmlsbD0iI0Y1RjVGNSIvPgo8cGF0aCBkPSJNMzMuODg2NCAyMi4yMTgyTDI0Ljk5NzYgMTcuMDg2NVY1LjEzNTc0TDEzIDEyLjA2MjhWMjUuOTE2TDI0Ljk5NzYgMTguOTg4OVYzMC45Mzk2TDEzIDM3Ljg2NjhMMjQuOTk3NiA0NC43OTM4TDM2Ljk5NTIgMzcuODY2OFYyNy42MDMzQzM2Ljk5NTIgMjUuMzgxNiAzNS44MDk4IDIzLjMyOTEgMzMuODg2NCAyMi4yMTgyWiIgZmlsbD0iIzFFMUYyMiIvPgo8L2c+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMTMyNDlfMTYyMjgwIiB4MT0iMCIgeTE9IjAiIHgyPSI1Mi4zMjg1IiB5Mj0iNDcuNDMxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkMwMTAiLz4KPHN0b3Agb2Zmc2V0PSIwLjQ4IiBzdG9wLWNvbG9yPSIjRUJBMzEyIi8+CjxzdG9wIG9mZnNldD0iMC43MSIgc3RvcC1jb2xvcj0iI0QzODAxNSIvPgo8c3RvcCBvZmZzZXQ9IjAuOTkiIHN0b3AtY29sb3I9IiNCMjRGMTgiLz4KPC9saW5lYXJHcmFkaWVudD4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMzI0OV8xNjIyODAiPgo8cmVjdCB3aWR0aD0iMjQiIGhlaWdodD0iNDAiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMyA1KSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo=';
|
|
7
|
+
export const APP_URL = 'https://safe.bako.global';
|
|
8
|
+
export const HOST_URL = 'https://api.bako.global';
|
|
9
|
+
export const SOCKET_URL = 'https://api.bako.global';
|
|
10
|
+
// Window object
|
|
11
|
+
export const HAS_WINDOW = typeof window !== 'undefined';
|
|
12
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
13
|
+
export const WINDOW = HAS_WINDOW ? window : {};
|
|
14
|
+
export const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(WINDOW.navigator?.userAgent ?? '');
|
|
15
|
+
//storage
|
|
16
|
+
export const SESSION_ID = 'sessionId';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './BakoSafeConnector';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { urlJoin } from 'fuels';
|
|
2
|
+
export class RequestAPI {
|
|
3
|
+
constructor(baseUrl) {
|
|
4
|
+
this.baseUrl = baseUrl;
|
|
5
|
+
}
|
|
6
|
+
async get(pathname) {
|
|
7
|
+
const data = await fetch(urlJoin(this.baseUrl, pathname)).then((res) => res.json());
|
|
8
|
+
return data;
|
|
9
|
+
}
|
|
10
|
+
async delete(pathname) {
|
|
11
|
+
await fetch(urlJoin(this.baseUrl, pathname), {
|
|
12
|
+
method: 'DELETE',
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export var BakoSafeConnectorEvents;
|
|
2
|
+
(function (BakoSafeConnectorEvents) {
|
|
3
|
+
//default
|
|
4
|
+
BakoSafeConnectorEvents["DEFAULT"] = "message";
|
|
5
|
+
//client
|
|
6
|
+
BakoSafeConnectorEvents["CLIENT_DISCONNECTED"] = "[CLIENT_DISCONNECTED]";
|
|
7
|
+
BakoSafeConnectorEvents["CLIENT_CONNECTED"] = "[CONNECTED]";
|
|
8
|
+
//transactions
|
|
9
|
+
BakoSafeConnectorEvents["TX_PENDING"] = "[TX_EVENT_REQUESTED]";
|
|
10
|
+
BakoSafeConnectorEvents["TX_CONFIRMED"] = "[TX_EVENT_CONFIRMED]";
|
|
11
|
+
BakoSafeConnectorEvents["TX_TIMEOUT"] = "[TX_EVENT_TIMEOUT]";
|
|
12
|
+
//switchNetwork
|
|
13
|
+
BakoSafeConnectorEvents["CHANGE_NETWORK"] = "[CHANGE_NETWORK]";
|
|
14
|
+
BakoSafeConnectorEvents["NETWORK_CHANGED"] = "[NETWORK_CHANGED]";
|
|
15
|
+
//auth
|
|
16
|
+
BakoSafeConnectorEvents["AUTH_CONFIRMED"] = "[AUTH_CONFIRMED]";
|
|
17
|
+
BakoSafeConnectorEvents["CONNECTION_STATE"] = "[CONNECTION_STATE]";
|
|
18
|
+
BakoSafeConnectorEvents["DISCONNECT"] = "[DISCONNECT]";
|
|
19
|
+
})(BakoSafeConnectorEvents || (BakoSafeConnectorEvents = {}));
|
|
20
|
+
export var BakoSafeUsernames;
|
|
21
|
+
(function (BakoSafeUsernames) {
|
|
22
|
+
BakoSafeUsernames["CONNECTOR"] = "[CONNECTOR]";
|
|
23
|
+
BakoSafeUsernames["CLIENT"] = "[UI]";
|
|
24
|
+
BakoSafeUsernames["SERVER"] = "[API]";
|
|
25
|
+
})(BakoSafeUsernames || (BakoSafeUsernames = {}));
|