Example #1
0
 public ExtPrivkey DerivePrivkey(string path)
 {
     if (path is null)
     {
         throw new ArgumentNullException(nameof(path));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdCreateExtkeyFromParentPath(
             handle.GetHandle(), extkey, path, (int)networkType,
             (int)CfdExtKeyType.Privkey, out IntPtr tempExtkey);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string childExtkey = CCommon.ConvertToString(tempExtkey);
         return(new ExtPrivkey(childExtkey));
     }
 }
Example #2
0
 /// <summary>
 /// privkey tweak mul.
 /// </summary>
 /// <param name="tweak">tweak bytes</param>
 /// <returns>tweaked privkey</returns>
 public Privkey TweakMul(ByteData tweak)
 {
     if (tweak is null)
     {
         throw new ArgumentNullException(nameof(tweak));
     }
     using (var handle = new ErrorHandle())
     {
         CfdErrorCode ret;
         ret = NativeMethods.CfdPrivkeyTweakMul(
             handle.GetHandle(), privkey, tweak.ToHexString(),
             out IntPtr tweakedKey);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         return(new Privkey(CCommon.ConvertToString(tweakedKey)));
     }
 }
 /// <summary>
 /// Verify ECDSA-adaptor signature.
 /// </summary>
 /// <param name="adaptorSignature">adaptor signature</param>
 /// <param name="adaptorProof">adaptor proof</param>
 /// <param name="adaptor">adaptor pubkey</param>
 /// <param name="msg">32-byte msg</param>
 /// <param name="pubkey">pubkey</param>
 /// <returns>verify result</returns>
 public static bool Verify(ByteData adaptorSignature, ByteData adaptorProof, Pubkey adaptor,
                           ByteData msg, Pubkey pubkey)
 {
     if (adaptorSignature is null)
     {
         throw new ArgumentNullException(nameof(adaptorSignature));
     }
     if (adaptorProof is null)
     {
         throw new ArgumentNullException(nameof(adaptorProof));
     }
     if (adaptor is null)
     {
         throw new ArgumentNullException(nameof(adaptor));
     }
     if (msg is null)
     {
         throw new ArgumentNullException(nameof(msg));
     }
     if (pubkey is null)
     {
         throw new ArgumentNullException(nameof(pubkey));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdVerifyEcdsaAdaptor(
             handle.GetHandle(), adaptorSignature.ToHexString(),
             adaptorProof.ToHexString(),
             adaptor.ToHexString(),
             msg.ToHexString(),
             pubkey.ToHexString());
         if (ret == CfdErrorCode.Success)
         {
             return(true);
         }
         else if (ret != CfdErrorCode.SignVerificationError)
         {
             handle.ThrowError(ret);
         }
     }
     return(false);
 }
Example #4
0
 public string ToHexString()
 {
     if (commitmentValue.Length == 0)
     {
         using (var handle = new ErrorHandle())
         {
             var ret = NativeMethods.CfdGetConfidentialValueHex(
                 handle.GetHandle(), satoshiValue, false, out IntPtr valueHex);
             if (ret != CfdErrorCode.Success)
             {
                 handle.ThrowError(ret);
             }
             return(CCommon.ConvertToString(valueHex));
         }
     }
     else
     {
         return(commitmentValue);
     }
 }
Example #5
0
        /// <summary>
        /// constructor by address string.
        /// </summary>
        /// <param name="addressString">address string.</param>
        public ConfidentialAddress(string addressString)
        {
            confidentialAddress = addressString;
            using (var handle = new ErrorHandle())
            {
                var ret = NativeMethods.CfdParseConfidentialAddress(
                    handle.GetHandle(), addressString,
                    out IntPtr address,
                    out IntPtr confidentialKey, out int networkType);
                if (ret != CfdErrorCode.Success)
                {
                    handle.ThrowError(ret);
                }
                var unconfidenialAddressStr = CCommon.ConvertToString(address);
                var keyStr = CCommon.ConvertToString(confidentialKey);

                unconfidenialAddress = new Address(unconfidenialAddressStr);
                key = new Pubkey(keyStr);
            }
        }
Example #6
0
 /// <summary>
 /// get privkey wif string. (not hex)
 /// </summary>
 /// <returns>privkey wif string</returns>
 public string GetWif(CfdNetworkType networkType, bool isCompressedPubkey)
 {
     if ((privkeyWif.Length != 0) && (networkType == this.networkType) &&
         (isCompressedPubkey == isCompressed))
     {
         return(privkeyWif);
     }
     using (var handle = new ErrorHandle())
     {
         CfdErrorCode ret;
         ret = NativeMethods.CfdGetPrivkeyWif(
             handle.GetHandle(), privkey, (int)networkType, isCompressedPubkey,
             out IntPtr wif);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         return(CCommon.ConvertToString(wif));
     }
 }
Example #7
0
 /// <summary>
 /// encode by DER.
 /// </summary>
 /// <param name="signature">signature</param>
 /// <param name="sighashType">sighash type</param>
 /// <returns>DER encoded data</returns>
 public static ByteData EncodeToDer(ByteData signature, SignatureHashType sighashType)
 {
     if (signature is null)
     {
         throw new ArgumentNullException(nameof(signature));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdEncodeSignatureByDer(
             handle.GetHandle(), signature.ToHexString(),
             sighashType.GetValue(),
             sighashType.IsSighashAnyoneCanPay,
             out IntPtr derSignature);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         return(new ByteData(CCommon.ConvertToString(derSignature)));
     }
 }
Example #8
0
        internal void GetAllData(ErrorHandle handle, TreeHandle treeHandle)
        {
            var tree  = GetBranchData(handle, treeHandle);
            var count = tree.branches.Length;

            TapBranch[]   branchList = new TapBranch[count];
            ByteData256[] nodeList   = new ByteData256[count];
            for (var index = 0; index < count; ++index)
            {
                var ret = NativeMethods.CfdGetTapBranchHandle(
                    handle.GetHandle(), treeHandle.GetHandle(), (byte)index,
                    out IntPtr branchHash, out IntPtr branchTreeHandle);
                if (ret != CfdErrorCode.Success)
                {
                    handle.ThrowError(ret);
                }
                CCommon.ConvertToString(branchHash);
                using (var branchHandle = new TreeHandle(handle, branchTreeHandle))
                {
                    TapBranch branch = new TapBranch();
                    branch.GetAllData(handle, branchHandle);
                    branchList[index] = branch;
                }
            }
            if (count != 0)
            {
                branches = branchList;
            }
            topHash    = tree.topHash;
            treeString = tree.treeString;
            if (!tree.tapscript.IsEmpty())
            {
                tapscript   = tree.tapscript;
                leafVersion = tree.leafVersion;
                for (var index = 0; index < count; ++index)
                {
                    nodeList[index] = branchList[index].topHash;
                }
                targetNodes = nodeList;
            }
        }
Example #9
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="privkey">privkey(wif or hex)</param>
 public Privkey(string privkey)
 {
     if (privkey is null)
     {
         throw new ArgumentNullException(nameof(privkey));
     }
     if (string.IsNullOrEmpty(privkey))
     {
         this.privkey = "";
         privkeyWif   = "";
         isCompressed = true;
     }
     else if (privkey.Length == Size * 2)
     {
         // hex
         this.privkey = privkey;
         networkType  = CfdNetworkType.Mainnet;
         privkeyWif   = "";
         isCompressed = true;
     }
     else
     {
         // wif
         privkeyWif = privkey;
         using (var handle = new ErrorHandle())
         {
             CfdErrorCode ret;
             ret = NativeMethods.CfdParsePrivkeyWif(
                 handle.GetHandle(), privkeyWif,
                 out IntPtr tempPrivkeyHex,
                 out int tempNetworkType,
                 out isCompressed);
             if (ret != CfdErrorCode.Success)
             {
                 handle.ThrowError(ret);
             }
             this.privkey = CCommon.ConvertToString(tempPrivkeyHex);
             networkType  = (CfdNetworkType)tempNetworkType;
         }
     }
 }
 static string[] Verify(string signature)
 {
     using (var handle = new ErrorHandle())
     {
         if (signature.Length == AddedSigHashTypeSize * 2)
         {
             signature = signature.Substring(0, (int)(Size * 2));
         }
         var ret = NativeMethods.CfdSplitSchnorrSignature(
             handle.GetHandle(), signature,
             out IntPtr schnorrNonce,
             out IntPtr privkey);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string nonceStr = CCommon.ConvertToString(schnorrNonce);
         string keyStr   = CCommon.ConvertToString(privkey);
         return(new string[] { nonceStr, keyStr });
     }
 }
Example #11
0
 /// <summary>
 /// Get address from locking script.
 /// </summary>
 /// <param name="inputLockingScript">locking script</param>
 /// <param name="network">network type</param>
 /// <returns>address object</returns>
 public static Address GetAddressByLockingScript(Script inputLockingScript, CfdNetworkType network)
 {
     if (inputLockingScript is null)
     {
         throw new ArgumentNullException(nameof(inputLockingScript));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdGetAddressFromLockingScript(
             handle.GetHandle(),
             inputLockingScript.ToHexString(),
             (int)network,
             out IntPtr outputAddress);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string tempAddress = CCommon.ConvertToString(outputAddress);
         return(new Address(tempAddress));
     }
 }
Example #12
0
 /// <summary>
 /// get pubkey.
 /// </summary>
 /// <returns>pubkey</returns>
 public Pubkey GetPubkey()
 {
     if (privkeyWif.Length == 0)
     {
         return(GetPubkey(true));
     }
     else
     {
         using (var handle = new ErrorHandle())
         {
             var ret = NativeMethods.CfdGetPubkeyFromPrivkey(
                 handle.GetHandle(), privkey, privkeyWif, isCompressed,
                 out IntPtr pubkeyHex);
             if (ret != CfdErrorCode.Success)
             {
                 handle.ThrowError(ret);
             }
             return(new Pubkey(CCommon.ConvertToString(pubkeyHex)));
         }
     }
 }
        /// <summary>
        /// Get tweaked privkey from internal privkey.
        /// </summary>
        /// <param name="privkey">internal privkey.</param>
        /// <returns>tweaked privkey.</returns>
        public Privkey GetTweakedPrivkey(Privkey privkey)
        {
            if (privkey is null)
            {
                throw new ArgumentNullException(nameof(privkey));
            }
            using (var handle = new ErrorHandle())
                using (var treeHandle = new TreeHandle(handle))
                {
                    Load(handle, treeHandle);
                    var ret = NativeMethods.CfdGetTaprootTweakedPrivkey(
                        handle.GetHandle(), treeHandle.GetHandle(), privkey.ToHexString(),
                        out IntPtr tweakedPrivkey);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    var tweakedPrivkeyStr = CCommon.ConvertToString(tweakedPrivkey);

                    return(new Privkey(tweakedPrivkeyStr));
                }
        }
Example #14
0
 /// <summary>
 /// Add branches.
 /// </summary>
 /// <param name="treeStringList">tree string list</param>
 public void AddBranches(string[] treeStringList)
 {
     if (treeStringList is null)
     {
         throw new ArgumentNullException(nameof(treeStringList));
     }
     using (var handle = new ErrorHandle())
         using (var treeHandle = new TreeHandle(handle))
         {
             Load(handle, treeHandle);
             foreach (var treeStr in treeStringList)
             {
                 var ret = NativeMethods.CfdAddTapBranchByScriptTreeString(
                     handle.GetHandle(), treeHandle.GetHandle(), treeStr);
                 if (ret != CfdErrorCode.Success)
                 {
                     handle.ThrowError(ret);
                 }
             }
             UpdateAllData(handle, treeHandle);
         }
 }
Example #15
0
        private void Initialize(ErrorHandle handle, string addressString, out CfdNetworkType outputNetwork,
                                out CfdWitnessVersion outputWitnessVersion, out string outputLockingScript, out string outputHash)
        {
            var ret = NativeMethods.CfdGetAddressInfo(
                handle.GetHandle(),
                addressString,
                out int networkType,
                out int hashType,
                out int segwitVersion,
                out IntPtr lockingScript,
                out IntPtr hashString);

            if (ret != CfdErrorCode.Success)
            {
                handle.ThrowError(ret);
            }
            outputNetwork        = (CfdNetworkType)networkType;
            addressType          = (CfdAddressType)hashType;
            outputWitnessVersion = (CfdWitnessVersion)segwitVersion;
            outputLockingScript  = CCommon.ConvertToString(lockingScript);
            outputHash           = CCommon.ConvertToString(hashString);
        }
Example #16
0
 /// <summary>
 /// Exist txid in block.
 /// </summary>
 /// <param name="txid">txid</param>
 /// <returns>true is exist txid.</returns>
 public bool ExistTxid(Txid txid)
 {
     if (txid is null)
     {
         throw new ArgumentNullException(nameof(txid));
     }
     using (var handle = new ErrorHandle())
         using (var txHandle = new BlockHandle(handle, defaultNetType, hex))
         {
             var ret = NativeMethods.CfdExistTxidInBlock(
                 handle.GetHandle(), txHandle.GetHandle(), txid.ToHexString());
             if (ret == CfdErrorCode.Success)
             {
                 return(true);
             }
             else if (ret != CfdErrorCode.NotFound)
             {
                 handle.ThrowError(ret);
             }
             return(false);
         }
 }
Example #17
0
 /// <summary>
 /// constructor.
 /// </summary>
 /// <param name="seed">seed bytes</param>
 /// <param name="networkType">network type</param>
 public ExtPrivkey(ByteData seed, CfdNetworkType networkType)
 {
     if (seed is null)
     {
         throw new ArgumentNullException(nameof(seed));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdCreateExtkeyFromSeed(
             handle.GetHandle(), seed.ToHexString(), (int)networkType,
             (int)CfdExtKeyType.Privkey, out IntPtr tempExtkey);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         extkey = CCommon.ConvertToString(tempExtkey);
         GetExtkeyInformation(handle, extkey,
                              out version, out fingerprint,
                              out chainCode, out depth, out childNumber, out _);
         privkey          = GetPrivkeyFromExtKey(handle, extkey, networkType);
         this.networkType = networkType;
     }
 }
Example #18
0
 /// <summary>
 /// Calculate ec-signature.
 /// </summary>
 /// <param name="sighash">signature hash.</param>
 /// <param name="hasGrindR">use grind-R.</param>
 /// <returns></returns>
 public SignParameter CalculateEcSignature(ByteData sighash, bool hasGrindR)
 {
     if (sighash is null)
     {
         throw new ArgumentNullException(nameof(sighash));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdCalculateEcSignature(
             handle.GetHandle(), sighash.ToHexString(),
             privkey, privkeyWif, (int)networkType, hasGrindR,
             out IntPtr signatureHex);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         SignParameter     signature   = new SignParameter(CCommon.ConvertToString(signatureHex));
         SignatureHashType sighashType = new SignatureHashType(CfdSighashType.All, false);
         signature.SetDerEncode(sighashType);
         signature.SetRelatedPubkey(GetPubkey());
         return(signature);
     }
 }
Example #19
0
        private static void GetExtkeyInformation(ErrorHandle handle, string extkey,
                                                 out ByteData version, out ByteData fingerprint, out ByteData chainCode,
                                                 out uint depth, out uint childNumber, out CfdNetworkType networkType)
        {
            var ret = NativeMethods.CfdGetExtkeyInformation(
                handle.GetHandle(), extkey,
                out IntPtr tempVersion,
                out IntPtr tempFingerprint,
                out IntPtr tempChainCode,
                out depth,
                out childNumber);

            if (ret != CfdErrorCode.Success)
            {
                handle.ThrowError(ret);
            }
            string workVersion     = CCommon.ConvertToString(tempVersion);
            string workFingerprint = CCommon.ConvertToString(tempFingerprint);
            string workChainCode   = CCommon.ConvertToString(tempChainCode);

            version     = new ByteData(workVersion);
            fingerprint = new ByteData(workFingerprint);
            chainCode   = new ByteData(workChainCode);
            if (VersionMainnet == version.ToHexString())
            {
                networkType = CfdNetworkType.Mainnet;
            }
            else
            {
                networkType = CfdNetworkType.Testnet;
                if (VersionTestnet != version.ToHexString())
                {
                    CfdCommon.ThrowError(CfdErrorCode.IllegalArgumentError,
                                         "Failed to version format.");
                }
            }
        }
Example #20
0
 /// <summary>
 /// constructor.
 /// </summary>
 /// <param name="address">address</param>
 /// <param name="confidentialKey">confidential key</param>
 public ConfidentialAddress(Address address, Pubkey confidentialKey)
 {
     if (address is null)
     {
         throw new ArgumentNullException(nameof(address));
     }
     if (confidentialKey is null)
     {
         throw new ArgumentNullException(nameof(confidentialKey));
     }
     unconfidenialAddress = address;
     key = confidentialKey;
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdCreateConfidentialAddress(
             handle.GetHandle(), address.ToAddressString(), confidentialKey.ToHexString(),
             out IntPtr outputConfidentialAddr);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         confidentialAddress = CCommon.ConvertToString(outputConfidentialAddr);
     }
 }
 /// <summary>
 /// Adapt ECDSA-adaptor signature.
 /// </summary>
 /// <param name="adaptorSignature">adaptor signature</param>
 /// <param name="adaptorSecret">adaptor secret key</param>
 /// <returns>ecdsa signature in compact format</returns>
 public static ByteData Adapt(ByteData adaptorSignature, Privkey adaptorSecret)
 {
     if (adaptorSignature is null)
     {
         throw new ArgumentNullException(nameof(adaptorSignature));
     }
     if (adaptorSecret is null)
     {
         throw new ArgumentNullException(nameof(adaptorSecret));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdAdaptEcdsaAdaptor(
             handle.GetHandle(), adaptorSignature.ToHexString(),
             adaptorSecret.ToHexString(),
             out IntPtr signature);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string sig = CCommon.ConvertToString(signature);
         return(new ByteData(sig));
     }
 }
Example #22
0
        /// <summary>
        /// create script from asm string list.
        /// </summary>
        /// <param name="asmList">asm string list</param>
        /// <returns>script object</returns>
        public static Script CreateFromAsm(string[] asmList)
        {
            if (asmList is null)
            {
                throw new ArgumentNullException(nameof(asmList));
            }
            using (var handle = new ErrorHandle())
            {
                StringBuilder builder = new StringBuilder();
                foreach (string asm in asmList)
                {
#pragma warning disable IDE0059 // Unnecessary value assignment
                    IntPtr hexString = IntPtr.Zero;
#pragma warning restore IDE0059 // Unnecessary value assignment
                    var ret = NativeMethods.CfdConvertScriptAsmToHex(handle.GetHandle(), asm, out hexString);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    builder.Append(CCommon.ConvertToString(hexString));
                }
                return(new Script(builder.ToString()));
            }
        }
Example #23
0
 /// <summary>
 /// decode from DER.
 /// </summary>
 /// <param name="derSignature">DER encoded data</param>
 /// <returns>signature (SignParameter object)</returns>
 public static SignParameter DecodeFromDer(ByteData derSignature)
 {
     if (derSignature is null)
     {
         throw new ArgumentNullException(nameof(derSignature));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdDecodeSignatureFromDer(
             handle.GetHandle(), derSignature.ToHexString(),
             out IntPtr signature,
             out int signatureHashType,
             out bool _);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string            signatureStr = CCommon.ConvertToString(signature);
         SignatureHashType sighashType  = new SignatureHashType(signatureHashType);
         SignParameter     signParam    = new SignParameter(signatureStr);
         signParam.SetDerEncode(sighashType);
         return(signParam);
     }
 }
Example #24
0
 /// <summary>
 /// convert entropy to mnemonic.
 /// </summary>
 /// <param name="entropy">entropy</param>
 /// <param name="language">language</param>
 /// <returns>mnemonic words</returns>
 public static string[] ConvertEntropyToMnemonic(
     ByteData entropy, string language)
 {
     if (entropy is null)
     {
         throw new ArgumentNullException(nameof(entropy));
     }
     if (language is null)
     {
         throw new ArgumentNullException(nameof(language));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdConvertEntropyToMnemonic(handle.GetHandle(),
                                                             entropy.ToHexString(),
                                                             language, out IntPtr tempMnemonic);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         string mnemonic = CCommon.ConvertToString(tempMnemonic);
         return(mnemonic.Split(' '));
     }
 }
Example #25
0
 public ExtPubkey(CfdNetworkType networkType, ByteData fingerprint,
                  Pubkey pubkey, ByteData chainCode, uint depth, uint childNumber)
 {
     if (fingerprint is null)
     {
         throw new ArgumentNullException(nameof(fingerprint));
     }
     if (pubkey is null)
     {
         throw new ArgumentNullException(nameof(pubkey));
     }
     if (chainCode is null)
     {
         throw new ArgumentNullException(nameof(chainCode));
     }
     using (var handle = new ErrorHandle())
     {
         var ret = NativeMethods.CfdCreateExtkey(
             handle.GetHandle(), (int)networkType, (int)CfdExtKeyType.Pubkey, "",
             fingerprint.ToHexString(), pubkey.ToHexString(), chainCode.ToHexString(),
             (byte)depth, childNumber, out IntPtr tempExtkey);
         if (ret != CfdErrorCode.Success)
         {
             handle.ThrowError(ret);
         }
         extkey           = CCommon.ConvertToString(tempExtkey);
         this.networkType = networkType;
         this.fingerprint = fingerprint;
         this.pubkey      = pubkey;
         this.chainCode   = chainCode;
         this.depth       = depth;
         this.childNumber = childNumber;
         GetExtkeyInformation(handle, extkey, out version, out _,
                              out _, out _, out _, out _);
     }
 }
Example #26
0
        /// <summary>
        /// Select coins.
        /// </summary>
        /// <param name="utxoList">utxo list</param>
        /// <param name="txFeeAmount">transaction fee</param>
        /// <param name="targetAmount">target amount of asset. Amount more than the specified amount is set in txout. default is 0 (disable).</param>
        /// <param name="effectiveFeeRate">fee rate</param>
        /// <param name="longTermFeeRate">long-term fee rate</param>
        /// <param name="dustFeeRate">dust fee rate</param>
        /// <param name="knapsackMinChange">knapsack min change value. knapsack logic's threshold. Recommended value is 1.</param>
        /// <returns>select utxo list.</returns>
        public UtxoData[] SelectCoins(UtxoData[] utxoList, long txFeeAmount, long targetAmount,
                                      double effectiveFeeRate, double longTermFeeRate, double dustFeeRate, long knapsackMinChange)
        {
            if (utxoList is null)
            {
                throw new ArgumentNullException(nameof(utxoList));
            }
            if (utxoList.Length <= 0)
            {
                throw new InvalidOperationException("utxoList is empty.");
            }
            using (var handle = new ErrorHandle())
            {
                var ret = NativeMethods.CfdInitializeCoinSelection(
                    handle.GetHandle(), (uint)utxoList.Length, 1, "", txFeeAmount,
                    effectiveFeeRate, longTermFeeRate, dustFeeRate, knapsackMinChange,
                    out IntPtr coinSelectHandle);
                if (ret != CfdErrorCode.Success)
                {
                    handle.ThrowError(ret);
                }
                try
                {
                    for (uint index = 0; index < utxoList.Length; ++index)
                    {
                        string desc = (utxoList[index].GetDescriptor() is null) ?
                                      "" : utxoList[index].GetDescriptor().ToString();
                        ret = NativeMethods.CfdAddCoinSelectionUtxoTemplate(
                            handle.GetHandle(), coinSelectHandle, index,
                            utxoList[index].GetOutPoint().GetTxid().ToHexString(),
                            utxoList[index].GetOutPoint().GetVout(),
                            utxoList[index].GetAmount(), "",
                            desc, utxoList[index].GetScriptSigTemplate().ToHexString());
                        if (ret != CfdErrorCode.Success)
                        {
                            handle.ThrowError(ret);
                        }
                    }
                    ret = NativeMethods.CfdAddCoinSelectionAmount(
                        handle.GetHandle(), coinSelectHandle, 0, targetAmount, "");
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }

                    ret = NativeMethods.CfdFinalizeCoinSelection(
                        handle.GetHandle(), coinSelectHandle, out long utxoFeeAmount);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }

                    uint[] collectIndexes = new uint[utxoList.Length];
                    uint   collectCount   = 0;
                    if ((utxoFeeAmount > 0) || (targetAmount > 0))
                    {
                        for (uint index = 0; index < utxoList.Length; ++index)
                        {
                            ret = NativeMethods.CfdGetSelectedCoinIndex(
                                handle.GetHandle(), coinSelectHandle,
                                index, out int utxoIndex);
                            if (ret != CfdErrorCode.Success)
                            {
                                handle.ThrowError(ret);
                            }
                            if (utxoIndex < 0)
                            {
                                break;
                            }
                            if (utxoList.Length <= utxoIndex)
                            {
                                throw new InvalidProgramException("utxoIndex maximum over.");
                            }
                            ++collectCount;
                            collectIndexes[index] = (uint)utxoIndex;
                        }
                    }

                    /*
                     * ret = NativeMethods.CfdGetSelectedCoinAssetAmount(
                     * handle.GetHandle(), coinSelectHandle, 0, out long collectAmount);
                     * if (ret != CfdErrorCode.Success)
                     * {
                     * handle.ThrowError(ret);
                     * }
                     */

                    UtxoData[] selectedUtxoList = new UtxoData[collectCount];
                    for (uint index = 0; index < collectCount; ++index)
                    {
                        selectedUtxoList[index] = utxoList[collectIndexes[index]];
                    }
                    lastSelectedUtxoFee = utxoFeeAmount;
                    return(selectedUtxoList);
                }
                finally
                {
                    NativeMethods.CfdFreeCoinSelectionHandle(handle.GetHandle(), coinSelectHandle);
                }
            }
        }
Example #27
0
        /// <summary>
        /// Select coins for elements.
        /// </summary>
        /// <param name="utxoList">utxo list</param>
        /// <param name="targetAssetAmountMap">target amount of asset. Amount more than the specified amount is set in txout. default is 0 (disable).</param>
        /// <param name="feeAsset">asset by fee</param>
        /// <param name="txFeeAmount">transaction fee</param>
        /// <param name="effectiveFeeRate">fee rate</param>
        /// <param name="exponent">blinding exponent</param>
        /// <param name="minimumBits">blinding minimum bits</param>
        /// <param name="longTermFeeRate">long-term fee rate</param>
        /// <param name="dustFeeRate">dust fee rate</param>
        /// <param name="knapsackMinChange">knapsack min change value. knapsack logic's threshold. Recommended value is 1.</param>
        /// <returns>select utxo list.</returns>
        public ElementsUtxoData[] SelectCoinsForElements(
            ElementsUtxoData[] utxoList,
            IDictionary <ConfidentialAsset, long> targetAssetAmountMap,
            ConfidentialAsset feeAsset, long txFeeAmount,
            double effectiveFeeRate, int exponent, int minimumBits,
            double longTermFeeRate,
            double dustFeeRate, long knapsackMinChange)
        {
            if (utxoList is null)
            {
                throw new ArgumentNullException(nameof(utxoList));
            }
            if (utxoList.Length <= 0)
            {
                throw new InvalidOperationException("utxoList is empty.");
            }
            if (targetAssetAmountMap is null)
            {
                throw new ArgumentNullException(nameof(targetAssetAmountMap));
            }
            if (targetAssetAmountMap.Count <= 0)
            {
                throw new InvalidOperationException("targetAssetAmountMap is empty.");
            }
            if (feeAsset is null)
            {
                throw new ArgumentNullException(nameof(feeAsset));
            }
            if (feeAsset.HasBlinding())
            {
                throw new InvalidOperationException(
                          "fee asset has blinding. fee asset is unblind only.");
            }
            using (var handle = new ErrorHandle())
            {
                var ret = NativeMethods.CfdInitializeCoinSelection(
                    handle.GetHandle(), (uint)utxoList.Length, (uint)targetAssetAmountMap.Count,
                    feeAsset.ToHexString(), txFeeAmount,
                    effectiveFeeRate, longTermFeeRate, dustFeeRate, knapsackMinChange,
                    out IntPtr coinSelectHandle);
                if (ret != CfdErrorCode.Success)
                {
                    handle.ThrowError(ret);
                }
                try
                {
                    for (uint index = 0; index < utxoList.Length; ++index)
                    {
                        string desc = (utxoList[index].GetDescriptor() is null) ?
                                      "" : utxoList[index].GetDescriptor().ToString();
                        ret = NativeMethods.CfdAddCoinSelectionUtxoTemplate(
                            handle.GetHandle(), coinSelectHandle, index,
                            utxoList[index].GetOutPoint().GetTxid().ToHexString(),
                            utxoList[index].GetOutPoint().GetVout(),
                            utxoList[index].GetAmount(),
                            utxoList[index].GetAsset(),
                            desc, utxoList[index].GetScriptSigTemplate().ToHexString());
                        if (ret != CfdErrorCode.Success)
                        {
                            handle.ThrowError(ret);
                        }
                    }
                    long targetAmountAll = 0;
                    uint assetIndex      = 0;
                    foreach (var key in targetAssetAmountMap.Keys)
                    {
                        ret = NativeMethods.CfdAddCoinSelectionAmount(
                            handle.GetHandle(), coinSelectHandle, assetIndex,
                            targetAssetAmountMap[key], key.ToHexString());
                        if (ret != CfdErrorCode.Success)
                        {
                            handle.ThrowError(ret);
                        }
                        ++assetIndex;
                        targetAmountAll += targetAssetAmountMap[key];
                    }

                    if (exponent >= -1)
                    {
                        ret = NativeMethods.CfdSetOptionCoinSelection(handle.GetHandle(), coinSelectHandle,
                                                                      Exponent, exponent, 0, false);
                        if (ret != CfdErrorCode.Success)
                        {
                            handle.ThrowError(ret);
                        }
                    }
                    if (minimumBits >= 0)
                    {
                        ret = NativeMethods.CfdSetOptionCoinSelection(handle.GetHandle(), coinSelectHandle,
                                                                      MinimumBits, minimumBits, 0, false);
                        if (ret != CfdErrorCode.Success)
                        {
                            handle.ThrowError(ret);
                        }
                    }

                    ret = NativeMethods.CfdFinalizeCoinSelection(
                        handle.GetHandle(), coinSelectHandle, out long utxoFeeAmount);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }

                    uint[] collectIndexes = new uint[utxoList.Length];
                    uint   collectCount   = 0;
                    if ((utxoFeeAmount > 0) || (targetAmountAll > 0))
                    {
                        for (uint index = 0; index < utxoList.Length; ++index)
                        {
                            ret = NativeMethods.CfdGetSelectedCoinIndex(
                                handle.GetHandle(), coinSelectHandle,
                                index, out int utxoIndex);
                            if (ret != CfdErrorCode.Success)
                            {
                                handle.ThrowError(ret);
                            }
                            if (utxoIndex < 0)
                            {
                                break;
                            }
                            if (utxoList.Length <= utxoIndex)
                            {
                                throw new InvalidProgramException("utxoIndex maximum over.");
                            }
                            ++collectCount;
                            collectIndexes[index] = (uint)utxoIndex;
                        }
                    }

                    /*
                     * assetIndex = 0;
                     * collectAmountList = new Dictionary<ConfidentialAsset, long>();
                     * foreach (var key in targetAssetAmountMap.Keys)
                     * {
                     * ret = NativeMethods.CfdGetSelectedCoinAssetAmount(
                     *  handle.GetHandle(), coinSelectHandle, assetIndex,
                     *  out long collectAmount);
                     * if (ret != CfdErrorCode.Success)
                     * {
                     *  handle.ThrowError(ret);
                     * }
                     ++assetIndex;
                     * collectAmountList.Add(key, collectAmount);
                     * }
                     */

                    ElementsUtxoData[] selectedUtxoList = new ElementsUtxoData[collectCount];
                    for (uint index = 0; index < collectCount; ++index)
                    {
                        selectedUtxoList[index] = utxoList[collectIndexes[index]];
                    }
                    lastSelectedUtxoFee = utxoFeeAmount;
                    return(selectedUtxoList);
                }
                finally
                {
                    NativeMethods.CfdFreeCoinSelectionHandle(handle.GetHandle(), coinSelectHandle);
                }
            }
        }
Example #28
0
        private static CfdDescriptorScriptData[] ParseDescriptor(
            ErrorHandle handle, string descriptorString,
            string derivePath, CfdNetworkType network, out CfdDescriptorScriptData rootData)
        {
            var ret = NativeMethods.CfdParseDescriptor(
                handle.GetHandle(), descriptorString, (int)network, derivePath,
                out IntPtr descriptorHandle, out uint maxIndex);

            if (ret != CfdErrorCode.Success)
            {
                handle.ThrowError(ret);
            }
            try
            {
                bool isMultisig = false;
                uint maxKeyNum  = 0;
                uint requireNum = 0;
                {
                    ret = NativeMethods.CfdGetDescriptorRootData(
                        handle.GetHandle(), descriptorHandle,
                        out int scriptType, out IntPtr lockingScript, out IntPtr address,
                        out int hashType, out IntPtr redeemScript,
                        out int keyType, out IntPtr pubkey, out IntPtr extPubkey,
                        out IntPtr extPrivkey, out IntPtr schnorrPubkey, out IntPtr treeString,
                        out isMultisig, out maxKeyNum, out requireNum);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    CCommon.ConvertToString(lockingScript);
                    string tempAddress        = CCommon.ConvertToString(address);
                    string tempRedeemScript   = CCommon.ConvertToString(redeemScript);
                    string tempPubkey         = CCommon.ConvertToString(pubkey);
                    string tempExtPubkey      = CCommon.ConvertToString(extPubkey);
                    string tempExtPrivkey     = CCommon.ConvertToString(extPrivkey);
                    string tempSchnorr        = CCommon.ConvertToString(schnorrPubkey);
                    string tempTreeStr        = CCommon.ConvertToString(treeString);
                    CfdDescriptorKeyType type = (CfdDescriptorKeyType)keyType;
                    CfdKeyData           keyData;
                    TapBranch            scriptTree = new TapBranch();
                    if (type == CfdDescriptorKeyType.Bip32)
                    {
                        keyData = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                    }
                    else if (type == CfdDescriptorKeyType.Bip32Priv)
                    {
                        keyData = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                    }
                    else if (type == CfdDescriptorKeyType.SchnorrPubkey)
                    {
                        keyData = new CfdKeyData(new SchnorrPubkey(tempSchnorr));
                    }
                    else if (type == CfdDescriptorKeyType.Public)
                    {
                        keyData = new CfdKeyData(new Pubkey(tempPubkey));
                    }
                    else
                    {
                        keyData = new CfdKeyData();
                    }
                    Address addr = new Address();
                    if (tempAddress.Length > 0)
                    {
                        addr = new Address(tempAddress);
                    }
                    if (tempTreeStr.Length > 0)
                    {
                        scriptTree = new TapBranch(tempTreeStr);
                    }
                    rootData = new CfdDescriptorScriptData((CfdDescriptorScriptType)scriptType, 0,
                                                           (CfdHashType)hashType, addr, new Script(tempRedeemScript),
                                                           scriptTree, keyData, Array.Empty <CfdKeyData>(), 0);
                }
                CfdDescriptorScriptData[] list = new CfdDescriptorScriptData[maxIndex + 1];
                for (uint index = 0; index <= maxIndex; ++index)
                {
                    // force initialized because guard illegal memory access.
                    IntPtr lockingScript = IntPtr.Zero;
                    IntPtr redeemScript  = IntPtr.Zero;
                    IntPtr address       = IntPtr.Zero;
                    IntPtr pubkey        = IntPtr.Zero;
                    IntPtr extPubkey     = IntPtr.Zero;
                    IntPtr extPrivkey    = IntPtr.Zero;
                    ret = NativeMethods.CfdGetDescriptorData(
                        handle.GetHandle(), descriptorHandle, index, out _, out uint depth,
                        out int scriptType, out lockingScript, out address,
                        out int hashType, out redeemScript,
                        out int keyType, out pubkey, out extPubkey, out extPrivkey,
                        out isMultisig, out maxKeyNum, out requireNum);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    CCommon.ConvertToString(lockingScript);
                    string tempAddress      = CCommon.ConvertToString(address);
                    string tempRedeemScript = CCommon.ConvertToString(redeemScript);
                    string tempPubkey       = CCommon.ConvertToString(pubkey);
                    string tempExtPubkey    = CCommon.ConvertToString(extPubkey);
                    string tempExtPrivkey   = CCommon.ConvertToString(extPrivkey);
                    CfdDescriptorScriptData data;
                    CfdKeyData           keyData;
                    CfdDescriptorKeyType type;
                    switch ((CfdDescriptorScriptType)scriptType)
                    {
                    case CfdDescriptorScriptType.Combo:
                    case CfdDescriptorScriptType.Pk:
                    case CfdDescriptorScriptType.Pkh:
                    case CfdDescriptorScriptType.Wpkh:
                    case CfdDescriptorScriptType.Taproot:
                        type = (CfdDescriptorKeyType)keyType;
                        if (type == CfdDescriptorKeyType.Bip32)
                        {
                            keyData = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                        }
                        else if (type == CfdDescriptorKeyType.Bip32Priv)
                        {
                            keyData = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                        }
                        else if (type == CfdDescriptorKeyType.SchnorrPubkey)
                        {
                            keyData = new CfdKeyData(new SchnorrPubkey(tempPubkey));
                        }
                        else
                        {
                            keyData = new CfdKeyData(new Pubkey(tempPubkey));
                        }
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, (CfdHashType)hashType, new Address(tempAddress), keyData);
                        break;

                    case CfdDescriptorScriptType.Sh:
                    case CfdDescriptorScriptType.Wsh:
                    case CfdDescriptorScriptType.Multi:
                    case CfdDescriptorScriptType.SortedMulti:
                        if (isMultisig)
                        {
                            CfdKeyData[] keyList = new CfdKeyData[maxKeyNum];
                            for (uint multisigIndex = 0; multisigIndex < maxKeyNum; ++multisigIndex)
                            {
                                IntPtr multisigPubkey     = IntPtr.Zero;
                                IntPtr multisigExtPubkey  = IntPtr.Zero;
                                IntPtr multisigExtPrivkey = IntPtr.Zero;
                                ret = NativeMethods.CfdGetDescriptorMultisigKey(handle.GetHandle(), descriptorHandle,
                                                                                multisigIndex, out int multisigKeyType, out multisigPubkey,
                                                                                out multisigExtPubkey, out multisigExtPrivkey);
                                if (ret != CfdErrorCode.Success)
                                {
                                    handle.ThrowError(ret);
                                }
                                tempPubkey     = CCommon.ConvertToString(multisigPubkey);
                                tempExtPubkey  = CCommon.ConvertToString(multisigExtPubkey);
                                tempExtPrivkey = CCommon.ConvertToString(multisigExtPrivkey);
                                type           = (CfdDescriptorKeyType)multisigKeyType;
                                if (type == CfdDescriptorKeyType.Bip32)
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                                }
                                else if (type == CfdDescriptorKeyType.Bip32Priv)
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                                }
                                else
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new Pubkey(tempPubkey));
                                }
                            }
                            data = new CfdDescriptorScriptData(
                                (CfdDescriptorScriptType)scriptType,
                                depth, (CfdHashType)hashType, new Address(tempAddress),
                                new Script(tempRedeemScript), keyList, requireNum);
                            rootData = new CfdDescriptorScriptData(rootData.ScriptType, 0,
                                                                   rootData.HashType, rootData.Address, rootData.RedeemScript,
                                                                   rootData.KeyData, keyList, requireNum);
                        }
                        else
                        {
                            data = new CfdDescriptorScriptData(
                                (CfdDescriptorScriptType)scriptType,
                                depth, (CfdHashType)hashType, new Address(tempAddress),
                                new Script(tempRedeemScript));
                        }
                        break;

                    case CfdDescriptorScriptType.Raw:
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, new Script(tempRedeemScript));
                        break;

                    case CfdDescriptorScriptType.Addr:
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, (CfdHashType)hashType, new Address(tempAddress));
                        break;

                    default:
                        data = new CfdDescriptorScriptData();
                        break;
                    }
                    list[index] = data;

                    if (scriptType == (int)CfdDescriptorScriptType.Combo)
                    {
                        // TODO: combo data is top only.
                        CfdDescriptorScriptData[] newList = { list[0] };
                        list = newList;
                        break;
                    }
                }
                return(list);
            }
            finally
            {
                NativeMethods.CfdFreeDescriptorHandle(
                    handle.GetHandle(), descriptorHandle);
            }
        }