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); }
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)); }
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); }