From fe8917e8962d07cdf07db706c8df712d6aa5534f Mon Sep 17 00:00:00 2001 From: Martin Schere Date: Thu, 27 Feb 2025 09:41:12 +0100 Subject: [PATCH 1/3] feat: allow hot wallet to sign with stake key --- packages/blaze-wallet/src/hot.ts | 50 +++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/packages/blaze-wallet/src/hot.ts b/packages/blaze-wallet/src/hot.ts index 68c60ea..efb7ee3 100644 --- a/packages/blaze-wallet/src/hot.ts +++ b/packages/blaze-wallet/src/hot.ts @@ -50,7 +50,7 @@ export class HotWallet implements Wallet { signingKey: Bip32PrivateKey, publicKey: Bip32PublicKey, provider: Provider, - stakePaymentKey?: Bip32PrivateKey, + stakePaymentKey?: Bip32PrivateKey ) { this.address = address; this.rewardAddress = rewardAddress; @@ -66,7 +66,7 @@ export class HotWallet implements Wallet { static async generateAccountAddressFromMasterkey( masterkey: Bip32PrivateKey, networkId: NetworkId = NetworkId.Testnet, - addressType: AddressType = AddressType.BasePaymentKeyStakeKey, + addressType: AddressType = AddressType.BasePaymentKeyStakeKey ): Promise<{ address: Address; paymentKey: Bip32PrivateKey; @@ -78,7 +78,7 @@ export class HotWallet implements Wallet { addressType !== AddressType.EnterpriseKey ) { throw new Error( - "Hot wallets only support the BasePaymentKeyStakeKey and EnterpriseKey adresses!", + "Hot wallets only support the BasePaymentKeyStakeKey and EnterpriseKey adresses!" ); } @@ -98,7 +98,7 @@ export class HotWallet implements Wallet { paymentPart: { type: CredentialType.KeyHash, hash: Hash28ByteBase16.fromEd25519KeyHashHex( - (await (await paymentKey.toPublic()).toRawKey().hash()).hex(), + (await (await paymentKey.toPublic()).toRawKey().hash()).hex() ), }, delegationPart: @@ -112,7 +112,7 @@ export class HotWallet implements Wallet { await (await (await accountKey.derive([2, 0])).toPublic()) .toRawKey() .hash() - ).hex(), + ).hex() ), }, }); @@ -129,7 +129,7 @@ export class HotWallet implements Wallet { masterkey: Bip32PrivateKeyHex, provider: Provider, networkId: NetworkId = NetworkId.Testnet, - addressType: AddressType = AddressType.BasePaymentKeyStakeKey, + addressType: AddressType = AddressType.BasePaymentKeyStakeKey ): Promise { const rootKey = Bip32PrivateKey.fromHex(masterkey); @@ -137,7 +137,7 @@ export class HotWallet implements Wallet { await this.generateAccountAddressFromMasterkey( rootKey, networkId, - addressType, + addressType ); return new HotWallet( @@ -146,7 +146,7 @@ export class HotWallet implements Wallet { paymentKey, publicKey, provider, - stakePaymentKey, + stakePaymentKey ); } @@ -215,27 +215,51 @@ export class HotWallet implements Wallet { * Requests a transaction signature from the wallet. * @param {string} tx - The transaction to sign. * @param {boolean} partialSign - Whether to partially sign the transaction. + * @param {boolean} signWithStakeKey - Whether to also sign the transaction with the stake key. * @returns {Promise} - The signed transaction. */ async signTransaction( tx: Transaction, partialSign: boolean = true, + signWithStakeKey: boolean = false ): Promise { if (partialSign == false) { throw new Error( - "signTx: Hot wallet only supports partial signing = true", + "signTx: Hot wallet only supports partial signing = true" ); } const signature = await this.signingKey .toRawKey() .sign(HexBlob(tx.getId())); + const tws = new TransactionWitnessSet(); - const vkw = new VkeyWitness( + + const payemntVkw = new VkeyWitness( this.publicKey.toRawKey().hex(), - signature.hex(), + signature.hex() ); - tws.setVkeys(CborSet.fromCore([vkw.toCore()], VkeyWitness.fromCore)); + + const vkeys = [payemntVkw.toCore()]; + + if (signWithStakeKey) { + if (!this.stakeSigningKey) { + throw new Error( + "signTx: Signing with stake key requested but no stake key is available" + ); + } + const stakeSignature = await this.stakeSigningKey + .toRawKey() + .sign(HexBlob(tx.getId())); + const stakePublicKey = (await this.stakeSigningKey.toPublic()) + .toRawKey() + .hex(); + const stakeVkw = new VkeyWitness(stakePublicKey, stakeSignature.hex()); + + vkeys.push(stakeVkw.toCore()); + } + + tws.setVkeys(CborSet.fromCore(vkeys, VkeyWitness.fromCore)); return tws; } @@ -247,7 +271,7 @@ export class HotWallet implements Wallet { */ async signData( address: Address, - payload: string, + payload: string ): Promise { const paymentKey = address.getProps().paymentPart; const signingPublic = await this.signingKey.toPublic(); From 6db65403a4f0a8f438ee2dd3e6340b1e5915d1a8 Mon Sep 17 00:00:00 2001 From: Martin Schere Date: Thu, 27 Feb 2025 10:31:39 +0100 Subject: [PATCH 2/3] fix: fmt --- packages/blaze-wallet/src/hot.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/blaze-wallet/src/hot.ts b/packages/blaze-wallet/src/hot.ts index efb7ee3..693ac39 100644 --- a/packages/blaze-wallet/src/hot.ts +++ b/packages/blaze-wallet/src/hot.ts @@ -50,7 +50,7 @@ export class HotWallet implements Wallet { signingKey: Bip32PrivateKey, publicKey: Bip32PublicKey, provider: Provider, - stakePaymentKey?: Bip32PrivateKey + stakePaymentKey?: Bip32PrivateKey, ) { this.address = address; this.rewardAddress = rewardAddress; @@ -66,7 +66,7 @@ export class HotWallet implements Wallet { static async generateAccountAddressFromMasterkey( masterkey: Bip32PrivateKey, networkId: NetworkId = NetworkId.Testnet, - addressType: AddressType = AddressType.BasePaymentKeyStakeKey + addressType: AddressType = AddressType.BasePaymentKeyStakeKey, ): Promise<{ address: Address; paymentKey: Bip32PrivateKey; @@ -78,7 +78,7 @@ export class HotWallet implements Wallet { addressType !== AddressType.EnterpriseKey ) { throw new Error( - "Hot wallets only support the BasePaymentKeyStakeKey and EnterpriseKey adresses!" + "Hot wallets only support the BasePaymentKeyStakeKey and EnterpriseKey adresses!", ); } @@ -98,7 +98,7 @@ export class HotWallet implements Wallet { paymentPart: { type: CredentialType.KeyHash, hash: Hash28ByteBase16.fromEd25519KeyHashHex( - (await (await paymentKey.toPublic()).toRawKey().hash()).hex() + (await (await paymentKey.toPublic()).toRawKey().hash()).hex(), ), }, delegationPart: @@ -112,7 +112,7 @@ export class HotWallet implements Wallet { await (await (await accountKey.derive([2, 0])).toPublic()) .toRawKey() .hash() - ).hex() + ).hex(), ), }, }); @@ -129,7 +129,7 @@ export class HotWallet implements Wallet { masterkey: Bip32PrivateKeyHex, provider: Provider, networkId: NetworkId = NetworkId.Testnet, - addressType: AddressType = AddressType.BasePaymentKeyStakeKey + addressType: AddressType = AddressType.BasePaymentKeyStakeKey, ): Promise { const rootKey = Bip32PrivateKey.fromHex(masterkey); @@ -137,7 +137,7 @@ export class HotWallet implements Wallet { await this.generateAccountAddressFromMasterkey( rootKey, networkId, - addressType + addressType, ); return new HotWallet( @@ -146,7 +146,7 @@ export class HotWallet implements Wallet { paymentKey, publicKey, provider, - stakePaymentKey + stakePaymentKey, ); } @@ -221,11 +221,11 @@ export class HotWallet implements Wallet { async signTransaction( tx: Transaction, partialSign: boolean = true, - signWithStakeKey: boolean = false + signWithStakeKey: boolean = false, ): Promise { if (partialSign == false) { throw new Error( - "signTx: Hot wallet only supports partial signing = true" + "signTx: Hot wallet only supports partial signing = true", ); } @@ -237,7 +237,7 @@ export class HotWallet implements Wallet { const payemntVkw = new VkeyWitness( this.publicKey.toRawKey().hex(), - signature.hex() + signature.hex(), ); const vkeys = [payemntVkw.toCore()]; @@ -245,7 +245,7 @@ export class HotWallet implements Wallet { if (signWithStakeKey) { if (!this.stakeSigningKey) { throw new Error( - "signTx: Signing with stake key requested but no stake key is available" + "signTx: Signing with stake key requested but no stake key is available", ); } const stakeSignature = await this.stakeSigningKey @@ -271,7 +271,7 @@ export class HotWallet implements Wallet { */ async signData( address: Address, - payload: string + payload: string, ): Promise { const paymentKey = address.getProps().paymentPart; const signingPublic = await this.signingKey.toPublic(); From 6dd0e74262e4618bc3e4e50da378783db078f6a1 Mon Sep 17 00:00:00 2001 From: Martin Schere Date: Thu, 27 Feb 2025 10:33:30 +0100 Subject: [PATCH 3/3] chore: changeset --- .changeset/ten-stingrays-study.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ten-stingrays-study.md diff --git a/.changeset/ten-stingrays-study.md b/.changeset/ten-stingrays-study.md new file mode 100644 index 0000000..335523c --- /dev/null +++ b/.changeset/ten-stingrays-study.md @@ -0,0 +1,5 @@ +--- +"@blaze-cardano/wallet": minor +--- + +Add the ability to sign with the stake key