1
1
/* eslint-disable no-use-before-define */
2
2
import {
3
3
BackgroundServices ,
4
+ Metadata ,
4
5
UserPromptService ,
5
6
adaPriceProperties ,
6
7
disconnectPortTestObjProperties ,
@@ -9,10 +10,14 @@ import {
9
10
} from './util' ;
10
11
import {
11
12
RemoteApiPropertyType ,
13
+ SignerManager ,
12
14
WalletManagerUi ,
15
+ WalletType ,
13
16
consumeRemoteApi ,
14
17
consumeSupplyDistributionTracker ,
15
- exposeApi
18
+ createKeyAgentFactory ,
19
+ exposeApi ,
20
+ exposeSignerManagerApi
16
21
} from '@cardano-sdk/web-extension' ;
17
22
import {
18
23
adaPriceServiceChannel ,
@@ -21,12 +26,20 @@ import {
21
26
userPromptServiceChannel ,
22
27
walletName
23
28
} from './const' ;
24
- import { keyManagementFactory } from '../../../src' ;
25
29
30
+ import * as Crypto from '@cardano-sdk/crypto' ;
31
+ import { Buffer } from 'buffer' ;
26
32
import { Cardano } from '@cardano-sdk/core' ;
33
+ import {
34
+ CommunicationType ,
35
+ InMemoryKeyAgent ,
36
+ SerializableInMemoryKeyAgentData ,
37
+ emip3encrypt ,
38
+ util
39
+ } from '@cardano-sdk/key-management' ;
27
40
import { HexBlob } from '@cardano-sdk/util' ;
28
41
import { SodiumBip32Ed25519 } from '@cardano-sdk/crypto' ;
29
- import { combineLatest , firstValueFrom , of } from 'rxjs' ;
42
+ import { combineLatest , firstValueFrom , merge , of } from 'rxjs' ;
30
43
import { runtime } from 'webextension-polyfill' ;
31
44
32
45
const delegationConfig = {
@@ -198,7 +211,48 @@ const cleanupMultidelegationInfo = (multiDelegationDiv: Element) => {
198
211
}
199
212
} ;
200
213
201
- const walletManager = new WalletManagerUi ( { walletName } , { logger, runtime } ) ;
214
+ const signerManager = new SignerManager (
215
+ {
216
+ hwOptions : {
217
+ communicationType : CommunicationType . Web ,
218
+ manifest : {
219
+ appUrl : 'https://web-extension.app' ,
220
+
221
+ }
222
+ }
223
+ } ,
224
+ {
225
+ keyAgentFactory : createKeyAgentFactory ( {
226
+ bip32Ed25519 : new Crypto . SodiumBip32Ed25519 ( ) ,
227
+ logger
228
+ } )
229
+ }
230
+ ) ;
231
+
232
+ const passphraseByteArray = Uint8Array . from (
233
+ env . KEY_MANAGEMENT_PARAMS . passphrase . split ( '' ) . map ( ( letter ) => letter . charCodeAt ( 0 ) )
234
+ ) ;
235
+ merge ( signerManager . signDataRequest$ , signerManager . transactionWitnessRequest$ ) . subscribe ( ( req ) => {
236
+ logger . info ( 'Sign request' , req ) ;
237
+ if ( req . walletType === WalletType . InMemory ) {
238
+ req . sign ( new Uint8Array ( passphraseByteArray ) ) ;
239
+ } else {
240
+ req . sign ( ) ;
241
+ }
242
+ logger . info ( 'Signed' , req ) ;
243
+ } ) ;
244
+
245
+ // Expose signer manager.
246
+ exposeSignerManagerApi (
247
+ {
248
+ signerManager
249
+ } ,
250
+ { logger, runtime }
251
+ ) ;
252
+
253
+ // TODO: toSerializableObj does not support serializing empty obj {}
254
+ const walletManager = new WalletManagerUi < Metadata > ( { walletName } , { logger, runtime } ) ;
255
+
202
256
// Wallet object does not change when wallets are activated/deactivated.
203
257
// Instead, it's observable properties emit from the currently active wallet.
204
258
const wallet = walletManager . wallet ;
@@ -220,30 +274,72 @@ wallet.delegation.distribution$.subscribe((delegationDistrib) => {
220
274
}
221
275
} ) ;
222
276
223
- const createWallet = async ( accountIndex : number ) => {
224
- clearWalletValues ( ) ;
225
-
226
- const keyAgent = await (
227
- await keyManagementFactory . create (
228
- env . KEY_MANAGEMENT_PROVIDER ,
277
+ const createWalletIfNotExistsAndActivate = async ( accountIndex : number ) => {
278
+ const wallets = await firstValueFrom ( walletManager . repository . wallets$ ) ;
279
+ let walletId = wallets . find (
280
+ ( w ) => w . type !== WalletType . Script && w . accounts . some ( ( a ) => a . accountIndex === accountIndex )
281
+ ) ?. walletId ;
282
+ if ( ! walletId ) {
283
+ logger . log ( 'creating wallet' ) ;
284
+ clearWalletValues ( ) ;
285
+ const bip32Ed25519 = new SodiumBip32Ed25519 ( ) ;
286
+ const mnemonicWords = env . KEY_MANAGEMENT_PARAMS . mnemonic . split ( ' ' ) ;
287
+ const passphrase = new Uint8Array ( passphraseByteArray ) ;
288
+ const keyAgent = await InMemoryKeyAgent . fromBip39MnemonicWords (
229
289
{
230
- ...env . KEY_MANAGEMENT_PARAMS ,
231
- accountIndex
290
+ accountIndex,
291
+ chainId : env . KEY_MANAGEMENT_PARAMS . chainId ,
292
+ getPassphrase : async ( ) => passphrase ,
293
+ mnemonicWords
232
294
} ,
233
- logger
234
- )
235
- ) ( { bip32Ed25519 : new SodiumBip32Ed25519 ( ) , logger } ) ;
295
+ { bip32Ed25519, logger }
296
+ ) ;
297
+ const encryptedRootPrivateKey = ( keyAgent . serializableData as SerializableInMemoryKeyAgentData )
298
+ . encryptedRootPrivateKeyBytes ;
299
+
300
+ const entropy = Buffer . from ( util . mnemonicWordsToEntropy ( mnemonicWords ) , 'hex' ) ;
301
+ const encryptedEntropy = await emip3encrypt ( entropy , passphraseByteArray ) ;
302
+
303
+ logger . log ( 'adding to repository wallet' ) ;
304
+ // Add wallet to the repository.
305
+ walletId = await walletManager . repository . addWallet ( {
306
+ encryptedSecrets : {
307
+ entropy : HexBlob . fromBytes ( encryptedEntropy ) ,
308
+ rootPrivateKeyBytes : HexBlob . fromBytes ( new Uint8Array ( encryptedRootPrivateKey ) )
309
+ } ,
310
+ extendedAccountPublicKey : keyAgent . serializableData . extendedAccountPublicKey ,
311
+ type : WalletType . InMemory
312
+ } ) ;
313
+ await walletManager . repository . addAccount ( {
314
+ accountIndex,
315
+ metadata : { name : `Wallet #${ accountIndex + 1 } ` } ,
316
+ walletId
317
+ } ) ;
236
318
237
- await walletManager . destroy ( ) ;
238
- await walletManager . activate ( { keyAgent, observableWalletName : getObservableWalletName ( accountIndex ) } ) ;
319
+ logger . log ( `Wallet added: ${ walletId } ` ) ;
320
+ } else {
321
+ logger . info ( `Wallet with accountIndex ${ accountIndex } already exists` ) ;
322
+ }
323
+
324
+ // await walletManager.destroy();
325
+ await walletManager . activate ( {
326
+ accountIndex,
327
+ chainId : env . KEY_MANAGEMENT_PARAMS . chainId ,
328
+ observableWalletName : getObservableWalletName ( accountIndex ) ,
329
+ walletId
330
+ } ) ;
239
331
240
332
// Same wallet object will return different names, based on which wallet is active
241
333
// Calling this method before any wallet is active, will resolve only once a wallet becomes active
242
334
setName ( await wallet . getName ( ) ) ;
243
335
} ;
244
336
245
- document . querySelector ( selectors . btnActivateWallet1 ) ! . addEventListener ( 'click' , async ( ) => await createWallet ( 0 ) ) ;
246
- document . querySelector ( selectors . btnActivateWallet2 ) ! . addEventListener ( 'click' , async ( ) => await createWallet ( 1 ) ) ;
337
+ document
338
+ . querySelector ( selectors . btnActivateWallet1 ) !
339
+ . addEventListener ( 'click' , async ( ) => await createWalletIfNotExistsAndActivate ( 0 ) ) ;
340
+ document
341
+ . querySelector ( selectors . btnActivateWallet2 ) !
342
+ . addEventListener ( 'click' , async ( ) => await createWalletIfNotExistsAndActivate ( 1 ) ) ;
247
343
document . querySelector ( selectors . deactivateWallet ) ! . addEventListener ( 'click' , async ( ) => await deactivateWallet ( ) ) ;
248
344
document . querySelector ( selectors . destroyWallet ) ! . addEventListener ( 'click' , async ( ) => await destroyWallet ( ) ) ;
249
345
document . querySelector ( selectors . btnDelegate ) ! . addEventListener ( 'click' , async ( ) => {
@@ -253,7 +349,10 @@ document.querySelector(selectors.btnDelegate)!.addEventListener('click', async (
253
349
} ) ;
254
350
255
351
document . querySelector ( selectors . btnSignAndBuildTx ) ! . addEventListener ( 'click' , async ( ) => {
352
+ logger . info ( 'Building transaction' ) ;
256
353
const [ { address : ownAddress } ] = await firstValueFrom ( wallet . addresses$ ) ;
354
+ logger . info ( `Address: ${ ownAddress } ` ) ;
355
+
257
356
const builtTx = wallet
258
357
. createTxBuilder ( )
259
358
. addOutput ( {
@@ -264,6 +363,7 @@ document.querySelector(selectors.btnSignAndBuildTx)!.addEventListener('click', a
264
363
const { body } = await builtTx . inspect ( ) ;
265
364
logger . info ( 'Built tx' , body . outputs . length ) ;
266
365
const { tx : signedTx } = await builtTx . sign ( ) ;
366
+ logger . error ( signedTx ) ;
267
367
setSignature ( signedTx . witness . signatures . values ( ) . next ( ) . value ) ;
268
368
} ) ;
269
369
0 commit comments