After reading the documentation for Solidity v0.6.0 docs, I still don't understand the meaning of the fallback functions. I read that it was split into 2 functions: fallback () external payable and receive () external payable. That they are anonymous and do not accept any parameters, and in the overwhelming majority of cases, receive () external payable is used to receive funds. Can you please explain with the example of my code, some use cases for these functions, in order to understand all their features, otherwise somehow everything is in a vacuum, but I understand that this is an important concept? Even the meaning of the receive () external payable function is not clear, in which I call on the buyToken () method, why is it needed if I call on the buyToken () in the Remix directly, bypassing the receive () external payable since she is not visible and anonymous.
pragma solidity ^0.7.0;
// SPDX-License-Identifier: MIT
contract BuyToken {
mapping(address => uint256) public balances;
address payable wallet;
event Purchase(
address indexed buyer,
uint256 amount
);
constructor(address payable _wallet) {
wallet = _wallet;
}
fallback() external payable {
}
receive() external payable {
buyToken();
}
function buyToken() public payable {
balances[msg.sender] += 1;
wallet.transfer(msg.value);
emit Purchase(msg.sender, 1);
}
}
When the sender sends ETH to your contract address and doesn't specify any function (i.e. the data field of the tx is empty), the receive() gets executed.
Since the receive() just calls buyToken(), it produces the same set of actions as if the user executed the buyToken() directly.
But other contracts can make a different use of the receive() function. Example of a simple bank contract:
pragma solidity ^0.8;
contract MyContract {
mapping (address => uint256) public balances;
receive() external payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 _amount) external {
require(_amount <= balances[msg.sender], 'Insufficient balance');
balances[msg.sender] -= _amount;
payable(msg.sender).transfer(_amount);
}
}
Or a timelock:
pragma solidity ^0.8;
contract MyContract {
uint256 public constant unlockAfter = 1640995200; // 2022-01-01
receive() external payable {
// anyone can send funds to this contract
}
function withdraw() external {
require(msg.sender == address(0x123), 'Not authorized');
require(block.timestamp >= unlockAfter, 'Not unlocked yet');
payable(msg.sender).transfer(address(this).balance);
}
}
The fallback() functions is used when the function signature (first 4 bytes of the data field) doesn't match any of the existing functions.
pragma solidity ^0.8;
contract MyContract {
function foo() external {
// executed when the `data` field starts with `0xc2985578`, the signature of `foo()`
}
fallback() external {
// executed when the `data` field is empty or starts with an unknown function signature
}
}
I'm not sure about your code example but here it goes:
Fallback function - I think here is a good explanation. So if not marked payable, it will throw exception if contract receives plain ether without data.
External payable - This post explains External well. So it costs less gas to call external than public. Only in your example it would make sense to change buyToken() from "public" to "external". Far as I understand there is no benefit to call public from external...
The fallback functions are invoked automatically by the Ethereum Virtual Machine (EVM) which is why they are marked as external. Since it cannot be called explicitly, gas cannot be sent explicitly to this function. Instead, the EVM provides a fixed stipend of 2,300 gas for this function. If the gas cost is more than 2300 an exception will be thrown. It is important that you should be testing fallback function's gas consumption before deploying your contract
contract Fallback {
fallback () external payable {
}
}
It has no arguments and
return data. It gets executed every time ether is received. It is required to be implemented within a contract if the contract is intended to receive ether; otherwise,
an exception will be thrown and ether will be returned.
Update
After pragma solidity ^0.8.12;, fallback can receive argument and have a return statement
If you call a function that does not exist in the contract, your contract will fall back into the fallback(). it will invoke fallback
If the contract is expected to receive
ether, then the fallback function has to be declared with the payable modifier.
Another use case is for proxy contracts which routes the incoming requests to the upgradeable target contract. the fallback function in proxy contract actually calls the target contract's functions.
function _fallback() internal virtual {
_beforeFallback();
// calling the target function code
_delegate(_implementation());
}
receive()
fallback function is called under multiple conditions and this makes writing code for each condition hard. That is why receive is added. receive is called only when contract receives ether so fallback should be executed only if a function signature is not
implemented within a contract.
Related
As I understand I should make transfer function payable but it says "Overriding function changes state mutability from "payable" to "nonpayable".
Solidity currently (v0.8) doesn't allow overriding non-payable methods (e.g. the OpenZeppelin transfer() function) to payable. So this approach won't work:
pragma solidity ^0.8;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MyT") {
}
// cannot override non-payable function to payable
function transfer(address to, uint256 amount) override public payable returns (bool) {
}
}
The ERC-20 standard doesn't say anything about the transfer() function being payable - it doesn't explicitly allow nor disallow it.
There are two ways to define a payable transfer() function in your case:
Create a local fork of the OpenZeppelin ERC20.sol contract, as well as its dependencies, and change the declaration of their transfer() function to payable. Then you can override it in a child contract and implement a custom fee.
Implement the ERC20 standard from scratch in your contract without using OpenZeppelin. Then you'll be able define a custom transfer() function with the payable modifier.
I am a new blockchain developer as well as Solidity. I am having a function call problem in the code below. The compiler is throwing some warning. Though the code runs fine, I want to understand the error. Thanks.
function add() public view returns(uint256){
uint256 a= 5;
uint256 b= 4;
uint256 sum = a + b;
return sum;
}
Warning: Function state mutability can be restricted to pure
Your add() function declares the view state mutability. Which means that the function cannot write to the storage (and perform other state changes such as emit events) but it's allowed to read from the storage.
The warning says that you can use more strict state mutability called pure, which disallows the function not only to write to the storage but also to read from it.
I have a security problem in my Solidity contracts and I can't figure out how to fix it.
The flow goes like this:
First, we create an instance of contract A;
Create an instance of contract B, which receives the contract A instance in the constructor (its address);
At some point, contract B calls a function 'foo' from contract A which tells contract A to send money to an address (the address is received as a parameter);
Contract A sees the msg.sender as the address of contract B;
My problem is:
I want to restrict the access for the function 'foo' in contract B only to be called by contract A (no calls made by humans manually);
I cannot make a modifier to check the address. Since I create Contract A before Contract B, I cannot know the address of Contract B in Contract A;
I cannot make the function internal as the contracts are not derived;
Can you please offer me advice on how to fix this problem or explain another approach on this? I am new to Solidity.
Thank you!
I cannot make a modifier to check the address.
You can, but the address needs to be in a variable, set after the contract B has been deployed.
pragma solidity ^0.8;
contract ContractA {
address contractB;
modifier onlyContractB {
require(msg.sender == contractB);
_;
}
function foo() external onlyContractB {
}
function setContractBAddress(address _contractB) external {
contractB = _contractB;
}
}
pragma solidity ^0.8;
interface IContractA {
function foo() external;
}
contract ContractB {
IContractA contractA;
constructor(address _contractA) {
contractA = IContractA(_contractA);
}
function callFoo() external {
contractA.foo();
}
}
Deploy contract A
Deploy contract B, passing it the "A" address in the constructor
Set the contractB value in "Contract A".
I left out any auth mechanism while setting the contractB address in ContractA for simplicity. In this example, anyone can set the address, which you probably don't want, and you should add a mechanism allowing only authorized senders to set the contractB value in ContractA.
In Solidity we have four types of access. Two of them are private and internal.
What is the difference if both of them can be used inside smart contract and both of them are not visible after deploying?
Access types:
public - can be used when contract was deployed, can be used in inherited contract
external can be used when contract was deployed , can NOT be used in inherited contract
internal - can NOT be used when contract was deployed , can be used in inherited contract
private - can NOT be used when contract was deployed, can NOT be used in inherited contract
internal properties can be accessed from child contracts (but not from external contracts).
private properties can't be accessed even from child contracts.
pragma solidity ^0.8;
contract Parent {
bool internal internalProperty;
bool private privateProperty;
}
contract Child is Parent {
function foo() external {
// ok
internalProperty = true;
// error, not visible
privateProperty = true;
}
}
You can find more info in the docs section Visibility and Getters.
public: anyone can access the function
private: only this smart contract can call this function
internal: only this smart contract and smart contracts that inherit from it can call this function
external: anyone can access this function unless this smart contract
Note that external uses less gas than public so if the function is not used by your contract, prefer external over public.
More explanations in this article
Assalamualaikum,
I am new to blockchain. So I was thinking of deploying a smart contract as rest api, and use it in my another smart contract.
Is it possible?
I know oracle helps to fetch data but can it help interacting two deployed contracts?
Thank in advance.
You can define an interface of the target contract in the source contract. Example:
TargetContract, deployed on the 0x123 address:
pragma solidity ^0.8;
contract TargetContract {
function foo() external pure returns (bool) {
return true;
}
}
SourceContract, pointing to the 0x123 TargetContract
pragma solidity ^0.8;
interface ITargetContract {
function foo() external returns (bool);
}
contract SourceContract {
function baz() external {
ITargetContract targetContract = ITargetContract(address(0x123));
bool returnedValue = targetContract.foo();
}
}