public static TransitQueueMessage ToTransitQueueMessage(this TransactionMongoEntity entity) { var result = new TransitQueueMessage { TxId = entity.TxId }; foreach (var vin in entity.Vins) { result.Vins.Add(new Vin { Address = vin.Addresses, Amount = vin.Amount }); } foreach (var vout in entity.Vouts) { result.Vouts.Add(new Vout { Address = vout.Addresses, Amount = vout.Amount }); } return(result); }
public async Task cashin_handler_test() { long s = 100000000; // accedpted vout amounts are in satoshis, should conver to solar coins, 1 slr = 10^8 satoshis //Arrange var hotWalletAddress = Guid.NewGuid().ToString(); var txFee = 0.01m; var minTxAmount = 0.1m; //Arranging generated wallets storage var generatedWallets = new NoSqlTableInMemory <WalletStorageEntity>(); generatedWallets.Insert(new WalletStorageEntity { PartitionKey = "part", RowKey = Guid.NewGuid().ToString(), Address = "8first_generated_address", PrivateKey = "first_priv_key" }); generatedWallets.Insert(new WalletStorageEntity { PartitionKey = "part", RowKey = Guid.NewGuid().ToString(), Address = "8second_generated_address", PrivateKey = "second_priv_key" }); generatedWallets.Insert(new WalletStorageEntity { PartitionKey = "part", RowKey = Guid.NewGuid().ToString(), Address = "8third_generated_address", PrivateKey = "third_priv_key" }); generatedWallets.Insert(new WalletStorageEntity { PartitionKey = "part", RowKey = Guid.NewGuid().ToString(), Address = "8fourth_generated_address", PrivateKey = "fourth_priv_key" }); var fakeTxesQueue = Substitute.For <IQueueExt>(); var fakeRpcClient = Substitute.For <IJsonRpcClient>(); fakeRpcClient.CreateRawTransaction(Arg.Any <object[]>(), Arg.Any <Dictionary <string, decimal> >()).Returns("string"); fakeRpcClient.SignRawTransaction(Arg.Any <string>(), Arg.Any <string>()).Returns(new SignRawTransactionResponseModel()); fakeRpcClient.SendRawTransaction(Arg.Any <string>()).Returns("string"); var fakeSlackNotifier = Substitute.For <ISlackNotifier>(); var fakeLogger = Substitute.For <ILog>(); var queueTrigger = new CashInHandlerQueueTrigger("SolarCoinApi.Test.CashInHandlerJobRunner", generatedWallets, fakeLogger, fakeTxesQueue, fakeRpcClient, fakeSlackNotifier, hotWalletAddress, txFee, minTxAmount); string txId = Guid.NewGuid().ToString(); var message = new TransitQueueMessage { TxId = txId, Vouts = new List <Vout> { new Vout { Address = "8third_generated_address", Amount = (long)(2.3652m * s) }, new Vout { Address = "some_unrelated_address_1", Amount = (long)(5m * s) }, // should be ignored new Vout { Address = "some_unrelated_address_2", Amount = (long)(6.365m * s) }, // should be ignored new Vout { Address = "8third_generated_address", Amount = (long)(2.146m * s) }, new Vout { Address = "some_unrelated_address_3", Amount = (long)(9.213m * s) }, // should be ignored new Vout { Address = "8first_generated_address", Amount = (long)(0.09m * s) }, // this shouldn't be put to queue because it's less than min tx amount new Vout { Address = "8fourth_generated_address", Amount = (long)(100.2568m * s) } } }; // Act await queueTrigger.ReceiveMessage(message); // Assert // Check if all relevant outputs where put in the queue correctly await fakeTxesQueue.Received(1).PutRawMessageAsync(Arg.Is <string>(x => JsonConvert.DeserializeObject <QueueModel>(x).Equals(new QueueModel { Address = "8third_generated_address", TxId = txId, Amount = 2.3652m + 2.146m }))); await fakeTxesQueue.Received(1).PutRawMessageAsync(Arg.Is <string>(x => JsonConvert.DeserializeObject <QueueModel>(x).Equals(new QueueModel { Address = "8fourth_generated_address", TxId = txId, Amount = 100.2568m }))); await fakeTxesQueue.Received(2).PutRawMessageAsync(Arg.Any <string>()); // Check if all relevant outputs where transferred to the hot wallet await fakeRpcClient.Received(1).CreateRawTransaction( Arg.Is <object[]>( x => x.Count() == 1 && x.All(y => (string)(y.GetType().GetProperty("txid").GetValue(y)) == txId) && x.Any(y => (int)(y.GetType().GetProperty("vout").GetValue(y)) == 6)), Arg.Is <Dictionary <string, decimal> >(x => x.Count == 1 && x[hotWalletAddress] == 100.2568m - txFee)); await fakeRpcClient.Received(1).CreateRawTransaction( Arg.Is <object[]>(x => x.Count() == 2 && x.All(y => (string)(y.GetType().GetProperty("txid").GetValue(y)) == txId) && x.Any(y => (int)(y.GetType().GetProperty("vout").GetValue(y)) == 0) && x.Any(y => (int)(y.GetType().GetProperty("vout").GetValue(y)) == 3)), Arg.Is <Dictionary <string, decimal> >(x => x.Count == 1 && x[hotWalletAddress] == 2.3652m + 2.146m - txFee)); await fakeRpcClient.Received(2).CreateRawTransaction(Arg.Any <object[]>(), Arg.Any <Dictionary <string, decimal> >()); await fakeRpcClient.Received(1).SignRawTransaction(Arg.Any <string>(), "third_priv_key"); await fakeRpcClient.Received(1).SignRawTransaction(Arg.Any <string>(), "fourth_priv_key"); await fakeRpcClient.Received(2).SignRawTransaction(Arg.Any <string>(), Arg.Any <string>()); await fakeRpcClient.Received(2).SendRawTransaction(Arg.Any <string>()); }
public async Task ReceiveMessage(TransitQueueMessage message) { try { await _log.WriteInfoAsync(_component, "", message.TxId, "beginning to process"); var ourVouts = new List <VoutEx>(); // get outputs that where dedicated to our users for (int i = 0; i < message.Vouts.Count; i++) { var vout = message.Vouts[i]; if (await _generatedWallets.GetDataAsync("part", vout.Address) != null) { ourVouts.Add(new VoutEx { Address = vout.Address, Amount = vout.Amount, voutId = i }); } } // if none of the outputs where dedicated to our users, return; if (ourVouts.Count == 0) { await _log.WriteInfoAsync(_component, "", message.TxId, "didn't contain relevant addresses"); return; } foreach (var addr in ourVouts.Select(x => x.Address).Distinct()) { var changePerAddress = ourVouts.Where(x => x.Address == addr).Sum(x => x.Amount); var changePerAddressInSlr = changePerAddress / 100000000m; if (changePerAddressInSlr < _minTxAmount) { continue; } var dest = new Dictionary <string, decimal> { { _hotWalletAddress, changePerAddressInSlr - _txFee } }; var userWallet = _generatedWallets.FirstOrDefault(x => x.Address == addr); var rawTx = await _rpcClient.CreateRawTransaction(ourVouts.Where(x => x.Address == addr).Select(x => new { txid = message.TxId, vout = x.voutId }).ToArray(), dest); var signedTx = await _rpcClient.SignRawTransaction(rawTx, userWallet.PrivateKey); var sentTx = await _rpcClient.SendRawTransaction(signedTx.Hex); await _log.WriteInfoAsync(_component, "", message.TxId, "transferred. posting to queue."); await _txesQueue.PutRawMessageAsync(JsonConvert.SerializeObject(new QueueModel { Address = addr, Amount = changePerAddressInSlr, TxId = message.TxId })); } } catch (Exception e) { //await _slackNotifier.Notify(new SlackMessage { Sender = _component, Type = "Errors", Message = "Error occured during cashin handling" }); await _log.WriteErrorAsync(_component, "", message.TxId, e); throw; } }