Security Considerations

thanks a lot Dani for your help, could you please explain what has changed regarding msg.sender?
you mean that it changed from not being payable to now being payable? so that when CryptoXyz on April wrote the post about his error, the mag.sender wasn’t payable address yet?

1 Like

Hey @Kamil37

msg.sender was payable by default but now it is not.
If you need msg.sender to be payable, you have to cast it:

payable(msg.sender)

Cheers,
Dani

2 Likes

This is so disappointing that contracts often have backdoors for the owner. Non developers are under the impression that once a contract is deployed, it’s immutable. What’s the point of having a blockchain contract that is no different than an external service running on a private machine that can be changed at any time?

I suppose that the only important difference is, that people reading the code of the smart contract can tell that there is a backdoor and that they will have to TRUST the owner if they interact with that wallet.

There are other ways that developers can alter the code which has to do with changing the contract addresses of sub-contracts. That’s how the Squidgame hack happened.

The solution to this is a battle hardened library that has the bugs removed (if that’s possible). And developers should only use that when writing smart contracts. There are Ethereum wallets that hold billions of dollars.

Binance Wallet: https://etherscan.io/address/0x3f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be

If one of these gets hacked, it’s going to destroy the credibility of Ethererum for large investors.

Now I’m a bit ignorant about Ethereum wallets at this time: they may not be implemented as smart contracts. So, good.

On the Checks, Effects, Interactions (+Undo if the Interaction fails)

There is an issue.

The fallback function of the malicious contract could return an error i.e. “send failed” even if the transfer succeeded, at which point, the victim contract would reset the balance for another exploit.

Is that possible?

P.S. I notice the fallback and receive have no “returns” so I guess the EVM determines the return value so it can’t be corrupted by a malicious contract.

@filip

I have question about function call
In the course say the better way to sent ether is use call()
but it not limit amount of gas for fallback function.Doesn’t it vulnerable more than send() and transfer()?.I understand about send() and transfer() has limit 2300 gas and in the future the gas may less than this time but still not understand why select the one that unlimit gas or just use CHECK, EFFECT (CHANGING STATE), INTERACTION - pattern is good enough.

@filip

Another question about fall back function recieve()

I am not sure about empty data to trigger receive()
Is it mean like this?
(bool sent,memory data) = _to.call{value: msg.value}(""); //empty data mean no function signature inside this ("")

1 Like

hey @thanasornsawan what is it exactly your trying to do there.

@mcgrane5 I just want an example of the definition that fallback function receive() want
As it require empty data with value.
So, I just want to be sure that is it use call() function like that to trigger fallback function.
I just want to understand that empty data for receive() fallback function mean ("") in the call() function that I wrote or not

1 Like

hey @thanasornsawan so its pretty much to do with executing code whenver ether is sent to a smart contract on its own with no metadata or anything attached. as for your other post above where you on about the security issues between .transfer and .call, this is one of those type of things where you could ask 10 people which is better to use and they all give you different awnsers som epeople prefer .call and some .transfer and to me i personally use .transfer as it reads easier and its the first thing i learned.

the line of code

(bool sent,memory data) = _to.call{value: msg.value}("");

sends ether to some destination smart contract. if that destination smart contract has the recieve fallback it will get executed in that destination contract and execute any code defined in its implementation because its only an ether value getting sent to the desintation contract and the optional calldata message is blank as denoted by the empty quotes, “”.

a simple example of an implementation of the recieve falllback is

pragma solidity 0.8.0;

contract Test {
    event Received(address, uint);
    receive() external payable {
        emit Received(msg.sender, msg.value);
    }
}

if someone sends ether to this contract with no call data as per the line of code above this function will getexecuted and the Reecieved event will be emmitted letting anyone know that the contaract has recived funds and who from. This could be useful and you could do other post processing in this function here.

However in the case where the user wanted to send optional metadata along with the transaction then their is another fallback function that we can use instead of receive which is just called fallback. It also has to be payable. Say we wanted to send ether to a smar contract but more specifically we also wanted to update the balance of a particular user in that smart contract, then we could send optionall calldata with the message in such a ways that we could use the calldata information to figure out which balance to update in the destination contract. Things like this.

Just note that there are times when you should choose to use either receive or fallback which i mention below. Having said that these are not functions you will be using that often so i wouldnt get too flustered about them.

  • receive() external payable — for empty calldata (and any value)
  • fallback() external payable — when no other function matches (not even the receive function). Optionally payable .
1 Like

also it should be noted you dont need to implement the receive or fallback functiontion in order to be able to send ether to another smartb conract. These are only useful for the scenario where you want to execute some specific logic on such an event as demonstrated in the sample code that i provided above

1 Like

thank you so much for help explaining :pray: :pray:

Hi,
If send() and transfer() functions do not send all the remaining gas but only the 2300 gas stipend to prevent re-entrancy attack, does that mean that we must not set up the gas limit to 3000000 to avoid loosing gas?

Hi @fsicard

The gas limit is unrelated to the used stipend. There is a fixed gas limit to prevent contract from performing any complex logic. The unused gas is returned/ not deducted from the users wallet.

Hope this answers your question.

1 Like