public async Task <TransactionReceipt> CallFunctionReceipt(Function function, HexBigInteger value, HexBigInteger gasLimit = null, params object[] parameters)
        {
            // Calls the function to see if it can be executed
            // Check if private key is supplied in web3 instance
            if (string.IsNullOrEmpty(Web3.TransactionManager.Account.Address))
            {
                throw new AuthenticationException("No private key provided in the underlying Web3 instance.");
            }

            string senderAddress = Web3.TransactionManager.Account.Address;

            // Calls the function to see if it can be executed
            HexBigInteger gas = gasLimit ?? await EstimateGas(new CallInput()
            {
                From  = Web3.TransactionManager.Account.Address,
                Data  = function.GetData(parameters),
                To    = function.ContractAddress,
                Value = value ?? new HexBigInteger(0)
            }).ConfigureAwait(false);

            // Estimate gas price
            BigInteger gasPrice = await GasEstimator.EstimateGasPrice();

            HexBigInteger balance = await Web3.Eth.GetBalance.SendRequestAsync(senderAddress);

            if (gasPrice * gas.Value >= (balance.Value * 19 / 20))
            {
                throw new BalanceException("Insufficient balance for gas.");
            }

            BigInteger nonce = await GetNonce(senderAddress);

            return(await function.SendTransactionAndWaitForReceiptAsync(new TransactionInput()
            {
                GasPrice = new HexBigInteger(gasPrice),
                Gas = gas,
                From = senderAddress,
                To = function.ContractAddress,
                Value = value ?? new HexBigInteger(0),
                Nonce = new HexBigInteger(nonce),
                Data = function.GetData(parameters)
            }, null, parameters));
        }
            public TestEnvironment()
            {
                _specProvider = MainnetSpecProvider.Instance;
                MemDb     stateDb   = new();
                TrieStore trieStore = new(stateDb, LimboLogs.Instance);

                _stateProvider = new StateProvider(trieStore, new MemDb(), LimboLogs.Instance);
                _stateProvider.CreateAccount(TestItem.AddressA, 1.Ether());
                _stateProvider.Commit(_specProvider.GenesisSpec);
                _stateProvider.CommitTree(0);

                StorageProvider storageProvider = new(trieStore, _stateProvider, LimboLogs.Instance);
                VirtualMachine  virtualMachine  = new(TestBlockhashProvider.Instance, _specProvider, LimboLogs.Instance);

                _transactionProcessor = new TransactionProcessor(_specProvider, _stateProvider, storageProvider, virtualMachine, LimboLogs.Instance);
                _ethereumEcdsa        = new EthereumEcdsa(_specProvider.ChainId, LimboLogs.Instance);

                tracer    = new();
                estimator = new(_transactionProcessor, _stateProvider, _specProvider);
            }
        public async Task <string> CallFunction(Function function, HexBigInteger value, string privateKey, HexBigInteger gasLimit = null, params object[] parameters)
        {
            // Create the account for retrieving from address
            Account senderAccount = new Account(privateKey);

            // Calls the function to see if it can be executed
            HexBigInteger gas = gasLimit ?? await EstimateGas(new CallInput()
            {
                From  = senderAccount.Address,
                Data  = function.GetData(parameters),
                To    = function.ContractAddress,
                Value = value ?? new HexBigInteger(0)
            }).ConfigureAwait(false);

            // Estimate gas price
            BigInteger gasPrice = await GasEstimator.EstimateGasPrice();

            HexBigInteger balance = await Web3.Eth.GetBalance.SendRequestAsync(senderAccount.Address);

            if (gasPrice * gas.Value >= (balance.Value * 19 / 20))
            {
                throw new BalanceException("Insufficient balance for gas.");
            }

            BigInteger nonce = await GetNonce(senderAccount.Address);

            string signedTx = await new EthereumTxSigner(privateKey)
                              .Sign(new TransactionInput()
            {
                GasPrice = new HexBigInteger(gasPrice),
                Gas      = new HexBigInteger(gas),
                From     = senderAccount.Address,
                To       = function.ContractAddress,
                Value    = value ?? new HexBigInteger(0),
                Nonce    = new HexBigInteger(nonce),
                Data     = function.GetData(parameters)
            });

            return(await Web3.Eth.Transactions.SendRawTransaction.SendRequestAsync(signedTx));
        }