public void GetOperationIdTest() { var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = ASSET_ID, FromAddress = WALLET_ADDRESS, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); // Stefan/ with dashes var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { PKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); }
public void PostTransactionsBroadcastTest() { var model = new BuildSingleTransactionRequest() { Amount = "100002", AssetId = ASSET_ID, FromAddress = WALLET_ADDRESS, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString("N"); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { PKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response.Validate.StatusCode(HttpStatusCode.OK); }
public void HwEwTransferTest() { Assert.That(EXTERNAL_WALLET, Is.Not.Null.Or.Empty, "External wallet address and key are empty!"); var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = ASSET_ID, FromAddress = HOT_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = EXTERNAL_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { HOT_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); }
public async Task <IActionResult> BuildSingleTransaction([FromBody] BuildSingleTransactionRequest request) { // Do not scale the fee const int feeFactor = 1; return(await BuildTxInternal(request, feeFactor)); }
private async Task <IActionResult> BuildTxInternal(BuildSingleTransactionRequest request, decimal feeFactor) { _addressValidationService.AssertValid(request?.FromAddress); _addressValidationService.AssertValid(request?.ToAddress); try { var response = await _txBuilderService.BuildSingleTransactionAsync(request, feeFactor); return(Json(response)); } catch (BusinessException exception) when(exception.Reason == ErrorReason.AmountTooSmall) { Response.StatusCode = (int)HttpStatusCode.Conflict; return(Json(new { errorCode = "amountIsTooSmall", transactionContext = (string)null })); } catch (BusinessException exception) when(exception.Reason == ErrorReason.NotEnoughBalance) { Response.StatusCode = (int)HttpStatusCode.Conflict; return(Json(new { errorCode = "notEnoughBalance", transactionContext = (string)null })); } }
public async Task <BuildTransactionResponse> BuildSingleTransactionAsync(BuildSingleTransactionRequest request, decimal feeFactor) { if (request.OperationId == Guid.Empty) { throw new BusinessException(ErrorReason.BadRequest, "Operation id is invalid"); } // Check to see if already broadcasted. var cachedResult = await _broadcastTxRepo.GetAsync(request.OperationId.ToString()); if (cachedResult != null) { throw new BusinessException(ErrorReason.DuplicateRecord, "Operation already broadcast"); } var unsignedTx = await _unsignedTxRepo.GetAsync(request.OperationId.ToString()); if (unsignedTx?.ResponseJson != null) { return(JsonConvert.DeserializeObject <BuildTransactionResponse>(unsignedTx.ResponseJson)); } var response = await _builder.BuildSingleTransactionAsync(request, feeFactor); var entity = new UnsignedTransactionEntity( request.OperationId, JsonConvert.SerializeObject(request), JsonConvert.SerializeObject(response) ); await _unsignedTxRepo.InsertAsync(entity); return(response); }
public void PostTransactionsBroadcastTest() { AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET, FromAddressContext = wallet.AddressContext }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { wallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response.Validate.StatusCode(HttpStatusCode.OK); }
public async Task <IActionResult> Build([FromBody] BuildSingleTransactionRequest request) { var txParams = await _transactionService.CalculateTransactionParamsAsync ( BigInteger.Parse(request.Amount), request.IncludeFee, request.ToAddress.ToLowerInvariant() ); if (txParams.Amount <= 0) { return(BadRequest ( ErrorResponse.Create("Amount is too small.") )); } var txData = await _transactionService.BuildTransactionAsync ( txParams.Amount, txParams.Fee, request.FromAddress.ToLowerInvariant(), txParams.GasPrice, request.IncludeFee, request.OperationId, request.ToAddress.ToLowerInvariant() ); return(Ok(new BuildTransactionResponse { TransactionContext = txData })); }
public void CheckBalanceIsZeroBeforeGetBalanceTest() { // enable observation var pResponse = blockchainApi.Balances.PostBalances(WALLET_SINGLE_USE); blockchainApi.Balances.GetBalances("500", null).Validate.StatusCode(HttpStatusCode.OK); Assert.That(() => blockchainApi.Balances.GetBalances("500", null).GetResponseObject().Items.ToList().Any(a => a.Address == WALLET_SINGLE_USE), Is.True.After(10 * 60 * 1000, 1 * 1000), "Wallet is not present in Get Balances after 10 minutes"); //create transaction and broadcast it long time1 = 0; long time2 = 0; var startBalance = blockchainApi.Balances.GetBalances("500", null).GetResponseObject().Items.ToList().Find(a => a.Address == WALLET_SINGLE_USE).Balance; var model = new BuildSingleTransactionRequest() { Amount = "100002", AssetId = CurrentAssetId(), FromAddress = WALLET_SINGLE_USE, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString("N"); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { KEY_WALLET_SINGLE_USE }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); Parallel.Invoke(() => { GetBalanceDissapearingTime(startBalance, out time1); }, () => { GetTransactionCompleteStatusTime(operationId, out time2); }); TestContext.Out.WriteLine($"tick when balance changed: {time1} \n tick when we get Complete status: {time2}"); Assert.Multiple(() => { Assert.That(time1, Is.LessThanOrEqualTo(time2), $"Time in Ticks. Time of balance changing is not less than Status became complete"); Assert.That(long.Parse(startBalance) - 100002, Is.EqualTo(long.Parse(blockchainApi.Balances.GetBalances("500", null).GetResponseObject().Items.ToList().Find(a => a.Address == WALLET_SINGLE_USE).Balance)), "New balance is not as expected"); }); }
public void DWHWTransferTest() { Assert.That(HOT_WALLET, Is.Not.Null.Or.Empty, "Hot wallet address and key are empty!"); blockchainApi.Balances.PostBalances(wallet.PublicAddress); AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); var take = "500"; int i = 60; while (i-- > 0 && !blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.Any(w => w.Address == wallet.PublicAddress)) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2)); } var currentBalance = blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.FirstOrDefault(w => w.Address == wallet.PublicAddress)?.Balance; Assert.That(currentBalance, Is.Not.Null, $"{wallet.PublicAddress} does not present in GetBalances or its balance is null"); var model = new BuildSingleTransactionRequest() { Amount = currentBalance, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { wallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); if (getResponse.GetResponseObject().State == BroadcastedTransactionState.Completed) { Assert.That(() => blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.FirstOrDefault(w => w.Address == wallet.PublicAddress)?.Balance, Is.EqualTo("0").Or.Null.After(60 * 1000, 2 * 1000), $"Unexpected balance for wallet {wallet.PublicAddress}"); } else { //validate balance is 0 or null Assert.That(() => blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.FirstOrDefault(w => w.Address == wallet.PublicAddress)?.Balance, Is.EqualTo("0").Or.Null.After(5 * 60 * 1000, 2 * 1000), $"Unexpected balance for wallet {wallet.PublicAddress}"); } }
public void GetTransactionsManyInputsTest() { var run = blockchainApi.Capabilities.GetCapabilities().GetResponseObject().AreManyInputsSupported; if (!run.Value) { Assert.Ignore("Many inputs are not supported by blockchain"); } AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET, FromAddressContext = wallet.AddressContext }; var request = new BuildTransactionWithManyInputsRequest() { AssetId = ASSET_ID, OperationId = model.OperationId, ToAddress = HOT_WALLET, Inputs = new List <TransactionInputContract>() { new TransactionInputContract() { Amount = AMOUNT, FromAddress = wallet.PublicAddress } } }; var response = blockchainApi.Operations.PostTransactionsManyInputs(request); response.Validate.StatusCode(HttpStatusCode.OK); var signResponse = blockchainSign.PostSign(new SignRequest() { TransactionContext = response.GetResponseObject().TransactionContext, PrivateKeys = new List <string>() { wallet.PrivateKey } }); var broadcastRequset = new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.GetResponseObject().SignedTransaction }; var broadcatedResponse = blockchainApi.Operations.PostTransactionsBroadcast(broadcastRequset); var getResponse = blockchainApi.Operations.GetTransactionsManyInputs(model.OperationId.ToString()); getResponse.Validate.StatusCode(HttpStatusCode.OK); }
public void DWHWPartialTransferDoubleBroadcastTest() { AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); string take = "500"; int i = 60; while (i-- > 0 && !blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.Any(w => w.Address == wallet.PublicAddress)) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2)); } var currentBalance = blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.FirstOrDefault(w => w.Address == wallet.PublicAddress)?.Balance; var partialBalance = Math.Round(long.Parse(currentBalance) * 0.9).ToString(); var model = new BuildSingleTransactionRequest() { Amount = partialBalance, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { wallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response.Validate.StatusCode(HttpStatusCode.OK); var response1 = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response1.Validate.StatusCode(HttpStatusCode.Conflict); WaitForOperationGotCompleteStatus(model.OperationId.ToString()); var balanceAfterTransaction = blockchainApi.Balances.GetBalances(take, null).GetResponseObject().Items.FirstOrDefault(w => w.Address == wallet.PublicAddress)?.Balance; Assert.That(balanceAfterTransaction, Is.EqualTo(Math.Round(long.Parse(currentBalance) * 0.1).ToString()), "Unexpected Balance after partial transaction"); }
protected static void AddCyptoToBalanceFromExternal(string walletAddress, string walletKey = null) { var api = new BlockchainApi(BlockchainApi); var sign = new BlockchainSign(_currentSettings.Value.BlockchainSign); var transferSupported = api.Capabilities.GetCapabilities().GetResponseObject().IsTestingTransfersSupported; var recieveSupport = api.Capabilities.GetCapabilities().GetResponseObject().IsReceiveTransactionRequired; if (transferSupported != null && transferSupported.Value) { api.Balances.PostBalances(walletAddress); TestingTransferRequest request = new TestingTransferRequest() { amount = AMOUT_WITH_FEE, assetId = ASSET_ID, fromAddress = EXTERNAL_WALLET, fromPrivateKey = EXTERNAL_WALLET_KEY, toAddress = walletAddress }; var response = api.Testing.PostTestingTransfer(request); } else if (BlockChainName == "RaiBlocks" || (recieveSupport != null && recieveSupport.Value)) //raiblocks - temp. will be removed after capablities enabled { AddCryptoToWalletWithRecieveTransaction(walletAddress, walletKey); } else { api.Balances.PostBalances(walletAddress); var model = new BuildSingleTransactionRequest() { Amount = AMOUT_WITH_FEE, AssetId = ASSET_ID, FromAddress = EXTERNAL_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = walletAddress, FromAddressContext = EXTERNAL_WALLET_ADDRESS_CONTEXT }; var responseTransaction = api.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = sign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { EXTERNAL_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = api.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = api.Operations.GetOperationId(operationId); WaitForOperationGotCompleteStatus(operationId); } WaitForBalance(walletAddress); }
public void PostTransactionsEmptyObjectTest() { var model = new BuildSingleTransactionRequest() { }; var response = blockchainApi.Operations.PostTransactions(model); response.Validate.StatusCode(HttpStatusCode.BadRequest); }
public async Task BuildSingleTransactionAsync_WithSingleUnspentOutput_BuildsExpectedTx() { var fromAddr = "Tso2MVTUeVrjHTBFedFhiyM7yVTbieqp91h"; var toAddr = "TsntCvtbzaDtx4DwGehWcM3Ydb6Muc79YbV"; // Send 1 decred out of 2 total var amountToSend = 100000000; var unspentOutput = new UnspentTxOutput() { BlockHeight = 0, BlockIndex = 0, Hash = HexUtil.FromByteArray(new byte[32]), OutputIndex = 1, OutputValue = 2 * 100000000, OutputVersion = 0, Tree = 0, PkScript = new byte[0] }; _mockTxRepo.Setup(m => m.GetConfirmedUtxos(fromAddr)).ReturnsAsync(new[] { unspentOutput }); _mockTxRepo.Setup(m => m.GetMempoolUtxos(fromAddr)).ReturnsAsync(new[] { unspentOutput }); _mockDcrdClient.Setup(m => m.EstimateFeeAsync(It.IsAny <int>())).ReturnsAsync(0.001m); _mockBroadcastedOutpointRepo.Setup(m => m.GetAsync($"{unspentOutput.Hash}:1")) .ReturnsAsync((BroadcastedOutpoint)null); var txFeeService = new TransactionFeeService(_mockDcrdClient.Object); var subject = new TransactionBuilder( txFeeService, _mockTxRepo.Object, _mockBroadcastedOutpointRepo.Object ); var request = new BuildSingleTransactionRequest { Amount = amountToSend.ToString(), AssetId = "DCR", FromAddress = fromAddr, ToAddress = toAddr, IncludeFee = true }; var result = await subject.BuildSingleTransactionAsync(request, 1); var transaction = Transaction.Deserialize(HexUtil.ToByteArray(result.TransactionContext)); var expectedFee = txFeeService.CalculateFee(100000, 1, 2, 1); Assert.Equal(expectedFee, 2 * 100000000 - transaction.Outputs.Sum(o => o.Amount)); Assert.Equal(2, transaction.Outputs.Length); // Sent amount - fee Assert.Equal(1, transaction.Outputs.Count(o => o.Amount + expectedFee == 100000000)); // Change Assert.Equal(1, transaction.Outputs.Count(o => o.Amount == 100000000)); }
public void GetTransactionsManyOutputsTest() { var run = blockchainApi.Capabilities.GetCapabilities().GetResponseObject().AreManyOutputsSupported; if (!run.Value) { Assert.Ignore("Many outputs are not supported by blockachain"); } var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = ASSET_ID, FromAddress = WALLET_ADDRESS, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var request = new BuildTransactionWithManyOutputsRequest() { AssetId = ASSET_ID, OperationId = model.OperationId, FromAddress = WALLET_ADDRESS, Outputs = new List <TransactionOutputContract>() { new TransactionOutputContract() { Amount = "100001", ToAddress = HOT_WALLET } } }; var response = blockchainApi.Operations.PostTransactionsManyOutputs(request); response.Validate.StatusCode(HttpStatusCode.OK); var signResponse = blockchainSign.PostSign(new SignRequest() { TransactionContext = response.GetResponseObject().TransactionContext, PrivateKeys = new List <string>() { PKey } }); var broadcastRequset = new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.GetResponseObject().SignedTransaction }; var broadcatedResponse = blockchainApi.Operations.PostTransactionsBroadcast(broadcastRequset); var getResponse = blockchainApi.Operations.GetTransactionsManyOutputs(model.OperationId.ToString()); getResponse.Validate.StatusCode(HttpStatusCode.OK); }
public void PostTransactionsEmptyObjectTest() { var model = new BuildSingleTransactionRequest() { }; var response = blockchainApi.Operations.PostTransactions(model); response.Validate.StatusCode(HttpStatusCode.BadRequest); Assert.That(response.Content, Does.Contain("errorMessage").IgnoreCase); }
protected static void AddCyptoToBalanceFromExternal(string walletAddress) { var api = new BlockchainApi(BlockchainApi); var sign = new BlockchainSign(_currentSettings.Value.BlockchainSign); bool transferSupported = api.Capabilities.GetCapabilities().GetResponseObject().IsTestingTransfersSupported; if (transferSupported) { api.Balances.PostBalances(EXTERNAL_WALLET); api.Balances.PostBalances(walletAddress); TestingTransferRequest request = new TestingTransferRequest() { amount = "100001", assetId = ASSET_ID, fromAddress = EXTERNAL_WALLET, fromPrivateKey = EXTERNAL_WALLET_KEY, toAddress = walletAddress }; var response = api.Testing.PostTestingTransfer(request); } else { api.Balances.PostBalances(walletAddress); var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = ASSET_ID, FromAddress = EXTERNAL_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = walletAddress, FromAddressContext = EXTERNAL_WALLET_ADDRESS_CONTEXT }; var responseTransaction = api.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString("N"); var signResponse = sign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { EXTERNAL_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = api.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = api.Operations.GetOperationId(operationId); // response.Validate.StatusCode(HttpStatusCode.OK, "Could not update Balance from external wallet"); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); } }
public void EWDWTransferTest() { Assert.That(EXTERNAL_WALLET, Is.Not.Null.Or.Empty, "External wallet address and key are empty!"); bool transferSupported = blockchainApi.Capabilities.GetCapabilities().GetResponseObject().IsTestingTransfersSupported; if (transferSupported) { blockchainApi.Balances.PostBalances(EXTERNAL_WALLET); var balanceBefore = blockchainApi.Balances.GetBalances("1000", null).GetResponseObject(). Items.First(w => w.Address == EXTERNAL_WALLET).Balance; TestingTransferRequest request = new TestingTransferRequest() { amount = "100001", assetId = ASSET_ID, fromAddress = EXTERNAL_WALLET, fromPrivateKey = EXTERNAL_WALLET_KEY, toAddress = WALLET_ADDRESS }; var response = blockchainApi.Testing.PostTestingTransfer(request); Assert.That(() => long.Parse(blockchainApi.Balances.GetBalances("1000", null).GetResponseObject(). Items.First(w => w.Address == EXTERNAL_WALLET).Balance), Is.GreaterThan(long.Parse(balanceBefore)).After(5 * 60 * 1000, 1 * 1000), "Balance after 5 minute after transaction not greater then berfore transaction"); } else { var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = ASSET_ID, FromAddress = EXTERNAL_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = WALLET_ADDRESS }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString("N"); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { EXTERNAL_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); } }
public void EWDWTransferTest() { Assert.That(EXTERNAL_WALLET, Is.Not.Null.Or.Empty, "External wallet address and key are empty!"); blockchainApi.Balances.PostBalances(wallet.PublicAddress); var transferSupported = blockchainApi.Capabilities.GetCapabilities().GetResponseObject().IsTestingTransfersSupported; if (transferSupported != null && transferSupported.Value) { TestingTransferRequest request = new TestingTransferRequest() { amount = AMOUNT, assetId = ASSET_ID, fromAddress = EXTERNAL_WALLET, fromPrivateKey = EXTERNAL_WALLET_KEY, toAddress = wallet.PublicAddress }; var response = blockchainApi.Testing.PostTestingTransfer(request); } else { var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = EXTERNAL_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = wallet.PublicAddress, FromAddressContext = EXTERNAL_WALLET_ADDRESS_CONTEXT }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { EXTERNAL_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); } }
public async Task <BuildTransactionResponse> BuildSingle([FromBody] BuildSingleTransactionRequest request) { if (request == null) { throw new BusinessException("Unable deserialize request", ErrorCode.BadInputParameter); } var amountSatoshi = MoneyConversionHelper.SatoshiFromContract(request.Amount); if (amountSatoshi <= 0) { throw new BusinessException($"Amount can't be less or equal to zero: {amountSatoshi}", ErrorCode.BadInputParameter); } if (request.AssetId != Constants.Assets.LiteCoin.AssetId) { throw new BusinessException("Invalid assetId", ErrorCode.BadInputParameter); } var toBitcoinAddress = _addressValidator.GetBitcoinAddress(request.ToAddress); if (toBitcoinAddress == null) { throw new BusinessException("Invalid ToAddress ", ErrorCode.BadInputParameter); } var fromBitcoinAddress = _addressValidator.GetBitcoinAddress(request.FromAddress); if (fromBitcoinAddress == null) { throw new BusinessException("Invalid FromAddress", ErrorCode.BadInputParameter); } if (request.OperationId == Guid.Empty) { throw new BusinessException("Invalid operation id (GUID)", ErrorCode.BadInputParameter); } var tx = await _operationService.GetOrBuildTransferTransaction(request.OperationId, fromBitcoinAddress, toBitcoinAddress, request.AssetId, new Money(amountSatoshi), request.IncludeFee); return(new BuildTransactionResponse { TransactionContext = tx.ToHex() }); }
public void DWHWTransferTest() { Assert.That(HOT_WALLET, Is.Not.Null.Or.Empty, "Hot wallet address and key are empty!"); //create DW and set balance, enable observation var newWallet = blockchainSign.PostWallet().GetResponseObject(); blockchainApi.Balances.PostBalances(newWallet.PublicAddress); AddCyptoToBalanceFromExternal(newWallet.PublicAddress); var take = "500"; var currentBalance = blockchainApi.Balances.GetBalances(take, "0").GetResponseObject().Items.First(w => w.Address == newWallet.PublicAddress).Balance; var model = new BuildSingleTransactionRequest() { Amount = currentBalance, AssetId = ASSET_ID, FromAddress = newWallet.PublicAddress, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { newWallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); var getResponse = blockchainApi.Operations.GetOperationId(operationId); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(getResponse.GetResponseObject().OperationId, Is.EqualTo(model.OperationId)); //validate balance is 0 Assert.That(() => blockchainApi.Balances.GetBalances(take, "0").GetResponseObject().Items.First(w => w.Address == newWallet.PublicAddress).Balance, Is.EqualTo("0").After(5 * 60 * 1000, 2 * 1000), "Unexpected balance"); }
public void PostTransactionsInvalidAddressTest() { var model = new BuildSingleTransactionRequest() { Amount = "10", AssetId = ASSET_ID, FromAddress = "testAddress", IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = "testAddress1" }; var response = blockchainApi.Operations.PostTransactions(model); response.Validate.StatusCode(HttpStatusCode.BadRequest); Assert.That(response.GetResponseObject().TransactionContext, Is.Null); }
public void PostTransactionsTest() { var model = new BuildSingleTransactionRequest() { Amount = "100001", AssetId = CurrentAssetId(), FromAddress = WALLET_ADDRESS, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET }; var response = blockchainApi.Operations.PostTransactions(model); response.Validate.StatusCode(HttpStatusCode.OK); Assert.That(response.GetResponseObject().TransactionContext, Is.Not.Null); }
public void DeleteOperationIdTest() { AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); Assert.That(() => blockchainApi.Balances.GetBalances("500", null).GetResponseObject().Items.Any(w => w.Address == wallet.PublicAddress), Is.True.After(2 * 60 * 1000, 2 * 1000), ""); var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET, FromAddressContext = wallet.AddressContext }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { wallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response.Validate.StatusCode(HttpStatusCode.OK); var responseDelete = blockchainApi.Operations.DeleteOperationId(operationId); responseDelete.Validate.StatusCode(HttpStatusCode.OK); }
private async Task <IActionResult> BuildTxInternal(BuildSingleTransactionRequest request, decimal feeFactor) { _addressValidationService.AssertValid(request?.FromAddress); _addressValidationService.AssertValid(request?.ToAddress); try { var response = await _txBuilderService.BuildSingleTransactionAsync(request, feeFactor); return(Json(response)); } catch (BusinessException exception) when(exception.Reason == ErrorReason.AmountTooSmall) { Response.StatusCode = (int)HttpStatusCode.Conflict; return(Json(new { errorCode = BlockchainErrorCode.AmountIsTooSmall, transactionContext = (string)null })); } catch (BusinessException exception) when(exception.Reason == ErrorReason.NotEnoughBalance) { Response.StatusCode = (int)HttpStatusCode.Conflict; return(Json(new { errorCode = BlockchainErrorCode.NotEnoughBalance, transactionContext = (string)null })); } catch (BusinessException ex) when(ex.Reason == ErrorReason.DuplicateRecord) { // If this operationid was already broadcast, return 409 conflict. return(await GenericErrorResponse(ex, request.OperationId, HttpStatusCode.Conflict)); } }
public void PostTransactionsBroadcastInvalidTransactionTest() { AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = true, OperationId = Guid.NewGuid(), ToAddress = HOT_WALLET, FromAddressContext = wallet.AddressContext }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { wallet.PrivateKey }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); string sTransaction = Guid.NewGuid().ToString(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = sTransaction }); response.Validate.StatusCode(HttpStatusCode.BadRequest); Assert.That(response.Content, Does.Contain("errorMessage").IgnoreCase); }
public void HWEWTransferDoubleBroadcastTest() { var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = HOT_WALLET, IncludeFee = false, OperationId = Guid.NewGuid(), ToAddress = EXTERNAL_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model).GetResponseObject(); string operationId = model.OperationId.ToString(); var signResponse = blockchainSign.PostSign(new SignRequest() { PrivateKeys = new List <string>() { HOT_WALLET_KEY }, TransactionContext = responseTransaction.TransactionContext }).GetResponseObject(); var response = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response.Validate.StatusCode(HttpStatusCode.OK); var response1 = blockchainApi.Operations.PostTransactionsBroadcast(new BroadcastTransactionRequest() { OperationId = model.OperationId, SignedTransaction = signResponse.SignedTransaction }); response1.Validate.StatusCode(HttpStatusCode.Conflict); }
public void SameOperationIdFoDifferentTransactionsTest() { var operationId = Guid.NewGuid(); AddCyptoToBalanceFromExternal(wallet.PublicAddress, wallet.PrivateKey); var model = new BuildSingleTransactionRequest() { Amount = AMOUNT, AssetId = ASSET_ID, FromAddress = wallet.PublicAddress, IncludeFee = true, OperationId = operationId, ToAddress = HOT_WALLET }; var responseTransaction = blockchainApi.Operations.PostTransactions(model); var secondResponseTransaction = blockchainApi.Operations.PostTransactions(model); responseTransaction.Validate.StatusCode(HttpStatusCode.OK); Assert.That(responseTransaction.GetResponseObject().TransactionContext, Is.Not.Null.Or.Empty, "Transaction Context is null"); Assert.That(secondResponseTransaction.GetResponseObject().TransactionContext, Is.Not.Null.Or.Empty, "Transaction Context is null"); }
public async Task <IActionResult> Build([Required, FromBody] BuildSingleTransactionRequest request) { if (!ModelState.IsValid) { return(BadRequest(ModelState.ToErrorResponse())); } var fromAddress = _dynamicService.GetBitcoinAddress(request.FromAddress); if (fromAddress == null) { return(BadRequest(ErrorResponse.Create($"{nameof(request.FromAddress)} is not a valid"))); } var toAddress = _dynamicService.GetBitcoinAddress(request.ToAddress); if (toAddress == null) { return(BadRequest(ErrorResponse.Create($"{nameof(request.ToAddress)} is not a valid"))); } if (request.AssetId != Asset.Dynamic.Id) { return(BadRequest(ErrorResponse.Create($"{nameof(request.AssetId)} was not found"))); } var broadcast = await _dynamicService.GetBroadcastAsync(request.OperationId); if (broadcast != null) { return(new StatusCodeResult(StatusCodes.Status409Conflict)); } var build = await _buildRepository.GetAsync(request.OperationId); if (build != null) { return(Ok(new BuildTransactionResponse() { TransactionContext = build.TransactionContext })); } var amount = Conversions.CoinsFromContract(request.Amount, Asset.Dynamic.Accuracy); var fromAddressBalance = await _dynamicService.GetAddressBalance(request.FromAddress); var fee = _dynamicService.GetFee(); var requiredBalance = request.IncludeFee ? amount : amount + fee; if (amount < fee) { return(BadRequest(BlockchainErrorResponse.FromKnownError(BlockchainErrorCode.AmountIsTooSmall))); } if (requiredBalance > fromAddressBalance) { return(BadRequest(BlockchainErrorResponse.FromKnownError(BlockchainErrorCode.NotEnoughBalance))); } await _log.WriteInfoAsync(nameof(TransactionsController), nameof(Build), request.ToJson(), "Build transaction"); var transactionContext = await _dynamicService.BuildTransactionAsync(request.OperationId, fromAddress, toAddress, amount, request.IncludeFee); await _buildRepository.AddAsync(request.OperationId, transactionContext); return(Ok(new BuildTransactionResponse() { TransactionContext = transactionContext })); }