@moon-x/core 0.2.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/README.md +39 -0
- package/dist/chain-C9dvKXUY.d.mts +48 -0
- package/dist/chain-C9dvKXUY.d.ts +48 -0
- package/dist/chunk-264CEGDS.mjs +46 -0
- package/dist/chunk-CDT4MC7S.mjs +1532 -0
- package/dist/chunk-CMYR6AOY.mjs +0 -0
- package/dist/chunk-GQKIA37O.mjs +20 -0
- package/dist/chunk-IMLBIIJ4.mjs +36 -0
- package/dist/chunk-MOREUKOG.mjs +18 -0
- package/dist/chunk-SOKLPX7V.mjs +270 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +402 -0
- package/dist/index.mjs +33 -0
- package/dist/interfaces-9k0eKCc4.d.ts +120 -0
- package/dist/interfaces-fNhwnCeY.d.mts +120 -0
- package/dist/lib/index.d.mts +410 -0
- package/dist/lib/index.d.ts +410 -0
- package/dist/lib/index.js +1622 -0
- package/dist/lib/index.mjs +89 -0
- package/dist/passkey-cache-B9PT3AWX.d.mts +47 -0
- package/dist/passkey-cache-B9PT3AWX.d.ts +47 -0
- package/dist/passkey-metadata-QqFF2SWQ.d.mts +25 -0
- package/dist/passkey-metadata-QqFF2SWQ.d.ts +25 -0
- package/dist/post-message-C_99BCBh.d.mts +70 -0
- package/dist/post-message-C_99BCBh.d.ts +70 -0
- package/dist/react/ethereum.d.mts +26 -0
- package/dist/react/ethereum.d.ts +26 -0
- package/dist/react/ethereum.js +99 -0
- package/dist/react/ethereum.mjs +56 -0
- package/dist/react/index.d.mts +182 -0
- package/dist/react/index.d.ts +182 -0
- package/dist/react/index.js +586 -0
- package/dist/react/index.mjs +328 -0
- package/dist/react/solana.d.mts +17 -0
- package/dist/react/solana.d.ts +17 -0
- package/dist/react/solana.js +75 -0
- package/dist/react/solana.mjs +35 -0
- package/dist/sdk/index.d.mts +126 -0
- package/dist/sdk/index.d.ts +126 -0
- package/dist/sdk/index.js +864 -0
- package/dist/sdk/index.mjs +579 -0
- package/dist/types/index.d.mts +1190 -0
- package/dist/types/index.d.ts +1190 -0
- package/dist/types/index.js +64 -0
- package/dist/types/index.mjs +10 -0
- package/dist/utils/index.d.mts +11 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.js +365 -0
- package/dist/utils/index.mjs +25 -0
- package/dist/web/index.d.mts +20 -0
- package/dist/web/index.d.ts +20 -0
- package/dist/web/index.js +470 -0
- package/dist/web/index.mjs +155 -0
- package/package.json +111 -0
|
@@ -0,0 +1,1622 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/index.ts
|
|
31
|
+
var lib_exports = {};
|
|
32
|
+
__export(lib_exports, {
|
|
33
|
+
DEFAULT_AUTH_URL: () => DEFAULT_AUTH_URL,
|
|
34
|
+
EthereumSiweMessage: () => EthereumSiweMessage,
|
|
35
|
+
SiwsMessage: () => SiwsMessage,
|
|
36
|
+
SolanaTransactionParser: () => SolanaTransactionParser,
|
|
37
|
+
arrayLikeToBytes: () => arrayLikeToBytes,
|
|
38
|
+
authState: () => authState,
|
|
39
|
+
broadcastEthereumRaw: () => broadcastEthereumRaw,
|
|
40
|
+
broadcastSolanaSigned: () => broadcastSolanaSigned,
|
|
41
|
+
bs58ToBytes: () => bs58ToBytes,
|
|
42
|
+
buildUrl: () => buildUrl,
|
|
43
|
+
clearParentAssertCache: () => clearParentAssertCache,
|
|
44
|
+
createManualSiweMessage: () => createManualSiweMessage,
|
|
45
|
+
estimateEvmGas: () => estimateEvmGas,
|
|
46
|
+
estimateEvmGasReserve: () => estimateEvmGasReserve,
|
|
47
|
+
formatPasskeyLabel: () => formatPasskeyLabel,
|
|
48
|
+
fromB64url: () => fromB64url,
|
|
49
|
+
generatePasskeyUserId: () => generatePasskeyUserId,
|
|
50
|
+
getAssertCacheTtlMs: () => getAssertCacheTtlMs,
|
|
51
|
+
getChainById: () => getChainById,
|
|
52
|
+
getDefaultChain: () => getDefaultChain,
|
|
53
|
+
getEvmGasPrice: () => getEvmGasPrice,
|
|
54
|
+
getEvmMaxPriorityFeePerGas: () => getEvmMaxPriorityFeePerGas,
|
|
55
|
+
getEvmNonce: () => getEvmNonce,
|
|
56
|
+
getInstructionsForHTML: () => getInstructionsForHTML,
|
|
57
|
+
getRpcUrl: () => getRpcUrl,
|
|
58
|
+
getSOLTransfersFromInstructions: () => getSOLTransfersFromInstructions,
|
|
59
|
+
getTransferInfoFromInstructions: () => getTransferInfoFromInstructions,
|
|
60
|
+
isChainSupported: () => isChainSupported,
|
|
61
|
+
prepareEvmSendTransaction: () => prepareEvmSendTransaction,
|
|
62
|
+
prepareEvmSignTransaction: () => prepareEvmSignTransaction,
|
|
63
|
+
readParentAssertCache: () => readParentAssertCache,
|
|
64
|
+
resolveEvmChain: () => resolveEvmChain,
|
|
65
|
+
resolvePasskeyMetadata: () => resolvePasskeyMetadata,
|
|
66
|
+
sanitizeUserData: () => sanitizeUserData,
|
|
67
|
+
serializeEthereumTransaction: () => serializeEthereumTransaction,
|
|
68
|
+
setAssertCacheTtlMs: () => setAssertCacheTtlMs,
|
|
69
|
+
setChainRpcUrl: () => setChainRpcUrl,
|
|
70
|
+
toB64url: () => toB64url,
|
|
71
|
+
validateChainConfig: () => validateChainConfig,
|
|
72
|
+
verifyIdToken: () => verifyIdToken,
|
|
73
|
+
withClearOnFailure: () => withClearOnFailure,
|
|
74
|
+
writeParentAssertCache: () => writeParentAssertCache
|
|
75
|
+
});
|
|
76
|
+
module.exports = __toCommonJS(lib_exports);
|
|
77
|
+
|
|
78
|
+
// src/lib/auth/authentication-state.ts
|
|
79
|
+
var AuthenticationState = class {
|
|
80
|
+
constructor() {
|
|
81
|
+
this.email = null;
|
|
82
|
+
}
|
|
83
|
+
setEmail(email) {
|
|
84
|
+
this.email = email;
|
|
85
|
+
}
|
|
86
|
+
getEmail() {
|
|
87
|
+
return this.email;
|
|
88
|
+
}
|
|
89
|
+
clearEmail() {
|
|
90
|
+
this.email = null;
|
|
91
|
+
}
|
|
92
|
+
clear() {
|
|
93
|
+
this.clearEmail();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var authState = new AuthenticationState();
|
|
97
|
+
|
|
98
|
+
// src/lib/auth/sanitize-user.ts
|
|
99
|
+
function sanitizeUserData(userData) {
|
|
100
|
+
if (!userData) return null;
|
|
101
|
+
const publicUser = {
|
|
102
|
+
user_id: userData.user_id,
|
|
103
|
+
first_name: userData.first_name,
|
|
104
|
+
last_name: userData.last_name,
|
|
105
|
+
status: userData.status,
|
|
106
|
+
active: userData.active,
|
|
107
|
+
is_guest: userData.is_guest,
|
|
108
|
+
emails: userData.emails,
|
|
109
|
+
phone_numbers: userData.phone_numbers,
|
|
110
|
+
idp_providers: userData.idp_providers,
|
|
111
|
+
wallets: userData.wallets,
|
|
112
|
+
totps: userData.totps,
|
|
113
|
+
webauthn_credentials: userData.webauthn_credentials,
|
|
114
|
+
created_at: userData.created_at,
|
|
115
|
+
updated_at: userData.updated_at
|
|
116
|
+
};
|
|
117
|
+
return Object.fromEntries(
|
|
118
|
+
Object.entries(publicUser).filter(([_, value]) => value !== void 0)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/utils/get-api-url.ts
|
|
123
|
+
var getMoonKeyApiUrl = () => {
|
|
124
|
+
if (process.env?.NEXT_PUBLIC_MOONKEY_API_URL) {
|
|
125
|
+
return process.env.NEXT_PUBLIC_MOONKEY_API_URL;
|
|
126
|
+
}
|
|
127
|
+
if (process.env?.NEXT_PUBLIC_MOONKEY_IFRAME_URL) {
|
|
128
|
+
const iframeUrl = process.env.NEXT_PUBLIC_MOONKEY_IFRAME_URL;
|
|
129
|
+
if (iframeUrl.includes("staging") || iframeUrl.includes("auth-staging")) {
|
|
130
|
+
return "https://api.moonx-dev.com";
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (process.env?.NEXT_PUBLIC_VERCEL_ENV === "preview") {
|
|
134
|
+
return "https://api.moonx-dev.com";
|
|
135
|
+
}
|
|
136
|
+
return "https://api.moonx-dev.com";
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/lib/auth/verify-id-token.ts
|
|
140
|
+
var verifyIdToken = async (publishableKey, idToken) => {
|
|
141
|
+
try {
|
|
142
|
+
const apiUrl = getMoonKeyApiUrl();
|
|
143
|
+
const response = await fetch(
|
|
144
|
+
`${apiUrl}/v1/auth/users/public/id_token/verify`,
|
|
145
|
+
{
|
|
146
|
+
method: "GET",
|
|
147
|
+
headers: {
|
|
148
|
+
"Content-Type": "application/json",
|
|
149
|
+
Authorization: `PublicToken ${publishableKey}`,
|
|
150
|
+
"X-Streambird-id-token": idToken
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
const errorData = await response.json().catch(() => ({}));
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
error: errorData.message || `Failed to verify ID token: ${response.statusText}`,
|
|
159
|
+
statusCode: response.status
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const responseData = await response.json();
|
|
163
|
+
const user = responseData.user || responseData;
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
user
|
|
167
|
+
};
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error("Error verifying ID token:", error);
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: error instanceof Error ? error.message : "Unknown error occurred"
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// src/lib/passkey/passkey-codec.ts
|
|
178
|
+
var fromB64url = (b64url) => {
|
|
179
|
+
const base64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
180
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
181
|
+
const binary = atob(padded);
|
|
182
|
+
const bytes = new Uint8Array(binary.length);
|
|
183
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
184
|
+
return bytes;
|
|
185
|
+
};
|
|
186
|
+
var toB64url = (bytes) => {
|
|
187
|
+
let str = "";
|
|
188
|
+
for (let i = 0; i < bytes.length; i++) str += String.fromCharCode(bytes[i]);
|
|
189
|
+
return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// src/lib/passkey/passkey-cache.ts
|
|
193
|
+
var cacheTtlMs = 0;
|
|
194
|
+
var cache = null;
|
|
195
|
+
var setAssertCacheTtlMs = (ms) => {
|
|
196
|
+
cacheTtlMs = Math.max(0, Math.floor(ms));
|
|
197
|
+
if (cacheTtlMs === 0) {
|
|
198
|
+
cache = null;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
var getAssertCacheTtlMs = () => cacheTtlMs;
|
|
202
|
+
var clearParentAssertCache = () => {
|
|
203
|
+
cache = null;
|
|
204
|
+
};
|
|
205
|
+
var readParentAssertCache = () => {
|
|
206
|
+
if (cacheTtlMs <= 0) return null;
|
|
207
|
+
if (!cache) return null;
|
|
208
|
+
if (Date.now() - cache.ts >= cacheTtlMs) return null;
|
|
209
|
+
return {
|
|
210
|
+
userHandleB64url: cache.userHandleB64url,
|
|
211
|
+
credentialIdB64url: cache.credentialIdB64url
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
var writeParentAssertCache = (entry) => {
|
|
215
|
+
if (cacheTtlMs <= 0) return;
|
|
216
|
+
cache = { ...entry, ts: Date.now() };
|
|
217
|
+
};
|
|
218
|
+
var withClearOnFailure = async (fn) => {
|
|
219
|
+
try {
|
|
220
|
+
return await fn();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
clearParentAssertCache();
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
var generatePasskeyUserId = () => {
|
|
227
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
228
|
+
return { userIdB64url: toB64url(bytes), userIdBytes: bytes };
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/lib/passkey/passkey-aaguid-registry.json
|
|
232
|
+
var passkey_aaguid_registry_default = {
|
|
233
|
+
"a11a5faa-9f32-4b8c-8c5d-2f7d13e8c942": {
|
|
234
|
+
name: "AliasVault"
|
|
235
|
+
},
|
|
236
|
+
"ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4": {
|
|
237
|
+
name: "Google Password Manager"
|
|
238
|
+
},
|
|
239
|
+
"adce0002-35bc-c60a-648b-0b25f1f05503": {
|
|
240
|
+
name: "Chrome on Mac"
|
|
241
|
+
},
|
|
242
|
+
"08987058-cadc-4b81-b6e1-30de50dcbe96": {
|
|
243
|
+
name: "Windows Hello"
|
|
244
|
+
},
|
|
245
|
+
"9ddd1817-af5a-4672-a2b9-3e3dd95000a9": {
|
|
246
|
+
name: "Windows Hello"
|
|
247
|
+
},
|
|
248
|
+
"6028b017-b1d4-4c02-b4b3-afcdafc96bb2": {
|
|
249
|
+
name: "Windows Hello"
|
|
250
|
+
},
|
|
251
|
+
"dd4ec289-e01d-41c9-bb89-70fa845d4bf2": {
|
|
252
|
+
name: "iCloud Keychain (Managed)"
|
|
253
|
+
},
|
|
254
|
+
"531126d6-e717-415c-9320-3d9aa6981239": {
|
|
255
|
+
name: "Dashlane"
|
|
256
|
+
},
|
|
257
|
+
"bada5566-a7aa-401f-bd96-45619a55120d": {
|
|
258
|
+
name: "1Password"
|
|
259
|
+
},
|
|
260
|
+
"b84e4048-15dc-4dd0-8640-f4f60813c8af": {
|
|
261
|
+
name: "NordPass"
|
|
262
|
+
},
|
|
263
|
+
"0ea242b4-43c4-4a1b-8b17-dd6d0b6baec6": {
|
|
264
|
+
name: "Keeper"
|
|
265
|
+
},
|
|
266
|
+
"891494da-2c90-4d31-a9cd-4eab0aed1309": {
|
|
267
|
+
name: "S\xE9same"
|
|
268
|
+
},
|
|
269
|
+
"f3809540-7f14-49c1-a8b3-8f813b225541": {
|
|
270
|
+
name: "Enpass"
|
|
271
|
+
},
|
|
272
|
+
"b5397666-4885-aa6b-cebf-e52262a439a2": {
|
|
273
|
+
name: "Chromium Browser"
|
|
274
|
+
},
|
|
275
|
+
"771b48fd-d3d4-4f74-9232-fc157ab0507a": {
|
|
276
|
+
name: "Edge on Mac"
|
|
277
|
+
},
|
|
278
|
+
"39a5647e-1853-446c-a1f6-a79bae9f5bc7": {
|
|
279
|
+
name: "IDmelon"
|
|
280
|
+
},
|
|
281
|
+
"d548826e-79b4-db40-a3d8-11116f7e8349": {
|
|
282
|
+
name: "Bitwarden"
|
|
283
|
+
},
|
|
284
|
+
"fbfc3007-154e-4ecc-8c0b-6e020557d7bd": {
|
|
285
|
+
name: "Apple Passwords"
|
|
286
|
+
},
|
|
287
|
+
"53414d53-554e-4700-0000-000000000000": {
|
|
288
|
+
name: "Samsung Pass"
|
|
289
|
+
},
|
|
290
|
+
"66a0ccb3-bd6a-191f-ee06-e375c50b9846": {
|
|
291
|
+
name: "Thales Bio iOS SDK"
|
|
292
|
+
},
|
|
293
|
+
"8836336a-f590-0921-301d-46427531eee6": {
|
|
294
|
+
name: "Thales Bio Android SDK"
|
|
295
|
+
},
|
|
296
|
+
"cd69adb5-3c7a-deb9-3177-6800ea6cb72a": {
|
|
297
|
+
name: "Thales PIN Android SDK"
|
|
298
|
+
},
|
|
299
|
+
"17290f1e-c212-34d0-1423-365d729f09d9": {
|
|
300
|
+
name: "Thales PIN iOS SDK"
|
|
301
|
+
},
|
|
302
|
+
"50726f74-6f6e-5061-7373-50726f746f6e": {
|
|
303
|
+
name: "Proton Pass"
|
|
304
|
+
},
|
|
305
|
+
"fdb141b2-5d84-443e-8a35-4698c205a502": {
|
|
306
|
+
name: "KeePassXC"
|
|
307
|
+
},
|
|
308
|
+
"eaecdef2-1c31-5634-8639-f1cbd9c00a08": {
|
|
309
|
+
name: "KeePassDX"
|
|
310
|
+
},
|
|
311
|
+
"cc45f64e-52a2-451b-831a-4edd8022a202": {
|
|
312
|
+
name: "ToothPic Passkey Provider"
|
|
313
|
+
},
|
|
314
|
+
"bfc748bb-3429-4faa-b9f9-7cfa9f3b76d0": {
|
|
315
|
+
name: "iPasswords"
|
|
316
|
+
},
|
|
317
|
+
"b35a26b2-8f6e-4697-ab1d-d44db4da28c6": {
|
|
318
|
+
name: "Zoho Vault"
|
|
319
|
+
},
|
|
320
|
+
"b78a0a55-6ef8-d246-a042-ba0f6d55050c": {
|
|
321
|
+
name: "LastPass"
|
|
322
|
+
},
|
|
323
|
+
"de503f9c-21a4-4f76-b4b7-558eb55c6f89": {
|
|
324
|
+
name: "Devolutions"
|
|
325
|
+
},
|
|
326
|
+
"22248c4c-7a12-46e2-9a41-44291b373a4d": {
|
|
327
|
+
name: "LogMeOnce"
|
|
328
|
+
},
|
|
329
|
+
"a10c6dd9-465e-4226-8198-c7c44b91c555": {
|
|
330
|
+
name: "Kaspersky Password Manager"
|
|
331
|
+
},
|
|
332
|
+
"d350af52-0351-4ba2-acd3-dfeeadc3f764": {
|
|
333
|
+
name: "pwSafe"
|
|
334
|
+
},
|
|
335
|
+
"d3452668-01fd-4c12-926c-83a4204853aa": {
|
|
336
|
+
name: "Microsoft Password Manager"
|
|
337
|
+
},
|
|
338
|
+
"6d212b28-a2c1-4638-b375-5932070f62e9": {
|
|
339
|
+
name: "initial"
|
|
340
|
+
},
|
|
341
|
+
"d49b2120-b865-4191-8cea-be84a52b0485": {
|
|
342
|
+
name: "Heimlane Vault"
|
|
343
|
+
},
|
|
344
|
+
"e8b7f4a2-c3d5-e6f7-890a-b1c2d3e4f567": {
|
|
345
|
+
name: "Sherlocked"
|
|
346
|
+
},
|
|
347
|
+
"d9be9d39-e6a6-4c28-a581-32b044d986e4": {
|
|
348
|
+
name: "Sticky Password Manager"
|
|
349
|
+
},
|
|
350
|
+
"70617373-7761-6c6c-6669-646f32303236": {
|
|
351
|
+
name: "Passwall"
|
|
352
|
+
},
|
|
353
|
+
"c9cadfc9-89a9-489e-a25a-c7e86a4d5f15": {
|
|
354
|
+
name: "Burp Suite Navigation Recorder"
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/lib/passkey/passkey-metadata.ts
|
|
359
|
+
var aaguidRegistry = passkey_aaguid_registry_default;
|
|
360
|
+
var ZERO_AAGUID = "00000000-0000-0000-0000-000000000000";
|
|
361
|
+
function resolveProvider(aaguid, transports) {
|
|
362
|
+
if (!aaguid) return "Unknown authenticator";
|
|
363
|
+
const entry = aaguidRegistry[aaguid];
|
|
364
|
+
if (entry?.name) return entry.name;
|
|
365
|
+
if (aaguid === ZERO_AAGUID) {
|
|
366
|
+
if (transports.includes("internal")) return "iCloud Keychain";
|
|
367
|
+
return "Unknown authenticator";
|
|
368
|
+
}
|
|
369
|
+
return "Unknown authenticator";
|
|
370
|
+
}
|
|
371
|
+
function resolveFormFactor(transports) {
|
|
372
|
+
if (transports.includes("hybrid")) return "hybrid";
|
|
373
|
+
if (transports.includes("internal")) return "platform";
|
|
374
|
+
if (transports.includes("usb") || transports.includes("nfc") || transports.includes("ble")) {
|
|
375
|
+
return "roaming";
|
|
376
|
+
}
|
|
377
|
+
return "unknown";
|
|
378
|
+
}
|
|
379
|
+
function formatPasskeyLabel(input) {
|
|
380
|
+
if (input.nickname && input.nickname.trim()) return input.nickname.trim();
|
|
381
|
+
const transports = input.transports ?? [];
|
|
382
|
+
const providerName = resolveProvider(input.aaguid, transports);
|
|
383
|
+
if (providerName.includes(" on ")) return providerName;
|
|
384
|
+
if (input.registeredBrowser) {
|
|
385
|
+
return `${providerName} on ${input.registeredBrowser}`;
|
|
386
|
+
}
|
|
387
|
+
return providerName;
|
|
388
|
+
}
|
|
389
|
+
function resolvePasskeyMetadata(input) {
|
|
390
|
+
const transports = input.transports ?? [];
|
|
391
|
+
const providerName = resolveProvider(input.aaguid, transports);
|
|
392
|
+
return {
|
|
393
|
+
providerName,
|
|
394
|
+
formFactor: resolveFormFactor(transports),
|
|
395
|
+
isCloudSynced: !!input.backupState,
|
|
396
|
+
label: formatPasskeyLabel(input)
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/lib/ethereum/chains.ts
|
|
401
|
+
var import_viem = require("viem");
|
|
402
|
+
function setChainRpcUrl(chain, rpcUrl) {
|
|
403
|
+
return {
|
|
404
|
+
...chain,
|
|
405
|
+
rpcUrls: {
|
|
406
|
+
...chain.rpcUrls,
|
|
407
|
+
default: {
|
|
408
|
+
http: [rpcUrl],
|
|
409
|
+
webSocket: chain.rpcUrls.default.webSocket
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function getRpcUrl(chain) {
|
|
415
|
+
return chain.rpcUrls.default.http[0];
|
|
416
|
+
}
|
|
417
|
+
async function getEvmMaxPriorityFeePerGas(rpcUrl) {
|
|
418
|
+
const response = await fetch(rpcUrl, {
|
|
419
|
+
method: "POST",
|
|
420
|
+
headers: { "Content-Type": "application/json" },
|
|
421
|
+
body: JSON.stringify({
|
|
422
|
+
jsonrpc: "2.0",
|
|
423
|
+
id: 1,
|
|
424
|
+
method: "eth_maxPriorityFeePerGas",
|
|
425
|
+
params: []
|
|
426
|
+
})
|
|
427
|
+
});
|
|
428
|
+
const result = await response.json();
|
|
429
|
+
if (result.error) {
|
|
430
|
+
throw new Error(
|
|
431
|
+
result.error.message || "eth_maxPriorityFeePerGas failed"
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
return BigInt(result.result);
|
|
435
|
+
}
|
|
436
|
+
async function getEvmGasPrice(rpcUrl) {
|
|
437
|
+
const response = await fetch(rpcUrl, {
|
|
438
|
+
method: "POST",
|
|
439
|
+
headers: { "Content-Type": "application/json" },
|
|
440
|
+
body: JSON.stringify({
|
|
441
|
+
jsonrpc: "2.0",
|
|
442
|
+
id: 1,
|
|
443
|
+
method: "eth_gasPrice",
|
|
444
|
+
params: []
|
|
445
|
+
})
|
|
446
|
+
});
|
|
447
|
+
const result = await response.json();
|
|
448
|
+
if (result.error) {
|
|
449
|
+
throw new Error(result.error.message || "eth_gasPrice failed");
|
|
450
|
+
}
|
|
451
|
+
return BigInt(result.result);
|
|
452
|
+
}
|
|
453
|
+
async function estimateEvmGas(rpcUrl, tx) {
|
|
454
|
+
const valueHex = (() => {
|
|
455
|
+
const v = tx.value;
|
|
456
|
+
if (v == null) return "0x0";
|
|
457
|
+
if (typeof v === "bigint") return `0x${v.toString(16)}`;
|
|
458
|
+
if (typeof v === "number") return `0x${BigInt(v).toString(16)}`;
|
|
459
|
+
if (typeof v === "string") {
|
|
460
|
+
if (v === "") return "0x0";
|
|
461
|
+
if (v.startsWith("0x")) return v;
|
|
462
|
+
if (v.includes(".")) {
|
|
463
|
+
return `0x${(0, import_viem.parseEther)(v).toString(16)}`;
|
|
464
|
+
}
|
|
465
|
+
try {
|
|
466
|
+
return `0x${BigInt(v).toString(16)}`;
|
|
467
|
+
} catch {
|
|
468
|
+
return "0x0";
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return "0x0";
|
|
472
|
+
})();
|
|
473
|
+
const params = {
|
|
474
|
+
from: tx.from,
|
|
475
|
+
value: valueHex,
|
|
476
|
+
data: tx.data || "0x"
|
|
477
|
+
};
|
|
478
|
+
if (tx.to) params.to = tx.to;
|
|
479
|
+
const response = await fetch(rpcUrl, {
|
|
480
|
+
method: "POST",
|
|
481
|
+
headers: { "Content-Type": "application/json" },
|
|
482
|
+
body: JSON.stringify({
|
|
483
|
+
jsonrpc: "2.0",
|
|
484
|
+
id: 1,
|
|
485
|
+
method: "eth_estimateGas",
|
|
486
|
+
params: [params]
|
|
487
|
+
})
|
|
488
|
+
});
|
|
489
|
+
const result = await response.json();
|
|
490
|
+
if (result.error) {
|
|
491
|
+
throw new Error(result.error.message || "eth_estimateGas failed");
|
|
492
|
+
}
|
|
493
|
+
return BigInt(result.result);
|
|
494
|
+
}
|
|
495
|
+
async function getEvmNonce(rpcUrl, address) {
|
|
496
|
+
const response = await fetch(rpcUrl, {
|
|
497
|
+
method: "POST",
|
|
498
|
+
headers: { "Content-Type": "application/json" },
|
|
499
|
+
body: JSON.stringify({
|
|
500
|
+
jsonrpc: "2.0",
|
|
501
|
+
id: 1,
|
|
502
|
+
method: "eth_getTransactionCount",
|
|
503
|
+
params: [address, "pending"]
|
|
504
|
+
})
|
|
505
|
+
});
|
|
506
|
+
const result = await response.json();
|
|
507
|
+
if (result.error) {
|
|
508
|
+
throw new Error(result.error.message || "eth_getTransactionCount failed");
|
|
509
|
+
}
|
|
510
|
+
return Number(BigInt(result.result));
|
|
511
|
+
}
|
|
512
|
+
function typicalSwapGasUnits(chainId) {
|
|
513
|
+
switch (chainId) {
|
|
514
|
+
case 1:
|
|
515
|
+
return 300000n;
|
|
516
|
+
// Ethereum mainnet
|
|
517
|
+
case 137:
|
|
518
|
+
return 300000n;
|
|
519
|
+
// Polygon
|
|
520
|
+
case 56:
|
|
521
|
+
return 250000n;
|
|
522
|
+
// BSC
|
|
523
|
+
case 42161:
|
|
524
|
+
return 1500000n;
|
|
525
|
+
// Arbitrum (incl L1 calldata)
|
|
526
|
+
case 8453:
|
|
527
|
+
case 10:
|
|
528
|
+
return 700000n;
|
|
529
|
+
// Base / Optimism (incl L1 calldata)
|
|
530
|
+
default:
|
|
531
|
+
return 300000n;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async function estimateEvmGasReserve(rpcUrl, chainId, opts = {}) {
|
|
535
|
+
const gasUnits = opts.gasUnits ?? typicalSwapGasUnits(chainId);
|
|
536
|
+
const rawBuffer = opts.bufferBps ?? 15e3;
|
|
537
|
+
const bufferBps = Math.max(
|
|
538
|
+
Number.isFinite(rawBuffer) ? Math.round(rawBuffer) : 15e3,
|
|
539
|
+
1
|
|
540
|
+
);
|
|
541
|
+
const gasPrice = await getEvmGasPrice(rpcUrl);
|
|
542
|
+
const reserveWei = gasPrice * gasUnits * BigInt(bufferBps) / 10000n;
|
|
543
|
+
return Number((0, import_viem.formatEther)(reserveWei));
|
|
544
|
+
}
|
|
545
|
+
function getChainById(chains, chainId) {
|
|
546
|
+
return chains.find((chain) => chain.id === chainId);
|
|
547
|
+
}
|
|
548
|
+
function isChainSupported(chains, chainId) {
|
|
549
|
+
return chains.some((chain) => chain.id === chainId);
|
|
550
|
+
}
|
|
551
|
+
function validateChainConfig(config) {
|
|
552
|
+
const { defaultChain, supportedChains } = config;
|
|
553
|
+
if (supportedChains && supportedChains.length === 0) {
|
|
554
|
+
throw new Error("supportedChains cannot be an empty array");
|
|
555
|
+
}
|
|
556
|
+
if (defaultChain && supportedChains) {
|
|
557
|
+
const isDefaultInSupported = supportedChains.some(
|
|
558
|
+
(chain) => chain.id === defaultChain.id
|
|
559
|
+
);
|
|
560
|
+
if (!isDefaultInSupported) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`defaultChain (${defaultChain.name}, ID: ${defaultChain.id}) must be included in supportedChains`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function getDefaultChain(config) {
|
|
568
|
+
if (config.defaultChain) {
|
|
569
|
+
return config.defaultChain;
|
|
570
|
+
}
|
|
571
|
+
if (config.supportedChains && config.supportedChains.length > 0) {
|
|
572
|
+
return config.supportedChains[0];
|
|
573
|
+
}
|
|
574
|
+
return void 0;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// src/lib/ethereum/siwe.ts
|
|
578
|
+
var import_siwe = require("siwe");
|
|
579
|
+
var import_viem2 = require("viem");
|
|
580
|
+
var EthereumSiweMessage = class {
|
|
581
|
+
constructor({
|
|
582
|
+
nonce,
|
|
583
|
+
domain,
|
|
584
|
+
address,
|
|
585
|
+
uri,
|
|
586
|
+
version = "1",
|
|
587
|
+
chainId = 1,
|
|
588
|
+
statement,
|
|
589
|
+
issuedAt,
|
|
590
|
+
expirationTime,
|
|
591
|
+
notBefore,
|
|
592
|
+
requestId,
|
|
593
|
+
resources
|
|
594
|
+
}) {
|
|
595
|
+
this.siweMessage = new import_siwe.SiweMessage({
|
|
596
|
+
domain,
|
|
597
|
+
address,
|
|
598
|
+
uri,
|
|
599
|
+
version,
|
|
600
|
+
chainId,
|
|
601
|
+
nonce,
|
|
602
|
+
statement,
|
|
603
|
+
issuedAt,
|
|
604
|
+
expirationTime,
|
|
605
|
+
notBefore,
|
|
606
|
+
requestId,
|
|
607
|
+
resources
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
prepareMessage() {
|
|
611
|
+
return this.siweMessage.prepareMessage();
|
|
612
|
+
}
|
|
613
|
+
getMessage() {
|
|
614
|
+
return this.siweMessage;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
function createManualSiweMessage({
|
|
618
|
+
nonce,
|
|
619
|
+
domain,
|
|
620
|
+
address,
|
|
621
|
+
uri = typeof window !== "undefined" ? window.location.origin : "",
|
|
622
|
+
version = "1",
|
|
623
|
+
chainId = 1,
|
|
624
|
+
statement,
|
|
625
|
+
issuedAt = (/* @__PURE__ */ new Date()).toISOString(),
|
|
626
|
+
walletName = "Ethereum"
|
|
627
|
+
}) {
|
|
628
|
+
let checksummedAddress;
|
|
629
|
+
try {
|
|
630
|
+
checksummedAddress = (0, import_viem2.getAddress)(address);
|
|
631
|
+
} catch (error) {
|
|
632
|
+
checksummedAddress = address;
|
|
633
|
+
}
|
|
634
|
+
let siweMessage = `${domain} wants you to sign in with your Ethereum account:
|
|
635
|
+
`;
|
|
636
|
+
siweMessage += `${checksummedAddress}`;
|
|
637
|
+
const defaultStatement = `Sign in with Ethereum to MoonKey using ${walletName}.`;
|
|
638
|
+
siweMessage += `
|
|
639
|
+
|
|
640
|
+
${statement || defaultStatement}`;
|
|
641
|
+
const fields = [];
|
|
642
|
+
fields.push(`URI: ${uri}`);
|
|
643
|
+
fields.push(`Version: ${version}`);
|
|
644
|
+
fields.push(`Chain ID: ${chainId}`);
|
|
645
|
+
fields.push(`Nonce: ${nonce}`);
|
|
646
|
+
fields.push(`Issued At: ${issuedAt}`);
|
|
647
|
+
siweMessage += `
|
|
648
|
+
|
|
649
|
+
${fields.join("\n")}`;
|
|
650
|
+
return siweMessage;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// src/lib/ethereum/tx-prep.ts
|
|
654
|
+
var import_viem3 = require("viem");
|
|
655
|
+
function resolveEvmChain({
|
|
656
|
+
requestedChainId,
|
|
657
|
+
walletChainId,
|
|
658
|
+
supportedChains,
|
|
659
|
+
defaultChain,
|
|
660
|
+
strict = false
|
|
661
|
+
}) {
|
|
662
|
+
let target;
|
|
663
|
+
if (requestedChainId && supportedChains) {
|
|
664
|
+
target = getChainById(supportedChains, Number(requestedChainId));
|
|
665
|
+
}
|
|
666
|
+
if (!target && walletChainId && supportedChains) {
|
|
667
|
+
target = getChainById(supportedChains, walletChainId);
|
|
668
|
+
}
|
|
669
|
+
if (!target) {
|
|
670
|
+
target = defaultChain;
|
|
671
|
+
}
|
|
672
|
+
if (!target) {
|
|
673
|
+
throw new Error(
|
|
674
|
+
"No chain configured. Please set ethereum.defaultChain in MoonKeyProvider config."
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
if (strict && requestedChainId && Number(requestedChainId) !== target.id) {
|
|
678
|
+
throw new Error(
|
|
679
|
+
`Requested chainId ${requestedChainId} is not in the configured supportedChains.`
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
return target;
|
|
683
|
+
}
|
|
684
|
+
async function prepareEvmSignTransaction({
|
|
685
|
+
transaction,
|
|
686
|
+
wallet,
|
|
687
|
+
supportedChains,
|
|
688
|
+
defaultChain
|
|
689
|
+
}) {
|
|
690
|
+
if (typeof transaction === "string") {
|
|
691
|
+
return { serializedTransaction: transaction, chain: void 0 };
|
|
692
|
+
}
|
|
693
|
+
const txObj = transaction;
|
|
694
|
+
const transactionType = txObj.type ?? 2;
|
|
695
|
+
const chain = resolveEvmChain({
|
|
696
|
+
requestedChainId: txObj.chainId,
|
|
697
|
+
walletChainId: wallet.chainId,
|
|
698
|
+
supportedChains,
|
|
699
|
+
defaultChain,
|
|
700
|
+
strict: false
|
|
701
|
+
});
|
|
702
|
+
const derivedChainId = txObj.chainId || chain.id;
|
|
703
|
+
const formattedTransaction = {
|
|
704
|
+
to: txObj.to,
|
|
705
|
+
value: txObj.value ? typeof txObj.value === "bigint" ? txObj.value : (0, import_viem3.parseEther)(txObj.value.toString()) : BigInt(0),
|
|
706
|
+
data: txObj.data || "0x",
|
|
707
|
+
chainId: derivedChainId
|
|
708
|
+
};
|
|
709
|
+
if (transactionType === 2 || transactionType === "eip1559") {
|
|
710
|
+
formattedTransaction.type = "eip1559";
|
|
711
|
+
formattedTransaction.maxPriorityFeePerGas = txObj.maxPriorityFeePerGas ? typeof txObj.maxPriorityFeePerGas === "bigint" ? txObj.maxPriorityFeePerGas : (0, import_viem3.parseGwei)(txObj.maxPriorityFeePerGas.toString()) : BigInt(2e9);
|
|
712
|
+
formattedTransaction.maxFeePerGas = txObj.maxFeePerGas ? typeof txObj.maxFeePerGas === "bigint" ? txObj.maxFeePerGas : (0, import_viem3.parseGwei)(txObj.maxFeePerGas.toString()) : BigInt(22e9);
|
|
713
|
+
} else {
|
|
714
|
+
formattedTransaction.type = "legacy";
|
|
715
|
+
formattedTransaction.gasPrice = txObj.gasPrice ? typeof txObj.gasPrice === "bigint" ? txObj.gasPrice : (0, import_viem3.parseGwei)(txObj.gasPrice.toString()) : BigInt(2e9);
|
|
716
|
+
}
|
|
717
|
+
if (txObj.nonce !== void 0) {
|
|
718
|
+
formattedTransaction.nonce = Number(txObj.nonce);
|
|
719
|
+
}
|
|
720
|
+
if (txObj.gas !== void 0) {
|
|
721
|
+
formattedTransaction.gas = typeof txObj.gas === "bigint" ? txObj.gas : BigInt(txObj.gas);
|
|
722
|
+
}
|
|
723
|
+
if (txObj.gasLimit !== void 0) {
|
|
724
|
+
formattedTransaction.gas = typeof txObj.gasLimit === "bigint" ? txObj.gasLimit : BigInt(txObj.gasLimit);
|
|
725
|
+
}
|
|
726
|
+
return {
|
|
727
|
+
serializedTransaction: (0, import_viem3.serializeTransaction)(formattedTransaction),
|
|
728
|
+
chain
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
async function prepareEvmSendTransaction({
|
|
732
|
+
transaction,
|
|
733
|
+
wallet,
|
|
734
|
+
supportedChains,
|
|
735
|
+
defaultChain
|
|
736
|
+
}) {
|
|
737
|
+
const chain = resolveEvmChain({
|
|
738
|
+
requestedChainId: transaction.chainId,
|
|
739
|
+
walletChainId: wallet.chainId,
|
|
740
|
+
supportedChains,
|
|
741
|
+
defaultChain,
|
|
742
|
+
strict: true
|
|
743
|
+
});
|
|
744
|
+
const rpcUrl = getRpcUrl(chain);
|
|
745
|
+
if (!rpcUrl) {
|
|
746
|
+
throw new Error(
|
|
747
|
+
`No RPC URL found for chain ${chain.name}. Chain may be missing rpcUrls configuration.`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
const txWithChainId = {
|
|
751
|
+
...transaction,
|
|
752
|
+
chainId: chain.id
|
|
753
|
+
};
|
|
754
|
+
if (txWithChainId.nonce == null) {
|
|
755
|
+
try {
|
|
756
|
+
txWithChainId.nonce = await getEvmNonce(rpcUrl, wallet.public_address);
|
|
757
|
+
} catch {
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const callerGas = txWithChainId.gas ?? txWithChainId.gasLimit;
|
|
761
|
+
if (callerGas == null) {
|
|
762
|
+
try {
|
|
763
|
+
const estimate = await estimateEvmGas(rpcUrl, {
|
|
764
|
+
from: wallet.public_address,
|
|
765
|
+
to: txWithChainId.to,
|
|
766
|
+
data: txWithChainId.data,
|
|
767
|
+
value: txWithChainId.value
|
|
768
|
+
});
|
|
769
|
+
txWithChainId.gas = (estimate * 12n / 10n).toString();
|
|
770
|
+
} catch {
|
|
771
|
+
txWithChainId.gas = "800000";
|
|
772
|
+
}
|
|
773
|
+
} else if (callerGas != null && txWithChainId.gas == null) {
|
|
774
|
+
txWithChainId.gas = callerGas;
|
|
775
|
+
}
|
|
776
|
+
if (txWithChainId.maxFeePerGas == null && txWithChainId.gasPrice == null) {
|
|
777
|
+
try {
|
|
778
|
+
const [baseGasPrice, suggestedTipResult] = await Promise.all([
|
|
779
|
+
getEvmGasPrice(rpcUrl),
|
|
780
|
+
getEvmMaxPriorityFeePerGas(rpcUrl).catch(() => null)
|
|
781
|
+
]);
|
|
782
|
+
let tip;
|
|
783
|
+
if (suggestedTipResult != null && suggestedTipResult > 0n) {
|
|
784
|
+
tip = suggestedTipResult * 12n / 10n;
|
|
785
|
+
} else {
|
|
786
|
+
const cap = 2000000000n;
|
|
787
|
+
tip = baseGasPrice / 10n < cap ? baseGasPrice / 10n : cap;
|
|
788
|
+
if (tip <= 0n) tip = 1n;
|
|
789
|
+
}
|
|
790
|
+
const baseMaxFee = baseGasPrice > 0n ? baseGasPrice * 15n / 10n : tip * 2n;
|
|
791
|
+
const maxFee = baseMaxFee > tip ? baseMaxFee : tip + 1n;
|
|
792
|
+
txWithChainId.maxFeePerGas = `0x${maxFee.toString(16)}`;
|
|
793
|
+
txWithChainId.maxPriorityFeePerGas = `0x${tip.toString(16)}`;
|
|
794
|
+
} catch {
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return { transaction: txWithChainId, rpcUrl, chain };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/lib/solana/siws.ts
|
|
801
|
+
var nacl = __toESM(require("tweetnacl"));
|
|
802
|
+
var SiwsMessage = class {
|
|
803
|
+
constructor({
|
|
804
|
+
nonce,
|
|
805
|
+
domain,
|
|
806
|
+
address,
|
|
807
|
+
uri,
|
|
808
|
+
version,
|
|
809
|
+
chainId,
|
|
810
|
+
statement,
|
|
811
|
+
issuedAt,
|
|
812
|
+
expirationTime,
|
|
813
|
+
notBefore,
|
|
814
|
+
requestId,
|
|
815
|
+
resources,
|
|
816
|
+
message,
|
|
817
|
+
signature
|
|
818
|
+
}) {
|
|
819
|
+
this.nonce = nonce;
|
|
820
|
+
this.domain = domain;
|
|
821
|
+
this.address = address;
|
|
822
|
+
this.uri = uri;
|
|
823
|
+
this.version = version;
|
|
824
|
+
this.chainId = chainId;
|
|
825
|
+
this.statement = statement;
|
|
826
|
+
this.issuedAt = issuedAt;
|
|
827
|
+
this.expirationTime = expirationTime;
|
|
828
|
+
this.notBefore = notBefore;
|
|
829
|
+
this.requestId = requestId;
|
|
830
|
+
this.resources = resources;
|
|
831
|
+
this.message = message;
|
|
832
|
+
this.signature = signature;
|
|
833
|
+
}
|
|
834
|
+
prepareBasic() {
|
|
835
|
+
let message = `${this.domain} wants you to sign in with your Solana account:
|
|
836
|
+
`;
|
|
837
|
+
message += `${this.address}`;
|
|
838
|
+
if (this.statement) {
|
|
839
|
+
message += `
|
|
840
|
+
|
|
841
|
+
${this.statement}`;
|
|
842
|
+
}
|
|
843
|
+
const fields = [];
|
|
844
|
+
if (this.nonce) {
|
|
845
|
+
fields.push(`Nonce: ${this.nonce}`);
|
|
846
|
+
}
|
|
847
|
+
if (this.issuedAt) {
|
|
848
|
+
fields.push(`Issued At: ${this.issuedAt}`);
|
|
849
|
+
}
|
|
850
|
+
if (fields.length) {
|
|
851
|
+
message += `
|
|
852
|
+
|
|
853
|
+
${fields.join("\n")}`;
|
|
854
|
+
}
|
|
855
|
+
this.message = message;
|
|
856
|
+
return new TextEncoder().encode(message);
|
|
857
|
+
}
|
|
858
|
+
prepareAdvanced() {
|
|
859
|
+
const issuedAt = this.issuedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
860
|
+
let message = `${this.domain} wants you to sign in with your Solana account:
|
|
861
|
+
`;
|
|
862
|
+
message += `${this.address}`;
|
|
863
|
+
if (this.statement) {
|
|
864
|
+
message += `
|
|
865
|
+
|
|
866
|
+
${this.statement}`;
|
|
867
|
+
}
|
|
868
|
+
const fields = [];
|
|
869
|
+
if (this.uri) {
|
|
870
|
+
fields.push(`URI: ${this.uri}`);
|
|
871
|
+
}
|
|
872
|
+
if (this.version) {
|
|
873
|
+
fields.push(`Version: ${this.version}`);
|
|
874
|
+
}
|
|
875
|
+
if (this.chainId) {
|
|
876
|
+
fields.push(`Chain ID: ${this.chainId}`);
|
|
877
|
+
}
|
|
878
|
+
if (this.nonce) {
|
|
879
|
+
fields.push(`Nonce: ${this.nonce}`);
|
|
880
|
+
}
|
|
881
|
+
if (this.issuedAt) {
|
|
882
|
+
fields.push(`Issued At: ${this.issuedAt}`);
|
|
883
|
+
}
|
|
884
|
+
if (this.expirationTime) {
|
|
885
|
+
fields.push(`Expiration Time: ${this.expirationTime}`);
|
|
886
|
+
}
|
|
887
|
+
if (this.notBefore) {
|
|
888
|
+
fields.push(`Not Before: ${this.notBefore}`);
|
|
889
|
+
}
|
|
890
|
+
if (this.requestId) {
|
|
891
|
+
fields.push(`Request ID: ${this.requestId}`);
|
|
892
|
+
}
|
|
893
|
+
if (this.resources && this.resources.length > 0) {
|
|
894
|
+
fields.push(`Resources:`);
|
|
895
|
+
for (const resource of this.resources) {
|
|
896
|
+
fields.push(`- ${resource}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (fields.length) {
|
|
900
|
+
message += `
|
|
901
|
+
|
|
902
|
+
${fields.join("\n")}`;
|
|
903
|
+
}
|
|
904
|
+
this.message = message;
|
|
905
|
+
return new TextEncoder().encode(message);
|
|
906
|
+
}
|
|
907
|
+
async token(signature) {
|
|
908
|
+
const bs58 = await import("bs58");
|
|
909
|
+
this.signature = bs58.default.encode(signature);
|
|
910
|
+
const tokenData = Buffer.from(JSON.stringify(this));
|
|
911
|
+
return tokenData.toString("base64");
|
|
912
|
+
}
|
|
913
|
+
decode(token) {
|
|
914
|
+
const tokenObject = Buffer.from(token, "base64");
|
|
915
|
+
const siwsMessage = JSON.parse(tokenObject.toString("utf8"));
|
|
916
|
+
this.nonce = siwsMessage.nonce;
|
|
917
|
+
this.domain = siwsMessage.domain;
|
|
918
|
+
this.address = siwsMessage.address;
|
|
919
|
+
this.uri = siwsMessage.uri;
|
|
920
|
+
this.version = siwsMessage.version;
|
|
921
|
+
this.chainId = siwsMessage.chainId;
|
|
922
|
+
this.statement = siwsMessage.statement;
|
|
923
|
+
this.issuedAt = siwsMessage.issuedAt;
|
|
924
|
+
this.expirationTime = siwsMessage.expirationTime;
|
|
925
|
+
this.notBefore = siwsMessage.notBefore;
|
|
926
|
+
this.requestId = siwsMessage.requestId;
|
|
927
|
+
this.resources = siwsMessage.resources;
|
|
928
|
+
this.signature = siwsMessage.signature;
|
|
929
|
+
this.message = siwsMessage.message;
|
|
930
|
+
return this;
|
|
931
|
+
}
|
|
932
|
+
async validate() {
|
|
933
|
+
if (!this.message || !this.signature) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
const bs58 = await import("bs58");
|
|
937
|
+
const messageBytes = new TextEncoder().encode(this.message);
|
|
938
|
+
const publicKeyBytes = bs58.default.decode(this.address);
|
|
939
|
+
const signatureBytes = bs58.default.decode(this.signature);
|
|
940
|
+
const result = nacl.sign.detached.verify(
|
|
941
|
+
messageBytes,
|
|
942
|
+
signatureBytes,
|
|
943
|
+
publicKeyBytes
|
|
944
|
+
);
|
|
945
|
+
return result;
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
// src/lib/solana/transaction-log-parser.ts
|
|
950
|
+
var import_web3 = require("@solana/web3.js");
|
|
951
|
+
var import_bn = __toESM(require("bn.js"));
|
|
952
|
+
var base64ToUint8Array = (base64) => {
|
|
953
|
+
const binaryString = atob(base64);
|
|
954
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
955
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
956
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
957
|
+
}
|
|
958
|
+
return bytes;
|
|
959
|
+
};
|
|
960
|
+
var SolanaTransactionParser = class {
|
|
961
|
+
constructor(logs, base64Transaction, connection, userPublicKey) {
|
|
962
|
+
this.instructions = [];
|
|
963
|
+
this.logs = logs;
|
|
964
|
+
this.connection = connection;
|
|
965
|
+
this.userPublicKey = userPublicKey;
|
|
966
|
+
if (base64Transaction) {
|
|
967
|
+
try {
|
|
968
|
+
const txBuffer = base64ToUint8Array(base64Transaction);
|
|
969
|
+
try {
|
|
970
|
+
this.transaction = import_web3.VersionedTransaction.deserialize(txBuffer);
|
|
971
|
+
} catch {
|
|
972
|
+
this.transaction = import_web3.Transaction.from(txBuffer);
|
|
973
|
+
}
|
|
974
|
+
} catch (e) {
|
|
975
|
+
console.error("Failed to deserialize transaction:", e);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
async parse() {
|
|
980
|
+
if (!this.transaction) {
|
|
981
|
+
throw new Error("No transaction provided. Pass base64 transaction string to constructor.");
|
|
982
|
+
}
|
|
983
|
+
this.instructions = [];
|
|
984
|
+
const message = this.transaction instanceof import_web3.VersionedTransaction ? this.transaction.message : this.transaction.compileMessage();
|
|
985
|
+
const accountKeys = "staticAccountKeys" in message ? message.staticAccountKeys : message.accountKeys;
|
|
986
|
+
const compiledInstructions = "compiledInstructions" in message ? message.compiledInstructions : message.instructions;
|
|
987
|
+
for (let i = 0; i < compiledInstructions.length; i++) {
|
|
988
|
+
const ix = compiledInstructions[i];
|
|
989
|
+
const programId = accountKeys[ix.programIdIndex];
|
|
990
|
+
const programIdStr = programId.toBase58();
|
|
991
|
+
const ixAccounts = ix.accountKeyIndexes.map((idx) => accountKeys[idx]);
|
|
992
|
+
const data = ix.data instanceof Uint8Array ? ix.data : new Uint8Array(ix.data);
|
|
993
|
+
await this.parseInstruction(programIdStr, data, ixAccounts, i);
|
|
994
|
+
}
|
|
995
|
+
return this.instructions;
|
|
996
|
+
}
|
|
997
|
+
async parseInstruction(programId, data, accounts, instructionIndex) {
|
|
998
|
+
switch (programId) {
|
|
999
|
+
case "ComputeBudget11111111111111111111111111111111":
|
|
1000
|
+
this.parseComputeBudget(data);
|
|
1001
|
+
break;
|
|
1002
|
+
case "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL":
|
|
1003
|
+
this.parseAssociatedToken(accounts);
|
|
1004
|
+
break;
|
|
1005
|
+
case "11111111111111111111111111111111":
|
|
1006
|
+
this.parseSystemProgram(data, accounts);
|
|
1007
|
+
break;
|
|
1008
|
+
case "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA":
|
|
1009
|
+
this.parseTokenProgram(data, accounts);
|
|
1010
|
+
break;
|
|
1011
|
+
case "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4":
|
|
1012
|
+
break;
|
|
1013
|
+
default:
|
|
1014
|
+
this.parseGenericInstruction(programId, data, accounts, instructionIndex);
|
|
1015
|
+
break;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
parseGenericInstruction(programId, data, accounts, instructionIndex) {
|
|
1019
|
+
const instructionType = data.length > 0 ? data[0] : 0;
|
|
1020
|
+
this.instructions.push({
|
|
1021
|
+
type: "Unknown",
|
|
1022
|
+
details: {
|
|
1023
|
+
programId: this.truncate(programId, 8, 4),
|
|
1024
|
+
instructionType,
|
|
1025
|
+
dataLength: data.length,
|
|
1026
|
+
rawData: data.toString("hex"),
|
|
1027
|
+
accountCount: accounts.length,
|
|
1028
|
+
accounts: accounts.map((acc) => this.truncate(acc.toBase58(), 5, 4))
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
parseComputeBudget(data) {
|
|
1033
|
+
const instructionType = data[0];
|
|
1034
|
+
this.instructions.push({
|
|
1035
|
+
type: "ComputeBudget",
|
|
1036
|
+
details: {
|
|
1037
|
+
programId: this.truncate("ComputeBudget11111111111111111111111111111111", 8, 4),
|
|
1038
|
+
data: instructionType
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
parseAssociatedToken(accounts) {
|
|
1043
|
+
const owner = accounts[2];
|
|
1044
|
+
this.instructions.push({
|
|
1045
|
+
type: "CreateTokenAccount",
|
|
1046
|
+
details: {
|
|
1047
|
+
programId: this.truncate("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", 5, 4),
|
|
1048
|
+
owner: this.truncate(owner?.toBase58() || "Unknown", 5, 4)
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
parseSystemProgram(data, accounts) {
|
|
1053
|
+
const instructionType = data.readUInt32LE(0);
|
|
1054
|
+
if (instructionType === 2) {
|
|
1055
|
+
const lamports = new import_bn.default(data.slice(4, 12), "le");
|
|
1056
|
+
const destination = accounts[1];
|
|
1057
|
+
this.instructions.push({
|
|
1058
|
+
type: "Transfer",
|
|
1059
|
+
details: {
|
|
1060
|
+
amount: this.formatSOL(lamports.toString()),
|
|
1061
|
+
destination: this.truncate(destination?.toBase58() || "Unknown", 5, 4)
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
parseTokenProgram(data, accounts) {
|
|
1067
|
+
const instructionType = data[0];
|
|
1068
|
+
if (instructionType === 17) {
|
|
1069
|
+
this.instructions.push({
|
|
1070
|
+
type: "SyncNative",
|
|
1071
|
+
details: {
|
|
1072
|
+
programId: this.truncate("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", 5, 4)
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
} else if (instructionType === 9) {
|
|
1076
|
+
const source = accounts[0];
|
|
1077
|
+
const destination = accounts[1];
|
|
1078
|
+
const owner = accounts[2];
|
|
1079
|
+
this.instructions.push({
|
|
1080
|
+
type: "CloseAccount",
|
|
1081
|
+
details: {
|
|
1082
|
+
source: this.truncate(source?.toBase58() || "Unknown", 5, 4),
|
|
1083
|
+
destination: this.truncate(destination?.toBase58() || "Unknown", 5, 4),
|
|
1084
|
+
owner: this.truncate(owner?.toBase58() || "Unknown", 5, 4)
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
parseJupiterBasic(data, accounts) {
|
|
1090
|
+
let inAmount = "Unknown";
|
|
1091
|
+
let outAmount = "Unknown";
|
|
1092
|
+
let tokenIn = "Unknown";
|
|
1093
|
+
let tokenOut = "Unknown";
|
|
1094
|
+
for (const log of this.logs) {
|
|
1095
|
+
if (log.includes("Transfer") && log.includes("lamports")) {
|
|
1096
|
+
const lamportsMatch = log.match(/(\d+)\s*lamports/);
|
|
1097
|
+
if (lamportsMatch && inAmount === "Unknown") {
|
|
1098
|
+
inAmount = this.formatSOL(lamportsMatch[1]);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (log.includes("amount:") || log.includes("Amount:")) {
|
|
1102
|
+
const amountMatch = log.match(/amount:\s*(\d+)/i);
|
|
1103
|
+
if (amountMatch) {
|
|
1104
|
+
if (inAmount === "Unknown") {
|
|
1105
|
+
inAmount = amountMatch[1];
|
|
1106
|
+
} else if (outAmount === "Unknown") {
|
|
1107
|
+
outAmount = amountMatch[1];
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (log.includes("mint:") || log.includes("Mint:") || log.includes("mint=")) {
|
|
1112
|
+
const mintMatch = log.match(/(?:mint:|Mint:|mint=)\s*([A-Za-z0-9]{32,44})/i);
|
|
1113
|
+
if (mintMatch) {
|
|
1114
|
+
const mintAddress = mintMatch[1];
|
|
1115
|
+
if (tokenIn === "Unknown") {
|
|
1116
|
+
tokenIn = this.truncate(mintAddress, 5, 4);
|
|
1117
|
+
} else if (tokenOut === "Unknown") {
|
|
1118
|
+
tokenOut = this.truncate(mintAddress, 5, 4);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (log.includes("Program return: JUP6")) {
|
|
1123
|
+
const match = log.match(/Program return: \S+ (.+)/);
|
|
1124
|
+
if (match) {
|
|
1125
|
+
try {
|
|
1126
|
+
const decoded = base64ToUint8Array(match[1]);
|
|
1127
|
+
outAmount = new import_bn.default(decoded, "le").toString();
|
|
1128
|
+
} catch (e) {
|
|
1129
|
+
console.error("Failed to decode Jupiter return:", e);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
if (tokenIn === "Unknown" || tokenOut === "Unknown") {
|
|
1135
|
+
const wsolMint = "So11111111111111111111111111111111111111112";
|
|
1136
|
+
for (const account of accounts) {
|
|
1137
|
+
try {
|
|
1138
|
+
const accountStr = account.toBase58();
|
|
1139
|
+
if (!accountStr.includes("11111111111111111111111111111111") && !accountStr.includes("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") && !accountStr.includes("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL") && !accountStr.includes("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4")) {
|
|
1140
|
+
if (tokenIn === "Unknown") {
|
|
1141
|
+
tokenIn = this.truncate(accountStr, 5, 4);
|
|
1142
|
+
} else if (tokenOut === "Unknown") {
|
|
1143
|
+
tokenOut = this.truncate(accountStr, 5, 4);
|
|
1144
|
+
break;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
} catch (e) {
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (tokenIn === "Unknown") {
|
|
1151
|
+
tokenIn = this.truncate(wsolMint, 5, 4);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
this.instructions.push({
|
|
1155
|
+
type: "JupiterSwap",
|
|
1156
|
+
details: {
|
|
1157
|
+
inAmount,
|
|
1158
|
+
outAmount,
|
|
1159
|
+
tokenIn,
|
|
1160
|
+
tokenOut
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
parseTokenAccountData(data) {
|
|
1165
|
+
try {
|
|
1166
|
+
if (data.length < 146) {
|
|
1167
|
+
throw new Error(`Invalid token account data length: ${data.length}`);
|
|
1168
|
+
}
|
|
1169
|
+
const mint = new import_web3.PublicKey(data.slice(0, 32));
|
|
1170
|
+
const owner = new import_web3.PublicKey(data.slice(32, 64));
|
|
1171
|
+
const amount = new import_bn.default(data.slice(64, 72), "le");
|
|
1172
|
+
const delegate = data.slice(72, 104).every((b) => b === 0) ? null : new import_web3.PublicKey(data.slice(72, 104));
|
|
1173
|
+
const state = data[104];
|
|
1174
|
+
const isNative = data[105] === 1;
|
|
1175
|
+
const delegatedAmount = new import_bn.default(data.slice(106, 114), "le");
|
|
1176
|
+
const closeAuthority = data.slice(114, 146).every((b) => b === 0) ? null : new import_web3.PublicKey(data.slice(114, 146));
|
|
1177
|
+
return {
|
|
1178
|
+
mint,
|
|
1179
|
+
owner,
|
|
1180
|
+
amount,
|
|
1181
|
+
delegate,
|
|
1182
|
+
state,
|
|
1183
|
+
isNative,
|
|
1184
|
+
delegatedAmount,
|
|
1185
|
+
closeAuthority
|
|
1186
|
+
};
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
console.error("Error parsing token account data:", error);
|
|
1189
|
+
throw error;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
formatTokenAmount(amount, mint) {
|
|
1193
|
+
const wsolMint = "So11111111111111111111111111111111111111112";
|
|
1194
|
+
if (mint.toBase58() === wsolMint) {
|
|
1195
|
+
return this.formatSOL(amount.toString());
|
|
1196
|
+
}
|
|
1197
|
+
return amount.toString();
|
|
1198
|
+
}
|
|
1199
|
+
formatSOL(lamports) {
|
|
1200
|
+
try {
|
|
1201
|
+
const bn = new import_bn.default(lamports);
|
|
1202
|
+
const divisor = new import_bn.default(1e9);
|
|
1203
|
+
const sol = bn.div(divisor);
|
|
1204
|
+
const remainder = bn.mod(divisor);
|
|
1205
|
+
const decStr = remainder.toString().padStart(9, "0");
|
|
1206
|
+
const trimmed = decStr.replace(/0+$/, "");
|
|
1207
|
+
if (trimmed.length === 0) {
|
|
1208
|
+
return `${sol.toString()} SOL`;
|
|
1209
|
+
}
|
|
1210
|
+
return `${sol.toString()}.${trimmed} SOL`;
|
|
1211
|
+
} catch {
|
|
1212
|
+
return `${lamports} lamports`;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
truncate(address, start = 5, end = 4) {
|
|
1216
|
+
if (!address || address.length <= start + end) return address;
|
|
1217
|
+
return `${address.slice(0, start)}...${address.slice(-end)}`;
|
|
1218
|
+
}
|
|
1219
|
+
getInstructions() {
|
|
1220
|
+
return this.instructions;
|
|
1221
|
+
}
|
|
1222
|
+
getInstructionsByType(type) {
|
|
1223
|
+
return this.instructions.filter((i) => i.type === type);
|
|
1224
|
+
}
|
|
1225
|
+
};
|
|
1226
|
+
async function getInstructionsForHTML(base64Transaction, logs, connection, userPublicKey) {
|
|
1227
|
+
const parser = new SolanaTransactionParser(logs, base64Transaction, connection, userPublicKey);
|
|
1228
|
+
const instructions = await parser.parse();
|
|
1229
|
+
return instructions.map((instruction, index) => {
|
|
1230
|
+
const details = [];
|
|
1231
|
+
switch (instruction.type) {
|
|
1232
|
+
case "ComputeBudget":
|
|
1233
|
+
details.push(
|
|
1234
|
+
{ label: "Program ID", value: instruction.details.programId },
|
|
1235
|
+
{ label: "Data", value: instruction.details.data.toString() }
|
|
1236
|
+
);
|
|
1237
|
+
return {
|
|
1238
|
+
id: `${instruction.type}-${index}`,
|
|
1239
|
+
type: instruction.type,
|
|
1240
|
+
title: "",
|
|
1241
|
+
details
|
|
1242
|
+
};
|
|
1243
|
+
case "CreateTokenAccount":
|
|
1244
|
+
details.push(
|
|
1245
|
+
{ label: "Program ID", value: instruction.details.programId },
|
|
1246
|
+
{ label: "Owner", value: instruction.details.owner }
|
|
1247
|
+
);
|
|
1248
|
+
return {
|
|
1249
|
+
id: `${instruction.type}-${index}`,
|
|
1250
|
+
type: instruction.type,
|
|
1251
|
+
title: "Create token account",
|
|
1252
|
+
details
|
|
1253
|
+
};
|
|
1254
|
+
case "Transfer":
|
|
1255
|
+
details.push(
|
|
1256
|
+
{ label: "Amount", value: instruction.details.amount },
|
|
1257
|
+
{ label: "Destination", value: instruction.details.destination }
|
|
1258
|
+
);
|
|
1259
|
+
return {
|
|
1260
|
+
id: `${instruction.type}-${index}`,
|
|
1261
|
+
type: instruction.type,
|
|
1262
|
+
title: "Transfer",
|
|
1263
|
+
details
|
|
1264
|
+
};
|
|
1265
|
+
case "SyncNative":
|
|
1266
|
+
details.push(
|
|
1267
|
+
{ label: "Program ID", value: instruction.details.programId }
|
|
1268
|
+
);
|
|
1269
|
+
return {
|
|
1270
|
+
id: `${instruction.type}-${index}`,
|
|
1271
|
+
type: instruction.type,
|
|
1272
|
+
title: "Sync native",
|
|
1273
|
+
details
|
|
1274
|
+
};
|
|
1275
|
+
case "JupiterSwap":
|
|
1276
|
+
details.push(
|
|
1277
|
+
{ label: "in amount", value: instruction.details.inAmount },
|
|
1278
|
+
{ label: "out amount", value: instruction.details.outAmount },
|
|
1279
|
+
{ label: "Token in", value: instruction.details.tokenIn },
|
|
1280
|
+
{ label: "Token out", value: instruction.details.tokenOut }
|
|
1281
|
+
);
|
|
1282
|
+
return {
|
|
1283
|
+
id: `${instruction.type}-${index}`,
|
|
1284
|
+
type: instruction.type,
|
|
1285
|
+
title: "Jupiter swap",
|
|
1286
|
+
details
|
|
1287
|
+
};
|
|
1288
|
+
case "CloseAccount":
|
|
1289
|
+
details.push(
|
|
1290
|
+
{ label: "Source", value: instruction.details.source },
|
|
1291
|
+
{ label: "Destination", value: instruction.details.destination },
|
|
1292
|
+
{ label: "Owner", value: instruction.details.owner }
|
|
1293
|
+
);
|
|
1294
|
+
return {
|
|
1295
|
+
id: `${instruction.type}-${index}`,
|
|
1296
|
+
type: instruction.type,
|
|
1297
|
+
title: "Close token account",
|
|
1298
|
+
details
|
|
1299
|
+
};
|
|
1300
|
+
case "Unknown":
|
|
1301
|
+
details.push(
|
|
1302
|
+
{ label: "Program ID", value: instruction.details.programId },
|
|
1303
|
+
{ label: "Instruction Type", value: instruction.details.instructionType.toString() },
|
|
1304
|
+
{ label: "Data Length", value: instruction.details.dataLength.toString() },
|
|
1305
|
+
{ label: "Account Count", value: instruction.details.accountCount.toString() },
|
|
1306
|
+
{ label: "Raw Data", value: instruction.details.rawData },
|
|
1307
|
+
{ label: "Accounts", value: instruction.details.accounts.join(", ") }
|
|
1308
|
+
);
|
|
1309
|
+
return {
|
|
1310
|
+
id: `${instruction.type}-${index}`,
|
|
1311
|
+
type: instruction.type,
|
|
1312
|
+
title: "Unknown instruction",
|
|
1313
|
+
details
|
|
1314
|
+
};
|
|
1315
|
+
default:
|
|
1316
|
+
return {
|
|
1317
|
+
id: `${instruction.type}-${index}`,
|
|
1318
|
+
type: instruction.type,
|
|
1319
|
+
title: instruction.type,
|
|
1320
|
+
details: Object.entries(instruction.details).map(([key, value]) => ({
|
|
1321
|
+
label: key,
|
|
1322
|
+
value: String(value)
|
|
1323
|
+
}))
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
async function getTransferInfoFromInstructions(base64Transaction, logs, solPriceUsd) {
|
|
1329
|
+
const transfers = [];
|
|
1330
|
+
try {
|
|
1331
|
+
const parser = new SolanaTransactionParser(logs, base64Transaction);
|
|
1332
|
+
const instructions = await parser.parse();
|
|
1333
|
+
for (const instruction of instructions) {
|
|
1334
|
+
if (instruction.type === "Transfer") {
|
|
1335
|
+
let usdValue;
|
|
1336
|
+
if (solPriceUsd && instruction.details.amount.includes("SOL")) {
|
|
1337
|
+
const solAmountMatch = instruction.details.amount.match(/(\d+(?:\.\d+)?)\s*SOL/);
|
|
1338
|
+
if (solAmountMatch) {
|
|
1339
|
+
const solAmount = parseFloat(solAmountMatch[1]);
|
|
1340
|
+
const usdPrice = parseFloat(solPriceUsd);
|
|
1341
|
+
const usdAmount = solAmount * usdPrice;
|
|
1342
|
+
usdValue = `$${usdAmount.toFixed(2)}`;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
transfers.push({
|
|
1346
|
+
amount: instruction.details.amount,
|
|
1347
|
+
destination: instruction.details.destination,
|
|
1348
|
+
type: "SOL",
|
|
1349
|
+
usdValue
|
|
1350
|
+
});
|
|
1351
|
+
} else if (instruction.type === "JupiterSwap") {
|
|
1352
|
+
if (instruction.details.inAmount && instruction.details.outAmount) {
|
|
1353
|
+
let usdValue;
|
|
1354
|
+
if (solPriceUsd && instruction.details.inAmount.includes("SOL")) {
|
|
1355
|
+
const solAmountMatch = instruction.details.inAmount.match(/(\d+(?:\.\d+)?)\s*SOL/);
|
|
1356
|
+
if (solAmountMatch) {
|
|
1357
|
+
const solAmount = parseFloat(solAmountMatch[1]);
|
|
1358
|
+
const usdPrice = parseFloat(solPriceUsd);
|
|
1359
|
+
const usdAmount = solAmount * usdPrice;
|
|
1360
|
+
usdValue = `$${usdAmount.toFixed(2)}`;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
transfers.push({
|
|
1364
|
+
amount: instruction.details.inAmount,
|
|
1365
|
+
destination: "Jupiter Swap",
|
|
1366
|
+
type: "SOL",
|
|
1367
|
+
usdValue
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
console.error("Error parsing instructions for transfers:", error);
|
|
1374
|
+
}
|
|
1375
|
+
return transfers;
|
|
1376
|
+
}
|
|
1377
|
+
async function getSOLTransfersFromInstructions(base64Transaction, logs, solPriceUsd) {
|
|
1378
|
+
const transfers = [];
|
|
1379
|
+
try {
|
|
1380
|
+
const parser = new SolanaTransactionParser(logs, base64Transaction);
|
|
1381
|
+
const instructions = await parser.parse();
|
|
1382
|
+
for (const instruction of instructions) {
|
|
1383
|
+
if (instruction.type === "Transfer") {
|
|
1384
|
+
const amountStr = instruction.details.amount;
|
|
1385
|
+
const lamportsMatch = amountStr.match(/(\d+(?:\.\d+)?)\s*SOL/);
|
|
1386
|
+
const lamports = lamportsMatch ? Math.floor(parseFloat(lamportsMatch[1]) * 1e9).toString() : "0";
|
|
1387
|
+
let usdValue;
|
|
1388
|
+
if (solPriceUsd && lamportsMatch) {
|
|
1389
|
+
const solAmount = parseFloat(lamportsMatch[1]);
|
|
1390
|
+
const usdPrice = parseFloat(solPriceUsd);
|
|
1391
|
+
const usdAmount = solAmount * usdPrice;
|
|
1392
|
+
usdValue = `$${usdAmount.toFixed(2)}`;
|
|
1393
|
+
}
|
|
1394
|
+
transfers.push({
|
|
1395
|
+
amount: instruction.details.amount,
|
|
1396
|
+
destination: instruction.details.destination,
|
|
1397
|
+
lamports,
|
|
1398
|
+
usdValue
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
} catch (error) {
|
|
1403
|
+
console.error("Error parsing instructions for SOL transfers:", error);
|
|
1404
|
+
}
|
|
1405
|
+
return transfers;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// src/lib/build-url.ts
|
|
1409
|
+
var buildUrl = (baseUrl, sdkConfig, enableCaptcha, captchaSitekey) => {
|
|
1410
|
+
if (!sdkConfig.publishableKey) {
|
|
1411
|
+
throw new Error("MoonKey SDK Error: Publishable Key is required");
|
|
1412
|
+
}
|
|
1413
|
+
if (!baseUrl || typeof baseUrl !== "string" || baseUrl === "null" || baseUrl === "undefined") {
|
|
1414
|
+
console.error("Invalid baseUrl:", baseUrl);
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
`MoonKey SDK Error: Invalid base URL provided: "${baseUrl}"`
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
if (typeof window === "undefined") {
|
|
1420
|
+
const params = new URLSearchParams();
|
|
1421
|
+
params.append("publishableKey", sdkConfig.publishableKey);
|
|
1422
|
+
const hideClose = sdkConfig.config?.appearance?.hideClose;
|
|
1423
|
+
if (hideClose === true) {
|
|
1424
|
+
params.append("hideClose", "true");
|
|
1425
|
+
}
|
|
1426
|
+
if (enableCaptcha) {
|
|
1427
|
+
params.append("enableCaptcha", "true");
|
|
1428
|
+
}
|
|
1429
|
+
if (captchaSitekey) {
|
|
1430
|
+
params.append("captchaSitekey", captchaSitekey);
|
|
1431
|
+
}
|
|
1432
|
+
return `${baseUrl}?${params.toString()}`;
|
|
1433
|
+
}
|
|
1434
|
+
try {
|
|
1435
|
+
const url = new URL(baseUrl);
|
|
1436
|
+
url.searchParams.append("publishableKey", sdkConfig.publishableKey);
|
|
1437
|
+
const hideClose = sdkConfig.config?.appearance?.hideClose;
|
|
1438
|
+
if (hideClose === true) {
|
|
1439
|
+
url.searchParams.append("hideClose", "true");
|
|
1440
|
+
}
|
|
1441
|
+
if (enableCaptcha) {
|
|
1442
|
+
url.searchParams.append("enableCaptcha", "true");
|
|
1443
|
+
}
|
|
1444
|
+
if (captchaSitekey) {
|
|
1445
|
+
url.searchParams.append("captchaSitekey", captchaSitekey);
|
|
1446
|
+
}
|
|
1447
|
+
return url.toString();
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
throw new Error(
|
|
1450
|
+
`MoonKey SDK Error: Invalid base URL "${baseUrl}": ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
// src/lib/constants.ts
|
|
1456
|
+
var DEFAULT_AUTH_URL = "https://iframe.moonx-dev.com";
|
|
1457
|
+
|
|
1458
|
+
// src/lib/rpc-broadcast.ts
|
|
1459
|
+
var serializeEthereumTransaction = async (transaction) => {
|
|
1460
|
+
if (typeof transaction === "string") {
|
|
1461
|
+
return transaction;
|
|
1462
|
+
}
|
|
1463
|
+
if (!transaction || typeof transaction !== "object") {
|
|
1464
|
+
throw new Error("ethereum_transaction_invalid");
|
|
1465
|
+
}
|
|
1466
|
+
const { serializeTransaction: serializeTransaction2, parseEther: parseEther3, parseGwei: parseGwei2 } = await import("viem");
|
|
1467
|
+
const toWei = (val, humanUnit) => {
|
|
1468
|
+
if (val == null || val === "") return BigInt(0);
|
|
1469
|
+
if (typeof val === "bigint") return val;
|
|
1470
|
+
if (typeof val === "number") return BigInt(val);
|
|
1471
|
+
if (typeof val === "string") {
|
|
1472
|
+
if (val.startsWith("0x")) return BigInt(val);
|
|
1473
|
+
if (val.includes(".")) {
|
|
1474
|
+
return humanUnit === "ether" ? parseEther3(val) : parseGwei2(val);
|
|
1475
|
+
}
|
|
1476
|
+
return BigInt(val);
|
|
1477
|
+
}
|
|
1478
|
+
return BigInt(val);
|
|
1479
|
+
};
|
|
1480
|
+
const formatted = {
|
|
1481
|
+
to: transaction.to,
|
|
1482
|
+
value: toWei(transaction.value, "ether"),
|
|
1483
|
+
data: transaction.data || "0x",
|
|
1484
|
+
chainId: transaction.chainId || 1,
|
|
1485
|
+
type: "eip1559",
|
|
1486
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? toWei(transaction.maxPriorityFeePerGas, "gwei") : BigInt(2e9),
|
|
1487
|
+
maxFeePerGas: transaction.maxFeePerGas ? toWei(transaction.maxFeePerGas, "gwei") : BigInt(22e9),
|
|
1488
|
+
...transaction.nonce && { nonce: Number(transaction.nonce) },
|
|
1489
|
+
...transaction.gas && { gas: BigInt(transaction.gas) }
|
|
1490
|
+
};
|
|
1491
|
+
return serializeTransaction2(formatted);
|
|
1492
|
+
};
|
|
1493
|
+
var broadcastEthereumRaw = async (rpcUrl, signedSerialized) => {
|
|
1494
|
+
const controller = new AbortController();
|
|
1495
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
1496
|
+
try {
|
|
1497
|
+
const response = await fetch(rpcUrl, {
|
|
1498
|
+
method: "POST",
|
|
1499
|
+
headers: { "Content-Type": "application/json" },
|
|
1500
|
+
body: JSON.stringify({
|
|
1501
|
+
jsonrpc: "2.0",
|
|
1502
|
+
id: 1,
|
|
1503
|
+
method: "eth_sendRawTransaction",
|
|
1504
|
+
params: [signedSerialized]
|
|
1505
|
+
}),
|
|
1506
|
+
signal: controller.signal
|
|
1507
|
+
});
|
|
1508
|
+
const result = await response.json();
|
|
1509
|
+
if (result.error) {
|
|
1510
|
+
throw new Error(result.error.message || "eth_sendRawTransaction failed");
|
|
1511
|
+
}
|
|
1512
|
+
return result.result;
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1515
|
+
throw new Error("RPC request timed out after 30 seconds");
|
|
1516
|
+
}
|
|
1517
|
+
throw error;
|
|
1518
|
+
} finally {
|
|
1519
|
+
clearTimeout(timeoutId);
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
var broadcastSolanaSigned = async (rpcUrl, signedBase58) => {
|
|
1523
|
+
const { default: bs58 } = await import("bs58");
|
|
1524
|
+
const transactionBytes = bs58.decode(signedBase58);
|
|
1525
|
+
const base64Transaction = Buffer.from(transactionBytes).toString("base64");
|
|
1526
|
+
const response = await fetch(rpcUrl, {
|
|
1527
|
+
method: "POST",
|
|
1528
|
+
headers: { "Content-Type": "application/json" },
|
|
1529
|
+
body: JSON.stringify({
|
|
1530
|
+
jsonrpc: "2.0",
|
|
1531
|
+
id: 1,
|
|
1532
|
+
method: "sendTransaction",
|
|
1533
|
+
params: [
|
|
1534
|
+
base64Transaction,
|
|
1535
|
+
{
|
|
1536
|
+
encoding: "base64",
|
|
1537
|
+
skipPreflight: false,
|
|
1538
|
+
preflightCommitment: "confirmed",
|
|
1539
|
+
maxRetries: 3
|
|
1540
|
+
}
|
|
1541
|
+
]
|
|
1542
|
+
})
|
|
1543
|
+
});
|
|
1544
|
+
const result = await response.json();
|
|
1545
|
+
if (result.error) {
|
|
1546
|
+
throw new Error(`Solana RPC error: ${result.error.message}`);
|
|
1547
|
+
}
|
|
1548
|
+
return result.result;
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// src/lib/wire-codec.ts
|
|
1552
|
+
var arrayLikeToBytes = (value) => {
|
|
1553
|
+
if (value instanceof Uint8Array) return value;
|
|
1554
|
+
if (Array.isArray(value)) return new Uint8Array(value);
|
|
1555
|
+
if (value && typeof value === "object") {
|
|
1556
|
+
const keys = Object.keys(value);
|
|
1557
|
+
if (keys.length === 0) return new Uint8Array();
|
|
1558
|
+
if (keys.every((k) => /^\d+$/.test(k))) {
|
|
1559
|
+
const len = keys.length;
|
|
1560
|
+
const out = new Uint8Array(len);
|
|
1561
|
+
for (let i = 0; i < len; i++) {
|
|
1562
|
+
out[i] = value[String(i)] ?? 0;
|
|
1563
|
+
}
|
|
1564
|
+
return out;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
throw new Error(`arrayLikeToBytes: unsupported shape (${typeof value})`);
|
|
1568
|
+
};
|
|
1569
|
+
var bs58ToBytes = async (value) => {
|
|
1570
|
+
if (value instanceof Uint8Array) return value;
|
|
1571
|
+
if (Array.isArray(value)) return new Uint8Array(value);
|
|
1572
|
+
if (typeof value === "string") {
|
|
1573
|
+
const { default: bs58 } = await import("bs58");
|
|
1574
|
+
return bs58.decode(value);
|
|
1575
|
+
}
|
|
1576
|
+
return arrayLikeToBytes(value);
|
|
1577
|
+
};
|
|
1578
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1579
|
+
0 && (module.exports = {
|
|
1580
|
+
DEFAULT_AUTH_URL,
|
|
1581
|
+
EthereumSiweMessage,
|
|
1582
|
+
SiwsMessage,
|
|
1583
|
+
SolanaTransactionParser,
|
|
1584
|
+
arrayLikeToBytes,
|
|
1585
|
+
authState,
|
|
1586
|
+
broadcastEthereumRaw,
|
|
1587
|
+
broadcastSolanaSigned,
|
|
1588
|
+
bs58ToBytes,
|
|
1589
|
+
buildUrl,
|
|
1590
|
+
clearParentAssertCache,
|
|
1591
|
+
createManualSiweMessage,
|
|
1592
|
+
estimateEvmGas,
|
|
1593
|
+
estimateEvmGasReserve,
|
|
1594
|
+
formatPasskeyLabel,
|
|
1595
|
+
fromB64url,
|
|
1596
|
+
generatePasskeyUserId,
|
|
1597
|
+
getAssertCacheTtlMs,
|
|
1598
|
+
getChainById,
|
|
1599
|
+
getDefaultChain,
|
|
1600
|
+
getEvmGasPrice,
|
|
1601
|
+
getEvmMaxPriorityFeePerGas,
|
|
1602
|
+
getEvmNonce,
|
|
1603
|
+
getInstructionsForHTML,
|
|
1604
|
+
getRpcUrl,
|
|
1605
|
+
getSOLTransfersFromInstructions,
|
|
1606
|
+
getTransferInfoFromInstructions,
|
|
1607
|
+
isChainSupported,
|
|
1608
|
+
prepareEvmSendTransaction,
|
|
1609
|
+
prepareEvmSignTransaction,
|
|
1610
|
+
readParentAssertCache,
|
|
1611
|
+
resolveEvmChain,
|
|
1612
|
+
resolvePasskeyMetadata,
|
|
1613
|
+
sanitizeUserData,
|
|
1614
|
+
serializeEthereumTransaction,
|
|
1615
|
+
setAssertCacheTtlMs,
|
|
1616
|
+
setChainRpcUrl,
|
|
1617
|
+
toB64url,
|
|
1618
|
+
validateChainConfig,
|
|
1619
|
+
verifyIdToken,
|
|
1620
|
+
withClearOnFailure,
|
|
1621
|
+
writeParentAssertCache
|
|
1622
|
+
});
|