Can transaction fail but the calling contract will think it was successful? - ethereum

When making an ERC20 transfer it is a standard practice to wrap it in require statement so if it fails the tx will revert like this:
require(token.transfer(...));
What if I'm calling an external contract that doesn't return a boolean and the transaction fails.
Is it possible that the tx will fail(not revert) but the contract that called that function will think that it was successful?
Thanks. If the question isn't clear I'm happy to provide more context.

When you're using an external function call, as in your example, any sub-call revert propagates and reverts the main transaction.
Example:
function foo() public {
// if `transfer()` reverts, `foo()` reverts as well
token.transfer(recipient, amount);
}
If you used the low-level .call() method, a sub-call revert would not propagate to your main function. Instead, it would return false as the first return value.
function foo() public {
// if `transfer()` reverts,
// `success` returns `false` and `foo()` does NOT revert
(bool success, bytes memory returnedData) = address(token).call(
abi.encodeWithSignature(
"transfer(address,uint256)",
recipient,
amount
)
);
}
And if you catch the sub-call revert with a try/catch, that does not revert the main transaction either.
function foo() public {
// if `transfer()` reverts,
// the `catch` block is invoked and `foo()` does NOT revert
try token.transfer(recipient, amount) returns (bool) {
} catch Error (string memory reason) {
}
}

Related

solidity delegatecall prevention doesn't works

I am a newbie studying Uniswap V3's github code. I came up with noDelegateCall.sol and I found out the way to prevent a contract to be delegatecalled from another cotract. As I tried to implement this, I caught up with the problem.
pragma solidity >0.8.0;
contract Receiver {
string greeting = "Hello";
address private immutable original;
event Greeting(string greeting, address original, address addressThis);
constructor() {
original = address(this);
}
function checkNotDelegateCall() private view {
require(address(this) == original);
}
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
function greet() external noDelegateCall {
emit Greeting(greeting, original, address(this));
}
}
contract Sender {
string greeting = "Hi";
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
}
}
If I call function delegatedGreeting, I expect the function to be reverted because variables original and address(this) differs. However, although it emits an empty event, it still doesn't reverts. Why does this happen?
When the low-level delegatecall reverts, it doesn't automatically revert the main transaction. Instead, it returns false as the first return value of the delegatecall() function.
So you need to check the return value (in your case bool success) and validate that.
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
require(success == true, "delegatecall failed");
}

Is there a way to return a function as false and still execute code untill it reverts, eq: function owner() { owner = 0x0; revert(); }

So putting revert() or throw at the end of the function simply prevents any code from executing, I am looking for a clever way to escape this be it with external call, delegatecall or anything, so:
function thiss()
{
owner = 0x0...;
throw; //gives error, no changes whatsoever - what I want is to see changes and then "throw"...
}
One way to do that is to use event. You can emit an event and then return the function. You can know the error by looking at logs field in the transaction receipt.
event ErrorLog(string msg);
function this() public {
Owner = 0x583031D1113aD414F02576BD6afaBfb302140225;
emit ErrorLog("Error in function this");
return;
}

How to get keccak256 hash in Solidity

I just got started with solidity, I have used truffle to compile and deploy the code to ganache, everything works as I expect, I can call the other functions in the code, but there are certain functions that only the owner can access, the code appears to use keccak256 to get back the address calling the function and determine if the caller address is allowed, I have tried to hash my eth address using this website:
https://emn178.github.io/online-tools/keccak_256.html
and then add the hash to the code before recompiling again, but calling the owner function still throws this error:
"Error: VM Exception while processing transaction: revert"
What am i doing wrong ?
Here's the code with the original hash.
modifier onlyOwner(){
address _customerAddress = msg.sender;
require(owners[keccak256(_customerAddress)]);
_;
}
// owners list
mapping(bytes32 => bool) public owners;
function PetShop()
public
{
// add owners here
owners[0x66e62cf7a807daaf3e42f7af3befe7b2416a79ba5348820245a69fe701f80eb4] = true;
}
/*---------- Owner ONLY FUNCTIONS ----------*/
function disableDogs()
onlyOwner()
public
{
onlyDogs = false;
}
/*-----replace owner ------*/
function setOwner(bytes32 _identifier, bool _status)
onlyOwner()
public
{
owners[_identifier] = _status;
}
/*-----set price for pet adoption----*/
function setAdoptionRequirement(uint256 _amountOfTokens)
onlyOwner()
public
{
AdoptionRequirement = _amountOfTokens;
}
The keccak256 implementation in Solidity stores data differently.
keccak256(...) returns (bytes32):
compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
Just use the function yourself when creating the contract:
function PetShop() public {
// add owners here
owners[keccak256(msg.sender)] = true;
}
as of now
// .encodePacked merges inputs together
owners[keccak256(abi.encodePacked(_text, _num, _addr))}=true
abi.encodePacked() , Solidity supports a non-standard packed mode where:
types shorter than 32 bytes are neither zero padded nor sign extended
dynamic types are encoded in-place and without the length.
array elements are padded, but still encoded in-place

Ethereum smart contract no function return value

I'm new to smart contracts and I've deployed this test contract
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
returns (bytes32 myhash)
{
myhash = sha3(dest, num, data, nonce);
return (myhash);
}
}
I then call test.callme(eth.accounts[0], 10, 0xaaaaa, 1234) expecting it to return the sha3 hash of the passed parameters but there's no return value.
> test.callme(eth.accounts[0], 10, 0xaaaaa, 1234)
INFO [12-24|19:35:40] Submitted transaction fullhash=0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a recipient=0xed712462999f8f68BbF618C3845F4333eDC31cD5
"0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a"
Any help is appreciated
Your syntax is a little off - you don't need to name your return value myhash. Something like this should do the trick:
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
constant
returns (bytes32)
{
bytes32 myhash = sha3(dest, num, data, nonce);
return myhash;
}
}
I also threw in a constant keyword since the function isn't planning on changing anything in your contract's storage. It's a small change, but necessary for what you're trying to do.
Including the constant enables you to get a 'return' value, so to speak, because it says that you won't need to be modifying the blockchain - in essence, you're 'reading' the chain, not 'writing' to it.
Imagine a contract that did something like this:
contract test {
uint example;
function callme()
public
returns (uint)
{
example = example + 1;
return example;
}
}
The transaction we send to callme actually has to be executed before we return the value (since we're modifying the blockchain). Therefore, we can't really return the final value instantly (and we instead return information about the transaction), since we have to wait for the blockchain to be updated first.

Solidity: change a the value of a variable in a smart contract already published

I'm trying to change the value of a variable in a contract that is in the blockchain. I've deducted its code and is something like this:
pragma solidity ^0.4.8;
contract Trial {
address public owner;
address public person;
uint initialEther;
function Trial(address _person) payable {
owner = msg.sender;
person = _person;
initialEther = msg.value;
}
modifier only_person() {
if (msg.sender!=person && tx.origin!=person) throw;
_;
}
function() payable {}
bytes4 public signature = bytes4(sha3("libraryFunction()"));
bool variableToBeChanged = false;
function libraryInvocation(address libraryAddress) only_person {
bool doSomething = libraryAddress.delegatecall(signature);
if (variableToBeChanged) {
.....
}
}
}
Suppose that I have the right signature of the library function, what I'm trying to do is to change the value of "variableToBeChanged" in order to execute the code inside the if.
Probably there is a way to create a library with a function with a proper name and inserting assembler code in some way to change the value of the variable. But it's like using an atomic bomb to kill an ant. I'm looking for the simpler way to do this.
I also know this contract is not safe, I'm trying to understand if this is possible and I want to understand how risky this can be for a contract.
Without a function changing the variable it is not possible. Once the contract code is deployed, it is final, no change is possible. You need to deploy a new contract.
You could control with your contract which wallet is allowed to call the function by checking the msg.sender attribute for a specific wallet address.
address owner = 0x2FD4...;
if(msg.sender != owner) throw;
//code afterwards)