Ejemplo n.º 1
0
        private async Task ShieldCoinbaseEmulatedAsync()
        {
            logger.Info(() => $"[{LogCategory}] Shielding ZCash Coinbase funds (emulated)");

            // get t-addr unspent balance for just the coinbase address (pool wallet)
            var unspentResult = await daemon.ExecuteCmdSingleAsync <Utxo[]>(logger, BitcoinCommands.ListUnspent);

            if (unspentResult.Error != null)
            {
                logger.Error(() => $"[{LogCategory}] {BitcoinCommands.ListUnspent} returned error: {unspentResult.Error.Message} code {unspentResult.Error.Code}");
                return;
            }

            var balance = unspentResult.Response
                          .Where(x => x.Spendable && x.Address == poolConfig.Address)
                          .Sum(x => x.Amount);

            // make sure there's enough balance to shield after reserves
            if (balance - TransferFee <= TransferFee)
            {
                logger.Info(() => $"[{LogCategory}] Balance {FormatAmount(balance)} too small for emulated shielding");
                return;
            }

            logger.Info(() => $"[{LogCategory}] Transferring {FormatAmount(balance - TransferFee)} to pool's z-addr");

            // transfer to z-addr
            var recipient = new ZSendManyRecipient
            {
                Address = poolExtraConfig.ZAddress,
                Amount  = balance - TransferFee
            };

            var args = new object[]
            {
                poolConfig.Address, // default account
                new object[]        // addresses and associated amounts
                {
                    recipient
                },
                1,
                TransferFee
            };

            // send command
            var sendResult = await daemon.ExecuteCmdSingleAsync <string>(logger, EquihashCommands.ZSendMany, args);

            if (sendResult.Error != null)
            {
                logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} returned error: {unspentResult.Error.Message} code {unspentResult.Error.Code}");
                return;
            }

            var operationId = sendResult.Response;

            logger.Info(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} operation id: {operationId}");

            var continueWaiting = true;

            while (continueWaiting)
            {
                var operationResultResponse = await daemon.ExecuteCmdSingleAsync <ZCashAsyncOperationStatus[]>(logger,
                                                                                                               EquihashCommands.ZGetOperationResult, new object[] { new object[] { operationId } });

                if (operationResultResponse.Error == null &&
                    operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true)
                {
                    var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId);

                    if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status))
                    {
                        logger.Error(() => $"Unrecognized operation status: {operationResult.Status}");
                        break;
                    }

                    switch (status)
                    {
                    case ZOperationStatus.Success:
                        var txId = operationResult.Result?.Value <string>("txid") ?? string.Empty;
                        logger.Info(() => $"[{LogCategory}] Transfer completed with transaction id: {txId}");

                        continueWaiting = false;
                        continue;

                    case ZOperationStatus.Cancelled:
                    case ZOperationStatus.Failed:
                        logger.Error(() => $"{EquihashCommands.ZSendMany} failed: {operationResult.Error.Message} code {operationResult.Error.Code}");

                        continueWaiting = false;
                        continue;
                    }
                }

                logger.Info(() => $"[{LogCategory}] Waiting for shielding transfer completion: {operationId}");
                await Task.Delay(TimeSpan.FromSeconds(10));
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// ZCash coins are mined into a t-addr (transparent address), but can only be
        /// spent to a z-addr (shielded address), and must be swept out of the t-addr
        /// in one transaction with no change.
        /// </summary>
        private async Task ShieldCoinbaseAsync()
        {
            logger.Info(() => $"[{LogCategory}] Shielding ZCash Coinbase funds");

            // Emulate z_shieldcoinbase until its stable
#if true
            // get t-addr balance
            var balanceResult = await daemon.ExecuteCmdSingleAsync <object>(BitcoinCommands.GetBalance);

            if (balanceResult.Error != null)
            {
                logger.Error(() => $"[{LogCategory}] {BitcoinCommands.GetBalance} returned error: {balanceResult.Error.Message} code {balanceResult.Error.Code}");
                return;
            }

            var balance = (decimal)(double)balanceResult.Response;

            if (balance > 0)
            {
                logger.Info(() => $"[{LogCategory}] Transferring {FormatAmount(balance)} to pool's z-addr");

                // transfer to z-addr
                var recipient = new ZSendManyRecipient
                {
                    Address = poolExtraConfig.ZAddress,
                    Amount  = balance - TransferFee
                };

                var args = new object[]
                {
                    poolConfig.Address, // default account
                    new object[]        // addresses and associated amounts
                    {
                        recipient
                    },
                    10, // only spend funds covered by this many confirmations
                    TransferFee
                };

                // send command
                var sendResult = await daemon.ExecuteCmdSingleAsync <string>(ZCashCommands.ZSendMany, args);

                if (sendResult.Error != null)
                {
                    logger.Error(() => $"[{LogCategory}] {ZCashCommands.ZSendMany} returned error: {balanceResult.Error.Message} code {balanceResult.Error.Code}");
                    return;
                }

                var operationId = sendResult.Response;

                logger.Info(() => $"[{LogCategory}] {ZCashCommands.ZSendMany} operation id: {operationId}");

                var continueWaiting = true;

                while (continueWaiting)
                {
                    var operationResultResponse = await daemon.ExecuteCmdSingleAsync <ZCashAsyncOperationStatus[]>(
                        ZCashCommands.ZGetOperationResult, new object[] { new object[] { operationId } });

                    if (operationResultResponse.Error == null &&
                        operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true)
                    {
                        var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId);

                        if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status))
                        {
                            logger.Error(() => $"Unrecognized operation status: {operationResult.Status}");
                            break;
                        }

                        switch (status)
                        {
                        case ZOperationStatus.Success:
                            var txId = operationResult.Result?.Value <string>("txid") ?? string.Empty;
                            logger.Info(() => $"[{LogCategory}] Transfer completed with transaction id: {txId}");

                            continueWaiting = false;
                            continue;

                        case ZOperationStatus.Cancelled:
                        case ZOperationStatus.Failed:
                            logger.Error(() => $"{ZCashCommands.ZSendMany} failed: {operationResult.Error.Message} code {operationResult.Error.Code}");

                            continueWaiting = false;
                            continue;
                        }
                    }

                    logger.Info(() => $"[{LogCategory}] Waiting for transfer completion: {operationId}");
                    await Task.Delay(TimeSpan.FromSeconds(10));
                }
            }
#else
            var args = new object[]
            {
                poolConfig.Address,         // source: pool's t-addr receiving coinbase rewards
                poolExtraConfig.ZAddress,   // dest:   pool's z-addr
            };

            var result = await daemon.ExecuteCmdSingleAsync <string>(ZCashCommands.ZShieldCoinbase, args);

            if (result.Error != null)
            {
                logger.Error(() => $"[{LogCategory}] {ZCashCommands.ZShieldCoinbase} returned error: {result.Error.Message} code {result.Error.Code}");
                return;
            }

            var operationId = result.Response;

            logger.Info(() => $"[{LogCategory}] {ZCashCommands.ZShieldCoinbase} operation id: {operationId}");

            var continueWaiting = true;

            while (continueWaiting)
            {
                var operationResultResponse = await daemon.ExecuteCmdSingleAsync <ZCashAsyncOperationStatus[]>(
                    ZCashCommands.ZGetOperationResult, new object[] { new object[] { operationId } });

                if (operationResultResponse.Error == null &&
                    operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true)
                {
                    var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId);

                    if (!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status))
                    {
                        logger.Error(() => $"Unrecognized operation status: {operationResult.Status}");
                        break;
                    }

                    switch (status)
                    {
                    case ZOperationStatus.Success:
                        logger.Info(() => $"[{LogCategory}] {ZCashCommands.ZShieldCoinbase} successful");

                        continueWaiting = false;
                        continue;

                    case ZOperationStatus.Cancelled:
                    case ZOperationStatus.Failed:
                        logger.Error(() => $"{ZCashCommands.ZShieldCoinbase} failed: {operationResult.Error.Message} code {operationResult.Error.Code}");

                        continueWaiting = false;
                        continue;
                    }
                }

                logger.Info(() => $"[{LogCategory}] Waiting for operation completion: {operationId}");
                await Task.Delay(TimeSpan.FromSeconds(10));
            }
#endif
        }
Ejemplo n.º 3
0
        /// <summary>
        /// ZCash coins are mined into a t-addr (transparent address), but can only be
        /// spent to a z -addr (shielded address), and must be swept out of the t-addr
        /// in one transaction with no change.
        /// </summary>
        private async Task TransferTransparentPoolBalance()
        {
            // get t-addr balance
            var balanceResult = await daemon.ExecuteCmdSingleAsync <object>(BitcoinCommands.GetBalance);

            if (balanceResult.Error != null)
            {
                logger.Error(() => $"[{LogCategory}] Daemon command '{BitcoinCommands.GetBalance}' returned error: {balanceResult.Error.Message} code {balanceResult.Error.Code}");
                return;
            }

            var balance = (decimal)(double)balanceResult.Response;

            if (balance > 0)
            {
                logger.Info(() => $"[{LogCategory}] Transferring {FormatAmount(balance)} to pool's z-addr");

                // transfer to z-addr
                var recipient = new ZSendManyRecipient
                {
                    Address = poolExtraConfig.ZAddress,
                    Amount  = balance - TransferFee
                };

                var args = new object[]
                {
                    poolConfig.Address, // default account
                    new object[]        // addresses and associated amounts
                    {
                        recipient
                    },
                    10,                 // only spend funds covered by this many confirmations
                    TransferFee
                };

                // send command
                var sendResult = await daemon.ExecuteCmdSingleAsync <string>(ZCashCommands.ZSendMany, args);

                if (sendResult.Error != null)
                {
                    logger.Error(() => $"[{LogCategory}] Daemon command '{ZCashCommands.ZSendMany}' returned error: {balanceResult.Error.Message} code {balanceResult.Error.Code}");
                    return;
                }

                var operationId = sendResult.Response;

                logger.Info(() => $"[{LogCategory}] ZCash Balance Transfer operation id: {operationId}");

                var continueWaiting = true;

                while (continueWaiting)
                {
                    var operationResultResponse = await daemon.ExecuteCmdSingleAsync <ZCashAsyncOperationStatus[]>(
                        ZCashCommands.ZGetOperationResult, new object[] { new object[] { operationId } });

                    if (operationResultResponse.Error == null &&
                        operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true)
                    {
                        var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId);

                        switch (operationResult.Status.ToLower())
                        {
                        case "success":
                            // extract transaction id
                            var txId = operationResult.Result?.Value <string>("txid") ?? string.Empty;
                            logger.Info(() => $"[{LogCategory}] ZCash Balance Transfer transaction id: {txId}");

                            continueWaiting = false;
                            continue;

                        case "cancelled":
                        case "failed":
                            logger.Error(() => $"ZCash transparent balance transfer failed: {operationResult.Error.Message} code {operationResult.Error.Code}");

                            continueWaiting = false;
                            continue;
                        }
                    }

                    logger.Info(() => $"[{LogCategory}] Waiting for ZCash Balance transfer to complete: {operationId}");
                    await Task.Delay(TimeSpan.FromSeconds(10));
                }
            }
        }