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/contracts/CapManager.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {OwnableOperable} from "./OwnableOperable.sol";
import {ILiquidityProviderARM} from "./Interfaces.sol";
/**
* @title Manages capital limits of an Automated Redemption Manager (ARM).
* Caps the total assets and individual liquidity provider assets.
* @author Origin Protocol Inc
*/
contract CapManager is Initializable, OwnableOperable {
/// @notice The address of the linked Automated Redemption Manager (ARM).
address public immutable arm;
/// @notice true if a cap is placed on each liquidity provider's account.
bool public accountCapEnabled;
/// @notice The ARM's maximum allowed total assets.
uint248 public totalAssetsCap;
/// @notice The maximum allowed assets for each liquidity provider.
/// This is effectively a whitelist of liquidity providers as a zero amount prevents any deposits.
mapping(address liquidityProvider => uint256 cap) public liquidityProviderCaps;
uint256[48] private _gap;
event LiquidityProviderCap(address indexed liquidityProvider, uint256 cap);
event TotalAssetsCap(uint256 cap);
event AccountCapEnabled(bool enabled);
constructor(address _arm) {
arm = _arm;
}
function initialize(address _operator) external initializer {
_initOwnableOperable(_operator);
accountCapEnabled = false;
}
function postDepositHook(address liquidityProvider, uint256 assets) external {
require(msg.sender == arm, "LPC: Caller is not ARM");
// total assets has already been updated with the new assets
require(totalAssetsCap >= ILiquidityProviderARM(arm).totalAssets(), "LPC: Total assets cap exceeded");
if (!accountCapEnabled) return;
uint256 oldCap = liquidityProviderCaps[liquidityProvider];
require(oldCap >= assets, "LPC: LP cap exceeded");
uint256 newCap = oldCap - assets;
// Save the new LP cap to storage
liquidityProviderCaps[liquidityProvider] = newCap;
emit LiquidityProviderCap(liquidityProvider, newCap);
}
function setLiquidityProviderCaps(address[] calldata _liquidityProviders, uint256 cap)
external
onlyOperatorOrOwner
{
for (uint256 i = 0; i < _liquidityProviders.length; i++) {
liquidityProviderCaps[_liquidityProviders[i]] = cap;
emit LiquidityProviderCap(_liquidityProviders[i], cap);
}
}
/// @notice Set the ARM's maximum total assets.
/// Setting to zero will prevent any further deposits.
/// The liquidity provider can still withdraw assets.
function setTotalAssetsCap(uint248 _totalAssetsCap) external onlyOperatorOrOwner {
totalAssetsCap = _totalAssetsCap;
emit TotalAssetsCap(_totalAssetsCap);
}
/// @notice Enable or disable the account cap.
function setAccountCapEnabled(bool _accountCapEnabled) external onlyOwner {
require(accountCapEnabled != _accountCapEnabled, "LPC: Account cap already set");
accountCapEnabled = _accountCapEnabled;
emit AccountCapEnabled(_accountCapEnabled);
}
}
"
},
"dependencies/@openzeppelin-contracts-upgradeable-5.0.2-5.0.2/contracts/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"src/contracts/OwnableOperable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {Ownable} from "./Ownable.sol";
/**
* @title Base contract that provides ownership and operational control
* @author Origin Protocol Inc
*/
contract OwnableOperable is Ownable {
/// @notice The account that can request and claim withdrawals.
address public operator;
uint256[49] private _gap;
event OperatorChanged(address newAdmin);
function _initOwnableOperable(address _operator) internal {
_setOperator(_operator);
}
/// @notice Set the account that can request and claim withdrawals.
/// @param newOperator The address of the new operator.
function setOperator(address newOperator) external onlyOwner {
_setOperator(newOperator);
}
function _setOperator(address newOperator) internal {
operator = newOperator;
emit OperatorChanged(newOperator);
}
modifier onlyOperatorOrOwner() {
require(msg.sender == operator || msg.sender == _owner(), "ARM: Only operator or owner can call this function.");
_;
}
}
"
},
"src/contracts/Interfaces.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function decimals() external view returns (uint8);
event Transfer(address indexed from, address indexed to, uint256 value);
}
interface IOethARM {
function token0() external returns (address);
function token1() external returns (address);
function owner() external returns (address);
/**
* @notice Swaps an exact amount of input tokens for as many output tokens as possible.
* msg.sender should have already given the ARM contract an allowance of
* at least amountIn on the input token.
*
* @param inToken Input token.
* @param outToken Output token.
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param to Recipient of the output tokens.
*/
function swapExactTokensForTokens(
IERC20 inToken,
IERC20 outToken,
uint256 amountIn,
uint256 amountOutMin,
address to
) external;
/**
* @notice Uniswap V2 Router compatible interface. Swaps an exact amount of
* input tokens for as many output tokens as possible.
* msg.sender should have already given the ARM contract an allowance of
* at least amountIn on the input token.
*
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The input and output token addresses.
* @param to Recipient of the output tokens.
* @param deadline Unix timestamp after which the transaction will revert.
* @return amounts The input and output token amounts.
*/
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/**
* @notice Receive an exact amount of output tokens for as few input tokens as possible.
* msg.sender should have already given the router an allowance of
* at least amountInMax on the input token.
*
* @param inToken Input token.
* @param outToken Output token.
* @param amountOut The amount of output tokens to receive.
* @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
* @param to Recipient of the output tokens.
*/
function swapTokensForExactTokens(
IERC20 inToken,
IERC20 outToken,
uint256 amountOut,
uint256 amountInMax,
address to
) external;
/**
* @notice Uniswap V2 Router compatible interface. Receive an exact amount of
* output tokens for as few input tokens as possible.
* msg.sender should have already given the router an allowance of
* at least amountInMax on the input token.
*
* @param amountOut The amount of output tokens to receive.
* @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
* @param path The input and output token addresses.
* @param to Recipient of the output tokens.
* @param deadline Unix timestamp after which the transaction will revert.
* @return amounts The input and output token amounts.
*/
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function setOwner(address newOwner) external;
function transferToken(address token, address to, uint256 amount) external;
// From OethLiquidityManager
function requestWithdrawal(uint256 amount) external returns (uint256 requestId, uint256 queued);
function claimWithdrawal(uint256 requestId) external;
function claimWithdrawals(uint256[] calldata requestIds) external;
}
interface ILiquidityProviderARM is IERC20 {
function previewDeposit(uint256 assets) external returns (uint256 shares);
function deposit(uint256 assets) external returns (uint256 shares);
function deposit(uint256 assets, address liquidityProvider) external returns (uint256 shares);
function previewRedeem(uint256 shares) external returns (uint256 assets);
function requestRedeem(uint256 shares) external returns (uint256 requestId, uint256 assets);
function claimRedeem(uint256 requestId) external returns (uint256 assets);
function totalAssets() external returns (uint256 assets);
function convertToShares(uint256 assets) external returns (uint256 shares);
function convertToAssets(uint256 shares) external returns (uint256 assets);
function lastTotalAssets() external returns (uint256 assets);
}
interface ICapManager {
function postDepositHook(address liquidityProvider, uint256 assets) external;
}
interface LegacyAMM {
function transferToken(address tokenOut, address to, uint256 amount) external;
}
interface IOriginVault {
function mint(address _asset, uint256 _amount, uint256 _minimumOusdAmount) external;
function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;
function requestWithdrawal(uint256 amount) external returns (uint256 requestId, uint256 queued);
function claimWithdrawal(uint256 requestId) external returns (uint256 amount);
function claimWithdrawals(uint256[] memory requestIds)
external
returns (uint256[] memory amounts, uint256 totalAmount);
function addWithdrawalQueueLiquidity() external;
function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;
function governor() external view returns (address);
function dripper() external view returns (address);
function withdrawalQueueMetadata()
external
view
returns (uint128 queued, uint128 claimable, uint128 claimed, uint128 nextWithdrawalIndex);
function withdrawalRequests(uint256 requestId)
external
view
returns (address withdrawer, bool claimed, uint40 timestamp, uint128 amount, uint128 queued);
function withdrawalClaimDelay() external view returns (uint256);
}
interface IGovernance {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
function state(uint256 proposalId) external view returns (ProposalState);
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
function proposalDeadline(uint256 proposalId) external view returns (uint256);
function proposalEta(uint256 proposalId) external view returns (uint256);
function votingDelay() external view returns (uint256);
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
function queue(uint256 proposalId) external;
function execute(uint256 proposalId) external;
}
interface IWETH is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
interface ISTETH is IERC20 {
event Submitted(address indexed sender, uint256 amount, address referral);
// function() external payable;
function submit(address _referral) external payable returns (uint256);
}
interface IStETHWithdrawal {
event WithdrawalRequested(
uint256 indexed requestId,
address indexed requestor,
address indexed owner,
uint256 amountOfStETH,
uint256 amountOfShares
);
event WithdrawalsFinalized(
uint256 indexed from, uint256 indexed to, uint256 amountOfETHLocked, uint256 sharesToBurn, uint256 timestamp
);
event WithdrawalClaimed(
uint256 indexed requestId, address indexed owner, address indexed receiver, uint256 amountOfETH
);
struct WithdrawalRequestStatus {
/// @notice stETH token amount that was locked on withdrawal queue for this request
uint256 amountOfStETH;
/// @notice amount of stETH shares locked on withdrawal queue for this request
uint256 amountOfShares;
/// @notice address that can claim or transfer this request
address owner;
/// @notice timestamp of when the request was created, in seconds
uint256 timestamp;
/// @notice true, if request is finalized
bool isFinalized;
/// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)
bool isClaimed;
}
function transferFrom(address _from, address _to, uint256 _requestId) external;
function ownerOf(uint256 _requestId) external returns (address);
function requestWithdrawals(uint256[] calldata _amounts, address _owner)
external
returns (uint256[] memory requestIds);
function getLastCheckpointIndex() external view returns (uint256);
function findCheckpointHints(uint256[] calldata _requestIds, uint256 _firstIndex, uint256 _lastIndex)
external
view
returns (uint256[] memory hintIds);
function claimWithdrawals(uint256[] calldata _requestIds, uint256[] calldata _hints) external;
function getWithdrawalStatus(uint256[] calldata _requestIds)
external
view
returns (WithdrawalRequestStatus[] memory statuses);
function getWithdrawalRequests(address _owner) external view returns (uint256[] memory requestsIds);
function getLastRequestId() external view returns (uint256);
}
interface IOracle {
function price(address asset) external view returns (uint256 price);
}
interface IHarvestable {
function collectRewards() external returns (address[] memory tokens, uint256[] memory rewards);
}
interface IMagpieRouter {
function swapWithMagpieSignature(bytes calldata) external payable returns (uint256 amountOut);
}
library DistributionTypes {
struct IncentivesProgramCreationInput {
string name;
address rewardToken;
uint104 emissionPerSecond;
uint40 distributionEnd;
}
}
library IDistributionManager {
struct AccruedRewards {
uint256 amount;
bytes32 programId;
address rewardToken;
}
}
interface SiloIncentivesControllerGaugeLike {
function claimRewards(address _to) external returns (IDistributionManager.AccruedRewards[] memory accruedRewards);
function createIncentivesProgram(DistributionTypes.IncentivesProgramCreationInput memory _incentivesProgramInput)
external;
function getAllProgramsNames() external view returns (string[] memory programsNames);
function getRewardsBalance(address _user, string memory _programName)
external
view
returns (uint256 unclaimedRewards);
function incentivesPrograms(bytes32)
external
view
returns (
uint256 index,
address rewardToken,
uint104 emissionPerSecond,
uint40 lastUpdateTimestamp,
uint40 distributionEnd
);
function owner() external view returns (address);
}
interface IEETHWithdrawal {
function requestWithdraw(address receipient, uint256 amount) external returns (uint256 requestId);
}
interface IEETHWithdrawalNFT {
function finalizeRequests(uint256 requestId) external;
function claimWithdraw(uint256 requestId) external;
function batchClaimWithdraw(uint256[] calldata requestIds) external;
}
interface IEETHRedemptionManager {
function redeemWeEth(uint256 amount, address receiver) external;
function canRedeem(uint256 amount) external view returns (bool);
}
interface IDistributor {
function claim(
address[] calldata users,
address[] calldata tokens,
uint256[] calldata amounts,
bytes32[][] calldata proofs
) external;
}
"
},
"src/contracts/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
/**
* @title Base contract that provides ownership control
* @author Origin Protocol Inc
*/
contract Ownable {
/// @notice The slot used to store the owner of the contract.
/// This is also used as the proxy admin.
/// keccak256(“eip1967.proxy.admin”) - 1 per EIP 1967
bytes32 internal constant OWNER_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
event AdminChanged(address previousAdmin, address newAdmin);
constructor() {
assert(OWNER_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_setOwner(msg.sender);
}
/// @notice The contract owner and proxy admin.
function owner() public view returns (address) {
return _owner();
}
/// @notice Set the owner and proxy admin of the contract.
/// @param newOwner The address of the new owner.
function setOwner(address newOwner) external onlyOwner {
_setOwner(newOwner);
}
function _owner() internal view returns (address ownerOut) {
bytes32 position = OWNER_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
ownerOut := sload(position)
}
}
function _setOwner(address newOwner) internal {
emit AdminChanged(_owner(), newOwner);
bytes32 position = OWNER_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(position, newOwner)
}
}
function _onlyOwner() internal view {
require(msg.sender == _owner(), "ARM: Only owner can call this function.");
}
modifier onlyOwner() {
_onlyOwner();
_;
}
}
"
}
},
"settings": {
"remappings": [
"dependencies/@pendle-sy-1.0.0-1.0.0/:@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-4.9.3-4.9.3/contracts/",
"contracts/=src/contracts/",
"script/=script/",
"test/=test/",
"utils/=src/contracts/utils/",
"@solmate/=dependencies/solmate-6.7.0/src/",
"forge-std/=dependencies/forge-std-1.9.7/src/",
"@pendle-sy/=dependencies/@pendle-sy-1.0.0-1.0.0/contracts/",
"@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.0.2-5.0.2/contracts/",
"@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.0.2-5.0.2/contracts/"
],
"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-10-30 14:07:12
Comments
Log in to comment.
No comments yet.