public async Task <OffchainResult> CreateDirectTransfer(string clientId, string assetId, decimal amount, string prevTempPrivateKey)
        {
            var credentials = await _walletCredentialsRepository.GetAsync(clientId);

            var request = new { clientId, assetId, amount, prevTempPrivateKey };

            await _logger.WriteInfoAsync("CreateDirectTransfer", request.ToJson(), "Transfer requested");

            var offchainTransferResult = await _bitcoinApiClient.OffchainTransferAsync(new OffchainTransferData
            {
                Amount  = -amount,
                AssetId = assetId,
                ClientPrevPrivateKey = prevTempPrivateKey,
                ClientPubKey         = credentials.PublicKey,
                Required             = false
            });

            var createTransferResult = await _offchainTransferRepository.CreateTransfer(Guid.NewGuid().ToString(), clientId, assetId, amount, OffchainTransferType.DirectTransferFromClient, offchainTransferResult.TransferId?.ToString());

            if (offchainTransferResult.HasError)
            {
                return(await InternalErrorProcessing("CreateTransfer", offchainTransferResult.Error, credentials, createTransferResult, false));
            }

            var result = new OffchainResult
            {
                TransferId      = createTransferResult.Id,
                TransactionHex  = offchainTransferResult.Transaction,
                OperationResult = OffchainOperationResult.Transfer
            };

            await _logger.WriteInfoAsync("CreateDirectTransfer", request.ToJson(), new { result.TransferId, result.OperationResult }.ToJson());

            return(result);
        }
        private async Task <OffchainResult> CreateChannel(IWalletCredentials credentials, IOffchainTransfer offchainTransfer, bool required)
        {
            if (offchainTransfer == null || offchainTransfer.ClientId != credentials.ClientId || offchainTransfer.Completed)
            {
                throw new OffchainException(ErrorCode.Exception, offchainTransfer?.AssetId);
            }

            var fromClient = offchainTransfer.Type == OffchainTransferType.DirectTransferFromClient;

            var result = await _bitcoinApiClient.CreateChannelAsync(new CreateChannelData
            {
                AssetId            = offchainTransfer.AssetId,
                ClientPubKey       = credentials.PublicKey,
                ClientAmount       = fromClient ? offchainTransfer.Amount : 0,
                HubAmount          = 0,
                Required           = required,
                ExternalTransferId = offchainTransfer.ExternalTransferId
            });

            var offchainTransferInfo = (new {
                offchainTransfer.ClientId, Asset = offchainTransfer.AssetId,
                offchainTransfer.Amount,
                offchainTransfer.Type
            }).ToJson();

            if (!result.HasError)
            {
                await _offchainTransferRepository.UpdateTransfer(offchainTransfer.Id, result.TransferId?.ToString(), closing : result.ChannelClosing, onchain : true);

                var offchainResult = new OffchainResult
                {
                    TransferId      = offchainTransfer.Id,
                    TransactionHex  = result.Transaction,
                    OperationResult = result.ChannelClosing ? OffchainOperationResult.Transfer : OffchainOperationResult.CreateChannel
                };

                await _logger.WriteInfoAsync("CreateChannel", offchainTransferInfo, $"Offchain channel successfully created: {(new { offchainResult.TransferId, offchainResult.OperationResult }).ToJson()}");

                return(offchainResult);
            }

            await _logger.WriteErrorAsync("CreateChannel", offchainTransferInfo, new Exception($"{result.Error.Message}, Code: {result.Error.Code} "));

            throw new OffchainException(result.Error.ErrorCode, result.Error.Message, result.Error.Code, offchainTransfer.AssetId);
        }