Explicitly calling named functions inside solidity proxy contracts - ethereum

I am referencing the the Gnosis-safe proxy function here https://github.com/safe-global/safe-contracts/blob/main/contracts/proxies/SafeProxy.sol:
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/// #title IProxy - Helper interface to access masterCopy of the Proxy on-chain
/// #author Richard Meissner - <richard#gnosis.io>
interface IProxy {
function masterCopy() external view returns (address);
}
/// #title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
/// #author Stefan George - <stefan#gnosis.io>
/// #author Richard Meissner - <richard#gnosis.io>
contract GnosisSafeProxy {
// singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
// To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
address internal singleton;
/// #dev Constructor function sets address of singleton contract.
/// #param _singleton Singleton address.
constructor(address _singleton) {
require(_singleton != address(0), "Invalid singleton address provided");
singleton = _singleton;
}
/// #dev Fallback function forwards all transactions and returns all received return data.
fallback() external payable {
// solhint-disable-next-line no-inline-assembly
assembly {
let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
// 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
mstore(0, _singleton)
return(0, 0x20)
}
calldatacopy(0, 0, calldatasize())
let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
if eq(success, 0) {
revert(0, returndatasize())
}
return(0, returndatasize())
}
}
}
There are no named functions inside GnosisSafeProxy, and all calls to the Proxy will direct to fallback. In my use case, I'd like to have a few named functions inside the proxy, for example, I may want to do:
function namedFn(address _alice){
/// in pseudo-code:
/// call contract#singleton.namedFn(_alice)
}
I assume this is possible, if not an anti-pattern. But what would be the syntax for referencing contract#singleton.namedFn?
If I want GnosisSafeProxy to be Initializable, and let's assume GnosisSafeProxy is proxying an GnosisSafeUpgradeable, so that I can do an initialization of GnosisSafeProxy with:
function initGnosisSafeProxy(address _singleton, address _alice, address _bob ) initializer public {
singleton = _singleton;
contract#singleton.initialize(_alice,_bob);
}
This would also be possible assuming I can reference contract#singleton correct? What would be the syntax here, and is there some egregious error that I'm committing here conceptually?

Related

Is it possible to call methods of contract's initializer during its initialization?

I tried to deploy following smart contracts
pragma solidity 0.8.17;
contract Contract1 {
constructor() {
new Contract2(address(this));
}
function foo() public pure returns (string memory) {
return "bar";
}
}
contract Contract2 {
Contract1 contract1;
constructor(address _contract1) {
contract1 = Contract1(_contract1);
contract1.foo();
}
}
but it fails with following message:
The transaction has been reverted to the initial state. Note: The
called function should be payable if you send value and the value you
send should be less than your current balance. Debug the transaction
to get more information.
Seems like it's impossible to call methods of contract's initializer (the contract that created an instance of current one) during its initialization.
My question is how it happens that address of the Contract1 is already exists, but it's impossible to call any of its methods from the constructor of Contract2?
The address of Contract1 is not yet available when the constructor of Contract2 is called. The address of Contract1 is only available after the constructor of Contract1 has finished executing.
This means that the constructor of Contract2 cannot call any methods of Contract1 until after the constructor of Contract1 has finished executing.
In this case you can deploy the Contract1, wait for the tx complete and after deploy the Contract2 using the address of Contract1 in constructor arguments.

Explicit type conversion not allowed from "int_const" to "contract"

I am trying to deploy a contract from another contract following the example from here
At some point the example states:
Instanciating a new Counter for someone will look like this:
function createCounter() public {
require (_counters[msg.sender] == Counter(0));
_counters[msg.sender] = new Counter(msg.sender);
}
We first check if the person already owns a counter. If he does not own a counter we instantiate a new counter by passing his address to the Counter constructor and assign the newly created instance to the mapping.
However, when I try that in my factory contract:
pragma solidity >=0.7.0 <0.9.0;
contract Factory {
mapping(address => Campaign) _campaigns;
function createCampaign(uint minContrib) public {
require(_campaigns[msg.sender] == Campaign(0));
_campaigns[msg.sender] = new Campaign(minContrib, msg.sender);
}
}
...
contract Campaign {
/* Irrelevant code skipped ... */
constructor (uint minContrib, address creator) {
manager = creator;
minContribution = minContrib;
}
compilation error pops:
from solidity:
TypeError: Explicit type conversion not allowed from "int_const 0" to "contract Campaign".
--> contracts/3_Ballot.sol:10:43:
|
10 | require(_campaigns[msg.sender] == Campaign(0));
| ^^^^^^^^^^^
What comparison is being made here exactly?
require (_counters[msg.sender] == Counter(0));
What is Counter(0)? An instance of contract (like new Counter(0)) or a type conversion of parameter 'int_const' to 'contract'?
Found this this answer which made things a bit clearer.
Apparently this is trying to compare the Contract deployed at address 0 with thatever is stored at _counters[msg.sender] (which I believe should be the address of a deployed contract).
require (_counters[msg.sender] == Counter(0));
With that in mind, I get the error is saying "we're expecting a Counter or address of contract and you give us an int".
I fixed it with Counter(address(0)).

Solidity constructor declaration and statements between function signature and visibility modifieres

I just came across this in a Solidity contract, I don't understand it. Specifically I don't understand how there can be a function call after the constructor parameters block. If it were a modifier, it would be after "public", but it is immediately after the parameters. What does MerkleTreeWithHistory(_merkleTreeHeight) mean in this context?
constructor(
IVerifier _verifier,
uint256 _denomination,
uint32 _merkleTreeHeight,
address _operator
) MerkleTreeWithHistory(_merkleTreeHeight) public {
require(_denomination > 0, "denomination should be greater than 0");
verifier = _verifier;
operator = _operator;
denomination = _denomination;
}
MerkleTreeWithHistory(_merkleTreeHeight)
Calls the parent contract constructor. It is executed before entering the sub-contract constructor.

Solidity error message when executing smart contract: "the constructor should be payable if you send value"

I am trying to learn solidity through coding the smart contract below (see snippet below) .
I have been able to successfully compile (i.e. without bugs) the smart contract, the object of which is to payout an inheritance from one ethereum wallet address to another (e.g. a family member).
I have also been able to deploy it but I get the following error message (also see attached pic) when i try to transfer an inheritance to a payee.
Any help is greatly appreciated !
error message:
"transact to Will.setInheritance errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value. Debug the transaction to get more information"
pragma solidity ^0.5.1;
//Use a double forward slash to write a like this one
// Line1 : First we nominate which version of the SOLIDITY code we are using.
//This is always the first step in our code.
// Here we tell REMIX that the the source code we are using is version 0.5.1 or above (by using the ^ - carrot symbol)
// We will start building our SC which will eventually split the inheritance of a persons will (e.g. Grandfather) amongst the Family members
contract Will {
//Line 9 : Each new contract must be named as “contract”, then the name with the first letter always CAPITALIZED, followed by open/close curly brackets to contain the logic.
address owner;
uint fortune;
bool isDeceased;
// Line 13: here we declare the variables of the smart contract - each variable must be listed along with its variable type in SOLIDITY
// Line 13: owner is of the address type of variable in SOLIDITY (unique variable in SOLIDITY - refers to an ethereum network address)
// Line 14: fortune is of the type uint (unsigned integer = a positive only integer)
// Line 15: isDeceased is a boolean variable (i.e. TRUE or FALSE type)
constructor() public payable {
owner = msg.sender;
fortune = msg.value;
isDeceased = false;
}
// Line 22: here we use a constructor function to set these values in he contract
// The “public” keyword is what’s known as a “visibility modifier” which tells the contract who is allowed to call the function.
// Public means that the function can be called within the contract and outside of it by someone else or another contract.
// The “payable” keyword allows the function to send and receive ether.
// When we deploy the contract we can initialize it with an ether balance.
// When the contract receives ether, it will store it in its own address.
// Then we will use the SC to transfer the ether to another adress (or inheritor)
// Line 23: we set the owner to “msg.sender”, which is a built-in global variable representative of the address that is calling the function.
//In this case, it will be the owner of the funds.
// Line 24: The fortune is set to “msg.value”, which is another built-in variable that tells us how much ether has been sent.
// Line 25: We set the isDeceased to false
modifier onlyOwner {
require (msg.sender ==owner);
_;
}
modifier mustBeDeceased {
require (isDeceased == true);
_;
}
// Modifiers are add-ons to functions that contain conditional logic.
// Line 41 declares “onlyOwner” modifier.
// If added to a function, it can only be called if the caller (msg.sender) is equivalent to the owner variable as stated above (remember how we set the owner in the constructor). We will need this to allow the distribution of funds, which will be implemented later.
// The “require” keyword states that we want isDeceased to be true otherwise solidity will throw an error and the execution will stop.
// The “_;” at the end tells the execution to shift to the actual function after it’s done reading the modifier.
// Now we must declare how the inheritance is divided amongst the family members.
// We will need their public wallet keys (addresses) and their desired allotments.
// First we create a list to store the wallet addresses (of the family members)
// And we create a and a function that sets the inheritance for each address.
address payable[] wallets;
//ABOVE WE HAVE TO ENTER payable to tell SOLIDITY that the address for the payout of the money is the wallet address
// function will not work without adding "address" here
mapping (address => uint) inheritance;
function setInheritance(address payable _wallet, uint _inheritance) public onlyOwner {
wallets.push(_wallet);
inheritance [_wallet] = _inheritance;
}
// Line 67: declares an empty array called “wallets” for storing the family members’ wallet addresses.
// This is a list-like data structure . The square brackets after “address” indicate it’s an array of items rather than a single variable.
// Line 69: Creates a mapping from an address type to a uint type named “inheritance”
// We will use this for distributing the inheritance to a family members wallet (It’s the equivalent of a “dictionary” in other languages such as Python and Javascript, Key/Value Pair).
// Line 71 declares the function that adds an address to the (empty) inheritance array we just created and then sets the inheritance to be provided to this address.
// We added the the “onlyOwner” modifier we added to this function, which means that only the owner of the money can distribute the funds
// Finally we create the payout function, i.e. the actual transfer of the funds
function payout() private mustBeDeceased {
for (uint i=0; i<wallets.length; i++) {
wallets[i].transfer(inheritance[wallets[i]]);
}
}
function deceased() public payable onlyOwner {
isDeceased = true;
payout();
}
}
Solidity error message i receive when i try to transfer the payment to the payee
I executed your code and examine in depth. Note that currently remix and solidity does not show good and meaningful error messages.
The problem here is your constructor function is payable:
constructor() public payable {
owner = msg.sender;
fortune = msg.value;
isDeceased = false;
}
And if you execute constructor without any value it will execute also the setInheritance will execute without error and when you try to run the deceased function which is another payable function, then the things will blast. The remix will say the constructor is payable but did not sent any value.
Please try to send some value if you want to run any payable function. Here you can write value for payable functions.
Hope it helps.

In Solidity, can the constructor function have the same name as the contract?

According to this article, the constructor - or initialization - function has the same name as the contract. However, the remix compiler returns an error when I have a function with the same name, saying "defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead."
So, my question is, is using the same name in this situation something that should simply be avoided? (Perhaps it is an out of date practice?)
Since Solidity v0.4.23, constructors are now specified using the constructor keyword:
constructor () {}
Just to compare with the old ways, say we have a Smart Contract called Employee, in the past, you'd specify the contract with its constructor like this:
contract Employee {
// constructor
function Employee() public {
// ...
}
}
But the acceptable way to specify the Employee Smart Contract now is:
contract Employee {
// constructor
constructor() public {
// ...
}
}
Using the name of a contract as its constructor is now deprecated.