public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithoutMethodParameters()
        {
            byte[] contractExecutionCode = Encoding.UTF8.GetBytes(
                @"
                using System;
                using Stratis.SmartContracts;
                [References]

                public class Test : SmartContract
                { 
                    public void TestMethod()
                    {
                        [CodeToExecute]
                    }
                }"
                );

            var carrier = ContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)5000);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);
            Assert.Equal(1, callData.VmVersion);
            Assert.Equal((byte)ScOpcodeType.OP_CREATECONTRACT, callData.OpCodeType);
            Assert.Equal(contractExecutionCode, callData.ContractExecutionCode);
            Assert.Equal((Gas)1, callData.GasPrice);
            Assert.Equal((Gas)5000, callData.GasLimit);
        }
Beispiel #2
0
        public void ContractExecutionResult_OutOfGasException_NoRefundDue_NoFeeAdjustment()
        {
            var contractAddress = new uint160(1);

            var carrier = ContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (Money fee, TxOut refund) = this.refundProcessor.Process(carrier.ContractTxData, new Money(10500), carrier.Sender, (Gas)5000, true);

            Assert.Equal(10500, fee);
            Assert.Null(refund);
        }
Beispiel #3
0
        public void ContractExecutionResult_RefundDue_AdjustFee()
        {
            var contractAddress = new uint160(1);

            var carrier = ContractCarrier.CallContract(1, contractAddress, "ThrowException", 1, (Gas)5000);

            carrier.Sender = new uint160(2);

            (Money fee, TxOut refund) = this.refundProcessor.Process(carrier.ContractTxData, new Money(10500), carrier.Sender, (Gas)950, false);

            Assert.Equal(6450, fee);
            Assert.Equal(carrier.Sender.ToBytes(), refund.ScriptPubKey.GetDestination(this.network).ToBytes());
            Assert.Equal(4050, refund.Value);
        }
        public async Task SmartContractFormatRule_MultipleOutputs_SuccessAsync()
        {
            TestRulesContext        testContext = TestRulesContextFactory.CreateAsync(this.network);
            SmartContractFormatRule rule        = testContext.CreateRule <SmartContractFormatRule>();

            var context = new PowRuleContext(new ValidationContext(), testContext.DateTimeProvider.GetTimeOffset())
            {
                UnspentOutputSet = GetMockOutputSet()
            };

            context.ValidationContext.BlockToValidate = testContext.Network.Consensus.ConsensusFactory.CreateBlock();

            var gasPriceSatoshis  = 20;
            var gasLimit          = 4000000;
            var gasBudgetSatoshis = gasPriceSatoshis * gasLimit;
            var relayFeeSatoshis  = 10000;
            var change            = 200000;

            var totalSuppliedSatoshis = gasBudgetSatoshis + relayFeeSatoshis;

            var carrier    = ContractCarrier.CallContract(1, 0, "TestMethod", (ulong)gasPriceSatoshis, (Gas)gasLimit);
            var serialized = carrier.Serialize();

            Transaction funding = new Transaction
            {
                Outputs =
                {
                    new TxOut(totalSuppliedSatoshis + change, new Script())
                }
            };

            var transactionBuilder = new TransactionBuilder(testContext.Network);

            transactionBuilder.AddCoins(funding);
            transactionBuilder.SendFees(totalSuppliedSatoshis);
            transactionBuilder.Send(new Script(serialized), 0);

            // Add a change output to the transaction
            transactionBuilder.SetChange(new Script());

            Transaction transaction = transactionBuilder.BuildTransaction(false);

            context.ValidationContext.BlockToValidate.Transactions = new List <Transaction>
            {
                transaction
            };

            await rule.RunAsync(context);
        }
        public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithoutMethodParameters()
        {
            var smartContractCarrier = ContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(smartContractCarrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);
            Assert.Equal(smartContractCarrier.ContractTxData.VmVersion, callData.VmVersion);
            Assert.Equal(smartContractCarrier.ContractTxData.OpCodeType, callData.OpCodeType);
            Assert.Equal(smartContractCarrier.ContractTxData.ContractAddress, callData.ContractAddress);
            Assert.Equal(smartContractCarrier.ContractTxData.MethodName, callData.MethodName);
            Assert.Equal(smartContractCarrier.ContractTxData.GasPrice, callData.GasPrice);
            Assert.Equal(smartContractCarrier.ContractTxData.GasLimit, callData.GasLimit);
        }
        public void SmartContractFormatRule_FailureAsync()
        {
            TestRulesContext        testContext = TestRulesContextFactory.CreateAsync(this.network);
            SmartContractFormatRule rule        = testContext.CreateRule <SmartContractFormatRule>();

            var context = new PowRuleContext(new ValidationContext(), testContext.DateTimeProvider.GetTimeOffset());

            context.ValidationContext.BlockToValidate = testContext.Network.Consensus.ConsensusFactory.CreateBlock();

            var gasPriceSatoshis  = 20;
            var gasLimit          = 4000000;
            var gasBudgetSatoshis = gasPriceSatoshis * gasLimit;
            var relayFeeSatoshis  = 10000;

            var totalSuppliedSatoshis = gasBudgetSatoshis + relayFeeSatoshis;

            var higherGasLimit = gasLimit + 10000;

            var carrier    = ContractCarrier.CallContract(1, 0, "TestMethod", (ulong)gasPriceSatoshis, (Gas)higherGasLimit);
            var serialized = carrier.Serialize();

            Transaction funding = new Transaction
            {
                Outputs =
                {
                    new TxOut(totalSuppliedSatoshis, new Script())
                }
            };

            var transactionBuilder = new TransactionBuilder(testContext.Network);

            transactionBuilder.AddCoins(funding);
            transactionBuilder.SendFees(relayFeeSatoshis);
            transactionBuilder.Send(new Script(serialized), gasBudgetSatoshis);

            Transaction transaction = transactionBuilder.BuildTransaction(false);

            context.ValidationContext.BlockToValidate.Transactions = new List <Transaction>
            {
                transaction
            };

            Task <ConsensusErrorException> error = Assert.ThrowsAsync <ConsensusErrorException>(async() => await rule.RunAsync(context));
        }
Beispiel #7
0
        public void SendAndReceiveSmartContractTransactionsOnPosNetwork()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode scSender   = builder.CreateSmartContractPosNode();
                CoreNode scReceiver = builder.CreateSmartContractPosNode();

                builder.StartAll();

                scSender.NotInIBD();
                scReceiver.NotInIBD();

                scSender.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase);
                scReceiver.FullNode.WalletManager().CreateWallet(Password, WalletName, Passphrase);

                var       maturity      = (int)scSender.FullNode.Network.Consensus.CoinbaseMaturity;
                HdAddress senderAddress = TestHelper.MineBlocks(scSender, WalletName, Password, AccountName, maturity + 5).AddressUsed;

                // Wait for block repo for block sync to work.
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // The mining should add coins to the wallet.
                var total = scSender.FullNode.WalletManager().GetSpendableTransactionsInWallet(WalletName).Sum(s => s.Transaction.Amount);
                Assert.Equal(Money.COIN * 6 * 50, total);

                // Create a token contract
                ulong gasPrice  = 1;
                int   vmVersion = 1;
                Gas   gasLimit  = (Gas)5000;
                ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);

                var contractCarrier = ContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);

                var contractCreateScript = new Script(contractCarrier.Serialize());
                var txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                var transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(transferContractTransaction);

                // Ensure the smart contract transaction is in the mempool.
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);

                // Mine the token transaction and wait for it sync
                scSender.GenerateStratisWithMiner(1);
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Sync to the receiver node
                scSender.CreateRPCClient().AddNode(scReceiver.Endpoint, true);
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // Ensure that boths nodes has the contract
                IStateRepositoryRoot senderState      = scSender.FullNode.NodeService <IStateRepositoryRoot>();
                IStateRepositoryRoot receiverState    = scReceiver.FullNode.NodeService <IStateRepositoryRoot>();
                IAddressGenerator    addressGenerator = scSender.FullNode.NodeService <IAddressGenerator>();

                uint160 tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0);
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a transfer token contract
                compilationResult = ContractCompiler.CompileFile("SmartContracts/TransferTestPos.cs");
                Assert.True(compilationResult.Success);
                contractCarrier      = ContractCarrier.CreateContract(vmVersion, compilationResult.Compilation, gasPrice, gasLimit);
                contractCreateScript = new Script(contractCarrier.Serialize());
                txBuildContext       = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 0, ScriptPubKey = contractCreateScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                transferContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(transferContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);
                scSender.GenerateStratisWithMiner(1);

                // Ensure the node is synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));

                // Ensure both nodes are synced with each other
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                tokenContractAddress = addressGenerator.GenerateAddress(transferContractTransaction.GetHash(), 0); // nonce is 0 for user contract creation.
                Assert.NotNull(senderState.GetCode(tokenContractAddress));
                Assert.NotNull(receiverState.GetCode(tokenContractAddress));
                scSender.FullNode.MempoolManager().Clear();

                // Create a call contract transaction which will transfer funds
                contractCarrier = ContractCarrier.CallContract(1, tokenContractAddress, "Test", gasPrice, gasLimit);
                Script contractCallScript = new Script(contractCarrier.Serialize());
                txBuildContext = new TransactionBuildContext(scSender.FullNode.Network)
                {
                    AccountReference = new WalletAccountReference(WalletName, AccountName),
                    ChangeAddress    = senderAddress,
                    MinConfirmations = maturity,
                    FeeType          = FeeType.High,
                    WalletPassword   = Password,
                    Recipients       = new[] { new Recipient {
                                                   Amount = 1000, ScriptPubKey = contractCallScript
                                               } }.ToList()
                };

                // Build the transfer contract transaction
                var callContractTransaction = BuildTransferContractTransaction(scSender, txBuildContext);

                // Add the smart contract transaction to the mempool to be mined.
                scSender.AddToStratisMempool(callContractTransaction);

                // Wait for the token transaction to be picked up by the mempool
                TestHelper.WaitLoop(() => scSender.CreateRPCClient().GetRawMempool().Length > 0);
                scSender.GenerateStratisWithMiner(1);

                // Ensure the nodes are synced
                TestHelper.WaitLoop(() => TestHelper.IsNodeSynced(scSender));
                TestHelper.WaitLoop(() => TestHelper.AreNodesSynced(scReceiver, scSender));

                // The balance should now reflect the transfer
                Assert.Equal((ulong)900, senderState.GetCurrentBalance(tokenContractAddress));
            }
        }
Beispiel #8
0
        public void SmartContracts_AddToMempool_OnlyValid()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                var stratisNodeSync = builder.CreateSmartContractPowNode();
                builder.StartAll();

                stratisNodeSync.SetDummyMinerSecret(new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network));
                stratisNodeSync.GenerateStratisWithMiner(105); // coinbase maturity = 100
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.ConsensusManager().Tip.HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock);
                TestHelper.WaitLoop(() => stratisNodeSync.FullNode.GetBlockStoreTip().HashBlock == stratisNodeSync.FullNode.Chain.Tip.HashBlock);

                var block   = stratisNodeSync.FullNode.BlockStore().GetBlockAsync(stratisNodeSync.FullNode.Chain.GetBlock(4).HashBlock).Result;
                var prevTrx = block.Transactions.First();
                var dest    = new BitcoinSecret(new Key(), stratisNodeSync.FullNode.Network);

                // Gas higher than allowed limit
                Transaction tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                ContractCarrier smartContractCarrier = ContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(10_000_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // OP_SPEND in user's tx - we can't sign this because the TransactionBuilder recognises the ScriptPubKey is invalid.
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), new Script(new[] { (byte)ScOpcodeType.OP_SPEND })));
                smartContractCarrier = ContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(100_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                stratisNodeSync.Broadcast(tx);

                // 2 smart contract outputs
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                smartContractCarrier = ContractCarrier.CallContract(1, new uint160(0), "Test", 1, new Gas(100_000));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.AddOutput(new TxOut(1, new Script(smartContractCarrier.Serialize())));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // Send to contract
                uint160 contractAddress = new uint160(123);
                var     state           = stratisNodeSync.FullNode.NodeService <IStateRepositoryRoot>();
                state.CreateAccount(contractAddress);
                state.Commit();
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                tx.AddOutput(new TxOut(100, PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(new KeyId(contractAddress))));
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);

                // After 5 seconds (plenty of time but ideally we would have a more accurate measure) no txs in mempool. All failed validation.
                Thread.Sleep(5000);
                Assert.Empty(stratisNodeSync.CreateRPCClient().GetRawMempool());

                // Valid tx still works
                tx = new Transaction();
                tx.AddInput(new TxIn(new OutPoint(prevTrx.GetHash(), 0), PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(stratisNodeSync.MinerSecret.PubKey)));
                tx.AddOutput(new TxOut("25", dest.PubKey.Hash));
                tx.AddOutput(new TxOut("24", new Key().PubKey.Hash)); // 1 btc fee
                tx.Sign(stratisNodeSync.FullNode.Network, stratisNodeSync.MinerSecret, false);
                stratisNodeSync.Broadcast(tx);
                TestHelper.WaitLoop(() => stratisNodeSync.CreateRPCClient().GetRawMempool().Length == 1);
            }
        }
        public void SmartContract_CanSerialize_OP_CREATECONTRACT_WithMethodParameters()
        {
            byte[] contractExecutionCode = Encoding.UTF8.GetBytes(
                @"
                using System;
                using Stratis.SmartContracts;
                [References]

                public class Test : SmartContract
                { 
                    public void TestMethod(int orders, bool canOrder)
                    {
                        [CodeToExecute]
                    }
                }"
                );

            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 12),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te|s|t"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "te#st"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "#4#te#st#"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, '#'),
            };

            var carrier = ContractCarrier.CreateContract(1, contractExecutionCode, 1, (Gas)500000, methodParameters);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);
            Assert.Equal(carrier.ContractTxData.VmVersion, callData.VmVersion);
            Assert.Equal(carrier.ContractTxData.OpCodeType, callData.OpCodeType);
            Assert.Equal(carrier.ContractTxData.ContractExecutionCode, callData.ContractExecutionCode);
            Assert.Equal(6, callData.MethodParameters.Length);

            Assert.NotNull(callData.MethodParameters[0]);
            Assert.Equal(12, callData.MethodParameters[0]);

            Assert.NotNull(carrier.MethodParameters[1]);
            Assert.True((bool)callData.MethodParameters[1]);

            Assert.NotNull(callData.MethodParameters[2]);
            Assert.Equal("te|s|t", callData.MethodParameters[2]);

            Assert.NotNull(callData.MethodParameters[3]);
            Assert.Equal("te#st", callData.MethodParameters[3]);

            Assert.NotNull(callData.MethodParameters[4]);
            Assert.Equal("#4#te#st#", callData.MethodParameters[4]);

            Assert.NotNull(callData.MethodParameters[5]);
            Assert.Equal("#", callData.MethodParameters[5]);

            Assert.Equal(carrier.ContractTxData.GasPrice, callData.GasPrice);
            Assert.Equal(carrier.ContractTxData.GasLimit, callData.GasLimit);
        }
        public void SmartContract_CanSerialize_OP_CALLCONTRACT_WithMethodParameters()
        {
            string[] methodParameters = new string[]
            {
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Bool, true),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Byte, (byte)1),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ByteArray, BitConverter.ToString(Encoding.UTF8.GetBytes("test"))),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Char, 's'),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.SByte, -45),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Short, 7),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.String, "test"),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt, 36),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.UInt160, new uint160(new byte[20] {
                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
                })),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.ULong, 29),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("0x95D34980095380851902ccd9A1Fb4C813C2cb639")),
                string.Format("{0}#{1}", (int)SmartContractCarrierDataType.Address, new Address("mxKorCkWmtrPoekfWiMzERJPhaT13nnkMy"))
            };

            var carrier = ContractCarrier.CallContract(1, 100, "Execute", 1, (Gas)500000, methodParameters);

            var serializer = CallDataSerializer.Default;

            var callDataResult = serializer.Deserialize(carrier.Serialize());
            var callData       = callDataResult.Value;

            Assert.True(callDataResult.IsSuccess);

            Assert.NotNull(callData.MethodParameters[0]);
            Assert.Equal(carrier.MethodParameters[0], callData.MethodParameters[0]);

            Assert.NotNull(callData.MethodParameters[1]);
            Assert.Equal(carrier.MethodParameters[1], callData.MethodParameters[1]);

            Assert.NotNull(callData.MethodParameters[2]);
            Assert.Equal(carrier.MethodParameters[2], callData.MethodParameters[2]);

            Assert.NotNull(callData.MethodParameters[3]);
            Assert.Equal(carrier.MethodParameters[3], callData.MethodParameters[3]);

            Assert.NotNull(callData.MethodParameters[4]);
            Assert.Equal(carrier.MethodParameters[4], callData.MethodParameters[4]);

            Assert.NotNull(callData.MethodParameters[5]);
            Assert.Equal(carrier.MethodParameters[5], callData.MethodParameters[5]);

            Assert.NotNull(callData.MethodParameters[6]);
            Assert.Equal(carrier.MethodParameters[6], callData.MethodParameters[6]);

            Assert.NotNull(callData.MethodParameters[7]);
            Assert.Equal(carrier.MethodParameters[7], callData.MethodParameters[7]);

            Assert.NotNull(callData.MethodParameters[8]);
            Assert.Equal(carrier.MethodParameters[8], callData.MethodParameters[8]);

            Assert.NotNull(callData.MethodParameters[9]);
            Assert.Equal(carrier.MethodParameters[9], callData.MethodParameters[9]);

            Assert.NotNull(callData.MethodParameters[10]);
            Assert.Equal(carrier.MethodParameters[10], callData.MethodParameters[10]);

            Assert.NotNull(callData.MethodParameters[11]);
            Assert.Equal(carrier.MethodParameters[11], callData.MethodParameters[11]);
        }
        private BuildCallContractTransactionResponse BuildCallTx(BuildCallContractTransactionRequest request)
        {
            this.logger.LogTrace(request.ToString());

            AddressBalance addressBalance = this.walletManager.GetAddressBalance(request.Sender);

            if (addressBalance.AmountConfirmed == 0)
            {
                return(BuildCallContractTransactionResponse.Failed($"The 'Sender' address you're trying to spend from doesn't have a confirmed balance. Current unconfirmed balance: {addressBalance.AmountUnconfirmed}. Please check the 'Sender' address."));
            }

            var selectedInputs = new List <OutPoint>();

            selectedInputs = this.walletManager.GetSpendableTransactionsInWallet(request.WalletName, MinConfirmationsAllChecks).Where(x => x.Address.Address == request.Sender).Select(x => x.ToOutPoint()).ToList();

            ulong   gasPrice       = ulong.Parse(request.GasPrice);
            ulong   gasLimit       = ulong.Parse(request.GasLimit);
            uint160 addressNumeric = new Address(request.ContractAddress).ToUint160(this.network);

            ContractCarrier carrier;

            if (request.Parameters != null && request.Parameters.Any())
            {
                carrier = ContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit), request.Parameters);
            }
            else
            {
                carrier = ContractCarrier.CallContract(ReflectionVirtualMachine.VmVersion, addressNumeric, request.MethodName, gasPrice, new Gas(gasLimit));
            }

            HdAddress senderAddress = null;

            if (!string.IsNullOrWhiteSpace(request.Sender))
            {
                Features.Wallet.Wallet wallet = this.walletManager.GetWallet(request.WalletName);
                HdAccount account             = wallet.GetAccountByCoinType(request.AccountName, this.coinType);
                senderAddress = account.GetCombinedAddresses().FirstOrDefault(x => x.Address == request.Sender);
            }

            ulong totalFee = (gasPrice * gasLimit) + Money.Parse(request.FeeAmount);
            var   context  = new TransactionBuildContext(this.network)
            {
                AccountReference = new WalletAccountReference(request.WalletName, request.AccountName),
                TransactionFee   = totalFee,
                ChangeAddress    = senderAddress,
                SelectedInputs   = selectedInputs,
                MinConfirmations = MinConfirmationsAllChecks,
                WalletPassword   = request.Password,
                Recipients       = new[] { new Recipient {
                                               Amount = request.Amount, ScriptPubKey = new Script(carrier.Serialize())
                                           } }.ToList()
            };

            try
            {
                Transaction transaction = this.walletTransactionHandler.BuildTransaction(context);
                return(BuildCallContractTransactionResponse.Succeeded(request.MethodName, transaction, context.TransactionFee));
            }
            catch (Exception exception)
            {
                return(BuildCallContractTransactionResponse.Failed(exception.Message));
            }
        }