I have this contract deployed that is meant to send ether from itself to an another account
pragma solidity ^0.8.0;
contract Contract {
address public owner;
address public admin;
constructor(address _admin) public {
owner = msg.sender;
admin = _admin;
}
modifier onlyOwner(address sender) {
require(
sender == admin,
"Only the admin of the contract can perform this operation."
);_;
}
function sendTo (
address toAddress
) public payable onlyOwner(msg.sender) {
payable(toAddress).transfer(msg.value);
}
}
and I try to interact with it like so on the client side:
var contract = new web3.eth.Contract(abi, Address, null);
const transaction = {
from: mainAcct,
to: dummyAcct,
value: '10000000000000000',
gas: 30000
};
await contract.methods.sendTo(dummyAcct).send(
transaction , function(err, hash){
if(!err){
console.log("Transaction hash:", hash);
}else{
console.log(err);
}
});
} catch (e) {
console.log(e);
}
why do I get this error in the console:
Error: Transaction has been reverted by the EVM
Looks like you need to fund the contract before sending the amount out
I did something like below hre is hardhat object, but there will be way to add funds while deploying
const waveContractFactory = await hre.ethers.getContractFactory('contract_name');
const waveContract = await waveContractFactory.deploy({
value: hre.ethers.utils.parseEther('0.1'),
});
The problem could be with transfer, transfer limit the gas and that could be the reason of the error, try using call instead of transfer, check this web to see how to use it https://solidity-by-example.org/sending-ether/
Related
I am receiving the following message:
"Warning! Error encountered during contract execution [execution reverted]"
What I'm trying to do is simple, I have a contract, where I don't get token, I just use ethereum and users just pay gas fee to miners.
What I'm trying to do here is call a contract function, but it adds data to the blockchain, which wastes gas.
Here's the contract:
https://goerli.etherscan.io/address/0xa46dc78595315b94904182013888adb439c6009f
Contract Code:
/**
* #title Ballot
* #dev Implements voting process along with vote delegation
*/
contract Ballot is IHelper, Guard, Logging {
Confirmed[6] private _confirmedVotes;
Abstention private _abstentionVotes;
uint[6] private _candidates;
uint private _totalConfirmedVotes;
mapping(address => bool) private _electorHasAlreadyVoted;
constructor() {
_registerCandidates();
emit LogStartElection("Beginning of the election period, ballot box released!", getResult());
}
/** #dev Register Candidates **/
function _registerCandidates() private {
for (uint i = 0; i < _candidates.length; i++) {
_candidates[i] = i;
_confirmedVotes[i].candidate = i;
}
}
/**
* #dev Return Elector Has Already Voted
* #return value of '_electorHasAlreadyVoted'
*/
function getElectorHasAlreadyVoted() public view returns (bool) {
return _electorHasAlreadyVoted[msg.sender];
}
/**
* #dev Return Electoral Result
* #return value of 'ElectionResult'
*/
function getResult() public view returns (ElectionResult memory) {
return
ElectionResult({
candidates: _candidates,
totalConfirmedVotes: _totalConfirmedVotes,
confirmedVotes: _confirmedVotes,
abstentionVotes: _abstentionVotes
});
}
/**
* #dev Elector Vote Confirmation
* #param candidateID value to store
*/
function confirmVote(
uint candidateID
) public onlyCandidateRegistered(candidateID, _candidates.length) onlyElectorWhoDidNotVote(_electorHasAlreadyVoted[msg.sender]) {
_confirmedVotes[candidateID].totalVotes++;
_confirmedVotes[candidateID].elector.push(msg.sender);
_confirmedVotes[candidateID].candidate = candidateID;
_electorHasAlreadyVoted[msg.sender] = true;
_totalConfirmedVotes++;
emit LogElectorVote("Vote Confirmed and Computed!", getResult());
}
/** #dev Elector Vote Abstention **/
function abstainVote() public onlyElectorWhoDidNotVote(_electorHasAlreadyVoted[msg.sender]) {
_abstentionVotes.totalVotes++;
_abstentionVotes.elector.push(msg.sender);
_electorHasAlreadyVoted[msg.sender] = true;
emit LogElectorVote("Vote Abstained and Computed!", getResult());
}
}
DApp Ethers code:
const PROVIDER = ethers.providers.InfuraProvider.getWebSocketProvider({ chainId: 5, name: 'goerli' });
const PRIVATE_WALLET = new ethers.Wallet(process.env.REACT_APP_WALLET_PRIVATE_KEY || '', PROVIDER);
const CONTRACT = new ethers.Contract(
process.env.REACT_APP_SOLIDITY_CONTRACT_ADDRESS || '',
BallotContract.abi,
PRIVATE_WALLET
)
const ELECTOR_SIGNER = CONTRACT.connect(ELECTOR_WALLET);
const CONTRACT_ADDRESS = await infura.contract.resolvedAddress;
const GAS_LIMIT = await ELECTOR_SIGNER.estimateGas.confirmVote(1);
const TRANSACTION_HASH = await window.ethereum?.request({
method: 'eth_sendTransaction',
params: [
{
from: ELECTOR_SIGNER,
to: CONTRACT_ADDRESS,
gas: estimateGas._hex,
value: 0,
},
],
})
const TRANSACTION_RECEIPT = await PROVIDER.waitForTransaction(TRANSACTION_HASH);
const RESPONSE = await ELECTOR_SIGNER.confirmVote(1);
For a contract to accept ETH (or generally native tokens - BNB on Binance Smart Chain, MATIC on Polygon, ...), it needs to implement either of the special functions - receive() or payable fallback(). If the contract doesn't implement any of these functions, it rejects the incoming transfer.
contract Ballot {
// ...
receive() external payable {
// can be empty; or you can redirect the incoming transfer to an EOA
}
}
When you just send empty value and empty data, it tries to invoke the fallback() function, that is also not present. So the solution is similar in this case - implement the fallback() special function.
contract Ballot {
// ...
fallback() external payable {
// can be empty
}
}
I'm running the following javascript file and using web3js to call a smart contract (0xF3885ca057a42B10b6cb432B816FE11426a2E369) on Goerli:
const Web3 = require("web3");
// Loading the contract ABI
// (the results of a previous compilation step)
const fs = require("fs");
const { abi } = JSON.parse(fs.readFileSync("EtherSplitter.json"));
async function main() {
// Configuring the connection to an Ethereum node
const network = process.env.ETHEREUM_NETWORK;
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
)
);
// Creating a signing account from a private key
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.SIGNER_PRIVATE_KEY
);
web3.eth.accounts.wallet.add(signer);
// Creating a Contract instance
const contract = new web3.eth.Contract(
abi,
// Replace this with the address of your deployed contract
process.env.ETHERSPLITTER_CONTRACT
);
// Issuing a transaction that calls the splitEther method
const tx = contract.methods.splitEther(["0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc"]);
const receipt = await tx
.send({
from: signer.address,
value: 1e15, // IS THIS CORRECT? IF NOT, HOW DO I SPECIFY VALUE FOR SEND
gas: await tx.estimateGas(),
})
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
// The transaction is now on chain!
console.log(`Mined in block ${receipt.blockNumber}`);
}
require("dotenv").config();
main();
The smart contract is:
contract EtherSplitter {
function splitEther(address payable[] memory recipients) public payable {
uint fee = 10;
recipients[0].transfer(msg.value * fee / 100);
recipients[1].transfer(msg.value * (100 - fee) / 100);
}
receive() external payable {
}
}
Execution is reverting with the following error:
users/myusername/demo-eth-tx/node_modules/web3-core-helpers/lib/errors.js:28
var err = new Error('Returned error: ' + message);
I think I'm using send incorrectly, and incorrectly specifying the send value. How do I fix that?
Based on your code, seems like you mixed up some ether.js into your web3.js code coz in web3.js there when executing contract because in web3.js, function parameters doesn't need to be in an array like in ether.js
Try this
const tx = contract.methods.splitEther("0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc");
I have a basic ERC-20 Token defined as
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor() ERC20("Token", "TOKEN") {}
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
}
I have another contract Item that has a method I want to cost 1 Token, basing answer off https://ethereum.stackexchange.com/a/78911/30804
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Item {
IERC20 private token;
constructor(address tokenAddress) {
token = IERC20(tokenAddress);
}
function myMethod() public {
bool success = token.transferFrom(msg.sender, address(this), 1 ether); // also tried just 1
require(success, "Insufficient Funds: Requires 1 Token");
// do things
}
}
I'm running this inside a Hardhat test
const TokenFactory = await ethers.getContractFactory("Token");
Token = await Token.deploy();
await Token.mint(owner.address, ethers.utils.parseUnits("1", 18));
await Token.approve(owner.address, ethers.utils.parseUnits("1", 18));
const ItemFactory = await ethers.getContractFactory("Item");
Item = await ItemFactory.deploy(Token.address);
await Item.myMethod(); // this is the line that errors
Everything runs and I can see debug code from the solidity contracts, but I keep getting an error that
reverted with reason string 'ERC20: insufficient allowance'
that I traced back to the openzeppelin internal function _spendAllowance
After some debugging I thought that the culprit was because I needed to approve, so I added a call to approve but I'm still getting the same error
I'm assuming my issue is something basic can anyone see what it might be? Thanks in advance.
await Token.approve(owner.address, ethers.utils.parseUnits("1", 18));
You're giving the approval to the owner address, but the actual msg.sender inside the transferFrom() function is the Item address (as the caller of the function is the Item contract).
Solution: Approve the Item address as the spender.
// after the `Item` contract has been deployed
await Token.approve(Item.address, ethers.utils.parseUnits("1", 18));
await Item.myMethod();
I'm trying to transfer Matic to my smart contract in the Mumbai test net using ethers.
I'm using the most basic contract which comes with hardhat - Greeter. sol.
The error I keep getting is(in the polygonscan-mumbai):
The client side transfer using ethers:
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const erc20Contract = new ethers.Contract("0x0000000000000000000000000000000000001010", erc20abi, signer);
const parsedAmount = ethers.utils.parseUnits(amount.toString(), 'ether');
const transferTokens = await erc20Contract.transfer(contractAddress , parsedAmount);
Greeter.sol:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract Greeter {
string private greeting;
constructor(string memory _greeting) {
console.log("Deploying a Greeter with greeting:", _greeting);
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
Also when I manually try to send Matic to the smart contract using metamsk it's giving me the same error(only to contracts, not other wallets).
But if I try other tokens it works fine - am I missing something?
Your contract needs to implement either receive() or fallback() function to be able to accept native currency of the network.
Docs: https://docs.soliditylang.org/en/v0.8.13/contracts.html#special-functions
Example:
contract Greeter {
// ...
receive() external payable {
}
}
I've been successfully compiled and deployed my smart contract Campaign.sol. All the functions in my contract can run successfully but as I use my javascript file RequestRow.js to call my function finalizeRequest Metamask pops up the error Transaction error. Exception thrown in contract code
I've googled this error and tried to solve my question by this and this. However, they aren't helpful for my error.
Can anyone tells me where did I do wrong in my smart contract. I don't know how to solve it. Please help!
My Campaign.sol file
pragma solidity ^0.4.17;
contract CampaignFactory{
address[] public deployedCampaigns;
function createCampaign(uint minimum)public{
address newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaign() public view returns(address[]){
return deployedCampaigns;
}
}
contract Campaign{
struct Request {
string description;
uint value;
address recipient;
bool complete;
uint approvalCount;
mapping(address => bool) approvals;
}
Request[] public requests;
address public manager;
uint public minimumContribution;
mapping (address => bool) public approvers;
uint public approversCount;
modifier restricted(){
require(msg.sender == manager);
_;
}
function Campaign (uint minimum, address creator)public{
manager = creator;
minimumContribution = minimum;
}
function contribue()public payable{
require(msg.value > minimumContribution);
approvers[msg.sender] = true;
approversCount++;
}
function createRequest(string description, uint value, address recipient)public restricted{
Request memory newRequest = Request({
description: description,
value: value,
recipient: recipient,
complete: false,
approvalCount: 0
});
requests.push(newRequest);
}
function approveRequest(uint index)public{
Request storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvals[msg.sender]);
request.approvals[msg.sender] = true;
request.approvalCount++;
}
function finalizeRequest(uint index)public restricted{
Request storage request = requests[index];
require(request.approvalCount > (approversCount/2));
require(!request.complete);
request.recipient.transfer(request.value);
request.complete = true;
}
function getSummary() public view returns (
uint, uint, uint, uint, address
){
return (
minimumContribution,
this.balance,
requests.length,
approversCount,
manager
);
}
function getRequestsCount() public view returns (uint){
return requests.length;
}
}
My RequestRow.js file
import React, {Component} from 'react';
import {Table, Button} from 'semantic-ui-react';
import web3 from '../ethereum/web3';
import Campaign from '../ethereum/campaign';
class RequestRow extends Component{
onApprove = async() => {
const campaign = Campaign(this.props.address);
const accounts = await web3.eth.getAccounts();
await campaign.methods.approveRequest(this.props.id).send({
from: accounts[0]
});
};
onFinalize = async() => {
const campaign = Campaign(this.props.address);
const accounts = await web3.eth.getAccounts();
await campaign.methods.finalizeRequest(this.props.id).send({
from: accounts[0]
});
};
render(){
const {Row, Cell} = Table;
const {id, request, approversCount} = this.props;
return (
<Row>
<Cell>{id}</Cell>
<Cell>{request.description}</Cell>
<Cell>{web3.utils.fromWei(request.value,'ether')}</Cell>
<Cell>{request.recipient}</Cell>
<Cell>{request.approvalCount}/{approversCount}</Cell>
<Cell>
<Button color="green" basic onClick={this.onApprove}>
Approve
</Button>
</Cell>
<Cell>
<Button color="teal" basic onClick={this.onFinalize}>
Finalize
</Button>
</Cell>
</Row>
)
}
}
export default RequestRow;
The full error message that I got in the deveoper console
Uncaught (in promise) Error: Transaction has been reverted by the EVM:
{
"blockHash": "0xcca9f6dac8c99c2ecc1f9314661399bda3a6096bf0f36d1c1724d84dcece42b2",
"blockNumber": 5145820,
"contractAddress": null,
"cumulativeGasUsed": 270372,
"from": "0x284aea2dca83c9c6247907554cb27120f7ce1892",
"gasUsed": 55899,
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": false,
"to": "0x6ff70b2a9c30909431714902581539087fe25a3b",
"transactionHash": "0x24b15e5db8bb673375409327cdde0fba98844126f5909ed7681845ee3bccce84",
"transactionIndex": 2,
"events": {}
}
at index.js?959bf61:366
This error is due to the rather complicated account switching required.
First, you need to create a campaign with one of your MetaMask accounts,
Then you need to create a request while in this same account as 'manager'. When you copy and paste the address of the recipient make sure to switch back to the right account after, before submitting the request.
Then you need to contribute to the campaign with another MetaMask account, and approve the request while making sure you are still in the account that you contributed the funds with.
Normally this account switching would not be an issue but it is simulating multiple different users interacting with the contract.
Regards
Mark
you need use truffle/HDwallet and set provider.