Is it possible to use a modifier on a function that was overriden ?
I have a virtual function and overrided it in another class, but I get error when I call it due to using a modifier on it.
abstract contract A {
function stake(
address _userAddress,
uint256 _amount
) internal virtual {}
function investByToken(
address _userAddress,
IERC20Upgradeable _token,
uint256 _amount,
) external payable {
// ... calling some functions like deduct fee
stake(_userAddress, _liquidity);
}
}
contract B is A {
function stake(
address _userAddress,
uint256 _amount
) internal override updateRewards {}
}
Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason="Transaction reverted:
function selector was not recognized and there's no fallback function", method="estimateGas"
I'm getting this error while testing with hardhat, but it's working fine on Mainnet.
Yes, you can add modifiers to the overriding function.
pragma solidity ^0.8;
abstract contract A {
function stake(address _userAddress, uint256 _amount) internal virtual {}
}
contract B is A {
modifier updateRewards {
_;
}
function callStake() external {
stake(address(0x123), 1);
}
function stake(address _userAddress, uint256 _amount) internal override updateRewards {}
}
The "function selector was not recognized" error message is thrown when you're trying to invoke an unreachable or non-existing function. Mind that in your example, the stake() function has internal visibility which makes it unreachable for external callers (such as your JS app or IDE). See the docs page for more info on function visibility.
Either change its visibility to external or public (in both contracts) or wrap it with another external / public function (see the code of this answer).
Related
I am following a tutorial.
In that i imported one contract to another contract.
Then i used the name of imported contract as the datatype name to initialise an array.
How is it possible to use a contract name as datatype ?.
import "./SimpleStorage.sol"; //importing another contract
contract StorageFactory {
SimpleStorage[] public simpleStorageArray ; //global variable
function createSimpleStorageContract() public {
SimpleStorage simpleStorage = new SimpleStorage();
simpleStorageArray.push(simpleStorage);
}
function sfStore(uint256 _simpleStorageIndex, uint256 _simpleStorageNumber) public {
SimpleStorage simpleStorage = simpleStorageArray[_simpleStorageIndex];
simpleStorage.store(_simpleStorageNumber);
}
function sfGet(uint256 _simpleStorageIndex) public view returns(uint256){
SimpleStorage simpleStorage = simpleStorageArray[_simpleStorageIndex];
return simpleStorage.retrieve();
}
}
Contract and interface type acts as a pointer to the target contract. The code assumes that the target contract implements all external and public functions of this type.
In your case, StorageFactory assumes that all addresses stored in the simpleStorageArray array implement the interface of SimpleStorage.
So if SimpleStorage implement this function: get() external returns (uint256), StorageFactory is going to expect this function to return a binary response with the length of 256 bits, and then cast it to unsigned integer.
Docs: https://docs.soliditylang.org/en/v0.8.17/types.html#contract-types
function sendGift(uint256 _mintAmount,address recipient) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
require(supply + _mintAmount<= availableSupplyForSale);
//require(_amount >= cost * _mintAmount);
require(coinToken.allowance(msg.sender,address(this))>=cost * _mintAmount);
coinToken.transferFrom(msg.sender, address(this),cost * _mintAmount);
if(supply<currentSupply){
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(recipient, supply + i);
}
}
else{
uint256[] memory tokenIds = walletOfOwner(address(this));
for(uint256 i=1;i<=_mintAmount;i++)
transferFrom(address(this),recipient,tokenIds[i]);
}
}
Do I need to use payable here? Contract does not take any matic. It only takes custom token as payment .
(bool os, ) = payable(admin).call{value: address(this).balance}("");
require(os);
Also since I am not taking any matic, will this above line necessary for withdraw assets from contract as an owner? I have a sense that this above line only is useful to withdraw eth/polygon.
I am a new blockchain kid. Please help.
The payable modifier of a function is required when your function accepts native tokens (ETH, BNB, MATIC, ... depending on the network).
So in this case, you can safely remove it from the function header.
// removed `payable`
function sendGift(uint256 _mintAmount,address recipient) public {
The low-level .call() also doesn't require using payable to send native tokens.
payable(admin).call{value: address(this).balance}("");
However, if you used the high-level .transfer(), then you'd need to cast the admin variable type address to its extension type address payable using the typecasting function.
// will not work as it's type `address`
admin.transfer(address(this).balance);
// need to cast type `address` to type `address payable`
payable(admin).transfer(address(this).balance);
In order to withdraw tokens from your contract address, you need to invoke the transfer() function (defined in the ERC-20 standard) on the token contract. Do not confuse it with the native transfer() function of address payable, these are two separate things, just with the same name.
interface IERC20 {
function transfer(address, uint256) external returns (bool);
}
contract MyContract {
function withdrawToken() {
IERC20(tokenContractAddress).transfer(recipient, amount);
}
}
When releasing the ERC-20 token,
OZ(OpenZeppelin)'s util Context.sol is inherited.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
* #dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
I read that when using a meta-transaction solution such as EIP-2771, Context.sol is useful.
https://forum.openzeppelin.com/t/help-understanding-contract-context/10579
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) }
} else {
return super._msgSender();
}
}
But in the case of ERC-20, why shoud I use Context.sol's _msgSender()?
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
Doesn't make it more secure?
What is the usage of Context.sol within ERC-20?
Thank you in advance.
Context is needed to implement metatransactions, or gas free transactions for token transfers.
More about Context in Gas Station Network documentation.
If you do not plan to support this feature (hint: no one does today) you do not need to Context.
I got stucked in thoughts guys and I need bit of clarification to move it forward.
(Description is about real problem, code is for best (I hope so..) understanding me)
I have main contract A that uses erc20 token and its transfer functions, there is also inherited Ownable and whitelist with accessing addresses of contracts e.g. B,
I passing A address to the B constructor
I created instance of A in B (because in B I calculate collateral and I want to split to two different contracts)
Protecting A using Ownable it's enough from accessing A from 3rd party while interacting with A from A, Ownable in B isnt work because can't use right msg.sender, without modifiers someone can create instance of B in his contract and have access to my A, isn't it?
Thanks in advance
EDIT: I change a code for more to understand
// SPDX-License-Identifier: MIT
pragma solidity 0.8;
contract Ownable {
mapping (address => bool) private whiteListed;
modifier onlyWhiteListed {
require(whiteListed[msg.sender] == true, "You're not whitelisted");
_;
}
constructor () {
whiteListed[msg.sender] = true;
}
function setWhiteListed(address addr, bool trueOrFalse) public onlyWhiteListed {
whiteListed[addr] = trueOrFalse;
}
function getWhiteListed(address addr) public view returns (bool) {
return whiteListed[addr];
}
}
contract A is Ownable {
B public b;
event LogMsgSender(address who);
constructor() {
b = new B(address(this));
//setWhiteListed(address(this),true);
setWhiteListed(address(b),true);
}
function callMe() public onlyWhiteListed { // here I can only get real caller msg.sender
emit LogMsgSender(msg.sender); // when interact with that contract, not outside of contract
}
function callSender(address sender) public onlyWhiteListed { // here I can get real caller msg.sender from other contract
emit LogMsgSender(sender); // but is it worth to passing addresses ?
} // and HERE is my question: is this aproach secure??
}
contract B is Ownable {
A public a;
constructor(address addr) { //in remix I can't deploy in one time while
a = A(addr); //deploying A, I have to deploy copying addresses of A and do it separately
} //and after deploying also setWhiteListed() to whiteList in A
function callMe() public onlyWhiteListed { // this call isn't good for interact with sender, it's exlusive for calling as contract B
a.callMe(); // copies of this contract can
}
function callSender() public onlyWhiteListed { // modifiers protect from 3rd party contracts but
a.callSender(msg.sender); // that way it only can be used by deployer and whitelisted, (without modifiers they aren't secure)
} // bad idea ofc is adding to whitelist all over and over and
// it's impossible to recognize which to add which not
}
contract C {
B public b;
constructor(address addr) {
b = B(addr);
}
function callMe() public { //when modifiers is added this contract can't call these functions
b.callMe(); // but with modifiers functions can't be used to get right sender address
}
function callSender() public {
b.callSender();
}
}
So now I'm deciding to inherite e.g. B is A and I simply get right sender, what do you think?
You've got a lot of syntax/logic errors in the code you posted. Not only are you missing onlyOwner modifiers, but your calls in B are via the type A: A.receiveToken() is not the same as a.receiveToken() ... so you've probably made several typos in posting your question (Should say a=A(aAddr); in the constructor etc).
The msg.sender will be "b" when b calls a.sendToken() but tx.origin will be unchanged. Checking msg.sender checks which contract called you. In other words, it is checking (inside onlyOwner of A.sendToken) whether b is the one that called a.sendToken().
Start by fixing all the errors and then insert some debug logging for yourself, so you can see how msg.sender is changing during the calls. You can also log tx.origin to see how that remains the original sender.
The point is that the owner of the A that B created is that particular instance of B (b). It's therefore "natural" that inside B, it can call a.whatever() as a's owner.
You didn't specify, but if you are using the Ownable contract from openzeppelin you need to pass the modifier onlyOwner for the methods that you want to be protected. Ex:
function sendToken(uint value) public onlyOwner {
//transferFrom
emit Sent(value);
}
I got an example of a solidity Interface.
1/ Any clue if this method is accurate as it's implementing the Interface within the inherited from Contract and not within the extension Contract.
2/ I tried implementing it, contractA functions run correctly, however contractB getCount function is not running correctly.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface InterfaceA {
function count() external view returns (uint256);
function increment() external;
}
contract contractA {
uint256 number = 0;
function count() external view returns (uint256) {
return number;
}
function increment() external {
number++ ;
}
}
// SPDX-License-Identifier: MIT
import './contractA.sol' ;
pragma solidity ^0.8.0;
contract contractB {
address addressA;
function setPointer(address _addressA) external {
addressA = _addressA;
}
function getCount() external view returns (uint256) {
InterfaceA b = InterfaceA(addressA);
b.count();
}
function addToIncrement() external {
InterfaceA b = InterfaceA(addressA);
b.increment();
}
}
I think the only issue is you are not returning anything from getCount. You added the return signature, you should had a warning when you compiled it.
function getCount() external view returns (uint256) {
InterfaceA b = InterfaceA(addressA);
return b.count();
}