Skip to content

Instantly share code, notes, and snippets.

@AndreiMVP
Last active July 3, 2023 10:19
Show Gist options
  • Save AndreiMVP/62f75c88ebe28925bea1fce37f9170f1 to your computer and use it in GitHub Desktop.
Save AndreiMVP/62f75c88ebe28925bea1fce37f9170f1 to your computer and use it in GitHub Desktop.
A module that allows the owner of a safe registered on Proof of Humanity v2 to swap his old address with the new address corresponding to his PoH ID. Module is deployed with the PoH and Safe instances (the safe being used as governor; authorized is the keyword used for functions only the safe is allowed to call) and added to Gnosis Safe as a mod…
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
contract Enum {
enum Operation {
Call,
DelegateCall
}
}
interface GnosisSafe {
function isOwner(address owner) external view returns (bool);
function swapOwner(
address prevOwner,
address oldOwner,
address newOwner
) external;
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success);
}
interface IProofOfHumanity {
// See to which address belongs the humanity
function boundTo(bytes20 _humanity) external view returns (address);
// See to which humanity corresponds the address (if registered)
function humanityOf(address _humanAddress) external view returns (bytes20);
}
contract HumanSafeModule {
/// @dev The Gnosis Safe this module will be added to
GnosisSafe public safe;
/// @dev The ProofOfHumanity instance
IProofOfHumanity public proofOfHumanity;
/// @dev Mapping of safe owner address to corresponding PoHId
mapping(address => bytes20) public ownerToPoHId;
modifier onlySafe() {
require(msg.sender == address(safe), "Can only be called from safe");
_;
}
/** @dev Setup the module
* @param _proofOfHumanity Address of ProofOfHumanity instance
* @param _safe Address of Safe instance
*/
function setup(address _proofOfHumanity, address _safe) external {
require(address(safe) == address(0x0), "Safe has already been set");
safe = GnosisSafe(_safe);
proofOfHumanity = IProofOfHumanity(_proofOfHumanity);
}
/** @dev Change address of ProofOfHumanity instance
* @param _proofOfHumanity New address of ProofOfHumanity instance
*/
function setProofOfHumanity(address _proofOfHumanity) external onlySafe {
proofOfHumanity = IProofOfHumanity(_proofOfHumanity);
}
/** @dev Add a safe owner registered on ProofOfHumanity to the module
* @param _human Address of safe owner
*/
function initializePoHID(address _human) external onlySafe {
require(safe.isOwner(_human), "Address is not a safe owner");
bytes20 senderPoHId = proofOfHumanity.humanityOf(_human);
require(senderPoHId != bytes20(0x0), "Sender is not register");
ownerToPoHId[_human] = senderPoHId;
}
/** @dev Swap an owner of the safe address with a new one corresponding to the PoHId
* @param _prevOwner Owner that pointed to the owner to be replaced in the linked list
* @param _oldOwner Owner address to be replaced
*/
function recoverOwner(address _prevOwner, address _oldOwner) external {
require(safe.isOwner(_oldOwner), "Not a safe owner");
bytes20 pohId = ownerToPoHId[_oldOwner];
require(pohId != 0x0, "Owner not added to the module");
address newOwner = proofOfHumanity.boundTo(pohId);
require(newOwner != address(0x0), "PoH ID not bound to any address");
require(newOwner != _oldOwner, "New owner is the same as the old one");
delete ownerToPoHId[_oldOwner];
ownerToPoHId[newOwner] = pohId;
bytes memory data = abi.encodeCall(GnosisSafe.swapOwner, (_prevOwner, _oldOwner, newOwner));
require(safe.execTransactionFromModule(address(safe), 0, data, Enum.Operation.Call), "Safe execution failed");
}
/** @dev Remove an address from the module
* @param _owner Address of owner
*/
function removePoHID(address _owner) external onlySafe {
delete ownerToPoHId[_owner];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment