-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwallet.js
More file actions
117 lines (101 loc) · 3.73 KB
/
Copy pathwallet.js
File metadata and controls
117 lines (101 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* Agent Connect — Wallet Management
*
* Simple wallet operations for AI agents:
* createWallet() -> { mnemonic, address }
* importWallet(mnemonic) -> { address }
* getBalance(mnemonic) -> { address, p2p, udvpn, funded }
*/
import {
createWallet as sdkCreateWallet,
generateWallet,
isMnemonicValid,
getBalance as sdkGetBalance,
createClient,
formatP2P,
DEFAULT_RPC,
tryWithFallback,
RPC_ENDPOINTS,
} from 'blue-js-sdk';
// ─── Constants ───────────────────────────────────────────────────────────────
/** Minimum balance (in udvpn) to consider a wallet "funded" for VPN sessions.
* 1 P2P covers gas (~0.04 P2P) + cheapest node (~0.68 P2P/GB) with margin. */
const FUNDED_THRESHOLD = 1000000; // 1.0 P2P
// ─── createWallet() ──────────────────────────────────────────────────────────
/**
* Generate a brand new Sentinel wallet.
*
* @returns {Promise<{mnemonic: string, address: string}>}
*/
export async function createWallet() {
try {
const { mnemonic, account } = await generateWallet();
return {
mnemonic,
address: account.address,
};
} catch (err) {
throw new Error(`Wallet creation failed: ${err.message}`);
}
}
// ─── importWallet() ──────────────────────────────────────────────────────────
/**
* Import an existing wallet from a BIP39 mnemonic.
* Validates the mnemonic and derives the sent1... address.
*
* @param {string} mnemonic - 12 or 24 word BIP39 phrase
* @returns {Promise<{address: string}>}
*/
export async function importWallet(mnemonic) {
if (!mnemonic || typeof mnemonic !== 'string') {
throw new Error('importWallet() requires a mnemonic string');
}
if (!isMnemonicValid(mnemonic)) {
const wordCount = mnemonic.trim().split(/\s+/).length;
throw new Error(
`Invalid mnemonic: got ${wordCount} words, need at least 12. ` +
'Must be a valid BIP39 phrase.',
);
}
try {
const { account } = await sdkCreateWallet(mnemonic);
return { address: account.address };
} catch (err) {
throw new Error(`Wallet import failed: ${err.message}`);
}
}
// ─── getBalance() ────────────────────────────────────────────────────────────
/**
* Check the P2P token balance of a wallet.
*
* @param {string} mnemonic - 12 or 24 word BIP39 phrase
* @returns {Promise<{address: string, p2p: string, udvpn: number, funded: boolean}>}
*/
export async function getBalance(mnemonic) {
if (!mnemonic || typeof mnemonic !== 'string') {
throw new Error('getBalance() requires a mnemonic string');
}
if (!isMnemonicValid(mnemonic)) {
throw new Error('Invalid mnemonic. Must be a 12 or 24 word BIP39 phrase.');
}
try {
// Create wallet to get address
const { wallet, account } = await sdkCreateWallet(mnemonic);
// Connect to RPC with fallback
const { result: client } = await tryWithFallback(
RPC_ENDPOINTS,
async (url) => createClient(url, wallet),
'RPC connect (balance check)',
);
// Query balance
const bal = await sdkGetBalance(client, account.address);
return {
address: account.address,
p2p: formatP2P(bal.udvpn),
udvpn: bal.udvpn,
funded: bal.udvpn >= FUNDED_THRESHOLD,
};
} catch (err) {
throw new Error(`Balance check failed: ${err.message}`);
}
}