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); }
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); }
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)); }
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)); } }
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)); } }