Beispiel #1
0
            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));
            }
Beispiel #2
0
            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);
            }
Beispiel #3
0
            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));
        }
Beispiel #5
0
        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
            }));
        }
Beispiel #9
0
            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");
            }
Beispiel #13
0
        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);
        }
Beispiel #14
0
            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));
        }
Beispiel #16
0
            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);
            }
Beispiel #18
0
        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));
            }
        }
Beispiel #19
0
            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));
                }
            }
Beispiel #21
0
        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()
            });
        }
Beispiel #22
0
            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");
            }
Beispiel #23
0
            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");
            }
Beispiel #30
0
        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
            }));
        }