Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/factory/ConditionFactory.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.22;
import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";
import {ExecuteSelectorCondition} from "../ExecuteSelectorCondition.sol";
import {SelectorCondition} from "../SelectorCondition.sol";
import {SafeOwnerCondition, IOwnerManager} from "../SafeOwnerCondition.sol";
/// @title ConditionFactory
/// @author AragonX 2025
/// @notice A factory used to deploy new condition instances
contract ConditionFactory {
event ExecuteSelectorConditionDeployed(ExecuteSelectorCondition newContract);
event SelectorConditionDeployed(SelectorCondition newContract);
event SafeOwnerConditionDeployed(SafeOwnerCondition newContract);
function deployExecuteSelectorCondition(IDAO _dao, ExecuteSelectorCondition.SelectorTarget[] memory _initialEntries)
public
returns (ExecuteSelectorCondition newContract)
{
newContract = new ExecuteSelectorCondition(_dao, _initialEntries);
emit ExecuteSelectorConditionDeployed(newContract);
}
function deploySelectorCondition(IDAO _dao, bytes4[] memory _initialSelectors)
public
returns (SelectorCondition newContract)
{
newContract = new SelectorCondition(_dao, _initialSelectors);
emit SelectorConditionDeployed(newContract);
}
function deploySafeOwnerCondition(address _safe) public returns (SafeOwnerCondition newContract) {
newContract = new SafeOwnerCondition(IOwnerManager(_safe));
emit SafeOwnerConditionDeployed(newContract);
}
}
"
},
"lib/osx-commons/contracts/src/dao/IDAO.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
/// @title IDAO
/// @author Aragon X - 2022-2024
/// @notice The interface required for DAOs within the Aragon App DAO framework.
/// @custom:security-contact sirt@aragon.org
interface IDAO {
/// @notice Checks if an address has permission on a contract via a permission identifier and considers if `ANY_ADDRESS` was used in the granting process.
/// @param _where The address of the contract.
/// @param _who The address of a EOA or contract to give the permissions.
/// @param _permissionId The permission identifier.
/// @param _data The optional data passed to the `PermissionCondition` registered.
/// @return Returns true if the address has permission, false if not.
function hasPermission(
address _where,
address _who,
bytes32 _permissionId,
bytes memory _data
) external view returns (bool);
/// @notice Updates the DAO metadata (e.g., an IPFS hash).
/// @param _metadata The IPFS hash of the new metadata object.
function setMetadata(bytes calldata _metadata) external;
/// @notice Emitted when the DAO metadata is updated.
/// @param metadata The IPFS hash of the new metadata object.
event MetadataSet(bytes metadata);
/// @notice Emitted when a standard callback is registered.
/// @param interfaceId The ID of the interface.
/// @param callbackSelector The selector of the callback function.
/// @param magicNumber The magic number to be registered for the callback function selector.
event StandardCallbackRegistered(
bytes4 interfaceId,
bytes4 callbackSelector,
bytes4 magicNumber
);
/// @notice Deposits (native) tokens to the DAO contract with a reference string.
/// @param _token The address of the token or address(0) in case of the native token.
/// @param _amount The amount of tokens to deposit.
/// @param _reference The reference describing the deposit reason.
function deposit(address _token, uint256 _amount, string calldata _reference) external payable;
/// @notice Emitted when a token deposit has been made to the DAO.
/// @param sender The address of the sender.
/// @param token The address of the deposited token.
/// @param amount The amount of tokens deposited.
/// @param _reference The reference describing the deposit reason.
event Deposited(
address indexed sender,
address indexed token,
uint256 amount,
string _reference
);
/// @notice Emitted when a native token deposit has been made to the DAO.
/// @dev This event is intended to be emitted in the `receive` function and is therefore bound by the gas limitations for `send`/`transfer` calls introduced by [ERC-2929](https://eips.ethereum.org/EIPS/eip-2929).
/// @param sender The address of the sender.
/// @param amount The amount of native tokens deposited.
event NativeTokenDeposited(address sender, uint256 amount);
/// @notice Setter for the trusted forwarder verifying the meta transaction.
/// @param _trustedForwarder The trusted forwarder address.
function setTrustedForwarder(address _trustedForwarder) external;
/// @notice Getter for the trusted forwarder verifying the meta transaction.
/// @return The trusted forwarder address.
function getTrustedForwarder() external view returns (address);
/// @notice Emitted when a new TrustedForwarder is set on the DAO.
/// @param forwarder the new forwarder address.
event TrustedForwarderSet(address forwarder);
/// @notice Checks whether a signature is valid for a provided hash according to [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271).
/// @param _hash The hash of the data to be signed.
/// @param _signature The signature byte array associated with `_hash`.
/// @return Returns the `bytes4` magic value `0x1626ba7e` if the signature is valid and `0xffffffff` if not.
function isValidSignature(bytes32 _hash, bytes memory _signature) external returns (bytes4);
/// @notice Registers an ERC standard having a callback by registering its [ERC-165](https://eips.ethereum.org/EIPS/eip-165) interface ID and callback function signature.
/// @param _interfaceId The ID of the interface.
/// @param _callbackSelector The selector of the callback function.
/// @param _magicNumber The magic number to be registered for the function signature.
function registerStandardCallback(
bytes4 _interfaceId,
bytes4 _callbackSelector,
bytes4 _magicNumber
) external;
/// @notice Removed function being left here to not corrupt the IDAO interface ID. Any call will revert.
/// @dev Introduced in v1.0.0. Removed in v1.4.0.
function setSignatureValidator(address) external;
}
"
},
"src/ExecuteSelectorCondition.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.22;
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {DaoAuthorizable} from "@aragon/osx-commons-contracts/src/permission/auth/DaoAuthorizable.sol";
import {IPermissionCondition} from "@aragon/osx-commons-contracts/src/permission/condition/IPermissionCondition.sol";
import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";
import {IExecutor, Action} from "@aragon/osx-commons-contracts/src/executors/IExecutor.sol";
import {getSelector} from "./lib/common.sol";
/// @title ExecuteSelectorCondition
/// @author AragonX 2025
/// @notice A permission that only allows a specified group of function selectors to be invoked within DAO.execute()
contract ExecuteSelectorCondition is ERC165, IPermissionCondition, DaoAuthorizable {
/// @notice Contains a list of selectors for the given target (where) address
struct SelectorTarget {
/// @notice The address where the selectors below can be invoked
address where;
/// @notice The list of function selectors that can be invoked within an execute() call.
/// @notice Plain native transfers should contain 0 as the selector.
bytes4[] selectors;
}
/// @notice Stores whether the given address and selector are allowed
/// @dev allowedSelectors[where][selector]
mapping(address => mapping(bytes4 => bool)) public allowedSelectors;
/// @notice Stores whether native transfers are allowed to the given target address
mapping(address => bool) public allowedNativeTransfers;
bytes32 public constant MANAGE_SELECTORS_PERMISSION_ID = keccak256("MANAGE_SELECTORS_PERMISSION");
/// @notice Emitted when a new selector is allowed.
event SelectorAllowed(bytes4 selector, address where);
/// @notice Emitted when a selector is disallowed.
event SelectorDisallowed(bytes4 selector, address where);
/// @notice Emitted when native transfers are allowed to the given address
event NativeTransfersAllowed(address where);
/// @notice Emitted when native transfers are disallowed to the given address
event NativeTransfersDisallowed(address where);
/// @notice Configures a new instance with the given set of allowed selectors
/// @param _dao The address of the DAO where the contract should read the permissions from
/// @param _initialEntries The list of allowed selectors and the addresses where they can be invoked
constructor(IDAO _dao, SelectorTarget[] memory _initialEntries) DaoAuthorizable(_dao) {
for (uint256 i; i < _initialEntries.length; i++) {
_allowSelectors(_initialEntries[i]);
}
}
/// @notice Marks the given selectors as allowed on the given where address
/// @param _newEntry The new selectors and the address where they can be invoked
function allowSelectors(SelectorTarget memory _newEntry) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
_allowSelectors(_newEntry);
}
/// @notice Marks the given selector(s) as disallowed
/// @param _entry The selectors to remove and the address where they can no longer be invoked
function disallowSelectors(SelectorTarget memory _entry) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
_disallowSelectors(_entry);
}
/// @notice Allows actions with a non-zero `value` to pass for the given target address
/// @param _where The target address
function allowNativeTransfers(address _where) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
if (allowedNativeTransfers[_where]) return;
_allowNativeTransfers(_where);
}
/// @notice Restricts actions with a non-zero `value` for the given target address
/// @param _where The target address
function disallowNativeTransfers(address _where) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
if (!allowedNativeTransfers[_where]) return;
_disallowNativeTransfers(_where);
}
/// @inheritdoc IPermissionCondition
function isGranted(address _where, address _who, bytes32 _permissionId, bytes calldata _data)
public
view
virtual
returns (bool isPermitted)
{
(_where, _who, _permissionId);
// Calling execute()?
if (getSelector(_data) != IExecutor.execute.selector) {
return false;
}
// Decode proposal params
(, Action[] memory _actions,) = abi.decode(_data[4:], (bytes32, Action[], uint256));
for (uint256 i; i < _actions.length; i++) {
if (_actions[i].data.length == 0) {
if (_actions[i].value == 0) return false;
else if (!allowedNativeTransfers[_actions[i].to]) return false;
} else if (_actions[i].data.length < 4) {
return false;
} else if (!allowedSelectors[_actions[i].to][getSelector(_actions[i].data)]) {
return false;
} else if (_actions[i].value != 0 && !allowedNativeTransfers[_actions[i].to]) {
return false;
}
}
return true;
}
/// @notice Checks if an interface is supported by this or its parent contract.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return _interfaceId == type(IPermissionCondition).interfaceId || super.supportsInterface(_interfaceId);
}
// Internal helpers
function _allowSelectors(SelectorTarget memory _newEntry) internal virtual {
for (uint256 i; i < _newEntry.selectors.length; i++) {
if (allowedSelectors[_newEntry.where][_newEntry.selectors[i]]) {
// The requested state is already in place
continue;
}
allowedSelectors[_newEntry.where][_newEntry.selectors[i]] = true;
emit SelectorAllowed(_newEntry.selectors[i], _newEntry.where);
}
}
function _disallowSelectors(SelectorTarget memory _entry) internal virtual {
for (uint256 i; i < _entry.selectors.length; i++) {
if (!allowedSelectors[_entry.where][_entry.selectors[i]]) {
// The requested state is already in place
continue;
}
allowedSelectors[_entry.where][_entry.selectors[i]] = false;
emit SelectorDisallowed(_entry.selectors[i], _entry.where);
}
}
function _allowNativeTransfers(address _where) internal virtual {
allowedNativeTransfers[_where] = true;
emit NativeTransfersAllowed(_where);
}
function _disallowNativeTransfers(address _where) internal virtual {
allowedNativeTransfers[_where] = false;
emit NativeTransfersDisallowed(_where);
}
}
"
},
"src/SelectorCondition.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.22;
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {DaoAuthorizable} from "@aragon/osx-commons-contracts/src/permission/auth/DaoAuthorizable.sol";
import {IPermissionCondition} from "@aragon/osx-commons-contracts/src/permission/condition/IPermissionCondition.sol";
import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol";
import {getSelector} from "./lib/common.sol";
/// @title SelectorCondition
/// @author AragonX 2025
/// @notice A permission that only allows a specified group of function selectors to be invoked within DAO.execute()
contract SelectorCondition is ERC165, IPermissionCondition, DaoAuthorizable {
mapping(bytes4 => bool) public allowedSelectors;
bytes32 public constant MANAGE_SELECTORS_PERMISSION_ID = keccak256("MANAGE_SELECTORS_PERMISSION");
error AlreadyAllowed(bytes4 selector);
error AlreadyDisallowed(bytes4 selector);
event SelectorAllowed(bytes4 selector);
event SelectorDisallowed(bytes4 selector);
constructor(IDAO _dao, bytes4[] memory _initialSelectors) DaoAuthorizable(_dao) {
for (uint256 i; i < _initialSelectors.length; i++) {
allowedSelectors[_initialSelectors[i]] = true;
emit SelectorAllowed(_initialSelectors[i]);
}
}
/// @notice Marks the given selector as allowed
/// @param _selector The function selector to start allowing
function allowSelector(bytes4 _selector) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
if (allowedSelectors[_selector]) revert AlreadyAllowed(_selector);
allowedSelectors[_selector] = true;
emit SelectorAllowed(_selector);
}
/// @notice Marks the given selector as disallowed
/// @param _selector The function selector to stop allowing
function disallowSelector(bytes4 _selector) public virtual auth(MANAGE_SELECTORS_PERMISSION_ID) {
if (!allowedSelectors[_selector]) revert AlreadyDisallowed(_selector);
allowedSelectors[_selector] = false;
emit SelectorDisallowed(_selector);
}
/// @inheritdoc IPermissionCondition
function isGranted(address _where, address _who, bytes32 _permissionId, bytes calldata _data)
public
view
virtual
returns (bool isPermitted)
{
(_where, _who, _permissionId);
return allowedSelectors[getSelector(_data)];
}
/// @notice Checks if an interface is supported by this or its parent contract.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return _interfaceId == type(IPermissionCondition).interfaceId || super.supportsInterface(_interfaceId);
}
}
"
},
"src/SafeOwnerCondition.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.22;
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IPermissionCondition} from "@aragon/osx-commons-contracts/src/permission/condition/IPermissionCondition.sol";
import {IOwnerManager} from "./interfaces/IOwnerManager.sol";
/// @title SafeOwnerCondition
/// @author AragonX 2025
/// @notice A permission that only allows Safe owners to make use of a granted permission.
contract SafeOwnerCondition is ERC165, IPermissionCondition {
IOwnerManager public safe;
/// @notice Thrown when given address is not a compatible Safe.
/// @param invalidAddress The address received.
error InvalidSafe(address invalidAddress);
constructor(IOwnerManager _safe) {
// Check if the given address is compatible with a Safe
(bool success, bytes memory result) =
address(_safe).staticcall(abi.encodeWithSelector(IOwnerManager.isOwner.selector, address(0)));
if (!success || result.length != 32) {
revert InvalidSafe(address(_safe));
}
safe = _safe;
}
/// @inheritdoc IPermissionCondition
function isGranted(address _where, address _who, bytes32 _permissionId, bytes calldata _data)
public
view
virtual
returns (bool)
{
(_where, _permissionId, _data);
(bool success, bytes memory result) =
address(safe).staticcall(abi.encodeWithSelector(IOwnerManager.isOwner.selector, _who));
// If the call failed or returned malformed data, treat as "not owner"
if (!success || result.length != 32) {
return false;
}
return abi.decode(result, (bool));
}
/// @notice Checks if an interface is supported by this or its parent contract.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return _interfaceId == type(IPermissionCondition).interfaceId || super.supportsInterface(_interfaceId);
}
}
"
},
"lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
"
},
"lib/osx-commons/contracts/src/permission/auth/DaoAuthorizable.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IDAO} from "../../dao/IDAO.sol";
import {_auth} from "./auth.sol";
/// @title DaoAuthorizable
/// @author Aragon X - 2022-2023
/// @notice An abstract contract providing a meta-transaction compatible modifier for non-upgradeable contracts instantiated via the `new` keyword to authorize function calls through an associated DAO.
/// @custom:security-contact sirt@aragon.org
abstract contract DaoAuthorizable is Context {
/// @notice The associated DAO managing the permissions of inheriting contracts.
IDAO private immutable DAO;
/// @notice Constructs the contract by setting the associated DAO.
/// @param _dao The associated DAO address.
constructor(IDAO _dao) {
DAO = _dao;
}
/// @notice Returns the DAO contract.
/// @return The DAO contract.
function dao() public view returns (IDAO) {
return DAO;
}
/// @notice A modifier to make functions on inheriting contracts authorized. Permissions to call the function are checked through the associated DAO's permission manager.
/// @param _permissionId The permission identifier required to call the method this modifier is applied to.
modifier auth(bytes32 _permissionId) {
_auth(DAO, address(this), _msgSender(), _permissionId, _msgData());
_;
}
}
"
},
"lib/osx-commons/contracts/src/permission/condition/IPermissionCondition.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
/// @title IPermissionCondition
/// @author Aragon X - 2021-2023
/// @notice An interface to be implemented to support custom permission logic.
/// @dev To attach a condition to a permission, the `grantWithCondition` function must be used and refer to the implementing contract's address with the `condition` argument.
/// @custom:security-contact sirt@aragon.org
interface IPermissionCondition {
/// @notice Checks if a call is permitted.
/// @param _where The address of the target contract.
/// @param _who The address (EOA or contract) for which the permissions are checked.
/// @param _permissionId The permission identifier.
/// @param _data Optional data passed to the `PermissionCondition` implementation.
/// @return isPermitted Returns true if the call is permitted.
function isGranted(
address _where,
address _who,
bytes32 _permissionId,
bytes calldata _data
) external view returns (bool isPermitted);
}
"
},
"lib/osx-commons/contracts/src/executors/IExecutor.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
/// @notice The action struct to be consumed by the DAO's `execute` function resulting in an external call.
/// @param to The address to call.
/// @param value The native token value to be sent with the call.
/// @param data The bytes-encoded function selector and calldata for the call.
struct Action {
address to;
uint256 value;
bytes data;
}
/// @title IExecutor
/// @author Aragon X - 2024
/// @notice The interface required for Executors within the Aragon App DAO framework.
/// @custom:security-contact sirt@aragon.org
interface IExecutor {
/// @notice Emitted when a proposal is executed.
/// @dev The value of `callId` is defined by the component/contract calling the execute function.
/// A `Plugin` implementation can use it, for example, as a nonce.
/// @param actor The address of the caller.
/// @param callId The ID of the call.
/// @param actions The array of actions executed.
/// @param allowFailureMap The allow failure map encoding which actions are allowed to fail.
/// @param failureMap The failure map encoding which actions have failed.
/// @param execResults The array with the results of the executed actions.
event Executed(
address indexed actor,
bytes32 callId,
Action[] actions,
uint256 allowFailureMap,
uint256 failureMap,
bytes[] execResults
);
/// @notice Executes a list of actions. If a zero allow-failure map is provided, a failing action reverts the entire execution. If a non-zero allow-failure map is provided, allowed actions can fail without the entire call being reverted.
/// @param _callId The ID of the call. The definition of the value of `callId` is up to the calling contract and can be used, e.g., as a nonce.
/// @param _actions The array of actions.
/// @param _allowFailureMap A bitmap allowing execution to succeed, even if individual actions might revert. If the bit at index `i` is 1, the execution succeeds even if the `i`th action reverts. A failure map value of 0 requires every action to not revert.
/// @return The array of results obtained from the executed actions in `bytes`.
/// @return The resulting failure map containing the actions have actually failed.
function execute(
bytes32 _callId,
Action[] memory _actions,
uint256 _allowFailureMap
) external returns (bytes[] memory, uint256);
}
"
},
"src/lib/common.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.22;
/// @notice Extracts the selector given the calldata. If no calldata is passed, it returns zero
function getSelector(bytes memory _data) pure returns (bytes4 selector) {
if (_data.length < 4) revert("Data is too short");
// Slices are only supported for bytes calldata, not bytes memory
// Bytes memory requires an assembly block
assembly {
selector := mload(add(_data, 0x20)) // 32
}
}
"
},
"src/interfaces/IOwnerManager.sol": {
"content": "// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Owner Manager Interface
* @notice Interface for managing Safe owners and a threshold to authorize transactions.
* @author @safe-global/safe-protocol
*/
interface IOwnerManager {
/**
* @notice An owner was added.
* @param owner The address of the new owner.
*/
event AddedOwner(address indexed owner);
/**
* @notice An owner was removed.
* @param owner The address of the old owner.
*/
event RemovedOwner(address indexed owner);
/**
* @notice The signature threshold changed.
* @param threshold The new threshold for authorizing Safe transactions.
*/
event ChangedThreshold(uint256 threshold);
/**
* @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* ⚠️⚠️⚠️ A Safe can set itself as an owner which is a valid setup for EIP-7702 delegations.
* However, if address of the accounts is not an EOA and cannot sign for itself, you can
* potentially block access to the account completely. For example, if you have a `n/n`
* Safe (so `threshold == ownerCount`) and one of the owners is the Safe itself and not
* an EIP-7702 delegated account, then it will not be possible to produce a valid
* signature for the Safe. ⚠️⚠️⚠️
* @param owner New owner address.
* @param _threshold New threshold.
*/
function addOwnerWithThreshold(address owner, uint256 _threshold) external;
/**
* @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param prevOwner Owner that pointed to the `owner` to be removed in the linked list.
* If the owner to be removed is the first (or only) element of the list,
* `prevOwner` MUST be set to the sentinel address `0x1` (referred to as
* `SENTINEL_OWNERS` in the implementation).
* @param owner Owner address to be removed.
* @param _threshold New threshold.
*/
function removeOwner(address prevOwner, address owner, uint256 _threshold) external;
/**
* @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
* @dev This can only be done via a Safe transaction.
* ⚠️⚠️⚠️ A Safe can set itself as an owner which is a valid setup for EIP-7702 delegations.
* However, if address of the accounts is not an EOA and cannot sign for itself, you can
* potentially block access to the account completely. For example, if you have a `n/n`
* Safe (so `threshold == ownerCount`) and one of the owners is the Safe itself and not
* an EIP-7702 delegated account, then it will not be possible to produce a valid
* signature for the Safe. ⚠️⚠️⚠️
* @param prevOwner Owner that pointed to the `oldOwner` to be replaced in the linked list.
* If the owner to be replaced is the first (or only) element of the list,
* `prevOwner` MUST be set to the sentinel address `0x1` (referred to as
* `SENTINEL_OWNERS` in the implementation).
* @param oldOwner Owner address to be replaced.
* @param newOwner New owner address.
*/
function swapOwner(address prevOwner, address oldOwner, address newOwner) external;
/**
* @notice Changes the threshold of the Safe to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param _threshold New threshold.
*/
function changeThreshold(uint256 _threshold) external;
/**
* @notice Returns the number of required confirmations for a Safe transaction aka the threshold.
* @return Threshold number.
*/
function getThreshold() external view returns (uint256);
/**
* @notice Returns if `owner` is an owner of the Safe.
* @return Boolean if `owner` is an owner of the Safe.
*/
function isOwner(address owner) external view returns (bool);
/**
* @notice Returns a list of Safe owners.
* @return Array of Safe owners.
*/
function getOwners() external view returns (address[] memory);
}
"
},
"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
},
"lib/openzeppelin-contracts/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
"
},
"lib/osx-commons/contracts/src/permission/auth/auth.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.8;
import {IDAO} from "../../dao/IDAO.sol";
/// @title DAO Authorization Utilities
/// @author Aragon X - 2022-2024
/// @notice Provides utility functions for verifying if a caller has specific permissions in an associated DAO.
/// @custom:security-contact sirt@aragon.org
/// @notice Thrown if a call is unauthorized in the associated DAO.
/// @param dao The associated DAO.
/// @param where The context in which the authorization reverted.
/// @param who The address (EOA or contract) missing the permission.
/// @param permissionId The permission identifier.
error DaoUnauthorized(address dao, address where, address who, bytes32 permissionId);
/// @notice A free function checking if a caller is granted permissions on a target contract via a permission identifier that redirects the approval to a `PermissionCondition` if this was specified in the setup.
/// @param _where The address of the target contract for which `who` receives permission.
/// @param _who The address (EOA or contract) owning the permission.
/// @param _permissionId The permission identifier.
/// @param _data The optional data passed to the `PermissionCondition` registered.
function _auth(
IDAO _dao,
address _where,
address _who,
bytes32 _permissionId,
bytes calldata _data
) view {
if (!_dao.hasPermission(_where, _who, _permissionId, _data))
revert DaoUnauthorized({
dao: address(_dao),
where: _where,
who: _who,
permissionId: _permissionId
});
}
"
}
},
"settings": {
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@aragon/osx/=lib/osx/packages/contracts/src/",
"@aragon/osx-commons-contracts/=lib/osx-commons/contracts/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"ens-contracts.git/=lib/ens-contracts.git/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"osx-commons/=lib/osx-commons/",
"osx/=lib/osx/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}
}}
Submitted on: 2025-09-30 11:33:48
Comments
Log in to comment.
No comments yet.