diff --git a/src/ConfidentialTransaction.cs b/src/ConfidentialTransaction.cs index 2298af6..f129f52 100644 --- a/src/ConfidentialTransaction.cs +++ b/src/ConfidentialTransaction.cs @@ -2453,8 +2453,31 @@ public string[] FundRawTransaction( } using (var handle = new ErrorHandle()) { + int network = defaultNetType; + foreach (var key in reservedAddressMap.Keys) + { + var reservedAddress = reservedAddressMap[key]; + if (reservedAddress.Length > 0) + { + Address addr; + try + { + var ctAddr = new ConfidentialAddress(reservedAddress); + addr = ctAddr.GetAddress(); + } + catch (ArgumentException) + { + addr = new Address(reservedAddress); + } + if ((addr.GetNetwork() == CfdNetworkType.Liquidv1) || (addr.GetNetwork() == CfdNetworkType.ElementsRegtest)) + { + network = (int)addr.GetNetwork(); + break; + } + } + } var ret = NativeMethods.CfdInitializeFundRawTx( - handle.GetHandle(), defaultNetType, (uint)targetAssetAmountMap.Keys.Count, + handle.GetHandle(), network, (uint)targetAssetAmountMap.Keys.Count, feeAsset.ToHexString(), out IntPtr fundHandle); if (ret != CfdErrorCode.Success) { diff --git a/src/Transaction.cs b/src/Transaction.cs index 6b268ab..8c02be7 100644 --- a/src/Transaction.cs +++ b/src/Transaction.cs @@ -1749,8 +1749,23 @@ public string FundRawTransaction(UtxoData[] txinList, UtxoData[] utxoList, } using (var handle = new ErrorHandle()) { + int network = defaultNetType; + if (reservedAddress.Length > 0) + { + var addr = new Address(reservedAddress); + switch (addr.GetNetwork()) + { + case CfdNetworkType.Mainnet: + case CfdNetworkType.Testnet: + case CfdNetworkType.Regtest: + network = (int)addr.GetNetwork(); + break; + default: + break; + } + } var ret = NativeMethods.CfdInitializeFundRawTx( - handle.GetHandle(), defaultNetType, 1, "", out IntPtr fundHandle); + handle.GetHandle(), network, 1, "", out IntPtr fundHandle); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); diff --git a/test/ConfidentialTransactionTest.cs b/test/ConfidentialTransactionTest.cs index e98e0df..2eb9aa2 100644 --- a/test/ConfidentialTransactionTest.cs +++ b/test/ConfidentialTransactionTest.cs @@ -975,6 +975,104 @@ public void FundRawTransactionExistTxInTest() Assert.Equal(147, feeData.UtxoFee); } + [Fact] + public void FundRawTransactionRegtestCtAddressTest() + { + ElementsUtxoData[] utxos = GetElementsBnbUtxoList(CfdNetworkType.ElementsRegtest); + ExtPubkey key = new ExtPubkey("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy"); + Address setAddr1 = new Address(key.DerivePubkey(11).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.ElementsRegtest); + Address setAddr2 = new Address(key.DerivePubkey(12).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.ElementsRegtest); + + ConfidentialTransaction tx = new ConfidentialTransaction(2, 0, null, new[] { + new ConfidentialTxOut(new ConfidentialAsset(assetA), new ConfidentialValue(10000000), setAddr1.GetLockingScript()), + new ConfidentialTxOut(new ConfidentialAsset(assetB), new ConfidentialValue(500000), setAddr2.GetLockingScript()), + }); + output.WriteLine("tx: " + tx.ToHexString()); + Assert.Equal("020000000000020100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c00000000", + tx.ToHexString()); + + var feeAsset = new ConfidentialAsset(assetA); + var targetAssetMap = new Dictionary { + { new ConfidentialAsset(assetA), 0 }, + { new ConfidentialAsset(assetB), 0 }, + }; + var ctKey = key.DerivePubkey("1/1").GetPubkey(); + Address addr1 = new Address(key.DerivePubkey(1).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.ElementsRegtest); + Address addr2 = new Address(key.DerivePubkey(2).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.ElementsRegtest); + var ctAddr1 = new ConfidentialAddress(addr1, ctKey); + var reservedAddressMap = new Dictionary { + { new ConfidentialAsset(assetA), ctAddr1.ToAddressString() }, + { new ConfidentialAsset(assetB), addr2.ToAddressString() }, + }; + double feeRate = 0.1; + string[] usedAddr = tx.FundRawTransaction(null, utxos, targetAssetMap, reservedAddressMap, feeAsset, feeRate); + output.WriteLine("tx: " + tx.ToHexString()); + + Assert.Equal("0200000000020bfa8774c5f753ce2f801a8106413b470af94edbff5b4242ed4c5a26d20e72b90000000000ffffffff040b0000000000000000000000000000000000000000000000000000000000000000000000ffffffff050100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c0100000000000000000000000000000000000000000000000000000000000000aa0100000000000001ff00000100000000000000000000000000000000000000000000000000000000000000bb010000000001124c1e00160014a53be40113bb50f2b8b2d0bfea1e823e75632b5f0100000000000000000000000000000000000000000000000000000000000000aa0100000000004b595f034082879df418331794e4a55b87cd94d2d23cf1f22aa07081aa28b91c28b5e5a116001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", + tx.ToHexString()); + output.WriteLine(ConfidentialTransaction.DecodeRawTransaction(tx)); + Assert.Equal(2, usedAddr.Length); + if (usedAddr.Length == 2) + { + output.WriteLine("addr1: " + usedAddr[0]); + output.WriteLine("addr2: " + usedAddr[1]); + Assert.Equal(addr2.ToAddressString(), usedAddr[0]); + Assert.Equal(ctAddr1.ToAddressString(), usedAddr[1]); + } + Assert.Equal(511, tx.GetLastTxFee()); + + // calc fee + ElementsUtxoData[] feeUtxos = new[]{ + utxos[5], + utxos[9], + }; + FeeData feeData = tx.EstimateFee(feeUtxos, feeRate, feeAsset, true); + Assert.Equal(501, feeData.TxOutFee + feeData.UtxoFee); + Assert.Equal(482, feeData.TxOutFee); + Assert.Equal(19, feeData.UtxoFee); + } + + [Fact] + public void FundRawTransactionBitcoinAddressTest() + { + ElementsUtxoData[] utxos = GetElementsBnbUtxoList(CfdNetworkType.Liquidv1); + ExtPubkey key = new ExtPubkey("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy"); + Address setAddr1 = new Address(key.DerivePubkey(11).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Liquidv1); + Address setAddr2 = new Address(key.DerivePubkey(12).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Liquidv1); + + ConfidentialTransaction tx = new ConfidentialTransaction(2, 0, null, new[] { + new ConfidentialTxOut(new ConfidentialAsset(assetA), new ConfidentialValue(10000000), setAddr1.GetLockingScript()), + new ConfidentialTxOut(new ConfidentialAsset(assetB), new ConfidentialValue(500000), setAddr2.GetLockingScript()), + }); + output.WriteLine("tx: " + tx.ToHexString()); + Assert.Equal("020000000000020100000000000000000000000000000000000000000000000000000000000000aa010000000000989680001600144352a1a6e86311f22274f7ebb2746de21b09b15d0100000000000000000000000000000000000000000000000000000000000000bb01000000000007a120001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c00000000", + tx.ToHexString()); + + var feeAsset = new ConfidentialAsset(assetA); + var targetAssetMap = new Dictionary { + { new ConfidentialAsset(assetA), 0 }, + { new ConfidentialAsset(assetB), 0 }, + }; + Address addr1 = new Address(key.DerivePubkey(1).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Mainnet); + Address addr2 = new Address(key.DerivePubkey(2).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Mainnet); + var reservedAddressMap = new Dictionary { + { new ConfidentialAsset(assetA), addr1.ToAddressString() }, + { new ConfidentialAsset(assetB), addr2.ToAddressString() }, + }; + double feeRate = 0.1; + try + { + tx.FundRawTransaction(null, utxos, targetAssetMap, reservedAddressMap, feeAsset, feeRate); + Assert.True(false); + } + catch (Exception e) + { + output.WriteLine("Exception: " + e.ToString()); + Assert.Equal("CFD error[IllegalArgumentError] message:Base58 decode error.", e.Message); + Assert.True(e is System.ArgumentException); + } + } + [Fact] public void RawReissueAssetTest() { diff --git a/test/TransactionTest.cs b/test/TransactionTest.cs index 72dd08a..9b2ffcc 100644 --- a/test/TransactionTest.cs +++ b/test/TransactionTest.cs @@ -350,6 +350,33 @@ public void FundRawTransactionExistTxInTest() Assert.Equal(5400, feeData.UtxoFee); } + [Fact] + public void FundRawTransactionRegtestAddressTest() + { + UtxoData[] utxos = GetBitcoinBnbUtxoList(CfdNetworkType.Regtest); + ExtPubkey key = new ExtPubkey("xpub661MyMwAqRbcGB88KaFbLGiYAat55APKhtWg4uYMkXAmfuSTbq2QYsn9sKJCj1YqZPafsboef4h4YbXXhNhPwMbkHTpkf3zLhx7HvFw1NDy"); + Address setAddr1 = new Address(key.DerivePubkey(11).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); + Address setAddr2 = new Address(key.DerivePubkey(12).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); + + Transaction tx = new Transaction(2, 0, null, new[] { + new TxOut(10000000, setAddr1.GetLockingScript()), + new TxOut(4000000, setAddr2.GetLockingScript()), + }); + output.WriteLine("tx:\n" + tx.ToHexString()); + Assert.Equal("02000000000280969800000000001600144352a1a6e86311f22274f7ebb2746de21b09b15d00093d00000000001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470c00000000", + tx.ToHexString()); + + Address addr1 = new Address(key.DerivePubkey(1).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); + string usedAddr = tx.FundRawTransaction(null, utxos, addr1.ToAddressString(), 20.0); + output.WriteLine("tx: " + tx.ToHexString()); + + Assert.Equal("02000000010af4768e14f820cb9063f55833b5999119e53390ecf4bf181842909b11d0974d0000000000ffffffff0380969800000000001600144352a1a6e86311f22274f7ebb2746de21b09b15d00093d00000000001600148beaaac4654cf4ebd8e46ca5062b0e7fb3e7470ce47f19000000000016001478eb9fc2c9e1cdf633ecb646858ba862b21384ab00000000", + tx.ToHexString()); + output.WriteLine(Transaction.DecodeRawTransaction(tx)); + Assert.Equal(addr1.ToAddressString(), usedAddr); + Assert.Equal(3860, tx.GetLastTxFee()); + } + static UtxoData[] GetBitcoinBnbUtxoList(CfdNetworkType netType) { string desc = "sh(wpkh([ef735203/0'/0'/7']022c2409fbf657ba25d97bb3dab5426d20677b774d4fc7bd3bfac27ff96ada3dd1))#4z2vy08x";