What will happen if gas used out when invoke outside smart contract - solidity

contract Counter {
uint256 value = 0;
function addOne() external {
value += 1;
}
}
contract MyContract {
Counter a = .....;
Counter b = .....;
// .......
function myFunc() external {
// ......
a.addOne();
b.addOne();
}
}
What will happen if gas uses out while on executing b.addOne()?
If a.value will add one?
How can I avoid it?

Gas is the currency used to incentivize miners to execute OPCODEs on the EVM. Each transaction on Ethereum is ATOMic, meaning every OPCODE in the transaction must run otherwise the entire transaction is rejected. So if you run out of gas, your transaction will simply revert.
You can avoid this by using a gas estimator (e.g. Remix has this integrate out of the box) or doing it by hand (since every OPCODE's gas requirement is known, and so is the gas price, even if it does fluctuate moment to moment).
Then when you make the call, you specify how much gas to use eg: a.addOne{gas: 69696969 }()
If you send too much, the unspent gas will be returned to the caller.

Related

How to create a time-based upkeep directly from my contract rather than use the GUI?

I want to create a time-based upkeep directly from my contract. I was able to register and fund the upkeep but for some reason the function is not getting executed automatically.
Here's the code
`
// Goerli network
address public cronFactoryAddress = 0x1af3cE8de065774B0EC08942FC5779930d1A9622;
address public keeperRegistrar = 0x57A4a13b35d25EE78e084168aBaC5ad360252467;
constructor(){
cronFactory = ICronFactory(cronFactoryAddress);
}
function createUpkeep(string memory _cronString) public{
address _target = address(this);
bytes memory functionToCall = bytes(abi.encodeWithSignature("sendSalary(string)", _cronString));
bytes memory job = cronFactory.encodeCronJob(_target, functionToCall, _cronString);
uint256 maxJobs = cronFactory.s_maxJobs();
address delegateAddress = cronFactory.cronDelegateAddress();
address newCronUpkeep = address(new CronUpkeep(msg.sender, delegateAddress, maxJobs, job));
allUpkeeps.push(newCronUpkeep);
}
function fundUpkeep(uint256 _linkAmount, address _upkeepAddress) public{
bytes4 reg = bytes4(keccak256("register(string,bytes,address,uint32,address,bytes,bytes,uint96,address)"));
bytes memory _data = abi.encode(
"TestV2",
"",
_upkeepAddress,
uint32(500000),
address(this),
"",
"",
_linkAmount,
address(this)
);
bytes memory combinedData = abi.encodePacked(reg, _data);
LinkContract.transferAndCall(keeperRegistrar, _linkAmount, combinedData);
}
sendSalary is the function in my contract that I want to be executed at regular intervals.
cronFactory is the cron factory contract.
cronUpkeep is the cronUpkeep.sol contract from the chainlink github repo.
To create these functions, I created a time-based upkeep manually and used the transaction logs to find what all function are being called and implemented the same here.
But, Once I execute both these functions nothing happens, however, I am able to find the upkeep registered on chainlink's website . And also it shows the trigger as custom trigger on upkeep page on chainlink:
chanlink upkeep
Please let me know how I can solve this? Any help would be appreciated. Thanks in advance
Contracts cannot execute themselves. Function needs to be called. While contract (function) is not called, contract is sleeping, because every time it makes operations, they should be payed (aka gas), so there is no way to throw an allways-active-timer inside of the contract (infinite gas). It means that you have to make calls manually or use automation services like ChainLink, Openzepplin Defender etc.
You can make a requirement by time-passed with
uint256 private lastTimeStamp;
uint256 private interval;
constructor() {
lastTimeStamp = block.timestamp;
interval = 7 days;
}
function isTimePassed() public view returns (bool timePassed) {
timePassed = ((block.timestamp - lastTimeStamp) > /*7 days */ interval);
return timePassed;
}
function smth() public {
(bool timePassed) = isTimePassed();
...
}
Something like this.

Reentrancy attack with withdraw amount

I've been working on different ways to perform reentrancy attacks and there is one case which I have still not seen any working example on the internet. In the book Mastering Ethereum, the reentrancy attack is explained with a contract where the function withdraw(uint amount) takes the input amount. The version on Solidity has been updated a lot since then and whenever I try to perform a similar attack, it does not work. It works whenever the function withdraw() takes no arguments and it also works when using older versions.
Could anyone provide an example of a reentrancy attack where the target contract takes the withdraw amount as input?
Thank you!
Let's say you have 1 ether in the contract, and the contract has a total of 10 ether. You're trying to steal all 10 ether with re-entrancy, but that necessarily means the variable tracking your balance must underflow to the equivalent of uint256(-9) ether -- you're trying to withdraw 1 ether 10 times.. This will cause a revert in Solidity 0.8.0 or higher, since it has built in under/overflow protection. If you want it to work in 0.8.0, you have to wrap the balance reduction line with unchecked.
This code is still vulnerable to re-entrancy in 0.8.0, but only because it sets the balance to zero, and can't underflow
mapping(address => uint256) public balance;
function deposit() external payable {
balance[msg.sender] += msg.value;
}
function withdraw() external {
msg.sender.call{value: balance[msg.sender]}(""); // re-entrancy
balance[msg.sender] == 0; // cannot underflow
}
function withdrawV2(uint256 value) external {
require(value <= balance[msg.sender], "you don't have that much"); // not that this does anything...
msg.sender.call{value: balance[msg.sender]}("");
unchecked { // now it can underflow
balance[msg.sender] -= value;
}
}

When is function reverted?

so because of reentrancy attacks I'm structuring my function to not get hacked. So first updating mappings and so on and then sending the payment.
My question is what if the payment fails to go through. Will entire function be reverted of just the payment?
Because if only the payment than that would mean my mappings would be updated as if the payment went through.
Is this the case?
Thanks for answers!
function withdraw(uint256 _amount) external {
balances[msg.sender] -= _amount;
(bool success, ) = payable(msg.sender).call{value: _amount}("");
}
If the low-level .call() is unsuccessful, the value of success is set to false but that doesn't revert the whole transaction. So the balances value would be reflected even though the payment didn't go through.
You can add a require() condition to check the result of the payment. This will make the parent transaction fail if the internal transaction fails.
(bool success, ) = payable(msg.sender).call{value: _amount}("");
require(success);
Or you can use the .transfer() function (member of address payable, do not confuse with token transfers) that also fails the parent transaction if the internal transaction fals:
function withdraw(uint256 _amount) external {
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
If you're preventing the reentrancy attacks, you might probably use the modifiers. Therefore, when the Reentrancy is detected, the function would be reverted and even not allowed to enter the function. That is, there would be no other parameters updated.
Besides, I can show you some demo code to answer your question.
contract test {
uint public a = 0;
// a will still be a
function addRevert() public{
a += 1;
goRevert();
}
// a = a + 1
function addNoRevert() public{
a += 1;
}
function goRevert() pure public{
revert();
}
}

How can I set the tx ETH amount?

I know a user can send ETH to the contract/function manually, but is there way to request a specific amount directly in the code so that it is added to the gas fee, for example, the way dxsale.app does it when creating a presale (see screenshot below) - it adds the 0.1 ETH cost of presale to the 0.0072 gas fee for a total of 0.1072.
Can this be done in an ERC20 contract? I know I can receive ETH in a payable function, e.g.
function deposit() payable public {
require(msg.value > 0, "You need to send some Ether");
}
but can I specify the amount I want to receive (for a flat fee), so that it is added to the tx cost?
Thank you
TLDR: The contract function is executed after the transaction has been sent. So it's not possible to to set the transaction params from the contract.
is there way to request a specific amount directly in the code
Not in the Solidity code. You can only throw an exception if the sent amount is not an expected value.
function deposit() payable public {
require(msg.value == 0.1 ether, "You need to send 0.1 Ether");
}
You can specify the amount when you're creating the transaction request. For example MetaMask uses the Ethereum Provider API, so you can predefine the amount that MetaMask will show.
const params = [
{
from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
value: '0x9184e72a', // 2441406250
},
];
ethereum
.request({
method: 'eth_sendTransaction',
params,
});
But the user can override this option in their wallet, or they can always submit a transaction using a different way (not requested with the custom value).
The value (both in the params JS object and the Solidity msg.value global variable) always excludes the gas fees.
So if you're sending 0.1 ETH, the gas fees are added on top of that and the total cost might be 0.10012345. The params.value will contain 0.1 ETH (hex number in wei), as well as the msg.value will contain 0.1 ETH (decimal number in wei).

Sending ether in solidity smart contract

I'm writing a smart contract in solidity, and I need to send ether from my coinbase (eth.coinbase) to my friend coinbase (address = 0x0123).
If I try to use an address.send(value) the function doesn't decrease my account and doesn't increase my friend coin base.
I only can send ether in geth with "eth.sendTransaction(VALUE, {from:eth.coinbase, to:address})"
so I want to know if its possible to call an eth method in contract or a different way to send ether in smart contract
function withdraw() returns (bool) {
address x = 0x0123;
uint amount = 100 ether;
if (x.send(amount))
return true;
else
return false;
}
address.send does not propagate exception that's why you don't see any issue. Make sure you have enough Eth in your contract.
Have a look on this documentation that will explain how to set up your smart contract: https://developer.ibm.com/clouddataservices/2016/05/19/block-chain-technology-smart-contracts-and-ethereum/
You can use following function. just change variable name with yours.
function Transfer(uint amount,address reciever){
// check sender balance is less than of amount which he wants to send.
if(balance[msg.sender] < amount){
return;
}
// decrease sender's balance.
balance[msg.sender] = balance[msg.sender] - amount;
// increase reciever's balance.
balance[reciever] = balance[reciever] + amount;
// event
// transaction(msg.sender,reciever,amount);
}