From 54311e7926491d089ae963e462642d8f7f91dd91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=B6ren?= <hello@soerenschwert.de>
Date: Tue, 14 Jan 2025 16:00:11 +0100
Subject: [PATCH] Address review comments

- Simplify SignTransaction result creation (more in line with how it was before the switch to PoS)
- Explain swap refund transaction validity-start-height calculation drawbacks and lower-bound it to the HTLC creation VSH
---
 .../sign-transaction/SignTransaction.js       | 15 ++++--------
 src/request/swap-iframe/SwapIFrameApi.js      | 24 +++++++++++++++++--
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/request/sign-transaction/SignTransaction.js b/src/request/sign-transaction/SignTransaction.js
index 725acd8d..27815601 100644
--- a/src/request/sign-transaction/SignTransaction.js
+++ b/src/request/sign-transaction/SignTransaction.js
@@ -182,21 +182,16 @@ class SignTransaction {
             return;
         }
 
-        const privateKey = key.derivePrivateKey(request.keyPath);
-        const publicKey = Nimiq.PublicKey.derive(privateKey);
+        const publicKey = key.derivePublicKey(request.keyPath);
+        const signature = key.sign(request.keyPath, request.transaction.serializeContent());
 
-        const tx = request.transaction;
-
-        // Manually create signature proof, because tx.sign(keyPair) does not support HTLC redeeming transactions.
-        const signature = Nimiq.Signature.create(privateKey, publicKey, tx.serializeContent());
-        const proof = Nimiq.SignatureProof.singleSig(publicKey, signature);
-        tx.proof = proof.serialize();
+        request.transaction.proof = Nimiq.SignatureProof.singleSig(publicKey, signature).serialize();
 
         /** @type {KeyguardRequest.SignTransactionResult} */
         const result = {
             publicKey: publicKey.serialize(),
-            signature: tx.proof.subarray(tx.proof.length - 64),
-            serializedTx: tx.serialize(),
+            signature: signature.serialize(),
+            serializedTx: request.transaction.serialize(),
         };
         resolve(result);
     }
diff --git a/src/request/swap-iframe/SwapIFrameApi.js b/src/request/swap-iframe/SwapIFrameApi.js
index c4c9f571..d244b376 100644
--- a/src/request/swap-iframe/SwapIFrameApi.js
+++ b/src/request/swap-iframe/SwapIFrameApi.js
@@ -429,14 +429,34 @@ class SwapIFrameApi extends BitcoinRequestParserMixin(RequestParser) { // eslint
                 const feePerUnit = Number(transaction.fee) / transaction.serializedSize;
                 const fee = BigInt(Math.ceil(feePerUnit * 167)); // 167 = NIM HTLC refunding tx size
 
+                /**
+                 * Calculate future ValidityStartHeight for the refund transaction.
+                 *
+                 * This is not exact, unfortunately. But hopefully close enough. The calculated VSH is always
+                 * smaller than it should be (blocks are faster than 1/second on average, time taken between
+                 * request creation and this code is subtracted as well). Additionally, if the user's system
+                 * clock is off, the resulting VHS will be wrong, too.
+                 *
+                 * But the watchtower only sends the refund transaction once the timeout _timestamp_ of the swap
+                 * has passed, at which point the transaction will still be valid (except if totally wrong because
+                 * of system clock).
+                 *
+                 * If the refund transaction is invalid when it is supposed to be sent, the user can always
+                 * trigger a refund manually from the transaction details in the Wallet.
+                 */
+                const validityStartHeight = Math.max(
+                    transaction.validityStartHeight,
+                    transaction.validityStartHeight
+                        + (parsedRequest.fund.htlcDetails.timeoutTimestamp - Math.round(Date.now() / 1e3)),
+                );
+
                 // Create refund transaction
                 const refundTransaction = new Nimiq.Transaction(
                     transaction.recipient, Nimiq.AccountType.HTLC, new Uint8Array(0),
                     transaction.sender, Nimiq.AccountType.Basic, new Uint8Array(0),
                     transaction.value - fee, fee,
                     Nimiq.TransactionFlag.None,
-                    transaction.validityStartHeight
-                        + (parsedRequest.fund.htlcDetails.timeoutTimestamp - Math.round(Date.now() / 1e3)),
+                    validityStartHeight,
                     CONFIG.NIMIQ_NETWORK_ID,
                 );