public async ValueTask <bool> DeleteBitgoCoinEntityAsync(string coin) { if (string.IsNullOrEmpty(coin)) { throw new Exception("Cannot update coin. Coin cannot be empty"); } var entity = await _bitgoCoins.GetAsync(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); if (entity != null) { var assets = await _assetMap.GetAsync(); var existAssets = assets.Any(e => e.BitgoCoin == coin); if (existAssets) { throw new Exception("Cannot delete coin. Asset used it as coin"); } await _bitgoCoins.DeleteAsync(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); } return(true); }
public async ValueTask <bool> UpdateBitgoCoinEntityAsync(string coin, int accuracy, int requiredConfirmations, bool isMainNet) { if (string.IsNullOrEmpty(coin)) { throw new Exception("Cannot update coin. Coin cannot be empty"); } if (accuracy < 0) { throw new Exception("Cannot update coin. Accuracy can't be less then 0"); } if (requiredConfirmations < 0) { throw new Exception("Cannot update coin. RequiredConfirmations can't be less then 0"); } var entity = BitgoCoinEntity.Create(coin, accuracy, requiredConfirmations, isMainNet); var existingItem = await _bitgoCoins.GetAsync(entity.PartitionKey, entity.RowKey); if (existingItem == null) { throw new Exception("Cannot update coin. Coin not found"); } await _bitgoCoins.InsertOrReplaceAsync(entity); return(true); }
private static async Task GenerateAsstToBitgoMap() { var broker = "jetwallet"; var nosqlWriterUrl = "http://192.168.10.80:5123"; var clientAsset = new MyNoSqlServerDataWriter <BitgoAssetMapEntity>(() => nosqlWriterUrl, BitgoAssetMapEntity.TableName, true); var list = new List <BitgoAssetMapEntity>(); list.Add(BitgoAssetMapEntity.Create(broker, "BTC", "6054ba9ca9cc0e0024a867a7d8b401b2", "", "tbtc", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "XLM", "6054bc003dc1af002b0d54bf5b552f28", "", "txlm", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "LTC", "6054be73b765620006aa87311f43bd47", "", "tltc", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "XRP", "60584aaded0090000628ce59c01f3a5e", "", "txrp", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "BCH", "60584b79fd3e0500669e2cf9654d726b", "", "tbch", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "ALGO", "60584becbc3e2600240548d78e61c02b", "", "talgo", 0)); list.Add(BitgoAssetMapEntity.Create(broker, "EOS", "60584dcc6f5d31001d5a59371aeeb60a", "", "teos", 0)); await clientAsset.CleanAndKeepMaxPartitions(0); await clientAsset.BulkInsertOrReplaceAsync(list); var clientCoin = new MyNoSqlServerDataWriter <BitgoCoinEntity>(() => nosqlWriterUrl, BitgoCoinEntity.TableName, true); var listCoin = new List <BitgoCoinEntity>(); listCoin.Add(BitgoCoinEntity.Create("algo", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("bch", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("btc", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("dash", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("eos", 4, 1, false)); //listCoin.Add(BitgoCoinEntity.Create("eth", 18)); //listCoin.Add(BitgoCoinEntity.Create("hbar", 0)); listCoin.Add(BitgoCoinEntity.Create("ltc", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("trx", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("xlm", 7, 1, false)); listCoin.Add(BitgoCoinEntity.Create("xrp", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("zec", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("talgo", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("tbch", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("tbtc", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("tdash", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("teos", 4, 1, false)); //listCoin.Add(BitgoCoinEntity.Create("teth", 18)); //listCoin.Add(BitgoCoinEntity.Create("thbar", 0)); listCoin.Add(BitgoCoinEntity.Create("tltc", 8, 1, false)); listCoin.Add(BitgoCoinEntity.Create("ttrx", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("txlm", 7, 1, false)); listCoin.Add(BitgoCoinEntity.Create("txrp", 6, 1, false)); listCoin.Add(BitgoCoinEntity.Create("tzec", 8, 1, false)); await clientCoin.CleanAndKeepMaxRecords(BitgoCoinEntity.TableName, 0); await clientCoin.BulkInsertOrReplaceAsync(listCoin); }
public double ConvertAmountFromBitgo(string coin, long amount) { var coinSettings = _bitgoCoins.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); if (coinSettings == null) { throw new System.Exception($"Do not found settings for bitgo coin {coin} in nosql table {BitgoCoinEntity.TableName}"); } return(coinSettings.AmountFromAbsoluteValue(amount)); }
public decimal ConvertAmountToBitgo(string coin, double amount) { var coinSettings = _bitgoCoins.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); if (coinSettings == null) { throw new Exception( $"Do not found settings for bitgo coin {coin} in nosql table {BitgoCoinEntity.TableName}"); } return(coinSettings.AmountToAbsoluteValueDecimal(amount)); }
public int GetRequiredConfirmations(string coin) { var coinSettings = _bitgoCoins.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coin)); if (coinSettings == null) { throw new Exception( $"Do not found settings for bitgo coin {coin} in nosql table {BitgoCoinEntity.TableName}"); } return(coinSettings.RequiredConfirmations); }
public IBitGoApi GetByUser(string brokerId, string userId, string coinId, string newApiKey) { var bitGoUser = _bitgoUserReader.Get( BitGoUserNoSqlEntity.GeneratePartitionKey(brokerId), BitGoUserNoSqlEntity.GenerateRowKey(BitGoUserNoSqlEntity.TechSignerId, coinId)) ?? _bitgoUserReader.Get( BitGoUserNoSqlEntity.GeneratePartitionKey(brokerId), BitGoUserNoSqlEntity.GenerateRowKey(BitGoUserNoSqlEntity.TechSignerId, BitGoUserNoSqlEntity.DefaultCoin)); var apiKeyEnc = bitGoUser?.User?.ApiKey; if (string.IsNullOrEmpty(apiKeyEnc) && string.IsNullOrEmpty(newApiKey)) { _logger.LogError("Tech account is not configured, id = {techSignerName}", BitGoUserNoSqlEntity.TechSignerId); return(null); } lock (_clients) { if (!string.IsNullOrEmpty(apiKeyEnc) && _clients.TryGetValue(apiKeyEnc, out var api)) { return(api); } } var coin = _bitgoCointReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(coinId)); if (coin == null) { _logger.LogError("Cannot fond bitgo coin id = {symbol}", coinId); return(null); } var apiKey = string.IsNullOrEmpty(apiKeyEnc) ? newApiKey : _encryptionService.Decrypt(apiKeyEnc); var client = new BitGoClient( apiKey, Program.Settings.BitgoExpressUrlMainNet, apiKey, Program.Settings.BitgoExpressUrlTestNet); lock (_clients) { _clients[apiKey] = coin.IsMainNet ? client.MainNet : client.TestNet; return(_clients[apiKey]); } }
private async Task <BitgoCoinEntity> GetCoin(string bitgoCoin) { var coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(bitgoCoin)); if (coin == null) { await Task.Delay(5000); coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(bitgoCoin)); } if (coin == null) { throw new Exception($"BitGo coin '{bitgoCoin}' does not exist."); } return(coin); }
public async ValueTask <bool> UpdateBitgoAssetMapEntityAsync(string brokerId, string assetSymbol, string bitgoWalletId, string enabledBitgoWalletIds, string bitgoCoin, double minBalance, string tagSeparator) { if (string.IsNullOrEmpty(brokerId)) { throw new Exception("Cannot update asset map. BrokerId cannot be empty"); } if (string.IsNullOrEmpty(assetSymbol)) { throw new Exception("Cannot update asset map. AssetSymbol cannot be empty"); } if (string.IsNullOrEmpty(bitgoWalletId)) { throw new Exception("Cannot update asset map. BitgoWalletId cannot be empty"); } if (string.IsNullOrEmpty(bitgoCoin)) { throw new Exception("Cannot update asset map. BitgoCoin cannot be empty"); } var coin = await _bitgoCoins.GetAsync(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(bitgoCoin)); if (coin == null) { throw new Exception("Cannot update asset map. Unknown BitgoCoin."); } var entity = BitgoAssetMapEntity.Create(brokerId, assetSymbol, bitgoWalletId, enabledBitgoWalletIds, bitgoCoin, minBalance, tagSeparator); var existingEntity = await _assetMap.GetAsync(entity.PartitionKey, entity.RowKey); if (existingEntity == null) { throw new Exception("Cannot update asset map. Asset map not found"); } await _assetMap.InsertOrReplaceAsync(entity); return(true); }
public async Task HandledDepositAsync(SignalBitGoTransfer transferId) { transferId.AddToActivityAsJsonTag("bitgo signal"); _logger.LogInformation("Request to handle transfer from BitGo: {transferJson}", JsonConvert.SerializeObject(transferId)); var(brokerId, assetSymbol) = _assetMapper.BitgoCoinToAsset(transferId.Coin, transferId.WalletId); if (string.IsNullOrEmpty(brokerId) || string.IsNullOrEmpty(assetSymbol)) { _logger.LogWarning("Cannot handle BitGo deposit, asset do not found {transferJson}", JsonConvert.SerializeObject(transferId)); return; } var coin = _bitgoCoinReader.Get(BitgoCoinEntity.GeneratePartitionKey(), BitgoCoinEntity.GenerateRowKey(transferId.Coin)); var transferResp = await _bitgoClient.Get(coin.IsMainNet) .GetTransferAsync(transferId.Coin, transferId.WalletId, transferId.TransferId); var transfer = transferResp.Data; if (transfer == null) { _logger.LogWarning("Cannot handle BitGo deposit, transfer do not found {transferJson}", JsonConvert.SerializeObject(transferId)); Activity.Current?.SetStatus(Status.Error); return; } transfer.AddToActivityAsJsonTag("bitgo-transfer"); _logger.LogInformation("Transfer from BitGo: {transferJson}", JsonConvert.SerializeObject(transfer)); var requirement = _assetMapper.GetRequiredConfirmations(transfer.Coin); if (transfer.Confirmations < requirement) { _logger.LogError( $"Transaction do not has enough conformations. Transaction has: {transfer.Confirmations}, requirement: {requirement}"); Activity.Current?.SetStatus(Status.Error); throw new Exception( $"Transaction do not has enough conformations. Transaction has: {transfer.Confirmations}, requirement: {requirement}"); } if (!_assetMapper.IsWalletEnabled(transfer.Coin, transfer.WalletId)) { _logger.LogError( "Transfer {transferIdString} from BitGo is skipped, Wallet do not include in enabled wallet list", transfer.TransferId); Activity.Current?.SetStatus(Status.Error); return; } foreach (var entryGroup in transfer.Entries .Where(e => e.Value > 0 && !string.IsNullOrEmpty(e.Label) && e.WalletId == transferId.WalletId && (e.Token == null || e.Token == transferId.Coin)) .GroupBy(e => e.Label)) { var label = entryGroup.Key; var wallet = _walletMapper.BitgoLabelToWallet(label); if (wallet == null) { _logger.LogWarning("Cannot found wallet for transfer entry with label={label} address={address}", label, entryGroup.First().Address); continue; } wallet.WalletId.AddToActivityAsTag("walletId"); wallet.ClientId.AddToActivityAsTag("clientId"); var bitgoAmount = entryGroup.Sum(e => e.Value); var meAmount = _assetMapper.ConvertAmountFromBitgo(transferId.Coin, bitgoAmount); var accuracy = _assetsDictionary.GetAssetById(new AssetIdentity() { Symbol = assetSymbol, BrokerId = wallet.BrokerId }).Accuracy; var roundedAmount = Math.Round(meAmount, accuracy, MidpointRounding.ToNegativeInfinity); try { await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder); await ctx.InsertAsync(new DepositEntity { BrokerId = wallet.BrokerId, WalletId = wallet.WalletId, ClientId = wallet.ClientId, TransactionId = $"{transfer.TransferId}:{wallet.WalletId}", Amount = (decimal)roundedAmount, AssetSymbol = assetSymbol, Comment = $"Bitgo transfer [{transferId.Coin}:{transferId.WalletId}] entry label='{label}', count entry={entryGroup.Count()}", Integration = "BitGo", Txid = transfer.TxId, Status = DepositStatus.New, EventDate = DateTime.UtcNow, UpdateDate = DateTime.UtcNow, FeeAmount = 0, FeeAssetSymbol = assetSymbol, CardLast4 = string.Empty }); } catch (Exception e) { Console.WriteLine(e); throw; } } _logger.LogInformation("Deposit request from BitGo {transferIdString} is handled", transfer.TransferId); }