@dynamic-labs-wallet/sui 0.0.0-preview.160.0 → 0.0.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/index.cjs.js +230 -55
- package/index.esm.js +227 -52
- package/package.json +6 -4
- package/src/client/client.d.ts +66 -10
- package/src/client/client.d.ts.map +1 -1
- package/src/client/constants.d.ts +2 -0
- package/src/client/constants.d.ts.map +1 -1
package/index.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var browser = require('@dynamic-labs-wallet/browser');
|
|
4
4
|
var ed25519 = require('@mysten/sui/keypairs/ed25519');
|
|
5
5
|
var cryptography = require('@mysten/sui/cryptography');
|
|
6
|
+
var converter = require('bech32-converting');
|
|
6
7
|
var verify = require('@mysten/sui/verify');
|
|
7
8
|
var bcs = require('@mysten/sui/bcs');
|
|
8
9
|
var blake2b = require('@noble/hashes/blake2b');
|
|
@@ -18,11 +19,6 @@ function _extends() {
|
|
|
18
19
|
return _extends.apply(this, arguments);
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const ERROR_KEYGEN_FAILED = 'Error with keygen';
|
|
22
|
-
const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating sui wallet account';
|
|
23
|
-
const ERROR_VERIFY_MESSAGE_SIGNATURE = 'Error verifying message signature';
|
|
24
|
-
const ERROR_VERIFY_TRANSACTION_SIGNATURE = 'Error verifying transaction signature';
|
|
25
|
-
|
|
26
22
|
const formatMessage = (message, intentScope)=>{
|
|
27
23
|
if (intentScope === 'TransactionData') {
|
|
28
24
|
const txBytes = Uint8Array.from(Buffer.from(message, 'hex'));
|
|
@@ -41,8 +37,12 @@ const formatMessage = (message, intentScope)=>{
|
|
|
41
37
|
};
|
|
42
38
|
|
|
43
39
|
class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
44
|
-
async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
|
|
40
|
+
async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError, signedSessionId }) {
|
|
45
41
|
try {
|
|
42
|
+
let ceremonyCeremonyCompleteResolver;
|
|
43
|
+
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
44
|
+
ceremonyCeremonyCompleteResolver = resolve;
|
|
45
|
+
});
|
|
46
46
|
// Generate key shares for given threshold signature scheme (TSS)
|
|
47
47
|
const { rawPublicKey, clientKeyShares } = await this.keyGen({
|
|
48
48
|
chainName: this.chainName,
|
|
@@ -57,37 +57,45 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
57
57
|
thresholdSignatureScheme,
|
|
58
58
|
clientKeySharesBackupInfo: browser.getClientKeyShareBackupInfo()
|
|
59
59
|
});
|
|
60
|
+
this.logger.debug('walletMap updated for wallet', {
|
|
61
|
+
context: {
|
|
62
|
+
accountAddress,
|
|
63
|
+
walletId,
|
|
64
|
+
walletMap: this.walletMap
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
ceremonyCeremonyCompleteResolver(undefined);
|
|
60
68
|
}
|
|
61
69
|
});
|
|
70
|
+
// Wait for the ceremony to complete before proceeding
|
|
71
|
+
await ceremonyCompletePromise;
|
|
62
72
|
if (!rawPublicKey || !clientKeyShares) {
|
|
63
|
-
throw new Error(ERROR_KEYGEN_FAILED);
|
|
73
|
+
throw new Error(browser.ERROR_KEYGEN_FAILED);
|
|
64
74
|
}
|
|
65
75
|
const { accountAddress, publicKeyHex } = this.deriveAccountAddress({
|
|
66
76
|
rawPublicKey: rawPublicKey
|
|
67
77
|
});
|
|
68
78
|
// Update client key shares in wallet map
|
|
69
79
|
// warning: this might result in race condition if `onCeremonyComplete` executes at the same time
|
|
70
|
-
// TODO: remove this once iframe handling for secret shares is implemented
|
|
71
80
|
await this.setClientKeySharesToLocalStorage({
|
|
72
81
|
accountAddress,
|
|
73
82
|
clientKeyShares,
|
|
74
83
|
overwriteOrMerge: 'overwrite'
|
|
75
84
|
});
|
|
76
|
-
|
|
77
|
-
void this.storeEncryptedBackupByWalletWithRetry({
|
|
85
|
+
await this.storeEncryptedBackupByWalletWithRetry({
|
|
78
86
|
accountAddress,
|
|
79
87
|
clientKeyShares,
|
|
80
|
-
password
|
|
88
|
+
password,
|
|
89
|
+
signedSessionId
|
|
81
90
|
});
|
|
82
91
|
return {
|
|
83
92
|
accountAddress,
|
|
84
|
-
rawPublicKey,
|
|
85
|
-
publicKeyHex
|
|
86
|
-
clientKeyShares
|
|
93
|
+
rawPublicKey: rawPublicKey,
|
|
94
|
+
publicKeyHex
|
|
87
95
|
};
|
|
88
96
|
} catch (error) {
|
|
89
|
-
this.logger.error(ERROR_CREATE_WALLET_ACCOUNT, error);
|
|
90
|
-
throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
|
|
97
|
+
this.logger.error(browser.ERROR_CREATE_WALLET_ACCOUNT, error);
|
|
98
|
+
throw new Error(browser.ERROR_CREATE_WALLET_ACCOUNT);
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
async getRawPublicKeyFromClientKeyShares({ chainName, clientKeyShare }) {
|
|
@@ -103,22 +111,28 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
103
111
|
/**
|
|
104
112
|
* Format Ed25519 signature to string that satisfies Sui signature standard
|
|
105
113
|
*/ async formatSignature(signatureEd25519, accountAddress) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
try {
|
|
115
|
+
// get public key from keyshare
|
|
116
|
+
// TODO: handle this more gracefully from the client key shares if possible
|
|
117
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
118
|
+
accountAddress
|
|
119
|
+
});
|
|
120
|
+
const rawPublicKey = await this.getRawPublicKeyFromClientKeyShares({
|
|
121
|
+
chainName: this.chainName,
|
|
122
|
+
clientKeyShare: clientKeyShares[0]
|
|
123
|
+
});
|
|
124
|
+
const rawPublicKeyBytes = Uint8Array.from(Buffer.from(rawPublicKey, 'hex'));
|
|
125
|
+
const suiPublicKey = new ed25519.Ed25519PublicKey(rawPublicKeyBytes);
|
|
126
|
+
const serializedSignature = cryptography.toSerializedSignature({
|
|
127
|
+
signature: signatureEd25519,
|
|
128
|
+
signatureScheme: 'ED25519',
|
|
129
|
+
publicKey: suiPublicKey
|
|
130
|
+
});
|
|
131
|
+
return serializedSignature;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
this.logger.error('Error formatting signature:', error);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
137
|
async verifyMessageSignature({ message, signature, accountAddress }) {
|
|
124
138
|
try {
|
|
@@ -126,29 +140,29 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
126
140
|
const verifiedPublicKey = await verify.verifyPersonalMessageSignature(messageBytes, signature);
|
|
127
141
|
const isVerified = verifiedPublicKey.toSuiAddress().toLowerCase() === accountAddress.toLowerCase();
|
|
128
142
|
if (!isVerified) {
|
|
129
|
-
throw new Error(ERROR_VERIFY_MESSAGE_SIGNATURE);
|
|
143
|
+
throw new Error(browser.ERROR_VERIFY_MESSAGE_SIGNATURE);
|
|
130
144
|
}
|
|
131
145
|
} catch (error) {
|
|
132
146
|
this.logger.error('Error verifying signature:', error);
|
|
133
147
|
throw error;
|
|
134
148
|
}
|
|
135
149
|
}
|
|
136
|
-
async verifyTransactionSignature({
|
|
150
|
+
async verifyTransactionSignature({ transaction, signature, senderAddress }) {
|
|
137
151
|
try {
|
|
138
|
-
const txBytes = Uint8Array.from(Buffer.from(
|
|
152
|
+
const txBytes = Uint8Array.from(Buffer.from(transaction, 'hex'));
|
|
139
153
|
const verifiedPublicKey = await verify.verifyTransactionSignature(txBytes, signature);
|
|
140
|
-
const isVerified = verifiedPublicKey.toSuiAddress().toLowerCase() ===
|
|
154
|
+
const isVerified = verifiedPublicKey.toSuiAddress().toLowerCase() === senderAddress.toLowerCase();
|
|
141
155
|
if (!isVerified) {
|
|
142
|
-
throw new Error(ERROR_VERIFY_TRANSACTION_SIGNATURE);
|
|
156
|
+
throw new Error(browser.ERROR_VERIFY_TRANSACTION_SIGNATURE);
|
|
143
157
|
}
|
|
144
158
|
} catch (error) {
|
|
145
159
|
this.logger.error('Error verifying signature:', error);
|
|
146
160
|
throw error;
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
|
-
async signMessage({ message, accountAddress, password = undefined }) {
|
|
163
|
+
async signMessage({ message, accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
150
164
|
if (!accountAddress) {
|
|
151
|
-
throw new Error(
|
|
165
|
+
throw new Error(browser.ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
152
166
|
}
|
|
153
167
|
try {
|
|
154
168
|
const formattedMessage = formatMessage(message, 'PersonalMessage');
|
|
@@ -156,7 +170,9 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
156
170
|
message: formattedMessage,
|
|
157
171
|
accountAddress: accountAddress,
|
|
158
172
|
chainName: this.chainName,
|
|
159
|
-
password
|
|
173
|
+
password,
|
|
174
|
+
signedSessionId,
|
|
175
|
+
mfaToken
|
|
160
176
|
});
|
|
161
177
|
const formattedSignature = await this.formatSignature(signatureEd25519, accountAddress);
|
|
162
178
|
await this.verifyMessageSignature({
|
|
@@ -166,27 +182,29 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
166
182
|
});
|
|
167
183
|
return formattedSignature;
|
|
168
184
|
} catch (error) {
|
|
169
|
-
this.logger.error(
|
|
170
|
-
throw
|
|
185
|
+
this.logger.error(browser.ERROR_SIGN_MESSAGE, error);
|
|
186
|
+
throw new Error(browser.ERROR_SIGN_MESSAGE);
|
|
171
187
|
}
|
|
172
188
|
}
|
|
173
|
-
async signTransaction({
|
|
174
|
-
if (!
|
|
175
|
-
throw new Error(
|
|
189
|
+
async signTransaction({ transaction, senderAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
190
|
+
if (!senderAddress) {
|
|
191
|
+
throw new Error(browser.ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
176
192
|
}
|
|
177
193
|
try {
|
|
178
|
-
const formattedMessage = formatMessage(
|
|
194
|
+
const formattedMessage = formatMessage(transaction, 'TransactionData');
|
|
179
195
|
const signatureEd25519 = await this.sign({
|
|
180
196
|
message: formattedMessage,
|
|
181
|
-
accountAddress:
|
|
197
|
+
accountAddress: senderAddress,
|
|
182
198
|
chainName: this.chainName,
|
|
183
|
-
password
|
|
199
|
+
password,
|
|
200
|
+
signedSessionId,
|
|
201
|
+
mfaToken
|
|
184
202
|
});
|
|
185
|
-
const formattedSignature = await this.formatSignature(signatureEd25519,
|
|
203
|
+
const formattedSignature = await this.formatSignature(signatureEd25519, senderAddress);
|
|
186
204
|
await this.verifyTransactionSignature({
|
|
187
|
-
|
|
205
|
+
transaction,
|
|
188
206
|
signature: formattedSignature,
|
|
189
|
-
|
|
207
|
+
senderAddress
|
|
190
208
|
});
|
|
191
209
|
return formattedSignature;
|
|
192
210
|
} catch (error) {
|
|
@@ -195,26 +213,183 @@ class DynamicSuiWalletClient extends browser.DynamicWalletClient {
|
|
|
195
213
|
}
|
|
196
214
|
}
|
|
197
215
|
deriveAccountAddress({ rawPublicKey }) {
|
|
198
|
-
const
|
|
216
|
+
const pubKeyBytes = Buffer.from(rawPublicKey, 'hex');
|
|
217
|
+
const publicKey = new ed25519.Ed25519PublicKey(pubKeyBytes);
|
|
199
218
|
const accountAddress = publicKey.toSuiAddress();
|
|
200
219
|
return {
|
|
201
220
|
accountAddress,
|
|
202
|
-
publicKeyHex:
|
|
221
|
+
publicKeyHex: rawPublicKey
|
|
203
222
|
};
|
|
204
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Converts a Sui private key from Bech32 format to a 64-character hex string.
|
|
226
|
+
* The output is compatible with RFC8032 Ed25519 private key format.
|
|
227
|
+
*
|
|
228
|
+
* @param suiPrivateKey - The Sui private key in Bech32 format starting with "suiprivkey1"
|
|
229
|
+
* @returns An object containing the private key and the private key bytes
|
|
230
|
+
* @throws Error if the input is not a valid Sui private key format
|
|
231
|
+
*/ convertSuiPrivateKey(suiPrivateKey) {
|
|
232
|
+
if (!suiPrivateKey.startsWith('suiprivkey1')) {
|
|
233
|
+
this.logger.debug('Sui private key not in Bech32 format');
|
|
234
|
+
return {
|
|
235
|
+
privateKey: suiPrivateKey,
|
|
236
|
+
privateKeyBytes: Buffer.from(suiPrivateKey, 'hex')
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const suiConverter = converter('suiprivkey');
|
|
241
|
+
const hexKey = suiConverter.toHex(suiPrivateKey);
|
|
242
|
+
let cleanHex = hexKey.startsWith('0x00') ? hexKey.slice(4) : hexKey.startsWith('0x') ? hexKey.slice(2) : hexKey;
|
|
243
|
+
if (cleanHex.length > 64) {
|
|
244
|
+
cleanHex = cleanHex.slice(cleanHex.length - 64);
|
|
245
|
+
}
|
|
246
|
+
if (cleanHex.length !== 64) {
|
|
247
|
+
throw new Error(`Invalid output: Expected 64 characters, got ${cleanHex.length}`);
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
privateKey: cleanHex.toLowerCase(),
|
|
251
|
+
privateKeyBytes: Buffer.from(cleanHex, 'hex')
|
|
252
|
+
};
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (error instanceof Error) {
|
|
255
|
+
throw new Error(`Failed to convert Sui private key: ${error.message}`);
|
|
256
|
+
}
|
|
257
|
+
throw new Error('Failed to convert Sui private key: Unknown error');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Gets the public key for a given private key
|
|
262
|
+
* @param privateKeyBytes A Buffer containing the Ed25519 private key bytes
|
|
263
|
+
* @returns The public key (Sui address) derived from the private key
|
|
264
|
+
*/ getPublicKeyFromPrivateKey(privateKeyBytes) {
|
|
265
|
+
try {
|
|
266
|
+
const keypair = ed25519.Ed25519Keypair.fromSecretKey(privateKeyBytes);
|
|
267
|
+
const publicKey = keypair.getPublicKey();
|
|
268
|
+
const publicKeyBase58 = publicKey.toSuiAddress();
|
|
269
|
+
return publicKeyBase58;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
this.logger.error('Unable to derive public key from private key. Check private key format', error instanceof Error ? error.message : 'Unknown error');
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Imports the private key for a given account address
|
|
277
|
+
*
|
|
278
|
+
* @param privateKey The private key to import, accepts both Bech32 and hex formats
|
|
279
|
+
* @param chainName The chain name to import the private key for
|
|
280
|
+
* @param thresholdSignatureScheme The threshold signature scheme to use
|
|
281
|
+
* @param password The password for encrypted backup shares
|
|
282
|
+
* @returns The account address, raw public key, and client key shares
|
|
283
|
+
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError, signedSessionId }) {
|
|
284
|
+
try {
|
|
285
|
+
let ceremonyCeremonyCompleteResolver;
|
|
286
|
+
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
287
|
+
ceremonyCeremonyCompleteResolver = resolve;
|
|
288
|
+
});
|
|
289
|
+
const { privateKey: formattedPrivateKey, privateKeyBytes } = await this.convertSuiPrivateKey(privateKey);
|
|
290
|
+
const publicKey = this.getPublicKeyFromPrivateKey(privateKeyBytes);
|
|
291
|
+
const { rawPublicKey, clientKeyShares } = await this.importRawPrivateKey({
|
|
292
|
+
chainName,
|
|
293
|
+
privateKey: formattedPrivateKey,
|
|
294
|
+
thresholdSignatureScheme,
|
|
295
|
+
onError: (error)=>{
|
|
296
|
+
this.logger.error(browser.ERROR_IMPORT_PRIVATE_KEY, error);
|
|
297
|
+
onError == null ? void 0 : onError(error);
|
|
298
|
+
},
|
|
299
|
+
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
300
|
+
// update wallet map
|
|
301
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
|
|
302
|
+
accountAddress,
|
|
303
|
+
walletId,
|
|
304
|
+
chainName: this.chainName,
|
|
305
|
+
thresholdSignatureScheme,
|
|
306
|
+
clientKeySharesBackupInfo: browser.getClientKeyShareBackupInfo()
|
|
307
|
+
});
|
|
308
|
+
this.logger.debug('walletMap updated for wallet', {
|
|
309
|
+
context: {
|
|
310
|
+
accountAddress,
|
|
311
|
+
walletId,
|
|
312
|
+
walletMap: this.walletMap
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
ceremonyCeremonyCompleteResolver(undefined);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
// Wait for the ceremony to complete before proceeding
|
|
319
|
+
await ceremonyCompletePromise;
|
|
320
|
+
if (!rawPublicKey || !clientKeyShares) {
|
|
321
|
+
throw new Error(browser.ERROR_IMPORT_PRIVATE_KEY);
|
|
322
|
+
}
|
|
323
|
+
const { accountAddress } = await this.deriveAccountAddress({
|
|
324
|
+
rawPublicKey: rawPublicKey
|
|
325
|
+
});
|
|
326
|
+
if (accountAddress !== publicKey) {
|
|
327
|
+
throw new Error(`Public key mismatch: derived address ${accountAddress} !== public key ${publicKey}`);
|
|
328
|
+
}
|
|
329
|
+
// Update client key shares in wallet map
|
|
330
|
+
// warning: this might result in race condition if `onCeremonyComplete` executes at the same time
|
|
331
|
+
await this.setClientKeySharesToLocalStorage({
|
|
332
|
+
accountAddress,
|
|
333
|
+
clientKeyShares,
|
|
334
|
+
overwriteOrMerge: 'overwrite'
|
|
335
|
+
});
|
|
336
|
+
await this.storeEncryptedBackupByWalletWithRetry({
|
|
337
|
+
accountAddress,
|
|
338
|
+
clientKeyShares,
|
|
339
|
+
password,
|
|
340
|
+
signedSessionId
|
|
341
|
+
});
|
|
342
|
+
return {
|
|
343
|
+
accountAddress,
|
|
344
|
+
rawPublicKey: rawPublicKey,
|
|
345
|
+
clientKeyShares
|
|
346
|
+
};
|
|
347
|
+
} catch (error) {
|
|
348
|
+
this.logger.error(browser.ERROR_IMPORT_PRIVATE_KEY, error);
|
|
349
|
+
throw new Error(browser.ERROR_IMPORT_PRIVATE_KEY);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Exports the private key for a given account address
|
|
354
|
+
*
|
|
355
|
+
* @param accountAddress The account address to export the private key for
|
|
356
|
+
* @param password The password for encrypted backup shares
|
|
357
|
+
* @returns The private key in hex format
|
|
358
|
+
*/ async exportPrivateKey({ accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
359
|
+
try {
|
|
360
|
+
const { derivedPrivateKey } = await this.exportKey({
|
|
361
|
+
accountAddress,
|
|
362
|
+
chainName: this.chainName,
|
|
363
|
+
password,
|
|
364
|
+
signedSessionId,
|
|
365
|
+
mfaToken
|
|
366
|
+
});
|
|
367
|
+
if (!derivedPrivateKey) {
|
|
368
|
+
throw new Error('Derived private key is undefined');
|
|
369
|
+
}
|
|
370
|
+
const privateScalarHex = derivedPrivateKey.slice(0, 64);
|
|
371
|
+
return privateScalarHex;
|
|
372
|
+
} catch (error) {
|
|
373
|
+
this.logger.error(browser.ERROR_EXPORT_PRIVATE_KEY, error);
|
|
374
|
+
throw new Error(browser.ERROR_EXPORT_PRIVATE_KEY);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
205
377
|
async getSuiWallets() {
|
|
206
378
|
const wallets = await this.getWallets();
|
|
207
379
|
const suiWallets = wallets.filter((wallet)=>wallet.chainName === 'sui');
|
|
208
380
|
return suiWallets;
|
|
209
381
|
}
|
|
210
|
-
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug }){
|
|
382
|
+
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, featureFlags, authMode = browser.AuthMode.HEADER, sdkVersion }){
|
|
211
383
|
super({
|
|
212
384
|
environmentId,
|
|
213
385
|
authToken,
|
|
214
386
|
baseApiUrl,
|
|
215
387
|
baseMPCRelayApiUrl,
|
|
216
388
|
storageKey,
|
|
217
|
-
debug
|
|
389
|
+
debug,
|
|
390
|
+
featureFlags,
|
|
391
|
+
authMode,
|
|
392
|
+
sdkVersion
|
|
218
393
|
}), this.chainName = 'SUI';
|
|
219
394
|
}
|
|
220
395
|
}
|
package/index.esm.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { DynamicWalletClient, getClientKeyShareBackupInfo, getMPCChainConfig } from '@dynamic-labs-wallet/browser';
|
|
2
|
-
import { Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';
|
|
1
|
+
import { DynamicWalletClient, getClientKeyShareBackupInfo, ERROR_KEYGEN_FAILED, ERROR_CREATE_WALLET_ACCOUNT, getMPCChainConfig, ERROR_VERIFY_MESSAGE_SIGNATURE, ERROR_VERIFY_TRANSACTION_SIGNATURE, ERROR_ACCOUNT_ADDRESS_REQUIRED, ERROR_SIGN_MESSAGE, ERROR_IMPORT_PRIVATE_KEY, ERROR_EXPORT_PRIVATE_KEY, AuthMode } from '@dynamic-labs-wallet/browser';
|
|
2
|
+
import { Ed25519PublicKey, Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
3
3
|
import { messageWithIntent, toSerializedSignature } from '@mysten/sui/cryptography';
|
|
4
|
+
import converter from 'bech32-converting';
|
|
4
5
|
import { verifyPersonalMessageSignature, verifyTransactionSignature } from '@mysten/sui/verify';
|
|
5
6
|
import { bcs } from '@mysten/sui/bcs';
|
|
6
7
|
import { blake2b } from '@noble/hashes/blake2b';
|
|
@@ -16,11 +17,6 @@ function _extends() {
|
|
|
16
17
|
return _extends.apply(this, arguments);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
const ERROR_KEYGEN_FAILED = 'Error with keygen';
|
|
20
|
-
const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating sui wallet account';
|
|
21
|
-
const ERROR_VERIFY_MESSAGE_SIGNATURE = 'Error verifying message signature';
|
|
22
|
-
const ERROR_VERIFY_TRANSACTION_SIGNATURE = 'Error verifying transaction signature';
|
|
23
|
-
|
|
24
20
|
const formatMessage = (message, intentScope)=>{
|
|
25
21
|
if (intentScope === 'TransactionData') {
|
|
26
22
|
const txBytes = Uint8Array.from(Buffer.from(message, 'hex'));
|
|
@@ -39,8 +35,12 @@ const formatMessage = (message, intentScope)=>{
|
|
|
39
35
|
};
|
|
40
36
|
|
|
41
37
|
class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
42
|
-
async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
|
|
38
|
+
async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError, signedSessionId }) {
|
|
43
39
|
try {
|
|
40
|
+
let ceremonyCeremonyCompleteResolver;
|
|
41
|
+
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
42
|
+
ceremonyCeremonyCompleteResolver = resolve;
|
|
43
|
+
});
|
|
44
44
|
// Generate key shares for given threshold signature scheme (TSS)
|
|
45
45
|
const { rawPublicKey, clientKeyShares } = await this.keyGen({
|
|
46
46
|
chainName: this.chainName,
|
|
@@ -55,8 +55,18 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
55
55
|
thresholdSignatureScheme,
|
|
56
56
|
clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
|
|
57
57
|
});
|
|
58
|
+
this.logger.debug('walletMap updated for wallet', {
|
|
59
|
+
context: {
|
|
60
|
+
accountAddress,
|
|
61
|
+
walletId,
|
|
62
|
+
walletMap: this.walletMap
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
ceremonyCeremonyCompleteResolver(undefined);
|
|
58
66
|
}
|
|
59
67
|
});
|
|
68
|
+
// Wait for the ceremony to complete before proceeding
|
|
69
|
+
await ceremonyCompletePromise;
|
|
60
70
|
if (!rawPublicKey || !clientKeyShares) {
|
|
61
71
|
throw new Error(ERROR_KEYGEN_FAILED);
|
|
62
72
|
}
|
|
@@ -65,23 +75,21 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
65
75
|
});
|
|
66
76
|
// Update client key shares in wallet map
|
|
67
77
|
// warning: this might result in race condition if `onCeremonyComplete` executes at the same time
|
|
68
|
-
// TODO: remove this once iframe handling for secret shares is implemented
|
|
69
78
|
await this.setClientKeySharesToLocalStorage({
|
|
70
79
|
accountAddress,
|
|
71
80
|
clientKeyShares,
|
|
72
81
|
overwriteOrMerge: 'overwrite'
|
|
73
82
|
});
|
|
74
|
-
|
|
75
|
-
void this.storeEncryptedBackupByWalletWithRetry({
|
|
83
|
+
await this.storeEncryptedBackupByWalletWithRetry({
|
|
76
84
|
accountAddress,
|
|
77
85
|
clientKeyShares,
|
|
78
|
-
password
|
|
86
|
+
password,
|
|
87
|
+
signedSessionId
|
|
79
88
|
});
|
|
80
89
|
return {
|
|
81
90
|
accountAddress,
|
|
82
|
-
rawPublicKey,
|
|
83
|
-
publicKeyHex
|
|
84
|
-
clientKeyShares
|
|
91
|
+
rawPublicKey: rawPublicKey,
|
|
92
|
+
publicKeyHex
|
|
85
93
|
};
|
|
86
94
|
} catch (error) {
|
|
87
95
|
this.logger.error(ERROR_CREATE_WALLET_ACCOUNT, error);
|
|
@@ -101,22 +109,28 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
101
109
|
/**
|
|
102
110
|
* Format Ed25519 signature to string that satisfies Sui signature standard
|
|
103
111
|
*/ async formatSignature(signatureEd25519, accountAddress) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
try {
|
|
113
|
+
// get public key from keyshare
|
|
114
|
+
// TODO: handle this more gracefully from the client key shares if possible
|
|
115
|
+
const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
|
|
116
|
+
accountAddress
|
|
117
|
+
});
|
|
118
|
+
const rawPublicKey = await this.getRawPublicKeyFromClientKeyShares({
|
|
119
|
+
chainName: this.chainName,
|
|
120
|
+
clientKeyShare: clientKeyShares[0]
|
|
121
|
+
});
|
|
122
|
+
const rawPublicKeyBytes = Uint8Array.from(Buffer.from(rawPublicKey, 'hex'));
|
|
123
|
+
const suiPublicKey = new Ed25519PublicKey(rawPublicKeyBytes);
|
|
124
|
+
const serializedSignature = toSerializedSignature({
|
|
125
|
+
signature: signatureEd25519,
|
|
126
|
+
signatureScheme: 'ED25519',
|
|
127
|
+
publicKey: suiPublicKey
|
|
128
|
+
});
|
|
129
|
+
return serializedSignature;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
this.logger.error('Error formatting signature:', error);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
120
134
|
}
|
|
121
135
|
async verifyMessageSignature({ message, signature, accountAddress }) {
|
|
122
136
|
try {
|
|
@@ -131,11 +145,11 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
131
145
|
throw error;
|
|
132
146
|
}
|
|
133
147
|
}
|
|
134
|
-
async verifyTransactionSignature({
|
|
148
|
+
async verifyTransactionSignature({ transaction, signature, senderAddress }) {
|
|
135
149
|
try {
|
|
136
|
-
const txBytes = Uint8Array.from(Buffer.from(
|
|
150
|
+
const txBytes = Uint8Array.from(Buffer.from(transaction, 'hex'));
|
|
137
151
|
const verifiedPublicKey = await verifyTransactionSignature(txBytes, signature);
|
|
138
|
-
const isVerified = verifiedPublicKey.toSuiAddress().toLowerCase() ===
|
|
152
|
+
const isVerified = verifiedPublicKey.toSuiAddress().toLowerCase() === senderAddress.toLowerCase();
|
|
139
153
|
if (!isVerified) {
|
|
140
154
|
throw new Error(ERROR_VERIFY_TRANSACTION_SIGNATURE);
|
|
141
155
|
}
|
|
@@ -144,9 +158,9 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
144
158
|
throw error;
|
|
145
159
|
}
|
|
146
160
|
}
|
|
147
|
-
async signMessage({ message, accountAddress, password = undefined }) {
|
|
161
|
+
async signMessage({ message, accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
148
162
|
if (!accountAddress) {
|
|
149
|
-
throw new Error(
|
|
163
|
+
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
150
164
|
}
|
|
151
165
|
try {
|
|
152
166
|
const formattedMessage = formatMessage(message, 'PersonalMessage');
|
|
@@ -154,7 +168,9 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
154
168
|
message: formattedMessage,
|
|
155
169
|
accountAddress: accountAddress,
|
|
156
170
|
chainName: this.chainName,
|
|
157
|
-
password
|
|
171
|
+
password,
|
|
172
|
+
signedSessionId,
|
|
173
|
+
mfaToken
|
|
158
174
|
});
|
|
159
175
|
const formattedSignature = await this.formatSignature(signatureEd25519, accountAddress);
|
|
160
176
|
await this.verifyMessageSignature({
|
|
@@ -164,27 +180,29 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
164
180
|
});
|
|
165
181
|
return formattedSignature;
|
|
166
182
|
} catch (error) {
|
|
167
|
-
this.logger.error(
|
|
168
|
-
throw
|
|
183
|
+
this.logger.error(ERROR_SIGN_MESSAGE, error);
|
|
184
|
+
throw new Error(ERROR_SIGN_MESSAGE);
|
|
169
185
|
}
|
|
170
186
|
}
|
|
171
|
-
async signTransaction({
|
|
172
|
-
if (!
|
|
173
|
-
throw new Error(
|
|
187
|
+
async signTransaction({ transaction, senderAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
188
|
+
if (!senderAddress) {
|
|
189
|
+
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
174
190
|
}
|
|
175
191
|
try {
|
|
176
|
-
const formattedMessage = formatMessage(
|
|
192
|
+
const formattedMessage = formatMessage(transaction, 'TransactionData');
|
|
177
193
|
const signatureEd25519 = await this.sign({
|
|
178
194
|
message: formattedMessage,
|
|
179
|
-
accountAddress:
|
|
195
|
+
accountAddress: senderAddress,
|
|
180
196
|
chainName: this.chainName,
|
|
181
|
-
password
|
|
197
|
+
password,
|
|
198
|
+
signedSessionId,
|
|
199
|
+
mfaToken
|
|
182
200
|
});
|
|
183
|
-
const formattedSignature = await this.formatSignature(signatureEd25519,
|
|
201
|
+
const formattedSignature = await this.formatSignature(signatureEd25519, senderAddress);
|
|
184
202
|
await this.verifyTransactionSignature({
|
|
185
|
-
|
|
203
|
+
transaction,
|
|
186
204
|
signature: formattedSignature,
|
|
187
|
-
|
|
205
|
+
senderAddress
|
|
188
206
|
});
|
|
189
207
|
return formattedSignature;
|
|
190
208
|
} catch (error) {
|
|
@@ -193,26 +211,183 @@ class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
193
211
|
}
|
|
194
212
|
}
|
|
195
213
|
deriveAccountAddress({ rawPublicKey }) {
|
|
196
|
-
const
|
|
214
|
+
const pubKeyBytes = Buffer.from(rawPublicKey, 'hex');
|
|
215
|
+
const publicKey = new Ed25519PublicKey(pubKeyBytes);
|
|
197
216
|
const accountAddress = publicKey.toSuiAddress();
|
|
198
217
|
return {
|
|
199
218
|
accountAddress,
|
|
200
|
-
publicKeyHex:
|
|
219
|
+
publicKeyHex: rawPublicKey
|
|
201
220
|
};
|
|
202
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Converts a Sui private key from Bech32 format to a 64-character hex string.
|
|
224
|
+
* The output is compatible with RFC8032 Ed25519 private key format.
|
|
225
|
+
*
|
|
226
|
+
* @param suiPrivateKey - The Sui private key in Bech32 format starting with "suiprivkey1"
|
|
227
|
+
* @returns An object containing the private key and the private key bytes
|
|
228
|
+
* @throws Error if the input is not a valid Sui private key format
|
|
229
|
+
*/ convertSuiPrivateKey(suiPrivateKey) {
|
|
230
|
+
if (!suiPrivateKey.startsWith('suiprivkey1')) {
|
|
231
|
+
this.logger.debug('Sui private key not in Bech32 format');
|
|
232
|
+
return {
|
|
233
|
+
privateKey: suiPrivateKey,
|
|
234
|
+
privateKeyBytes: Buffer.from(suiPrivateKey, 'hex')
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const suiConverter = converter('suiprivkey');
|
|
239
|
+
const hexKey = suiConverter.toHex(suiPrivateKey);
|
|
240
|
+
let cleanHex = hexKey.startsWith('0x00') ? hexKey.slice(4) : hexKey.startsWith('0x') ? hexKey.slice(2) : hexKey;
|
|
241
|
+
if (cleanHex.length > 64) {
|
|
242
|
+
cleanHex = cleanHex.slice(cleanHex.length - 64);
|
|
243
|
+
}
|
|
244
|
+
if (cleanHex.length !== 64) {
|
|
245
|
+
throw new Error(`Invalid output: Expected 64 characters, got ${cleanHex.length}`);
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
privateKey: cleanHex.toLowerCase(),
|
|
249
|
+
privateKeyBytes: Buffer.from(cleanHex, 'hex')
|
|
250
|
+
};
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error instanceof Error) {
|
|
253
|
+
throw new Error(`Failed to convert Sui private key: ${error.message}`);
|
|
254
|
+
}
|
|
255
|
+
throw new Error('Failed to convert Sui private key: Unknown error');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Gets the public key for a given private key
|
|
260
|
+
* @param privateKeyBytes A Buffer containing the Ed25519 private key bytes
|
|
261
|
+
* @returns The public key (Sui address) derived from the private key
|
|
262
|
+
*/ getPublicKeyFromPrivateKey(privateKeyBytes) {
|
|
263
|
+
try {
|
|
264
|
+
const keypair = Ed25519Keypair.fromSecretKey(privateKeyBytes);
|
|
265
|
+
const publicKey = keypair.getPublicKey();
|
|
266
|
+
const publicKeyBase58 = publicKey.toSuiAddress();
|
|
267
|
+
return publicKeyBase58;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
this.logger.error('Unable to derive public key from private key. Check private key format', error instanceof Error ? error.message : 'Unknown error');
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Imports the private key for a given account address
|
|
275
|
+
*
|
|
276
|
+
* @param privateKey The private key to import, accepts both Bech32 and hex formats
|
|
277
|
+
* @param chainName The chain name to import the private key for
|
|
278
|
+
* @param thresholdSignatureScheme The threshold signature scheme to use
|
|
279
|
+
* @param password The password for encrypted backup shares
|
|
280
|
+
* @returns The account address, raw public key, and client key shares
|
|
281
|
+
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError, signedSessionId }) {
|
|
282
|
+
try {
|
|
283
|
+
let ceremonyCeremonyCompleteResolver;
|
|
284
|
+
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
285
|
+
ceremonyCeremonyCompleteResolver = resolve;
|
|
286
|
+
});
|
|
287
|
+
const { privateKey: formattedPrivateKey, privateKeyBytes } = await this.convertSuiPrivateKey(privateKey);
|
|
288
|
+
const publicKey = this.getPublicKeyFromPrivateKey(privateKeyBytes);
|
|
289
|
+
const { rawPublicKey, clientKeyShares } = await this.importRawPrivateKey({
|
|
290
|
+
chainName,
|
|
291
|
+
privateKey: formattedPrivateKey,
|
|
292
|
+
thresholdSignatureScheme,
|
|
293
|
+
onError: (error)=>{
|
|
294
|
+
this.logger.error(ERROR_IMPORT_PRIVATE_KEY, error);
|
|
295
|
+
onError == null ? void 0 : onError(error);
|
|
296
|
+
},
|
|
297
|
+
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
298
|
+
// update wallet map
|
|
299
|
+
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
|
|
300
|
+
accountAddress,
|
|
301
|
+
walletId,
|
|
302
|
+
chainName: this.chainName,
|
|
303
|
+
thresholdSignatureScheme,
|
|
304
|
+
clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
|
|
305
|
+
});
|
|
306
|
+
this.logger.debug('walletMap updated for wallet', {
|
|
307
|
+
context: {
|
|
308
|
+
accountAddress,
|
|
309
|
+
walletId,
|
|
310
|
+
walletMap: this.walletMap
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
ceremonyCeremonyCompleteResolver(undefined);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
// Wait for the ceremony to complete before proceeding
|
|
317
|
+
await ceremonyCompletePromise;
|
|
318
|
+
if (!rawPublicKey || !clientKeyShares) {
|
|
319
|
+
throw new Error(ERROR_IMPORT_PRIVATE_KEY);
|
|
320
|
+
}
|
|
321
|
+
const { accountAddress } = await this.deriveAccountAddress({
|
|
322
|
+
rawPublicKey: rawPublicKey
|
|
323
|
+
});
|
|
324
|
+
if (accountAddress !== publicKey) {
|
|
325
|
+
throw new Error(`Public key mismatch: derived address ${accountAddress} !== public key ${publicKey}`);
|
|
326
|
+
}
|
|
327
|
+
// Update client key shares in wallet map
|
|
328
|
+
// warning: this might result in race condition if `onCeremonyComplete` executes at the same time
|
|
329
|
+
await this.setClientKeySharesToLocalStorage({
|
|
330
|
+
accountAddress,
|
|
331
|
+
clientKeyShares,
|
|
332
|
+
overwriteOrMerge: 'overwrite'
|
|
333
|
+
});
|
|
334
|
+
await this.storeEncryptedBackupByWalletWithRetry({
|
|
335
|
+
accountAddress,
|
|
336
|
+
clientKeyShares,
|
|
337
|
+
password,
|
|
338
|
+
signedSessionId
|
|
339
|
+
});
|
|
340
|
+
return {
|
|
341
|
+
accountAddress,
|
|
342
|
+
rawPublicKey: rawPublicKey,
|
|
343
|
+
clientKeyShares
|
|
344
|
+
};
|
|
345
|
+
} catch (error) {
|
|
346
|
+
this.logger.error(ERROR_IMPORT_PRIVATE_KEY, error);
|
|
347
|
+
throw new Error(ERROR_IMPORT_PRIVATE_KEY);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Exports the private key for a given account address
|
|
352
|
+
*
|
|
353
|
+
* @param accountAddress The account address to export the private key for
|
|
354
|
+
* @param password The password for encrypted backup shares
|
|
355
|
+
* @returns The private key in hex format
|
|
356
|
+
*/ async exportPrivateKey({ accountAddress, password = undefined, signedSessionId, mfaToken }) {
|
|
357
|
+
try {
|
|
358
|
+
const { derivedPrivateKey } = await this.exportKey({
|
|
359
|
+
accountAddress,
|
|
360
|
+
chainName: this.chainName,
|
|
361
|
+
password,
|
|
362
|
+
signedSessionId,
|
|
363
|
+
mfaToken
|
|
364
|
+
});
|
|
365
|
+
if (!derivedPrivateKey) {
|
|
366
|
+
throw new Error('Derived private key is undefined');
|
|
367
|
+
}
|
|
368
|
+
const privateScalarHex = derivedPrivateKey.slice(0, 64);
|
|
369
|
+
return privateScalarHex;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
this.logger.error(ERROR_EXPORT_PRIVATE_KEY, error);
|
|
372
|
+
throw new Error(ERROR_EXPORT_PRIVATE_KEY);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
203
375
|
async getSuiWallets() {
|
|
204
376
|
const wallets = await this.getWallets();
|
|
205
377
|
const suiWallets = wallets.filter((wallet)=>wallet.chainName === 'sui');
|
|
206
378
|
return suiWallets;
|
|
207
379
|
}
|
|
208
|
-
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug }){
|
|
380
|
+
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, featureFlags, authMode = AuthMode.HEADER, sdkVersion }){
|
|
209
381
|
super({
|
|
210
382
|
environmentId,
|
|
211
383
|
authToken,
|
|
212
384
|
baseApiUrl,
|
|
213
385
|
baseMPCRelayApiUrl,
|
|
214
386
|
storageKey,
|
|
215
|
-
debug
|
|
387
|
+
debug,
|
|
388
|
+
featureFlags,
|
|
389
|
+
authMode,
|
|
390
|
+
sdkVersion
|
|
216
391
|
}), this.chainName = 'SUI';
|
|
217
392
|
}
|
|
218
393
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs-wallet/sui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"type": "commonjs",
|
|
5
6
|
"dependencies": {
|
|
6
|
-
"@dynamic-labs-wallet/browser": "0.0.
|
|
7
|
+
"@dynamic-labs-wallet/browser": "0.0.1",
|
|
7
8
|
"@mysten/sui": "1.26.0",
|
|
8
|
-
"@noble/hashes": "1.7.1"
|
|
9
|
+
"@noble/hashes": "1.7.1",
|
|
10
|
+
"bech32-converting": "^1.0.9"
|
|
9
11
|
},
|
|
10
12
|
"publishConfig": {
|
|
11
13
|
"access": "public"
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
"types": "./index.esm.d.ts",
|
|
28
30
|
"import": "./index.esm.js",
|
|
29
31
|
"require": "./index.cjs.js",
|
|
30
|
-
"default": "./index.
|
|
32
|
+
"default": "./index.esm.js"
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
}
|
package/src/client/client.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { ClientKeyShare, DynamicWalletClient,
|
|
1
|
+
import { ClientKeyShare, DynamicWalletClient, ThresholdSignatureScheme, DynamicWalletClientProps } from '@dynamic-labs-wallet/browser';
|
|
2
2
|
export declare class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
3
3
|
readonly chainName = "SUI";
|
|
4
|
-
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, }: DynamicWalletClientProps);
|
|
5
|
-
createWalletAccount({ thresholdSignatureScheme, password, onError, }: {
|
|
4
|
+
constructor({ environmentId, authToken, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, featureFlags, authMode, sdkVersion, }: DynamicWalletClientProps);
|
|
5
|
+
createWalletAccount({ thresholdSignatureScheme, password, onError, signedSessionId, }: {
|
|
6
6
|
thresholdSignatureScheme: ThresholdSignatureScheme;
|
|
7
7
|
password?: string;
|
|
8
8
|
onError?: (error: Error) => void;
|
|
9
|
+
signedSessionId: string;
|
|
9
10
|
}): Promise<{
|
|
10
11
|
accountAddress: string;
|
|
11
12
|
publicKeyHex: string;
|
|
12
|
-
rawPublicKey:
|
|
13
|
-
clientKeyShares: ClientKeyShare[];
|
|
13
|
+
rawPublicKey: string | undefined;
|
|
14
14
|
}>;
|
|
15
15
|
getRawPublicKeyFromClientKeyShares({ chainName, clientKeyShare, }: {
|
|
16
16
|
chainName: string;
|
|
@@ -22,22 +22,78 @@ export declare class DynamicSuiWalletClient extends DynamicWalletClient {
|
|
|
22
22
|
private formatSignature;
|
|
23
23
|
private verifyMessageSignature;
|
|
24
24
|
private verifyTransactionSignature;
|
|
25
|
-
signMessage({ message, accountAddress, password, }: {
|
|
25
|
+
signMessage({ message, accountAddress, password, signedSessionId, mfaToken, }: {
|
|
26
26
|
message: string;
|
|
27
27
|
accountAddress: string;
|
|
28
28
|
password?: string;
|
|
29
|
+
signedSessionId: string;
|
|
30
|
+
mfaToken?: string;
|
|
29
31
|
}): Promise<string>;
|
|
30
|
-
signTransaction({
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
signTransaction({ transaction, senderAddress, password, signedSessionId, mfaToken, }: {
|
|
33
|
+
transaction: string;
|
|
34
|
+
senderAddress: string;
|
|
33
35
|
password?: string;
|
|
36
|
+
signedSessionId: string;
|
|
37
|
+
mfaToken?: string;
|
|
34
38
|
}): Promise<string>;
|
|
35
39
|
deriveAccountAddress({ rawPublicKey }: {
|
|
36
|
-
rawPublicKey:
|
|
40
|
+
rawPublicKey: string;
|
|
37
41
|
}): {
|
|
38
42
|
accountAddress: string;
|
|
39
43
|
publicKeyHex: string;
|
|
40
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Converts a Sui private key from Bech32 format to a 64-character hex string.
|
|
47
|
+
* The output is compatible with RFC8032 Ed25519 private key format.
|
|
48
|
+
*
|
|
49
|
+
* @param suiPrivateKey - The Sui private key in Bech32 format starting with "suiprivkey1"
|
|
50
|
+
* @returns An object containing the private key and the private key bytes
|
|
51
|
+
* @throws Error if the input is not a valid Sui private key format
|
|
52
|
+
*/
|
|
53
|
+
convertSuiPrivateKey(suiPrivateKey: string): {
|
|
54
|
+
privateKey: string;
|
|
55
|
+
privateKeyBytes: Buffer;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Gets the public key for a given private key
|
|
59
|
+
* @param privateKeyBytes A Buffer containing the Ed25519 private key bytes
|
|
60
|
+
* @returns The public key (Sui address) derived from the private key
|
|
61
|
+
*/
|
|
62
|
+
getPublicKeyFromPrivateKey(privateKeyBytes: Buffer): string;
|
|
63
|
+
/**
|
|
64
|
+
* Imports the private key for a given account address
|
|
65
|
+
*
|
|
66
|
+
* @param privateKey The private key to import, accepts both Bech32 and hex formats
|
|
67
|
+
* @param chainName The chain name to import the private key for
|
|
68
|
+
* @param thresholdSignatureScheme The threshold signature scheme to use
|
|
69
|
+
* @param password The password for encrypted backup shares
|
|
70
|
+
* @returns The account address, raw public key, and client key shares
|
|
71
|
+
*/
|
|
72
|
+
importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, onError, signedSessionId, }: {
|
|
73
|
+
privateKey: string;
|
|
74
|
+
chainName: string;
|
|
75
|
+
thresholdSignatureScheme: ThresholdSignatureScheme;
|
|
76
|
+
password?: string;
|
|
77
|
+
onError?: (error: Error) => void;
|
|
78
|
+
signedSessionId: string;
|
|
79
|
+
}): Promise<{
|
|
80
|
+
accountAddress: string;
|
|
81
|
+
rawPublicKey: string | undefined;
|
|
82
|
+
clientKeyShares: ClientKeyShare[];
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Exports the private key for a given account address
|
|
86
|
+
*
|
|
87
|
+
* @param accountAddress The account address to export the private key for
|
|
88
|
+
* @param password The password for encrypted backup shares
|
|
89
|
+
* @returns The private key in hex format
|
|
90
|
+
*/
|
|
91
|
+
exportPrivateKey({ accountAddress, password, signedSessionId, mfaToken, }: {
|
|
92
|
+
accountAddress: string;
|
|
93
|
+
password?: string;
|
|
94
|
+
signedSessionId: string;
|
|
95
|
+
mfaToken?: string;
|
|
96
|
+
}): Promise<string>;
|
|
41
97
|
getSuiWallets(): Promise<any>;
|
|
42
98
|
}
|
|
43
99
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const ERROR_KEYGEN_FAILED = "Error with keygen";
|
|
2
2
|
export declare const ERROR_CREATE_WALLET_ACCOUNT = "Error creating sui wallet account";
|
|
3
|
+
export declare const ERROR_IMPORT_PRIVATE_KEY = "Error importing private key";
|
|
4
|
+
export declare const ERROR_EXPORT_PRIVATE_KEY = "Error exporting private key";
|
|
3
5
|
export declare const ERROR_SIGN_MESSAGE = "Error signing message";
|
|
4
6
|
export declare const ERROR_ACCOUNT_ADDRESS_REQUIRED = "Account address is required";
|
|
5
7
|
export declare const ERROR_VERIFY_MESSAGE_SIGNATURE = "Error verifying message signature";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/client/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,sBAAsB,CAAC;AAEvD,eAAO,MAAM,2BAA2B,sCAAsC,CAAC;AAE/E,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAE5E,eAAO,MAAM,8BAA8B,sCACN,CAAC;AAEtC,eAAO,MAAM,kCAAkC,0CACN,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/client/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,sBAAsB,CAAC;AAEvD,eAAO,MAAM,2BAA2B,sCAAsC,CAAC;AAE/E,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAEtE,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAEtE,eAAO,MAAM,kBAAkB,0BAA0B,CAAC;AAE1D,eAAO,MAAM,8BAA8B,gCAAgC,CAAC;AAE5E,eAAO,MAAM,8BAA8B,sCACN,CAAC;AAEtC,eAAO,MAAM,kCAAkC,0CACN,CAAC"}
|