public async Task <TransferResult> ExecuteAsync(TransferCommand transferCommand)
        {
            BlockchainType blockchainType = await _assetSettingsService.GetNetworkAsync(transferCommand.AssetId);

            IBlockchainApiClient blockchainClient = _blockchainClientProvider.Get(blockchainType);

            BlockchainTransferCommand cmd = new BlockchainTransferCommand(transferCommand.AssetId);

            string lykkeAssetId = transferCommand.AssetId.IsGuid()
                ? transferCommand.AssetId
                : await _lykkeAssetsResolver.GetLykkeId(transferCommand.AssetId);

            foreach (var transferCommandAmount in transferCommand.Amounts)
            {
                decimal balance = await blockchainClient.GetBalanceAsync(transferCommandAmount.Source, lykkeAssetId);

                if (transferCommandAmount.Amount == null)
                {
                    if (balance > 0)
                    {
                        cmd.Amounts.Add(new TransferAmount
                        {
                            Amount      = balance,
                            Source      = transferCommandAmount.Source,
                            Destination = transferCommandAmount.Destination
                        });

                        continue;
                    }

                    throw new InsufficientFundsException(transferCommandAmount.Source, transferCommand.AssetId);
                }

                if (transferCommandAmount.Amount > balance)
                {
                    throw new InsufficientFundsException(transferCommandAmount.Source, transferCommand.AssetId);
                }

                cmd.Amounts.Add(transferCommandAmount);
            }

            BlockchainTransferResult blockchainTransferResult = await blockchainClient.TransferAsync(cmd);

            ITransfer transfer = await _transferRepository.AddAsync(new Transfer
            {
                AssetId      = transferCommand.AssetId,
                Blockchain   = blockchainTransferResult.Blockchain,
                CreatedOn    = DateTime.UtcNow,
                Amounts      = transferCommand.Amounts,
                Transactions = Mapper.Map <IEnumerable <TransferTransaction> >(blockchainTransferResult.Transactions)
            });

            return(Mapper.Map <TransferResult>(transfer));
        }
        public async Task <BlockchainTransferResult> TransferAsync(BlockchainTransferCommand transfer)
        {
            BlockchainTransferResult result = new BlockchainTransferResult {
                Blockchain = BlockchainType.Bitcoin
            };

            foreach (var transferAmountGroup in transfer.Amounts.GroupBy(x => x.Destination))
            {
                string destination = transferAmountGroup.Key;

                var sources = transferAmountGroup.Select(x =>
                {
                    switch (transfer.AssetId)
                    {
                    case LykkeConstants.BitcoinAsset:
                        return(new ToOneAddress(x.Source, x.Amount));

                    case LykkeConstants.SatoshiAsset:
                        return(new ToOneAddress(x.Source, x.Amount?.SatoshiToBtc()));

                    default:
                        throw new AssetNotSupportedException(transfer.AssetId);
                    }
                }).ToList();

                OnchainResponse response = await _bitcoinServiceClient.TransactionMultipleTransfer(
                    Guid.NewGuid(),
                    destination,
                    LykkeConstants.BitcoinAsset,
                    _feeProvider.FeeRate,
                    _feeProvider.FixedFee,
                    sources);

                var errorMessage = response.HasError
                    ? $"Error placing MultipleTransfer transaction to destination address = {transferAmountGroup.Key}, code = {response.Error?.Code}, message = {response.Error?.Message}"
                    : string.Empty;

                result.Transactions.Add(new BlockchainTransactionResult
                {
                    Amount       = sources.Sum(x => x.Amount ?? 0),
                    AssetId      = LykkeConstants.BitcoinAsset,
                    Hash         = response.Transaction?.Hash,
                    IdentityType = TransactionIdentityType.Hash,
                    Identity     = response.Transaction?.Hash,
                    Sources      = sources.Select(x => x.Address),
                    Destinations = new List <string> {
                        destination
                    },
                    Error = errorMessage
                });
            }

            return(result);
        }
Example #3
0
        public async Task <TransferResult> ExecuteAsync(TransferCommand transferCommand)
        {
            BlockchainType blockchainType = transferCommand.AssetId.GetBlockchainType();

            IBlockchainApiClient blockchainClient = _blockchainClientProvider.Get(blockchainType);

            BlockchainTransferResult blockchainTransferResult =
                await blockchainClient.TransferAsync(transferCommand.ToBlockchainTransfer());

            ITransfer transfer = await _transferRepository.AddAsync(new Transfer
            {
                AssetId      = transferCommand.AssetId,
                Blockchain   = blockchainTransferResult.Blockchain,
                CreatedOn    = DateTime.UtcNow,
                Amounts      = transferCommand.Amounts,
                Transactions = Mapper.Map <IEnumerable <TransferTransaction> >(blockchainTransferResult.Transactions)
            });

            return(Mapper.Map <TransferResult>(transfer));
        }
Example #4
0
        public async Task <BlockchainTransferResult> TransferAsync(BlockchainTransferCommand transfer)
        {
            BlockchainTransferResult result = new BlockchainTransferResult {
                Blockchain = BlockchainType.Ethereum
            };

            string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(transfer.AssetId);

            Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId);

            if (asset.Type != AssetType.Erc20Token || !asset.IsTradable)
            {
                throw new AssetNotSupportedException(asset.Name);
            }

            ListOfErc20Token tokenSpecification =
                await _assetsService.Erc20TokenGetBySpecificationAsync(new Erc20TokenSpecification { Ids = new[] { asset.Id } });

            string tokenAddress = tokenSpecification?.Items.SingleOrDefault(x => x.AssetId == asset.Id)?.Address;

            foreach (TransferAmount transferAmount in transfer.Amounts)
            {
                var transferRequest = Mapper.Map <TransferFromDepositRequest>(transferAmount,
                                                                              opts => opts.Items["TokenAddress"] = tokenAddress);

                object response = await _ethereumServiceClient.ApiLykkePayErc20depositsTransferPostAsync(
                    _ethereumSettings.ApiKey, transferRequest);

                var errorMessage = string.Empty;

                var operationId = string.Empty;

                if (response is ApiException ex)
                {
                    await _log.WriteWarningAsync(nameof(TransferAsync), transferAmount.ToJson(), ex.Error?.ToJson());

                    errorMessage = ex.Error?.Message;
                }
                else if (response is OperationIdResponse op)
                {
                    operationId = op.OperationId;
                }
                else
                {
                    throw new UnrecognizedApiResponse(response?.GetType().FullName ?? "Response object is null");
                }

                result.Transactions.Add(new BlockchainTransactionResult
                {
                    Amount       = transferAmount.Amount,
                    AssetId      = asset.Name,
                    Hash         = string.Empty,
                    IdentityType = TransactionIdentityType.Specific,
                    Identity     = operationId,
                    Sources      = new List <string> {
                        transferAmount.Source
                    },
                    Destinations = new List <string> {
                        transferAmount.Destination
                    },
                    Error = errorMessage
                });
            }

            return(result);
        }
        public async Task <BlockchainTransferResult> TransferAsync(BlockchainTransferCommand transfer)
        {
            BlockchainTransferResult result = new BlockchainTransferResult {
                Blockchain = BlockchainType.EthereumIata
            };

            string lykkeAssetId = await _lykkeAssetsResolver.GetLykkeId(transfer.AssetId);

            Asset asset = await _assetsLocalCache.GetAssetByIdAsync(lykkeAssetId);

            if (asset.Type != AssetType.Erc20Token)
            {
                throw new AssetNotSupportedException(asset.Name);
            }

            ListOfErc20Token tokenSpecification =
                await _assetsService.Erc20TokenGetBySpecificationAsync(new Erc20TokenSpecification
                                                                       { Ids = new[] { asset.Id } });

            string tokenAddress = tokenSpecification?.Items.SingleOrDefault(x => x.AssetId == asset.Id)?.Address;

            foreach (TransferAmount transferAmount in transfer.Amounts)
            {
                var transferRequest = Mapper.Map <AirlinesTransferFromDepositRequest>(transferAmount,
                                                                                      opts =>
                {
                    opts.Items["TokenAddress"]    = tokenAddress;
                    opts.Items["AssetMultiplier"] = asset.MultiplierPower;
                    opts.Items["AssetAccuracy"]   = asset.Accuracy;
                });

                object response = await _retryPolicy.ExecuteAsync(() => InvokeTransfer(transferRequest));

                var ex = response as ApiException;

                var operation = response as OperationIdResponse;

                if (ex != null)
                {
                    _log.Warning(ex.Error?.Message);
                }

                if (ex == null && operation == null)
                {
                    throw new UnrecognizedApiResponse(response?.GetType().FullName ?? "Response object is null");
                }

                result.Transactions.Add(new BlockchainTransactionResult
                {
                    Amount       = transferAmount.Amount ?? 0,
                    AssetId      = asset.DisplayId,
                    Hash         = string.Empty,
                    IdentityType = TransactionIdentityType.Specific,
                    Identity     = operation?.OperationId ?? string.Empty,
                    Sources      = new List <string> {
                        transferAmount.Source
                    },
                    Destinations = new List <string> {
                        transferAmount.Destination
                    },
                    Error     = ex?.Error?.Message ?? string.Empty,
                    ErrorType = ex.GetDomainError()
                });
            }

            return(result);
        }