@getpara/core-sdk 2.19.0 → 2.20.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/cjs/ParaCore.js +18 -0
- package/dist/cjs/constants.js +1 -1
- package/dist/cjs/services/PregenWalletService.js +4 -2
- package/dist/cjs/services/WalletService.js +8 -3
- package/dist/cjs/shares/enclave.js +41 -0
- package/dist/cjs/utils/formatting.js +94 -0
- package/dist/cjs/utils/wallet.js +2 -1
- package/dist/esm/ParaCore.js +18 -0
- package/dist/esm/constants.js +1 -1
- package/dist/esm/services/PregenWalletService.js +4 -2
- package/dist/esm/services/WalletService.js +15 -4
- package/dist/esm/shares/enclave.js +41 -0
- package/dist/esm/utils/formatting.js +92 -0
- package/dist/esm/utils/wallet.js +2 -1
- package/dist/types/ParaCore.d.ts +11 -1
- package/dist/types/PlatformUtils.d.ts +2 -2
- package/dist/types/shares/enclave.d.ts +12 -0
- package/dist/types/utils/formatting.d.ts +2 -0
- package/package.json +3 -3
package/dist/cjs/ParaCore.js
CHANGED
|
@@ -2096,6 +2096,24 @@ const _ParaCore = class _ParaCore {
|
|
|
2096
2096
|
return yield __privateGet(this, _walletService).setUserShare(base64Wallets);
|
|
2097
2097
|
});
|
|
2098
2098
|
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Migrate a wallet share to the enclave. The share is ECIES-encrypted before
|
|
2101
|
+
* being sent so the plaintext never leaves the caller's process.
|
|
2102
|
+
*/
|
|
2103
|
+
migrateWalletShare(opts) {
|
|
2104
|
+
return __async(this, null, function* () {
|
|
2105
|
+
if (!this.ctx.enclaveClient) {
|
|
2106
|
+
throw new Error("Enclave client not initialized");
|
|
2107
|
+
}
|
|
2108
|
+
const scheme = opts.walletScheme || "DKLS";
|
|
2109
|
+
return this.ctx.enclaveClient.migrateShare({
|
|
2110
|
+
walletId: opts.walletId,
|
|
2111
|
+
userShare: opts.userShare,
|
|
2112
|
+
walletScheme: scheme,
|
|
2113
|
+
secretApiKey: opts.secretApiKey
|
|
2114
|
+
});
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2099
2117
|
getTransactionReviewUrl(transactionId, timeoutMs) {
|
|
2100
2118
|
return __async(this, null, function* () {
|
|
2101
2119
|
const authMethods = yield this.supportedUserAuthMethods();
|
package/dist/cjs/constants.js
CHANGED
|
@@ -46,7 +46,7 @@ __export(constants_exports, {
|
|
|
46
46
|
TRANSACTION_REVIEW_TIMEOUT_MS: () => TRANSACTION_REVIEW_TIMEOUT_MS
|
|
47
47
|
});
|
|
48
48
|
module.exports = __toCommonJS(constants_exports);
|
|
49
|
-
const PARA_CORE_VERSION = "2.
|
|
49
|
+
const PARA_CORE_VERSION = "2.20.0";
|
|
50
50
|
const PREFIX = "@CAPSULE/";
|
|
51
51
|
const PARA_PREFIX = "@PARA/";
|
|
52
52
|
const LOCAL_STORAGE_AUTH_INFO = `${PREFIX}authInfo`;
|
|
@@ -268,12 +268,14 @@ class PregenWalletService {
|
|
|
268
268
|
const [pregenIdentifierType, pregenIdentifier] = (0, import_user_management_client.toPregenTypeAndId)(pregenId);
|
|
269
269
|
let keygenRes;
|
|
270
270
|
switch (walletType) {
|
|
271
|
+
case "STELLAR":
|
|
271
272
|
case "SOLANA":
|
|
272
273
|
keygenRes = yield __privateGet(this, _paraCoreInterface).platformUtils.ed25519PreKeygen(
|
|
273
274
|
__privateGet(this, _paraCoreInterface).ctx,
|
|
274
275
|
pregenIdentifier,
|
|
275
276
|
pregenIdentifierType,
|
|
276
|
-
__privateGet(this, _paraCoreInterface).retrieveSessionCookie()
|
|
277
|
+
__privateGet(this, _paraCoreInterface).retrieveSessionCookie(),
|
|
278
|
+
walletType
|
|
277
279
|
);
|
|
278
280
|
break;
|
|
279
281
|
default:
|
|
@@ -292,7 +294,7 @@ class PregenWalletService {
|
|
|
292
294
|
__privateGet(this, _walletService).wallets[walletId] = {
|
|
293
295
|
id: walletId,
|
|
294
296
|
signer,
|
|
295
|
-
scheme: walletType === "SOLANA" ? "ED25519" : "DKLS",
|
|
297
|
+
scheme: walletType === "SOLANA" || walletType === "STELLAR" ? "ED25519" : "DKLS",
|
|
296
298
|
type: walletType,
|
|
297
299
|
isPregen: true,
|
|
298
300
|
pregenIdentifier,
|
|
@@ -158,7 +158,7 @@ class WalletService {
|
|
|
158
158
|
return (0, import_wallet2.getSchemes)(types != null ? types : yield __privateGet(this, _getMissingTypes).call(this)).map((scheme) => {
|
|
159
159
|
switch (scheme) {
|
|
160
160
|
case "ED25519":
|
|
161
|
-
return "SOLANA";
|
|
161
|
+
return supportedWalletTypes.some(({ type, optional }) => type === "STELLAR" && !optional) ? "STELLAR" : "SOLANA";
|
|
162
162
|
default:
|
|
163
163
|
return supportedWalletTypes.some(({ type, optional }) => type === "COSMOS" && !optional) ? "COSMOS" : "EVM";
|
|
164
164
|
}
|
|
@@ -210,12 +210,14 @@ class WalletService {
|
|
|
210
210
|
let wallet;
|
|
211
211
|
let keygenRes;
|
|
212
212
|
switch (walletType) {
|
|
213
|
+
case "STELLAR":
|
|
213
214
|
case "SOLANA": {
|
|
214
215
|
keygenRes = yield __privateGet(this, _paraCoreInterface).platformUtils.ed25519Keygen(
|
|
215
216
|
__privateGet(this, _paraCoreInterface).ctx,
|
|
216
217
|
__privateGet(this, _authService).userId,
|
|
217
218
|
__privateGet(this, _paraCoreInterface).retrieveSessionCookie(),
|
|
218
|
-
__privateGet(this, _paraCoreInterface).getBackupKitEmailProps()
|
|
219
|
+
__privateGet(this, _paraCoreInterface).getBackupKitEmailProps(),
|
|
220
|
+
walletType
|
|
219
221
|
);
|
|
220
222
|
break;
|
|
221
223
|
}
|
|
@@ -232,7 +234,7 @@ class WalletService {
|
|
|
232
234
|
}
|
|
233
235
|
}
|
|
234
236
|
const walletId = keygenRes.walletId;
|
|
235
|
-
const walletScheme = walletType === "SOLANA" ? "ED25519" : "DKLS";
|
|
237
|
+
const walletScheme = walletType === "SOLANA" || walletType === "STELLAR" ? "ED25519" : "DKLS";
|
|
236
238
|
signer = keygenRes.signer;
|
|
237
239
|
yield __privateGet(this, _pollingService).poll({
|
|
238
240
|
checkCondition: __privateGet(this, _pollingService).waitForWalletAddress({ walletId }),
|
|
@@ -366,6 +368,9 @@ class WalletService {
|
|
|
366
368
|
prefix = (_b = (_a = options.cosmosPrefix) != null ? _a : __privateGet(this, _paraCoreInterface).cosmosPrefix) != null ? _b : "cosmos";
|
|
367
369
|
str = (0, import_utils.getCosmosAddress)(wallet.publicKey, prefix);
|
|
368
370
|
break;
|
|
371
|
+
case "STELLAR":
|
|
372
|
+
str = wallet.publicKey ? (0, import_utils.getStellarAddress)(wallet.publicKey) : (0, import_utils.getStellarAddressFromSolana)(wallet.address);
|
|
373
|
+
break;
|
|
369
374
|
default:
|
|
370
375
|
prefix = __privateGet(this, _paraCoreInterface).cosmosPrefix;
|
|
371
376
|
str = wallet.address;
|
|
@@ -300,6 +300,47 @@ ${exportedAsBase64}
|
|
|
300
300
|
}
|
|
301
301
|
});
|
|
302
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Migrate a wallet share by encrypting it with the enclave's public key and
|
|
305
|
+
* sending the encrypted payload to the backend. The plaintext share never
|
|
306
|
+
* leaves the caller's process.
|
|
307
|
+
*/
|
|
308
|
+
migrateShare(opts) {
|
|
309
|
+
return __async(this, null, function* () {
|
|
310
|
+
const { walletId, userShare, walletScheme, secretApiKey } = opts;
|
|
311
|
+
try {
|
|
312
|
+
const signer = this.extractSignerFromUserShare(userShare, walletId);
|
|
313
|
+
const shareData = {
|
|
314
|
+
// The enclave requires a non-empty userId but pregen wallets may not have one.
|
|
315
|
+
// We use walletId as a placeholder — the signing flow never reads this field.
|
|
316
|
+
userId: walletId,
|
|
317
|
+
walletId,
|
|
318
|
+
walletScheme,
|
|
319
|
+
signer
|
|
320
|
+
};
|
|
321
|
+
const encryptedPayload = yield this.encryptForEnclave(JSON.stringify({ shares: [shareData] }));
|
|
322
|
+
return this.userManagementClient.migrateWalletShare(walletId, JSON.stringify(encryptedPayload), secretApiKey);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`Failed to migrate share for wallet ${walletId}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
extractSignerFromUserShare(userShare, walletId) {
|
|
331
|
+
const walletSegments = userShare.split("-");
|
|
332
|
+
for (const segment of walletSegments) {
|
|
333
|
+
try {
|
|
334
|
+
const decoded = JSON.parse(Buffer.from(segment, "base64").toString("utf-8"));
|
|
335
|
+
if (decoded.id === walletId && decoded.signer) {
|
|
336
|
+
return decoded.signer;
|
|
337
|
+
}
|
|
338
|
+
} catch (e) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
throw new Error(`No wallet with id ${walletId} found in the provided userShare`);
|
|
343
|
+
}
|
|
303
344
|
persistSharesWithRetry(shares) {
|
|
304
345
|
return __async(this, null, function* () {
|
|
305
346
|
return yield this.persistShares(shares);
|
|
@@ -30,6 +30,8 @@ __export(formatting_exports, {
|
|
|
30
30
|
compressPubkey: () => compressPubkey,
|
|
31
31
|
decimalToHex: () => decimalToHex,
|
|
32
32
|
getCosmosAddress: () => getCosmosAddress,
|
|
33
|
+
getStellarAddress: () => getStellarAddress,
|
|
34
|
+
getStellarAddressFromSolana: () => getStellarAddressFromSolana,
|
|
33
35
|
hexStringToBase64: () => hexStringToBase64,
|
|
34
36
|
hexToDecimal: () => hexToDecimal,
|
|
35
37
|
hexToSignature: () => hexToSignature,
|
|
@@ -87,6 +89,96 @@ function rawSecp256k1PubkeyToRawAddress(pubkeyData) {
|
|
|
87
89
|
}
|
|
88
90
|
return (0, import_ripemd160.ripemd160)((0, import_sha256.sha256)(pubkeyData));
|
|
89
91
|
}
|
|
92
|
+
const BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
93
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
94
|
+
const BASE58_MAP = {};
|
|
95
|
+
for (let i = 0; i < BASE58_ALPHABET.length; i++) BASE58_MAP[BASE58_ALPHABET[i]] = i;
|
|
96
|
+
const STELLAR_ED25519_VERSION_BYTE = 6 << 3;
|
|
97
|
+
function crc16xmodem(data) {
|
|
98
|
+
let crc = 0;
|
|
99
|
+
for (const byte of data) {
|
|
100
|
+
crc ^= byte << 8;
|
|
101
|
+
for (let j = 0; j < 8; j++) {
|
|
102
|
+
crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
|
|
103
|
+
crc &= 65535;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return crc;
|
|
107
|
+
}
|
|
108
|
+
function base32Encode(data) {
|
|
109
|
+
let result = "";
|
|
110
|
+
let bits = 0;
|
|
111
|
+
let value = 0;
|
|
112
|
+
for (const byte of data) {
|
|
113
|
+
value = value << 8 | byte;
|
|
114
|
+
bits += 8;
|
|
115
|
+
while (bits >= 5) {
|
|
116
|
+
result += BASE32_ALPHABET[value >>> bits - 5 & 31];
|
|
117
|
+
bits -= 5;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (bits > 0) {
|
|
121
|
+
result += BASE32_ALPHABET[value << 5 - bits & 31];
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
function base58Decode(str) {
|
|
126
|
+
const bytes = [0];
|
|
127
|
+
for (const char of str) {
|
|
128
|
+
let carry = BASE58_MAP[char];
|
|
129
|
+
if (carry === void 0) {
|
|
130
|
+
throw new Error(`Invalid base58 character: ${char}`);
|
|
131
|
+
}
|
|
132
|
+
for (let j = 0; j < bytes.length; j++) {
|
|
133
|
+
carry += bytes[j] * 58;
|
|
134
|
+
bytes[j] = carry & 255;
|
|
135
|
+
carry >>= 8;
|
|
136
|
+
}
|
|
137
|
+
while (carry > 0) {
|
|
138
|
+
bytes.push(carry & 255);
|
|
139
|
+
carry >>= 8;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
let leadingZeros = 0;
|
|
143
|
+
for (const char of str) {
|
|
144
|
+
if (char !== "1") break;
|
|
145
|
+
leadingZeros++;
|
|
146
|
+
}
|
|
147
|
+
let sigBytes = bytes.length;
|
|
148
|
+
while (sigBytes > 0 && bytes[sigBytes - 1] === 0) sigBytes--;
|
|
149
|
+
const result = new Uint8Array(leadingZeros + sigBytes);
|
|
150
|
+
for (let i = 0; i < sigBytes; i++) {
|
|
151
|
+
result[leadingZeros + sigBytes - 1 - i] = bytes[i];
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
function encodeEd25519PublicKey(pubKeyBytes) {
|
|
156
|
+
if (pubKeyBytes.length !== 32) {
|
|
157
|
+
throw new Error(`Invalid Ed25519 public key length: expected 32 bytes, got ${pubKeyBytes.length}`);
|
|
158
|
+
}
|
|
159
|
+
const payload = new Uint8Array(1 + pubKeyBytes.length);
|
|
160
|
+
payload[0] = STELLAR_ED25519_VERSION_BYTE;
|
|
161
|
+
payload.set(pubKeyBytes, 1);
|
|
162
|
+
const checksum = crc16xmodem(payload);
|
|
163
|
+
const full = new Uint8Array(payload.length + 2);
|
|
164
|
+
full.set(payload);
|
|
165
|
+
full[payload.length] = checksum & 255;
|
|
166
|
+
full[payload.length + 1] = checksum >> 8 & 255;
|
|
167
|
+
return base32Encode(full);
|
|
168
|
+
}
|
|
169
|
+
function getStellarAddress(publicKey) {
|
|
170
|
+
if (!publicKey || publicKey.length === 0) {
|
|
171
|
+
return "";
|
|
172
|
+
}
|
|
173
|
+
const pubKeyBytes = Buffer.from(publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey, "hex");
|
|
174
|
+
return encodeEd25519PublicKey(pubKeyBytes);
|
|
175
|
+
}
|
|
176
|
+
function getStellarAddressFromSolana(solanaAddress) {
|
|
177
|
+
if (!solanaAddress || solanaAddress.length === 0) {
|
|
178
|
+
return "";
|
|
179
|
+
}
|
|
180
|
+
return encodeEd25519PublicKey(base58Decode(solanaAddress));
|
|
181
|
+
}
|
|
90
182
|
function getCosmosAddress(publicKey, prefix) {
|
|
91
183
|
if (!publicKey || publicKey.length === 0) {
|
|
92
184
|
return "";
|
|
@@ -113,6 +205,8 @@ function truncateAddress(str, addressType, {
|
|
|
113
205
|
compressPubkey,
|
|
114
206
|
decimalToHex,
|
|
115
207
|
getCosmosAddress,
|
|
208
|
+
getStellarAddress,
|
|
209
|
+
getStellarAddressFromSolana,
|
|
116
210
|
hexStringToBase64,
|
|
117
211
|
hexToDecimal,
|
|
118
212
|
hexToSignature,
|
package/dist/cjs/utils/wallet.js
CHANGED
package/dist/esm/ParaCore.js
CHANGED
|
@@ -2038,6 +2038,24 @@ const _ParaCore = class _ParaCore {
|
|
|
2038
2038
|
return yield __privateGet(this, _walletService).setUserShare(base64Wallets);
|
|
2039
2039
|
});
|
|
2040
2040
|
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Migrate a wallet share to the enclave. The share is ECIES-encrypted before
|
|
2043
|
+
* being sent so the plaintext never leaves the caller's process.
|
|
2044
|
+
*/
|
|
2045
|
+
migrateWalletShare(opts) {
|
|
2046
|
+
return __async(this, null, function* () {
|
|
2047
|
+
if (!this.ctx.enclaveClient) {
|
|
2048
|
+
throw new Error("Enclave client not initialized");
|
|
2049
|
+
}
|
|
2050
|
+
const scheme = opts.walletScheme || "DKLS";
|
|
2051
|
+
return this.ctx.enclaveClient.migrateShare({
|
|
2052
|
+
walletId: opts.walletId,
|
|
2053
|
+
userShare: opts.userShare,
|
|
2054
|
+
walletScheme: scheme,
|
|
2055
|
+
secretApiKey: opts.secretApiKey
|
|
2056
|
+
});
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2041
2059
|
getTransactionReviewUrl(transactionId, timeoutMs) {
|
|
2042
2060
|
return __async(this, null, function* () {
|
|
2043
2061
|
const authMethods = yield this.supportedUserAuthMethods();
|
package/dist/esm/constants.js
CHANGED
|
@@ -220,12 +220,14 @@ class PregenWalletService {
|
|
|
220
220
|
const [pregenIdentifierType, pregenIdentifier] = toPregenTypeAndId(pregenId);
|
|
221
221
|
let keygenRes;
|
|
222
222
|
switch (walletType) {
|
|
223
|
+
case "STELLAR":
|
|
223
224
|
case "SOLANA":
|
|
224
225
|
keygenRes = yield __privateGet(this, _paraCoreInterface).platformUtils.ed25519PreKeygen(
|
|
225
226
|
__privateGet(this, _paraCoreInterface).ctx,
|
|
226
227
|
pregenIdentifier,
|
|
227
228
|
pregenIdentifierType,
|
|
228
|
-
__privateGet(this, _paraCoreInterface).retrieveSessionCookie()
|
|
229
|
+
__privateGet(this, _paraCoreInterface).retrieveSessionCookie(),
|
|
230
|
+
walletType
|
|
229
231
|
);
|
|
230
232
|
break;
|
|
231
233
|
default:
|
|
@@ -244,7 +246,7 @@ class PregenWalletService {
|
|
|
244
246
|
__privateGet(this, _walletService).wallets[walletId] = {
|
|
245
247
|
id: walletId,
|
|
246
248
|
signer,
|
|
247
|
-
scheme: walletType === "SOLANA" ? "ED25519" : "DKLS",
|
|
249
|
+
scheme: walletType === "SOLANA" || walletType === "STELLAR" ? "ED25519" : "DKLS",
|
|
248
250
|
type: walletType,
|
|
249
251
|
isPregen: true,
|
|
250
252
|
pregenIdentifier,
|
|
@@ -17,7 +17,13 @@ import {
|
|
|
17
17
|
migrateWallet,
|
|
18
18
|
WalletSchemeTypeMap
|
|
19
19
|
} from "../utils/wallet.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
dispatchEvent,
|
|
22
|
+
getCosmosAddress,
|
|
23
|
+
getStellarAddress,
|
|
24
|
+
getStellarAddressFromSolana,
|
|
25
|
+
truncateAddress
|
|
26
|
+
} from "../utils/index.js";
|
|
21
27
|
import { ParaEvent } from "../types/events.js";
|
|
22
28
|
import { LOCAL_STORAGE_CURRENT_WALLET_IDS, LOCAL_STORAGE_WALLETS, SHORT_POLLING_INTERVAL_MS } from "../constants.js";
|
|
23
29
|
import { distributeNewShare } from "../shares/shareDistribution.js";
|
|
@@ -96,7 +102,7 @@ class WalletService {
|
|
|
96
102
|
return getSchemes(types != null ? types : yield __privateGet(this, _getMissingTypes).call(this)).map((scheme) => {
|
|
97
103
|
switch (scheme) {
|
|
98
104
|
case "ED25519":
|
|
99
|
-
return "SOLANA";
|
|
105
|
+
return supportedWalletTypes.some(({ type, optional }) => type === "STELLAR" && !optional) ? "STELLAR" : "SOLANA";
|
|
100
106
|
default:
|
|
101
107
|
return supportedWalletTypes.some(({ type, optional }) => type === "COSMOS" && !optional) ? "COSMOS" : "EVM";
|
|
102
108
|
}
|
|
@@ -148,12 +154,14 @@ class WalletService {
|
|
|
148
154
|
let wallet;
|
|
149
155
|
let keygenRes;
|
|
150
156
|
switch (walletType) {
|
|
157
|
+
case "STELLAR":
|
|
151
158
|
case "SOLANA": {
|
|
152
159
|
keygenRes = yield __privateGet(this, _paraCoreInterface).platformUtils.ed25519Keygen(
|
|
153
160
|
__privateGet(this, _paraCoreInterface).ctx,
|
|
154
161
|
__privateGet(this, _authService).userId,
|
|
155
162
|
__privateGet(this, _paraCoreInterface).retrieveSessionCookie(),
|
|
156
|
-
__privateGet(this, _paraCoreInterface).getBackupKitEmailProps()
|
|
163
|
+
__privateGet(this, _paraCoreInterface).getBackupKitEmailProps(),
|
|
164
|
+
walletType
|
|
157
165
|
);
|
|
158
166
|
break;
|
|
159
167
|
}
|
|
@@ -170,7 +178,7 @@ class WalletService {
|
|
|
170
178
|
}
|
|
171
179
|
}
|
|
172
180
|
const walletId = keygenRes.walletId;
|
|
173
|
-
const walletScheme = walletType === "SOLANA" ? "ED25519" : "DKLS";
|
|
181
|
+
const walletScheme = walletType === "SOLANA" || walletType === "STELLAR" ? "ED25519" : "DKLS";
|
|
174
182
|
signer = keygenRes.signer;
|
|
175
183
|
yield __privateGet(this, _pollingService).poll({
|
|
176
184
|
checkCondition: __privateGet(this, _pollingService).waitForWalletAddress({ walletId }),
|
|
@@ -304,6 +312,9 @@ class WalletService {
|
|
|
304
312
|
prefix = (_b = (_a = options.cosmosPrefix) != null ? _a : __privateGet(this, _paraCoreInterface).cosmosPrefix) != null ? _b : "cosmos";
|
|
305
313
|
str = getCosmosAddress(wallet.publicKey, prefix);
|
|
306
314
|
break;
|
|
315
|
+
case "STELLAR":
|
|
316
|
+
str = wallet.publicKey ? getStellarAddress(wallet.publicKey) : getStellarAddressFromSolana(wallet.address);
|
|
317
|
+
break;
|
|
307
318
|
default:
|
|
308
319
|
prefix = __privateGet(this, _paraCoreInterface).cosmosPrefix;
|
|
309
320
|
str = wallet.address;
|
|
@@ -261,6 +261,47 @@ ${exportedAsBase64}
|
|
|
261
261
|
}
|
|
262
262
|
});
|
|
263
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Migrate a wallet share by encrypting it with the enclave's public key and
|
|
266
|
+
* sending the encrypted payload to the backend. The plaintext share never
|
|
267
|
+
* leaves the caller's process.
|
|
268
|
+
*/
|
|
269
|
+
migrateShare(opts) {
|
|
270
|
+
return __async(this, null, function* () {
|
|
271
|
+
const { walletId, userShare, walletScheme, secretApiKey } = opts;
|
|
272
|
+
try {
|
|
273
|
+
const signer = this.extractSignerFromUserShare(userShare, walletId);
|
|
274
|
+
const shareData = {
|
|
275
|
+
// The enclave requires a non-empty userId but pregen wallets may not have one.
|
|
276
|
+
// We use walletId as a placeholder — the signing flow never reads this field.
|
|
277
|
+
userId: walletId,
|
|
278
|
+
walletId,
|
|
279
|
+
walletScheme,
|
|
280
|
+
signer
|
|
281
|
+
};
|
|
282
|
+
const encryptedPayload = yield this.encryptForEnclave(JSON.stringify({ shares: [shareData] }));
|
|
283
|
+
return this.userManagementClient.migrateWalletShare(walletId, JSON.stringify(encryptedPayload), secretApiKey);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`Failed to migrate share for wallet ${walletId}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
extractSignerFromUserShare(userShare, walletId) {
|
|
292
|
+
const walletSegments = userShare.split("-");
|
|
293
|
+
for (const segment of walletSegments) {
|
|
294
|
+
try {
|
|
295
|
+
const decoded = JSON.parse(Buffer.from(segment, "base64").toString("utf-8"));
|
|
296
|
+
if (decoded.id === walletId && decoded.signer) {
|
|
297
|
+
return decoded.signer;
|
|
298
|
+
}
|
|
299
|
+
} catch (e) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
throw new Error(`No wallet with id ${walletId} found in the provided userShare`);
|
|
304
|
+
}
|
|
264
305
|
persistSharesWithRetry(shares) {
|
|
265
306
|
return __async(this, null, function* () {
|
|
266
307
|
return yield this.persistShares(shares);
|
|
@@ -48,6 +48,96 @@ function rawSecp256k1PubkeyToRawAddress(pubkeyData) {
|
|
|
48
48
|
}
|
|
49
49
|
return ripemd160(sha256(pubkeyData));
|
|
50
50
|
}
|
|
51
|
+
const BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
52
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
53
|
+
const BASE58_MAP = {};
|
|
54
|
+
for (let i = 0; i < BASE58_ALPHABET.length; i++) BASE58_MAP[BASE58_ALPHABET[i]] = i;
|
|
55
|
+
const STELLAR_ED25519_VERSION_BYTE = 6 << 3;
|
|
56
|
+
function crc16xmodem(data) {
|
|
57
|
+
let crc = 0;
|
|
58
|
+
for (const byte of data) {
|
|
59
|
+
crc ^= byte << 8;
|
|
60
|
+
for (let j = 0; j < 8; j++) {
|
|
61
|
+
crc = crc & 32768 ? crc << 1 ^ 4129 : crc << 1;
|
|
62
|
+
crc &= 65535;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return crc;
|
|
66
|
+
}
|
|
67
|
+
function base32Encode(data) {
|
|
68
|
+
let result = "";
|
|
69
|
+
let bits = 0;
|
|
70
|
+
let value = 0;
|
|
71
|
+
for (const byte of data) {
|
|
72
|
+
value = value << 8 | byte;
|
|
73
|
+
bits += 8;
|
|
74
|
+
while (bits >= 5) {
|
|
75
|
+
result += BASE32_ALPHABET[value >>> bits - 5 & 31];
|
|
76
|
+
bits -= 5;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (bits > 0) {
|
|
80
|
+
result += BASE32_ALPHABET[value << 5 - bits & 31];
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
function base58Decode(str) {
|
|
85
|
+
const bytes = [0];
|
|
86
|
+
for (const char of str) {
|
|
87
|
+
let carry = BASE58_MAP[char];
|
|
88
|
+
if (carry === void 0) {
|
|
89
|
+
throw new Error(`Invalid base58 character: ${char}`);
|
|
90
|
+
}
|
|
91
|
+
for (let j = 0; j < bytes.length; j++) {
|
|
92
|
+
carry += bytes[j] * 58;
|
|
93
|
+
bytes[j] = carry & 255;
|
|
94
|
+
carry >>= 8;
|
|
95
|
+
}
|
|
96
|
+
while (carry > 0) {
|
|
97
|
+
bytes.push(carry & 255);
|
|
98
|
+
carry >>= 8;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let leadingZeros = 0;
|
|
102
|
+
for (const char of str) {
|
|
103
|
+
if (char !== "1") break;
|
|
104
|
+
leadingZeros++;
|
|
105
|
+
}
|
|
106
|
+
let sigBytes = bytes.length;
|
|
107
|
+
while (sigBytes > 0 && bytes[sigBytes - 1] === 0) sigBytes--;
|
|
108
|
+
const result = new Uint8Array(leadingZeros + sigBytes);
|
|
109
|
+
for (let i = 0; i < sigBytes; i++) {
|
|
110
|
+
result[leadingZeros + sigBytes - 1 - i] = bytes[i];
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
function encodeEd25519PublicKey(pubKeyBytes) {
|
|
115
|
+
if (pubKeyBytes.length !== 32) {
|
|
116
|
+
throw new Error(`Invalid Ed25519 public key length: expected 32 bytes, got ${pubKeyBytes.length}`);
|
|
117
|
+
}
|
|
118
|
+
const payload = new Uint8Array(1 + pubKeyBytes.length);
|
|
119
|
+
payload[0] = STELLAR_ED25519_VERSION_BYTE;
|
|
120
|
+
payload.set(pubKeyBytes, 1);
|
|
121
|
+
const checksum = crc16xmodem(payload);
|
|
122
|
+
const full = new Uint8Array(payload.length + 2);
|
|
123
|
+
full.set(payload);
|
|
124
|
+
full[payload.length] = checksum & 255;
|
|
125
|
+
full[payload.length + 1] = checksum >> 8 & 255;
|
|
126
|
+
return base32Encode(full);
|
|
127
|
+
}
|
|
128
|
+
function getStellarAddress(publicKey) {
|
|
129
|
+
if (!publicKey || publicKey.length === 0) {
|
|
130
|
+
return "";
|
|
131
|
+
}
|
|
132
|
+
const pubKeyBytes = Buffer.from(publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey, "hex");
|
|
133
|
+
return encodeEd25519PublicKey(pubKeyBytes);
|
|
134
|
+
}
|
|
135
|
+
function getStellarAddressFromSolana(solanaAddress) {
|
|
136
|
+
if (!solanaAddress || solanaAddress.length === 0) {
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
return encodeEd25519PublicKey(base58Decode(solanaAddress));
|
|
140
|
+
}
|
|
51
141
|
function getCosmosAddress(publicKey, prefix) {
|
|
52
142
|
if (!publicKey || publicKey.length === 0) {
|
|
53
143
|
return "";
|
|
@@ -73,6 +163,8 @@ export {
|
|
|
73
163
|
compressPubkey,
|
|
74
164
|
decimalToHex,
|
|
75
165
|
getCosmosAddress,
|
|
166
|
+
getStellarAddress,
|
|
167
|
+
getStellarAddressFromSolana,
|
|
76
168
|
hexStringToBase64,
|
|
77
169
|
hexToDecimal,
|
|
78
170
|
hexToSignature,
|
package/dist/esm/utils/wallet.js
CHANGED
package/dist/types/ParaCore.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthMethod, AuthExtras, CurrentWalletIds, EmailTheme, PartnerEntity, TWalletType, PregenIds, BiometricLocationHint, Auth, SupportedWalletTypes, AuthIdentifier, AuthType, ExternalWalletInfo, PrimaryAuthInfo, SessionInfo, PrimaryAuth, PrimaryAuthType, AccountMetadata, LinkedAccounts, VerifyLinkParams, VerifyExternalWalletParams as VerifyExternalWalletParamsServer, SupportedAccountLinks, OnRampPurchase, BalancesConfig, Theme, IssueJwtParams } from '@getpara/user-management-client';
|
|
1
|
+
import { AuthMethod, AuthExtras, CurrentWalletIds, EmailTheme, PartnerEntity, TWalletType, PregenIds, BiometricLocationHint, Auth, SupportedWalletTypes, AuthIdentifier, AuthType, ExternalWalletInfo, PrimaryAuthInfo, SessionInfo, PrimaryAuth, PrimaryAuthType, AccountMetadata, LinkedAccounts, VerifyLinkParams, VerifyExternalWalletParams as VerifyExternalWalletParamsServer, SupportedAccountLinks, OnRampPurchase, BalancesConfig, Theme, IssueJwtParams, TWalletScheme } from '@getpara/user-management-client';
|
|
2
2
|
import type { pki as pkiType } from 'node-forge';
|
|
3
3
|
import { Ctx, Environment, Wallet, ConstructorOpts, CoreAuthInfo, CoreMethodParams, CoreMethodResponse, CoreInterface, AccountLinkInProgress, InternalMethodParams, InternalMethodResponse, OAuthResponse, AvailableWallet } from './types/index.js';
|
|
4
4
|
import { PlatformUtils } from './PlatformUtils.js';
|
|
@@ -721,6 +721,16 @@ export declare abstract class ParaCore implements CoreInterface {
|
|
|
721
721
|
* @param {string} base64Wallet the encoded wallet string
|
|
722
722
|
**/
|
|
723
723
|
setUserShare(base64Wallets: string): Promise<void>;
|
|
724
|
+
/**
|
|
725
|
+
* Migrate a wallet share to the enclave. The share is ECIES-encrypted before
|
|
726
|
+
* being sent so the plaintext never leaves the caller's process.
|
|
727
|
+
*/
|
|
728
|
+
migrateWalletShare(opts: {
|
|
729
|
+
walletId: string;
|
|
730
|
+
userShare: string;
|
|
731
|
+
secretApiKey: string;
|
|
732
|
+
walletScheme?: TWalletScheme;
|
|
733
|
+
}): Promise<any>;
|
|
724
734
|
private getTransactionReviewUrl;
|
|
725
735
|
private getOnRampTransactionUrl;
|
|
726
736
|
getWalletBalance(params: GetWalletBalanceParams): Promise<string>;
|
|
@@ -32,12 +32,12 @@ export interface PlatformUtils {
|
|
|
32
32
|
r: Buffer;
|
|
33
33
|
s: Buffer;
|
|
34
34
|
}>;
|
|
35
|
-
ed25519Keygen(ctx: Ctx, userId: string, sessionCookie: string, emailProps?: BackupKitEmailProps): Promise<{
|
|
35
|
+
ed25519Keygen(ctx: Ctx, userId: string, sessionCookie: string, emailProps?: BackupKitEmailProps, type?: TWalletType): Promise<{
|
|
36
36
|
signer: string;
|
|
37
37
|
walletId: string;
|
|
38
38
|
}>;
|
|
39
39
|
ed25519Sign(ctx: Ctx, userId: string, walletId: string, share: string, base64Bytes: string, sessionCookie: string): Promise<SignatureRes>;
|
|
40
|
-
ed25519PreKeygen(ctx: Ctx, pregenIdentifier: string, pregenIdentifierType: TPregenIdentifierType, sessionCookie: string): Promise<{
|
|
40
|
+
ed25519PreKeygen(ctx: Ctx, pregenIdentifier: string, pregenIdentifierType: TPregenIdentifierType, sessionCookie: string, type?: TWalletType): Promise<{
|
|
41
41
|
signer: string;
|
|
42
42
|
walletId: string;
|
|
43
43
|
}>;
|
|
@@ -88,6 +88,18 @@ export declare class EnclaveClient {
|
|
|
88
88
|
walletIds: string[];
|
|
89
89
|
partnerId: string;
|
|
90
90
|
}): Promise<ShareData[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Migrate a wallet share by encrypting it with the enclave's public key and
|
|
93
|
+
* sending the encrypted payload to the backend. The plaintext share never
|
|
94
|
+
* leaves the caller's process.
|
|
95
|
+
*/
|
|
96
|
+
migrateShare(opts: {
|
|
97
|
+
walletId: string;
|
|
98
|
+
userShare: string;
|
|
99
|
+
walletScheme: string;
|
|
100
|
+
secretApiKey: string;
|
|
101
|
+
}): Promise<any>;
|
|
102
|
+
private extractSignerFromUserShare;
|
|
91
103
|
persistSharesWithRetry(shares: ShareData[]): Promise<any>;
|
|
92
104
|
deleteSharesWithRetry(): Promise<void>;
|
|
93
105
|
}
|
|
@@ -12,6 +12,8 @@ export declare function hexToDecimal(hex: string): string;
|
|
|
12
12
|
export declare function decimalToHex(decimal: string): Hex;
|
|
13
13
|
export declare function compressPubkey(pubkey: Uint8Array): Uint8Array;
|
|
14
14
|
export declare function rawSecp256k1PubkeyToRawAddress(pubkeyData: Uint8Array): Uint8Array;
|
|
15
|
+
export declare function getStellarAddress(publicKey: string): string;
|
|
16
|
+
export declare function getStellarAddressFromSolana(solanaAddress: string): string;
|
|
15
17
|
export declare function getCosmosAddress(publicKey: string, prefix: string): string;
|
|
16
18
|
export declare function truncateAddress(str: string, addressType: TWalletType, { prefix, targetLength, }?: {
|
|
17
19
|
prefix?: string;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpara/core-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@celo/utils": "^8.0.2",
|
|
6
6
|
"@cosmjs/encoding": "^0.32.4",
|
|
7
7
|
"@ethereumjs/util": "^9.1.0",
|
|
8
|
-
"@getpara/user-management-client": "2.
|
|
8
|
+
"@getpara/user-management-client": "2.20.0",
|
|
9
9
|
"@noble/hashes": "^1.5.0",
|
|
10
10
|
"axios": "^1.8.4",
|
|
11
11
|
"base64url": "^3.0.1",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dist",
|
|
31
31
|
"package.json"
|
|
32
32
|
],
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "a8443bcc4018864f5e582f238ade1bb3b4e121f4",
|
|
34
34
|
"main": "dist/cjs/index.js",
|
|
35
35
|
"module": "dist/esm/index.js",
|
|
36
36
|
"scripts": {
|