@fastnear/api 0.0.1-rc.1
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 +76 -0
- package/dist/fastnear.cjs +35 -0
- package/dist/fastnear.ejs +35 -0
- package/dist/fastnear.js +35 -0
- package/package.json +33 -0
- package/src/crypto.js +37 -0
- package/src/index.js +8 -0
- package/src/near.js +567 -0
- package/src/transaction.js +287 -0
- package/src/utils.js +48 -0
package/src/near.js
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import Big from "big.js";
|
|
2
|
+
import { WalletAdapter } from "@fastnear/wallet-adapter";
|
|
3
|
+
import * as crypto from "./crypto";
|
|
4
|
+
import {
|
|
5
|
+
deepCopy,
|
|
6
|
+
lsGet,
|
|
7
|
+
lsSet,
|
|
8
|
+
toBase58,
|
|
9
|
+
toBase64,
|
|
10
|
+
tryParseJson,
|
|
11
|
+
} from "./utils";
|
|
12
|
+
import { sha256, signBytes } from "./crypto";
|
|
13
|
+
import {
|
|
14
|
+
serializeSignedTransaction,
|
|
15
|
+
serializeTransaction,
|
|
16
|
+
} from "./transaction";
|
|
17
|
+
|
|
18
|
+
Big.DP = 27;
|
|
19
|
+
|
|
20
|
+
// Constants
|
|
21
|
+
const MaxBlockDelayMs = 1000 * 60 * 60 * 6; // 6 hours
|
|
22
|
+
|
|
23
|
+
const DEFAULT_NETWORK_ID = "mainnet";
|
|
24
|
+
const NETWORKS = {
|
|
25
|
+
testnet: {
|
|
26
|
+
networkId: "testnet",
|
|
27
|
+
nodeUrl: "https://rpc.testnet.fastnear.com/",
|
|
28
|
+
},
|
|
29
|
+
mainnet: {
|
|
30
|
+
networkId: "mainnet",
|
|
31
|
+
nodeUrl: "https://rpc.mainnet.fastnear.com/",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// State
|
|
36
|
+
let _config = { ...NETWORKS[DEFAULT_NETWORK_ID] };
|
|
37
|
+
|
|
38
|
+
let _state;
|
|
39
|
+
{
|
|
40
|
+
const privateKey = lsGet("privateKey");
|
|
41
|
+
_state = {
|
|
42
|
+
accountId: lsGet("accountId"),
|
|
43
|
+
accessKeyContractId: lsGet("accessKeyContractId"),
|
|
44
|
+
lastWalletId: lsGet("lastWalletId"),
|
|
45
|
+
privateKey,
|
|
46
|
+
publicKey: privateKey ? crypto.publicKeyFromPrivate(privateKey) : null,
|
|
47
|
+
};
|
|
48
|
+
console.log("Initial state:", _state);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const _txHistory = {};
|
|
52
|
+
const _eventListeners = {
|
|
53
|
+
account: new Set(),
|
|
54
|
+
tx: new Set(),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function updateState(newState) {
|
|
58
|
+
const oldState = _state;
|
|
59
|
+
_state = { ..._state, ...newState };
|
|
60
|
+
lsSet("accountId", _state.accountId);
|
|
61
|
+
lsSet("privateKey", _state.privateKey);
|
|
62
|
+
lsSet("lastWalletId", _state.lastWalletId);
|
|
63
|
+
lsSet("accessKeyContractId", _state.accessKeyContractId);
|
|
64
|
+
if (
|
|
65
|
+
newState.hasOwnProperty("privateKey") &&
|
|
66
|
+
newState.privateKey !== oldState.privateKey
|
|
67
|
+
) {
|
|
68
|
+
_state.publicKey = newState.privateKey
|
|
69
|
+
? crypto.publicKeyFromPrivate(newState.privateKey)
|
|
70
|
+
: null;
|
|
71
|
+
lsSet("nonce", null);
|
|
72
|
+
}
|
|
73
|
+
if (newState.accountId !== oldState.accountId) {
|
|
74
|
+
notifyAccountListeners(newState.accountId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function updateTxHistory(txStatus) {
|
|
79
|
+
const txId = txStatus.txId;
|
|
80
|
+
_txHistory[txId] = { ...(_txHistory[txId] ?? {}), ...txStatus };
|
|
81
|
+
notifyTxListeners(_txHistory[txId]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function onAdapterStateUpdate(state) {
|
|
85
|
+
console.log("Adapter state update:", state);
|
|
86
|
+
updateState({
|
|
87
|
+
privateKey: state.privateKey,
|
|
88
|
+
accountId: state.accountId,
|
|
89
|
+
lastWalletId: state.lastWalletId,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create adapter instance
|
|
94
|
+
const _adapter = new WalletAdapter({
|
|
95
|
+
onStateUpdate: onAdapterStateUpdate,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Utils
|
|
99
|
+
function parseJsonFromBytes(bytes) {
|
|
100
|
+
try {
|
|
101
|
+
return JSON.parse(Buffer.from(bytes).toString());
|
|
102
|
+
} catch (e) {
|
|
103
|
+
try {
|
|
104
|
+
return Buffer.from(bytes);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
return bytes;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function withBlockId(params, blockId) {
|
|
112
|
+
return blockId === "final" || blockId === "optimistic"
|
|
113
|
+
? { ...params, finality: blockId }
|
|
114
|
+
: !!blockId
|
|
115
|
+
? { ...params, block_id: blockId }
|
|
116
|
+
: { ...params, finality: "optimistic" };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function queryRpc(method, params) {
|
|
120
|
+
const response = await fetch(_config.nodeUrl, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: { "Content-Type": "application/json" },
|
|
123
|
+
body: JSON.stringify({
|
|
124
|
+
jsonrpc: "2.0",
|
|
125
|
+
id: `fastnear-${Date.now()}`,
|
|
126
|
+
method,
|
|
127
|
+
params,
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const result = await response.json();
|
|
132
|
+
if (result.error) {
|
|
133
|
+
throw new Error(JSON.stringify(result.error));
|
|
134
|
+
}
|
|
135
|
+
return result.result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sendTxToRpc(signedTxBase64, waitUntil, txId) {
|
|
139
|
+
queryRpc("send_tx", {
|
|
140
|
+
signed_tx_base64: signedTxBase64,
|
|
141
|
+
wait_until: waitUntil ?? "INCLUDED",
|
|
142
|
+
})
|
|
143
|
+
.then((result) => {
|
|
144
|
+
updateTxHistory({
|
|
145
|
+
txId,
|
|
146
|
+
status: "Included",
|
|
147
|
+
});
|
|
148
|
+
queryRpc("tx", {
|
|
149
|
+
tx_hash: _txHistory[txId].txHash,
|
|
150
|
+
sender_account_id: _txHistory[txId].tx.signerId,
|
|
151
|
+
wait_until: "EXECUTED_OPTIMISTIC",
|
|
152
|
+
})
|
|
153
|
+
.then((result) => {
|
|
154
|
+
updateTxHistory({
|
|
155
|
+
txId,
|
|
156
|
+
status: "Executed",
|
|
157
|
+
result,
|
|
158
|
+
});
|
|
159
|
+
})
|
|
160
|
+
.catch((error) => {
|
|
161
|
+
updateTxHistory({
|
|
162
|
+
txId,
|
|
163
|
+
status: "ErrorAfterIncluded",
|
|
164
|
+
error: tryParseJson(error.message),
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
})
|
|
168
|
+
.catch((error) => {
|
|
169
|
+
updateTxHistory({
|
|
170
|
+
txId,
|
|
171
|
+
status: "Error",
|
|
172
|
+
error: tryParseJson(error.message),
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Event Notifiers
|
|
178
|
+
function notifyAccountListeners(accountId) {
|
|
179
|
+
_eventListeners.account.forEach((callback) => {
|
|
180
|
+
try {
|
|
181
|
+
callback(accountId);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.error(e);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function notifyTxListeners(tx) {
|
|
189
|
+
_eventListeners.tx.forEach((callback) => {
|
|
190
|
+
try {
|
|
191
|
+
callback(deepCopy(tx));
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.error(e);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function convertUnit(s, ...args) {
|
|
199
|
+
// Reconstruct raw string from template literal
|
|
200
|
+
if (Array.isArray(s)) {
|
|
201
|
+
s = s.reduce((acc, part, i) => {
|
|
202
|
+
return acc + (args[i - 1] || "") + part;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
// Convert from `100 NEAR` into yoctoNear
|
|
206
|
+
if (typeof s == "string") {
|
|
207
|
+
let match = s.match(/([0-9.,_]+)\s*([a-zA-Z]+)?/);
|
|
208
|
+
if (match) {
|
|
209
|
+
let amount = match[1].replace(/[_,]/g, "");
|
|
210
|
+
let unitPart = match[2];
|
|
211
|
+
if (unitPart) {
|
|
212
|
+
switch (unitPart.toLowerCase()) {
|
|
213
|
+
case "near":
|
|
214
|
+
return Big(amount).mul(Big(10).pow(24)).toFixed(0);
|
|
215
|
+
case "tgas":
|
|
216
|
+
return Big(amount).mul(Big(10).pow(12)).toFixed(0);
|
|
217
|
+
case "ggas":
|
|
218
|
+
return Big(amount).mul(Big(10).pow(9)).toFixed(0);
|
|
219
|
+
case "gas" || "yoctonear":
|
|
220
|
+
return Big(amount).toFixed(0);
|
|
221
|
+
default:
|
|
222
|
+
throw new Error(`Unknown unit: ${unit}`);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
return Big(amount).toFixed(0);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return Big(s).toFixed(0);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Core API Implementation
|
|
233
|
+
const api = {
|
|
234
|
+
// Context
|
|
235
|
+
get accountId() {
|
|
236
|
+
return _state.accountId;
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
get publicKey() {
|
|
240
|
+
return _state.publicKey;
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
config(newConfig) {
|
|
244
|
+
if (newConfig) {
|
|
245
|
+
if (newConfig.networkId && _config.networkId !== newConfig.networkId) {
|
|
246
|
+
throw new Error("TODO: Network ID change should handle scope");
|
|
247
|
+
}
|
|
248
|
+
_config = { ..._config, ...newConfig };
|
|
249
|
+
}
|
|
250
|
+
return _config;
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
get authStatus() {
|
|
254
|
+
if (!_state.accountId) return "SignedOut";
|
|
255
|
+
|
|
256
|
+
// Check for limited access key
|
|
257
|
+
const accessKey = _state.publicKey;
|
|
258
|
+
const contractId = _state.accessKeyContractId;
|
|
259
|
+
if (accessKey) {
|
|
260
|
+
return {
|
|
261
|
+
type: "SignedInWithLimitedAccessKey",
|
|
262
|
+
accessKey,
|
|
263
|
+
contractId,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
return "SignedIn";
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// Query Methods
|
|
270
|
+
async view({ contractId, methodName, args, argsBase64, blockId }) {
|
|
271
|
+
const encodedArgs =
|
|
272
|
+
argsBase64 || (args ? toBase64(JSON.stringify(args)) : "");
|
|
273
|
+
|
|
274
|
+
const result = await queryRpc(
|
|
275
|
+
"query",
|
|
276
|
+
withBlockId(
|
|
277
|
+
{
|
|
278
|
+
request_type: "call_function",
|
|
279
|
+
account_id: contractId,
|
|
280
|
+
method_name: methodName,
|
|
281
|
+
args_base64: encodedArgs,
|
|
282
|
+
},
|
|
283
|
+
blockId,
|
|
284
|
+
),
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
return parseJsonFromBytes(result.result);
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
async account({ accountId, blockId }) {
|
|
291
|
+
return queryRpc(
|
|
292
|
+
"query",
|
|
293
|
+
withBlockId(
|
|
294
|
+
{
|
|
295
|
+
request_type: "view_account",
|
|
296
|
+
account_id: accountId,
|
|
297
|
+
},
|
|
298
|
+
blockId,
|
|
299
|
+
),
|
|
300
|
+
);
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
async block({ blockId }) {
|
|
304
|
+
return queryRpc("block", withBlockId({}, blockId));
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
async accessKey({ accountId, publicKey, blockId }) {
|
|
308
|
+
return queryRpc(
|
|
309
|
+
"query",
|
|
310
|
+
withBlockId(
|
|
311
|
+
{
|
|
312
|
+
request_type: "view_access_key",
|
|
313
|
+
account_id: accountId,
|
|
314
|
+
public_key: publicKey,
|
|
315
|
+
},
|
|
316
|
+
blockId,
|
|
317
|
+
),
|
|
318
|
+
);
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
async tx({ txHash, accountId }) {
|
|
322
|
+
return queryRpc("tx", [txHash, accountId]);
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
localTxHistory() {
|
|
326
|
+
return [..._txHistory];
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
// Transaction Methods
|
|
330
|
+
async sendTx({ receiverId, actions, waitUntil }) {
|
|
331
|
+
if (!_state.accountId) {
|
|
332
|
+
throw new Error("Not signed in");
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (receiverId !== _state.accessKeyContractId) {
|
|
336
|
+
// _adapter.sendTransaction();
|
|
337
|
+
throw new Error("Need to use walletAdapter. Not implemented yet");
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const signerId = _state.accountId;
|
|
341
|
+
const publicKey = _state.publicKey;
|
|
342
|
+
const privateKey = _state.privateKey;
|
|
343
|
+
|
|
344
|
+
const toDoPromises = {};
|
|
345
|
+
let nonce = lsGet("nonce");
|
|
346
|
+
if (!nonce) {
|
|
347
|
+
toDoPromises.nonce = this.accessKey({
|
|
348
|
+
accountId: signerId,
|
|
349
|
+
publicKey,
|
|
350
|
+
}).then((accessKey) => {
|
|
351
|
+
lsSet("nonce", accessKey.nonce);
|
|
352
|
+
return accessKey.nonce;
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
let block = lsGet("block");
|
|
356
|
+
if (
|
|
357
|
+
!block ||
|
|
358
|
+
parseFloat(block.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs <
|
|
359
|
+
Date.now()
|
|
360
|
+
) {
|
|
361
|
+
toDoPromises.block = this.block({ blockId: "final" }).then((block) => {
|
|
362
|
+
block = {
|
|
363
|
+
header: {
|
|
364
|
+
prev_hash: block.header.prev_hash,
|
|
365
|
+
timestamp_nanosec: block.header.timestamp_nanosec,
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
lsSet("block", block);
|
|
369
|
+
return block;
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (Object.keys(toDoPromises).length > 0) {
|
|
374
|
+
let results = await Promise.all(Object.values(toDoPromises));
|
|
375
|
+
for (let i = 0; i < results.length; i++) {
|
|
376
|
+
if (Object.keys(toDoPromises)[i] === "nonce") {
|
|
377
|
+
nonce = results[i];
|
|
378
|
+
} else if (Object.keys(toDoPromises)[i] === "block") {
|
|
379
|
+
block = results[i];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const newNonce = nonce + 1;
|
|
385
|
+
lsSet("nonce", newNonce);
|
|
386
|
+
const blockHash = block.header.prev_hash;
|
|
387
|
+
|
|
388
|
+
const txId = `tx-${Date.now()}-${Math.random()}`;
|
|
389
|
+
|
|
390
|
+
const jsonTransaction = {
|
|
391
|
+
signerId,
|
|
392
|
+
publicKey,
|
|
393
|
+
nonce: newNonce,
|
|
394
|
+
receiverId,
|
|
395
|
+
blockHash,
|
|
396
|
+
actions,
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
console.log("Transaction:", jsonTransaction);
|
|
400
|
+
const transaction = serializeTransaction(jsonTransaction);
|
|
401
|
+
const txHash = toBase58(sha256(transaction));
|
|
402
|
+
const signature = crypto.signHash(txHash, privateKey);
|
|
403
|
+
const singedTransaction = serializeSignedTransaction(
|
|
404
|
+
jsonTransaction,
|
|
405
|
+
signature,
|
|
406
|
+
);
|
|
407
|
+
const signedTxBase64 = toBase64(singedTransaction);
|
|
408
|
+
|
|
409
|
+
updateTxHistory({
|
|
410
|
+
status: "Pending",
|
|
411
|
+
txId,
|
|
412
|
+
tx: deepCopy(jsonTransaction),
|
|
413
|
+
signature,
|
|
414
|
+
signedTxBase64,
|
|
415
|
+
txHash,
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
sendTxToRpc(signedTxBase64, waitUntil, txId);
|
|
419
|
+
|
|
420
|
+
return txId;
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
// Authentication Methods
|
|
424
|
+
async requestSignIn({ contractId }) {
|
|
425
|
+
updateState({
|
|
426
|
+
accessKeyContractId: contractId,
|
|
427
|
+
accountId: null,
|
|
428
|
+
privateKey: null,
|
|
429
|
+
});
|
|
430
|
+
const result = await _adapter.signIn({
|
|
431
|
+
networkId: _config.networkId,
|
|
432
|
+
contractId,
|
|
433
|
+
});
|
|
434
|
+
console.log("Sign in result:", result);
|
|
435
|
+
if (result.error) {
|
|
436
|
+
throw new Error(`Wallet error: ${result.error}`);
|
|
437
|
+
}
|
|
438
|
+
if (result.url) {
|
|
439
|
+
console.log("Redirecting to wallet:", result.url);
|
|
440
|
+
window.location.href = result.url;
|
|
441
|
+
} else if (result.accountId) {
|
|
442
|
+
updateState({
|
|
443
|
+
accountId: result.accountId,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
signOut() {
|
|
449
|
+
updateState({
|
|
450
|
+
accountId: null,
|
|
451
|
+
privateKey: null,
|
|
452
|
+
contractId: null,
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// TODO: Implement actual wallet integration
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
// Event Handlers
|
|
459
|
+
onAccount(callback) {
|
|
460
|
+
_eventListeners.account.add(callback);
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
onTx(callback) {
|
|
464
|
+
_eventListeners.tx.add(callback);
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
// Action Helpers
|
|
468
|
+
actions: {
|
|
469
|
+
functionCall: ({ methodName, gas, deposit, args, argsBase64 }) => ({
|
|
470
|
+
type: "FunctionCall",
|
|
471
|
+
methodName,
|
|
472
|
+
args,
|
|
473
|
+
argsBase64,
|
|
474
|
+
gas,
|
|
475
|
+
deposit,
|
|
476
|
+
}),
|
|
477
|
+
|
|
478
|
+
transfer: (yoctoAmount) => ({
|
|
479
|
+
type: "Transfer",
|
|
480
|
+
deposit: yoctoAmount,
|
|
481
|
+
}),
|
|
482
|
+
|
|
483
|
+
stakeNEAR: ({ amount, publicKey }) => ({
|
|
484
|
+
type: "Stake",
|
|
485
|
+
stake: amount,
|
|
486
|
+
publicKey,
|
|
487
|
+
}),
|
|
488
|
+
|
|
489
|
+
addFullAccessKey: ({ publicKey }) => ({
|
|
490
|
+
type: "AddKey",
|
|
491
|
+
publicKey: publicKey,
|
|
492
|
+
accessKey: { permission: "FullAccess" },
|
|
493
|
+
}),
|
|
494
|
+
|
|
495
|
+
addLimitedAccessKey: ({
|
|
496
|
+
publicKey,
|
|
497
|
+
allowance,
|
|
498
|
+
accountId,
|
|
499
|
+
methodNames,
|
|
500
|
+
}) => ({
|
|
501
|
+
type: "AddKey",
|
|
502
|
+
publicKey: publicKey,
|
|
503
|
+
accessKey: {
|
|
504
|
+
permission: "FunctionCall",
|
|
505
|
+
allowance,
|
|
506
|
+
receiverId: accountId,
|
|
507
|
+
methodNames,
|
|
508
|
+
},
|
|
509
|
+
}),
|
|
510
|
+
|
|
511
|
+
deleteKey: ({ publicKey }) => ({
|
|
512
|
+
type: "DeleteKey",
|
|
513
|
+
publicKey,
|
|
514
|
+
}),
|
|
515
|
+
|
|
516
|
+
deleteAccount: ({ beneficiaryId }) => ({
|
|
517
|
+
type: "DeleteAccount",
|
|
518
|
+
beneficiaryId,
|
|
519
|
+
}),
|
|
520
|
+
|
|
521
|
+
createAccount: () => ({
|
|
522
|
+
type: "CreateAccount",
|
|
523
|
+
}),
|
|
524
|
+
|
|
525
|
+
deployContract: ({ codeBase64 }) => ({
|
|
526
|
+
type: "DeployContract",
|
|
527
|
+
codeBase64,
|
|
528
|
+
}),
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// Handle wallet redirect if applicable
|
|
533
|
+
// TODO: Implement actual wallet integration
|
|
534
|
+
try {
|
|
535
|
+
const url = new URL(window.location.href);
|
|
536
|
+
const accountId = url.searchParams.get("account_id");
|
|
537
|
+
const publicKey = url.searchParams.get("public_key");
|
|
538
|
+
const errorCode = url.searchParams.get("error_code");
|
|
539
|
+
|
|
540
|
+
if (errorCode) {
|
|
541
|
+
console.error(new Error(`Wallet error: ${errorCode}`));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (accountId && publicKey) {
|
|
545
|
+
if (publicKey === _state.publicKey) {
|
|
546
|
+
updateState({
|
|
547
|
+
accountId,
|
|
548
|
+
});
|
|
549
|
+
} else {
|
|
550
|
+
console.error(
|
|
551
|
+
new Error("Public key mismatch from wallet redirect"),
|
|
552
|
+
publicKey,
|
|
553
|
+
_state.publicKey,
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Remove wallet parameters from the URL
|
|
558
|
+
url.searchParams.delete("account_id");
|
|
559
|
+
url.searchParams.delete("public_key");
|
|
560
|
+
url.searchParams.delete("error_code");
|
|
561
|
+
url.searchParams.delete("all_keys");
|
|
562
|
+
window.history.replaceState({}, "", url.toString());
|
|
563
|
+
} catch (e) {
|
|
564
|
+
console.error("Error handling wallet redirect:", e);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export { api, convertUnit };
|