// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
import "./IModule.sol";
import "./IWallet.sol";
/**
* @title BaseWallet
* @notice Simple modular wallet that authorises modules to call its invoke() method.
* @author Julien Niset - <julien@argent.xyz>
*/
contract BaseWallet is IWallet {
// The implementation of the proxy
address public implementation;
// The owner
address public override owner;
// The authorised modules
mapping (address => bool) public override authorised;
// The enabled static calls
mapping (bytes4 => address) public override enabled;
// The number of modules
uint public override modules;
event AuthorisedModule(address indexed module, bool value);
event EnabledStaticCall(address indexed module, bytes4 indexed method);
event Invoked(address indexed module, address indexed target, uint indexed value, bytes data);
event Received(uint indexed value, address indexed sender, bytes data);
event OwnerChanged(address owner);
/**
* @notice Throws if the sender is not an authorised module.
*/
modifier moduleOnly {
require(authorised[msg.sender], "BW: msg.sender not an authorized module");
_;
}
/**
* @notice Inits the wallet by setting the owner and authorising a list of modules.
* @param _owner The owner.
* @param _modules The modules to authorise.
*/
function init(address _owner, address[] calldata _modules) external {
require(owner == address(0) && modules == 0, "BW: wallet already initialised");
require(_modules.length > 0, "BW: construction requires at least 1 module");
owner = _owner;
modules = _modules.length;
for (uint256 i = 0; i < _modules.length; i++) {
require(authorised[_modules[i]] == false, "BW: module is already added");
authorised[_modules[i]] = true;
IModule(_modules[i]).init(address(this));
emit AuthorisedModule(_modules[i], true);
}
if (address(this).balance > 0) {
emit Received(address(this).balance, address(0), "");
}
}
/**
* @inheritdoc IWallet
*/
function authoriseModule(address _module, bool _value) external override moduleOnly {
if (authorised[_module] != _value) {
emit AuthorisedModule(_module, _value);
if (_value == true) {
modules += 1;
authorised[_module] = true;
IModule(_module).init(address(this));
} else {
modules -= 1;
require(modules > 0, "BW: wallet must have at least one module");
delete authorised[_module];
}
}
}
/**
* @inheritdoc IWallet
*/
function enableStaticCall(address _module, bytes4 _method) external override moduleOnly {
require(authorised[_module], "BW: must be an authorised module for static call");
enabled[_method] = _module;
emit EnabledStaticCall(_module, _method);
}
/**
* @inheritdoc IWallet
*/
function setOwner(address _newOwner) external override moduleOnly {
require(_newOwner != address(0), "BW: address cannot be null");
owner = _newOwner;
emit OwnerChanged(_newOwner);
}
/**
* @notice Performs a generic transaction.
* @param _target The address for the transaction.
* @param _value The value of the transaction.
* @param _data The data of the transaction.
*/
function invoke(address _target, uint _value, bytes calldata _data) external moduleOnly returns (bytes memory _result) {
bool success;
(success, _result) = _target.call{value: _value}(_data);
if (!success) {
// solhint-disable-next-line no-inline-assembly
assembly {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
emit Invoked(msg.sender, _target, _value, _data);
}
/**
* @notice This method delegates the static call to a target contract if the data corresponds
* to an enabled module, or logs the call otherwise.
*/
fallback() external payable {
address module = enabled[msg.sig];
if (module == address(0)) {
emit Received(msg.value, msg.sender, msg.data);
} else {
require(authorised[module], "BW: must be an authorised module for static call");
// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := staticcall(gas(), module, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {revert(0, returndatasize())}
default {return (0, returndatasize())}
}
}
}
receive() external payable {
}
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
interface IGuardianStorage {
/**
* @notice Lets an authorised module add a guardian to a wallet.
* @param _wallet The target wallet.
* @param _guardian The guardian to add.
*/
function addGuardian(address _wallet, address _guardian) external;
/**
* @notice Lets an authorised module revoke a guardian from a wallet.
* @param _wallet The target wallet.
* @param _guardian The guardian to revoke.
*/
function revokeGuardian(address _wallet, address _guardian) external;
/**
* @notice Checks if an account is a guardian for a wallet.
* @param _wallet The target wallet.
* @param _guardian The account.
* @return true if the account is a guardian for a wallet.
*/
function isGuardian(address _wallet, address _guardian) external view returns (bool);
function isLocked(address _wallet) external view returns (bool);
function getLock(address _wallet) external view returns (uint256);
function getLocker(address _wallet) external view returns (address);
function setLock(address _wallet, uint256 _releaseAfter) external;
function getGuardians(address _wallet) external view returns (address[] memory);
function guardianCount(address _wallet) external view returns (uint256);
}
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
/**
* @title ILimitStorage
* @notice LimitStorage interface
*/
interface ILimitStorage {
struct Limit {
// the current limit
uint128 current;
// the pending limit if any
uint128 pending;
// when the pending limit becomes the current limit
uint64 changeAfter;
}
struct DailySpent {
// The amount already spent during the current period
uint128 alreadySpent;
// The end of the current period
uint64 periodEnd;
}
function setLimit(address _wallet, Limit memory _limit) external;
function getLimit(address _wallet) external view returns (Limit memory _limit);
function setDailySpent(address _wallet, DailySpent memory _dailySpent) external;
function getDailySpent(address _wallet) external view returns (DailySpent memory _dailySpent);
function setLimitAndDailySpent(address _wallet, Limit memory _limit, DailySpent memory _dailySpent) external;
function getLimitAndDailySpent(address _wallet) external view returns (Limit memory _limit, DailySpent memory _dailySpent);
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
/**
* @title IModule
* @notice Interface for a module.
* A module MUST implement the addModule() method to ensure that a wallet with at least one module
* can never end up in a "frozen" state.
* @author Julien Niset - <julien@argent.xyz>
*/
interface IModule {
/**
* @notice Inits a module for a wallet by e.g. setting some wallet specific parameters in storage.
* @param _wallet The wallet.
*/
function init(address _wallet) external;
/**
* @notice Adds a module to a wallet. Cannot execute when wallet is locked (or under recovery)
* @param _wallet The target wallet.
* @param _module The modules to authorise.
*/
function addModule(address _wallet, address _module) external;
}
// Copyright (C) 2020 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
/**
* @title IModuleRegistry
* @notice Interface for the registry of authorised modules.
*/
interface IModuleRegistry {
function registerModule(address _module, bytes32 _name) external;
function deregisterModule(address _module) external;
function registerUpgrader(address _upgrader, bytes32 _name) external;
function deregisterUpgrader(address _upgrader) external;
function recoverToken(address _token) external;
function moduleInfo(address _module) external view returns (bytes32);
function upgraderInfo(address _upgrader) external view returns (bytes32);
function isRegisteredModule(address _module) external view returns (bool);
function isRegisteredModule(address[] calldata _modules) external view returns (bool);
function isRegisteredUpgrader(address _upgrader) external view returns (bool);
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "./ILimitStorage.sol";
/**
* @title IVersionManager
* @notice Interface for the VersionManager module.
* @author Olivier VDB - <olivier@argent.xyz>
*/
interface IVersionManager {
/**
* @notice Returns true if the feature is authorised for the wallet
* @param _wallet The target wallet.
* @param _feature The feature.
*/
function isFeatureAuthorised(address _wallet, address _feature) external view returns (bool);
/**
* @notice Lets a feature (caller) invoke a wallet.
* @param _wallet The target wallet.
* @param _to The target address for the transaction.
* @param _value The value of the transaction.
* @param _data The data of the transaction.
*/
function checkAuthorisedFeatureAndInvokeWallet(
address _wallet,
address _to,
uint256 _value,
bytes calldata _data
) external returns (bytes memory _res);
/* ******* Backward Compatibility with old Storages and BaseWallet *************** */
/**
* @notice Sets a new owner for the wallet.
* @param _newOwner The new owner.
*/
function setOwner(address _wallet, address _newOwner) external;
/**
* @notice Lets a feature write data to a storage contract.
* @param _wallet The target wallet.
* @param _storage The storage contract.
* @param _data The data of the call
*/
function invokeStorage(address _wallet, address _storage, bytes calldata _data) external;
/**
* @notice Upgrade a wallet to a new version.
* @param _wallet the wallet to upgrade
* @param _toVersion the new version
*/
function upgradeWallet(address _wallet, uint256 _toVersion) external;
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;
/**
* @title IWallet
* @notice Interface for the BaseWallet
*/
interface IWallet {
/**
* @notice Returns the wallet owner.
* @return The wallet owner address.
*/
function owner() external view returns (address);
/**
* @notice Returns the number of authorised modules.
* @return The number of authorised modules.
*/
function modules() external view returns (uint);
/**
* @notice Sets a new owner for the wallet.
* @param _newOwner The new owner.
*/
function setOwner(address _newOwner) external;
/**
* @notice Checks if a module is authorised on the wallet.
* @param _module The module address to check.
* @return `true` if the module is authorised, otherwise `false`.
*/
function authorised(address _module) external view returns (bool);
/**
* @notice Returns the module responsible for a static call redirection.
* @param _sig The signature of the static call.
* @return the module doing the redirection
*/
function enabled(bytes4 _sig) external view returns (address);
/**
* @notice Enables/Disables a module.
* @param _module The target module.
* @param _value Set to `true` to authorise the module.
*/
function authoriseModule(address _module, bool _value) external;
/**
* @notice Enables a static method by specifying the target module to which the call must be delegated.
* @param _module The target module.
* @param _method The static method signature.
*/
function enableStaticCall(address _module, bytes4 _method) external;
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;
import "./Owned.sol";
/**
* @title Managed
* @notice Basic contract that defines a set of managers. Only the owner can add/remove managers.
* @author Julien Niset - <julien@argent.xyz>
*/
contract Managed is Owned {
// The managers
mapping (address => bool) public managers;
/**
* @notice Throws if the sender is not a manager.
*/
modifier onlyManager {
require(managers[msg.sender] == true, "M: Must be manager");
_;
}
event ManagerAdded(address indexed _manager);
event ManagerRevoked(address indexed _manager);
/**
* @notice Adds a manager.
* @param _manager The address of the manager.
*/
function addManager(address _manager) external onlyOwner {
require(_manager != address(0), "M: Address must not be null");
if (managers[_manager] == false) {
managers[_manager] = true;
emit ManagerAdded(_manager);
}
}
/**
* @notice Revokes a manager.
* @param _manager The address of the manager.
*/
function revokeManager(address _manager) external onlyOwner {
require(managers[_manager] == true, "M: Target must be an existing manager");
delete managers[_manager];
emit ManagerRevoked(_manager);
}
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;
/**
* @title Owned
* @notice Basic contract to define an owner.
* @author Julien Niset - <julien@argent.xyz>
*/
contract Owned {
// The owner
address public owner;
event OwnerChanged(address indexed _newOwner);
/**
* @notice Throws if the sender is not the owner.
*/
modifier onlyOwner {
require(msg.sender == owner, "Must be owner");
_;
}
constructor() public {
owner = msg.sender;
}
/**
* @notice Lets the owner transfer ownership of the contract to a new owner.
* @param _newOwner The new owner.
*/
function changeOwner(address _newOwner) external onlyOwner {
require(_newOwner != address(0), "Address must not be null");
owner = _newOwner;
emit OwnerChanged(_newOwner);
}
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
/**
* @title Proxy
* @notice Basic proxy that delegates all calls to a fixed implementing contract.
* The implementing contract cannot be upgraded.
* @author Julien Niset - <julien@argent.xyz>
*/
contract Proxy {
address implementation;
event Received(uint indexed value, address indexed sender, bytes data);
constructor(address _implementation) public {
implementation = _implementation;
}
fallback() external payable {
// solhint-disable-next-line no-inline-assembly
assembly {
let target := sload(0)
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), target, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {revert(0, returndatasize())}
default {return (0, returndatasize())}
}
}
receive() external payable {
emit Received(msg.value, msg.sender, msg.data);
}
}
// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
import "./Proxy.sol";
import "./BaseWallet.sol";
import "./Owned.sol";
import "./Managed.sol";
import "./IGuardianStorage.sol";
import "./IModuleRegistry.sol";
import "./IVersionManager.sol";
/**
* @title WalletFactory
* @notice The WalletFactory contract creates and assigns wallets to accounts.
* @author Julien Niset - <julien@argent.xyz>
*/
contract WalletFactory is Owned, Managed {
// The address of the module dregistry
address public moduleRegistry;
// The address of the base wallet implementation
address public walletImplementation;
// The address of the GuardianStorage
address public guardianStorage;
// *************** Events *************************** //
event ModuleRegistryChanged(address addr);
event WalletCreated(address indexed wallet, address indexed owner, address indexed guardian);
// *************** Constructor ********************** //
/**
* @notice Default constructor.
*/
constructor(address _moduleRegistry, address _walletImplementation, address _guardianStorage) public {
require(_moduleRegistry != address(0), "WF: ModuleRegistry address not defined");
require(_walletImplementation != address(0), "WF: WalletImplementation address not defined");
require(_guardianStorage != address(0), "WF: GuardianStorage address not defined");
moduleRegistry = _moduleRegistry;
walletImplementation = _walletImplementation;
guardianStorage = _guardianStorage;
}
// *************** External Functions ********************* //
/**
* @notice Lets the manager create a wallet for an owner account.
* The wallet is initialised with the version manager module, a version number and a first guardian.
* The wallet is created using the CREATE opcode.
* @param _owner The account address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _version The version of the feature bundle.
*/
function createWallet(
address _owner,
address _versionManager,
address _guardian,
uint256 _version
)
external
onlyManager
{
validateInputs(_owner, _versionManager, _guardian, _version);
Proxy proxy = new Proxy(walletImplementation);
address payable wallet = address(proxy);
configureWallet(BaseWallet(wallet), _owner, _versionManager, _guardian, _version);
}
/**
* @notice Lets the manager create a wallet for an owner account at a specific address.
* The wallet is initialised with the version manager module, the version number and a first guardian.
* The wallet is created using the CREATE2 opcode.
* @param _owner The account address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _salt The salt.
* @param _version The version of the feature bundle.
*/
function createCounterfactualWallet(
address _owner,
address _versionManager,
address _guardian,
bytes32 _salt,
uint256 _version
)
external
onlyManager
returns (address _wallet)
{
validateInputs(_owner, _versionManager, _guardian, _version);
bytes32 newsalt = newSalt(_salt, _owner, _versionManager, _guardian, _version);
Proxy proxy = new Proxy{salt: newsalt}(walletImplementation);
address payable wallet = address(proxy);
configureWallet(BaseWallet(wallet), _owner, _versionManager, _guardian, _version);
return wallet;
}
/**
* @notice Gets the address of a counterfactual wallet with a first default guardian.
* @param _owner The account address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _salt The salt.
* @param _version The version of feature bundle.
* @return _wallet The address that the wallet will have when created using CREATE2 and the same input parameters.
*/
function getAddressForCounterfactualWallet(
address _owner,
address _versionManager,
address _guardian,
bytes32 _salt,
uint256 _version
)
external
view
returns (address _wallet)
{
validateInputs(_owner, _versionManager, _guardian, _version);
bytes32 newsalt = newSalt(_salt, _owner, _versionManager, _guardian, _version);
bytes memory code = abi.encodePacked(type(Proxy).creationCode, uint256(walletImplementation));
bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), newsalt, keccak256(code)));
_wallet = address(uint160(uint256(hash)));
}
/**
* @notice Lets the owner change the address of the module registry contract.
* @param _moduleRegistry The address of the module registry contract.
*/
function changeModuleRegistry(address _moduleRegistry) external onlyOwner {
require(_moduleRegistry != address(0), "WF: address cannot be null");
moduleRegistry = _moduleRegistry;
emit ModuleRegistryChanged(_moduleRegistry);
}
/**
* @notice Inits the module for a wallet by doing nothing.
* The method can only be called by the wallet itself.
* @param _wallet The wallet.
*/
function init(BaseWallet _wallet) external pure {
//do nothing
}
// *************** Internal Functions ********************* //
/**
* @notice Helper method to configure a wallet for a set of input parameters.
* @param _wallet The target wallet
* @param _owner The account address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _version The version of the feature bundle.
*/
function configureWallet(
BaseWallet _wallet,
address _owner,
address _versionManager,
address _guardian,
uint256 _version
)
internal
{
// add the factory to modules so it can add a guardian and upgrade the wallet to the required version
address[] memory extendedModules = new address[](2);
extendedModules[0] = _versionManager;
extendedModules[1] = address(this);
// initialise the wallet with the owner and the extended modules
_wallet.init(_owner, extendedModules);
// add guardian
IGuardianStorage(guardianStorage).addGuardian(address(_wallet), _guardian);
// upgrade the wallet
IVersionManager(_versionManager).upgradeWallet(address(_wallet), _version);
// remove the factory from the authorised modules
_wallet.authoriseModule(address(this), false);
// emit event
emit WalletCreated(address(_wallet), _owner, _guardian);
}
/**
* @notice Generates a new salt based on a provided salt, an owner, a list of modules and an optional guardian.
* @param _salt The slat provided.
* @param _owner The owner address.
* @param _versionManager The version manager module
* @param _guardian The guardian address.
* @param _version The version of feature bundle
*/
function newSalt(bytes32 _salt, address _owner, address _versionManager, address _guardian, uint256 _version) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_salt, _owner, _versionManager, _guardian, _version));
}
/**
* @notice Throws if the owner, guardian, version or version manager is invalid.
* @param _owner The owner address.
* @param _versionManager The version manager module
* @param _guardian The guardian address
* @param _version The version of feature bundle
*/
function validateInputs(address _owner, address _versionManager, address _guardian, uint256 _version) internal view {
require(_owner != address(0), "WF: owner cannot be null");
require(IModuleRegistry(moduleRegistry).isRegisteredModule(_versionManager), "WF: invalid _versionManager");
require(_guardian != (address(0)), "WF: guardian cannot be null");
require(_version > 0, "WF: invalid _version");
}
}
{
"compilationTarget": {
"WalletFactory.sol": "WalletFactory"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 999
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_moduleRegistry","type":"address"},{"internalType":"address","name":"_walletImplementation","type":"address"},{"internalType":"address","name":"_guardianStorage","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_manager","type":"address"}],"name":"ManagerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_manager","type":"address"}],"name":"ManagerRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"ModuleRegistryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"WalletCreated","type":"event"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"addManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_moduleRegistry","type":"address"}],"name":"changeModuleRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_versionManager","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"uint256","name":"_version","type":"uint256"}],"name":"createCounterfactualWallet","outputs":[{"internalType":"address","name":"_wallet","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_versionManager","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"uint256","name":"_version","type":"uint256"}],"name":"createWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_versionManager","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"uint256","name":"_version","type":"uint256"}],"name":"getAddressForCounterfactualWallet","outputs":[{"internalType":"address","name":"_wallet","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardianStorage","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract BaseWallet","name":"_wallet","type":"address"}],"name":"init","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"managers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"revokeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"walletImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]