From cdd135554878908f308c50c4bc06775d04911926 Mon Sep 17 00:00:00 2001 From: pm47 Date: Wed, 7 Jun 2023 17:55:14 +0200 Subject: [PATCH] generate swap-in potentiam address --- .../acinq/eclair/crypto/LocalKeyManager.scala | 26 +++++++++++++++++-- .../eclair/crypto/LocalKeyManagerSpec.scala | 12 +++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala index 161c14416..dc4be6841 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/LocalKeyManager.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.crypto import com.google.common.cache.{CacheBuilder, CacheLoader, LoadingCache} import fr.acinq.bitcoin.scala.Crypto.{PrivateKey, PublicKey} import fr.acinq.bitcoin.scala.DeterministicWallet.{derivePrivateKey, _} -import fr.acinq.bitcoin.scala.{Block, ByteVector32, ByteVector64, Crypto, DeterministicWallet} +import fr.acinq.bitcoin.scala.{Block, ByteVector32, ByteVector64, Crypto, DeterministicWallet, _} import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.transactions.Transactions.TransactionWithInputInfo @@ -136,7 +136,7 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana Transactions.sign(tx, currentKey) } - + /** * Ths method is used to spend revoked transactions, with the corresponding revocation key * @@ -157,4 +157,26 @@ class LocalKeyManager(seed: ByteVector, chainHash: ByteVector32) extends KeyMana val localFundingPrivKey = privateKeys.get(fundingKeyPath).privateKey Announcements.signChannelAnnouncement(chainHash, shortChannelId, localNodeSecret, remoteNodeId, localFundingPrivKey, remoteFundingKey, features) } + + def multisigSwapInAddress(serverPublicKey: Crypto.PublicKey, refundDelay: Int): String = { + val userKeyPath = chainHash match { + case Block.RegtestGenesisBlock.hash | Block.TestnetGenesisBlock.hash => + DeterministicWallet.hardened(51) :: DeterministicWallet.hardened(0) :: DeterministicWallet.hardened(0) :: Nil + case Block.LivenetGenesisBlock.hash => + DeterministicWallet.hardened(52) :: DeterministicWallet.hardened(0) :: DeterministicWallet.hardened(0) :: Nil + } + val userPrivateKey = DeterministicWallet.derivePrivateKey(master, userKeyPath).privateKey + val userPublicKey = userPrivateKey.publicKey + val redeemScript = OP_PUSHDATA(userPublicKey.value) :: OP_CHECKSIGVERIFY :: OP_PUSHDATA(serverPublicKey.value) :: OP_CHECKSIG :: OP_IFDUP :: OP_NOTIF :: OP_PUSHDATA(Script.encodeNumber(refundDelay)) :: OP_CHECKSEQUENCEVERIFY :: OP_ENDIF :: Nil + val pubkeyScript = Script.pay2wsh(redeemScript) + + val hrp = chainHash match { + case Block.RegtestGenesisBlock.hash => "bcrt" + case Block.TestnetGenesisBlock.hash => "tb" + case Block.LivenetGenesisBlock.hash => "bc" + } + val witnessScript = pubkeyScript(1).asInstanceOf[OP_PUSHDATA].data + val address = Bech32.encodeWitnessAddress(hrp, 0, witnessScript) + address + } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala index eb39704c9..da5067f60 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/crypto/LocalKeyManagerSpec.scala @@ -149,4 +149,16 @@ class LocalKeyManagerSpec extends AnyFunSuite { assert(keyManager.htlcPoint(channelKeyPath).publicKey == PrivateKey(hex"b1be27b5232e3bc5d6a261949b4ee68d96fa61f481998d36342e2ad99444cf8a").publicKey) assert(keyManager.commitmentSecret(channelKeyPath, 0).value == ShaChain.shaChainFromSeed(ByteVector32.fromValidHex("eeb3bad6808e8bb5f1774581ccf64aa265fef38eca80a1463d6310bb801b3ba7"), 0xFFFFFFFFFFFFL)) } + + test("generate multisig swap-in address") { + val entropy = ByteVector32.fromValidHex("0101010101010101010101010101010101010101010101010101010101010101") + val seed = MnemonicCode.toSeed(MnemonicCode.toMnemonics(entropy), "").take(32) + val keyManager = new LocalKeyManager(seed, Block.RegtestGenesisBlock.hash) + + val serverPublicKey = PublicKey(ByteVector.fromValidHex("02cd0e2ed9c42af42e0b30e2a0b339c8335bbdc1f895fe552d8e224aedc82d6c88")) + val swapInRefundDelay = 144 * 30 * 6 + val swapInAddress = keyManager.multisigSwapInAddress(serverPublicKey, swapInRefundDelay) + + assert(swapInAddress == "bcrt1qvwc4zcelvlj3pcy97pj09dz2hgq0ptav25nrjm54dt3ch09plxnq6pmjje") + } }