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