1

What parameter should I paste as prevOwner when I'm calling this from .sol smart contract? And how I can get this parameter?

function removeOwner(
        address prevOwner,
        address owner,
        uint256 _threshold
    ) public authorized 

(from https://github.com/gnosis/safe-contracts/blob/main/contracts/base/OwnerManager.sol)

It's related to How can I add/remove an owner to gnosis-safe wallet from solidity smart contract?

I'm creating a module contract, so modules can be used to extend the Safe functionality, and they can execute transactions from the Safe: https://docs.gnosis-safe.io/contracts/modules-1

I added addOwner function to my contract as described here https://gist.github.com/rmeissner/c66371a4b030109cde1020f427122462

But addOwner asking only for address which should be added, and there I need somehow get this address prevOwner.

How can I do this from solidity contract?


Сode:

ModuleContract.sol :

contract RecoveryKeyModule{ //MasterCopy {
    GnosisSafeVV2 public safe;
    address public recoverer;

    // modifier authorized() {//override {
    //     require(
    //         msg.sender == address(safe),
    //         "Method can only be called from this contract"
    //     );
    //     _;
    // }

    function setup(address _recoverer) public {
        require(address(safe) == address(0), "Module has already been setup");
        safe = GnosisSafeVV2(msg.sender);
        recoverer = _recoverer;
    }

    function recover() external {
        require(msg.sender == recoverer, "You are not allowed to do that");
        // add additionalOwner as owner and set threshold to 1
        bytes memory data = abi.encodeWithSignature(
            "addOwnerWithThreshold(address,uint256)",
            recoverer,
            1
        );
        safe.execTransactionFromModule(
            address(safe),
            0,
            data,
            Enum.Operation.Call
        );
    }

    ////
    function remover() external { ??????
        require(msg.sender == recoverer, "You are not allowed to do that");
        // add additionalOwner as owner and set threshold to 1
        bytes memory data = abi.encodeWithSignature(
            "removeOwner(address,uint256)", //????
            recoverer,
            1
        );
        safe.execTransactionFromModule(
            address(safe),
            0,
            data,
            Enum.Operation.Call
        );
    }
}

MyContract-from-where-Im-calling-add-and-remove-Gnosis-Owner.sol :

 function addOwnerToGnosis(address owner) public {
        //Only allow if caller has enough weight
        require(seed.calculateClaim(owner) >= (seed.fundingCollected() / 100) * 51);

        // Owner address cannot be null, the sentinel or the Safe itself.
        require(owner != address(0));

        // function recover(GnosisSafe safe) external
        rkmc.setup(owner);
        rkmc.recover();
        // seed.addOwnerThreshold(owner);
    }


function removeOwnerFromGnosis(address owner) public {
    //Only allow if caller has enough weight 
    require(seed.calculateClaim(owner)/100 >= seed.fundingCollected()/100*60);

      // Owner address cannot be null, the sentinel or the Safe itself.
      require(owner != address(0));

      // function recover(GnosisSafe safe) external
      rkmc.setup(owner);
      rkmc.remover();
    // seed.addOwnerThreshold(owner);
  }

Solved.

(I think so)

ModuleContract.sol :

function remover(address forRemOwner) external { 
    require(msg.sender == recoverer, "You are not allowed to do that");
    // add additionalOwner as owner and set threshold to 1

    bytes memory data = abi.encodeWithSignature(
        "removeOwner(address,address,uint256)", 
        recoverer, //address prevOwner,
        forRemOwner,
         //address owner,
        1
    );
    safe.execTransactionFromModule(
        address(safe),
        0,
        data,
        Enum.Operation.Call
    );
}

Ballot.sol :

function removeOwnerFromGnosis(address owner, address forRemOwner) public {
    //Only allow if caller has enough weight (51% and more)
    require(seed.calculateClaim(owner)/100 >= seed.fundingCollected()/100*60);

      // Owner address cannot be null, the sentinel or the Safe itself.
      require(owner != address(0));

      // function recover(GnosisSafe safe) external
      rkmc.setup(owner);
      rkmc.remover(forRemOwner);
}

1 Answer 1

2

The Safe contracts store the owners in a linked list (see https://github.com/gnosis/safe-contracts/blob/main/contracts/base/OwnerManager.sol#L15). With linked lists it is very is to check if an element is part of the list. When removing an item from the linked list you need to update the elements related to the element you are removing (e.g. the element linking to the element you want to remove). To avoid that the contract has to iterate the whole linked list (this is expensive gas cost wise), the Safe contract require that you specify the element linking to the element you want to remove. That element is called prevOwner. The Safe contract will then point the prevOwner element to the element that the element pointed to that your are removing (seeremoveOwner).

More info on linked lists can be found here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.