Ejemplo n.º 1
0
        private async Task <BtcTxnSignature> getBtcTxnSignaturesAsync(
            ECurrency currency,
            string address,
            string amount,
            string fee,
            string target,
            string reserve,
            string reservedFundsRedeemScript,
            string privateKey
            )
        {
            GluwaClient client = new GluwaClient(mEnv);

            Result <BalanceResponse, ErrorResponse> getUnspentOutput = await client.GetBalanceAsync(currency, address, true);

            List <UnspentOutput> unspentOutputs = getUnspentOutput.Data.UnspentOutputs.OrderByDescending(u => u.Amount).ToList();

            Money amountValue              = Money.Parse(amount);
            Money feeValue                 = Money.Parse(fee);
            Money reserveAmount            = amountValue + feeValue;
            Money totalRequiredAmountMoney = reserveAmount + feeValue;

            BigInteger totalRequiredAmount = new BigInteger(totalRequiredAmountMoney.Satoshi);

            BitcoinAddress sourceAddress  = BitcoinAddress.Create(address, mEnv.Network);
            BitcoinAddress targetAddress  = BitcoinAddress.Create(target, mEnv.Network);
            BitcoinAddress reserveAddress = BitcoinAddress.Create(reserve, mEnv.Network);

            BitcoinSecret secret = new BitcoinSecret(privateKey, mEnv.Network);

            List <UnspentOutput> usingUnspentOutputs      = new List <UnspentOutput>();
            BigInteger           unspentOutputTotalAmount = BigInteger.Zero;

            for (int i = 0; i < unspentOutputs.Count; i++)
            {
                if (unspentOutputTotalAmount < totalRequiredAmount && i >= MAX_UNSPENTOUTPUTS_COUNT)
                {
                    throw new InvalidOperationException($"Could not find up to {MAX_UNSPENTOUTPUTS_COUNT} BTC unspent outputs that can cover the amount and fee.");
                }

                if (unspentOutputTotalAmount >= totalRequiredAmount)
                {
                    break;
                }

                usingUnspentOutputs.Add(unspentOutputs[i]);
                Money sumAmount = Money.Parse(unspentOutputs[i].Amount);
                unspentOutputTotalAmount += new BigInteger(sumAmount.Satoshi);
            }

            List <Coin> coins = new List <Coin>();

            for (int i = 0; i < usingUnspentOutputs.Count; i++)
            {
                coins.Add(new Coin(
                              fromTxHash: new uint256(usingUnspentOutputs[i].TxHash),
                              fromOutputIndex: (uint)usingUnspentOutputs[i].Index,
                              amount: usingUnspentOutputs[i].Amount,
                              scriptPubKey: Script.FromHex(sourceAddress.ScriptPubKey.ToHex())
                              ));
            }

            TransactionBuilder builder = mEnv.Network.CreateTransactionBuilder();

            NBitcoin.Transaction reserveTxSignature = builder
                                                      .AddKeys(secret)
                                                      .AddCoins(coins)
                                                      .Send(reserveAddress, reserveAmount)
                                                      .SetChange(sourceAddress)
                                                      .SendFees(fee)
                                                      .BuildTransaction(true);

            IEnumerable <Coin> reserveTxCoins = reserveTxSignature.Outputs.AsCoins();
            Coin reserveTxCoin = reserveTxCoins.First(
                c => c.TxOut.ScriptPubKey.GetDestinationAddress(mEnv.Network) == reserveAddress);
            Script     reservedFundsRedeemScriptValue = new Script(reservedFundsRedeemScript);
            ScriptCoin reservedCoin = new ScriptCoin(reserveTxCoin, reservedFundsRedeemScriptValue);

            builder = mEnv.Network.CreateTransactionBuilder();
            PSBT executePsbt = builder
                               .AddKeys(secret)
                               .AddCoins(reservedCoin)
                               .Send(targetAddress, amount)
                               .SendFees(feeValue)
                               .SetChange(reserveAddress)
                               .BuildPSBT(true);

            builder = mEnv.Network.CreateTransactionBuilder();
            PSBT reclaimPsbt = builder
                               .AddKeys(secret)
                               .AddCoins(reservedCoin)
                               .Send(sourceAddress, amount)
                               .SendFees(feeValue)
                               .SetChange(reserveAddress)
                               .BuildPSBT(true);

            BtcTxnSignature bTCTxnSignature = new BtcTxnSignature()
            {
                ReserveTxnSignature = reserveTxSignature.ToHex(),
                ExecuteTxnSignature = executePsbt.ToHex(),
                ReclaimTxnSignature = reclaimPsbt.ToHex()
            };

            return(bTCTxnSignature);
        }