MurePool
Inherits: EIP712Upgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable, ERC165Upgradeable, AccessControlUpgradeable, PoolApp
Title: MurePool
Author: Mure
Facilitates secure and configurable pool management, supporting operations such as pool creation, deposits, withdrawals, and refunds.
Core implementation contract for pooled investments in the Mure protocol. Utilizes the beacon proxy pattern to deploy multiple proxies, each representing a distinct application within the protocol. The MureFactory contract handles these deployments. Implements the EIP-712 standard for signature validation, preventing unauthorized access. Relies on the MureConfig contract to verify EIP-712 signatures and manage the pool creation process. Interaction with the MureConfig contract allows dynamic configuration and signature validation. Security measures include the OpenZeppelin PausableUpgradeable pattern for emergency pausing, ReentrancyGuardUpgradeable to prevent reentrancy attacks, and role based access control through AccessControlUpgradeable. Flag-based functionality enables features like refundability, passthrough of funds, and more. Provides hooks for custom functionality in pool-related operations Depending on the kind of application, the MurePool proxy instance could be linked to a MureDelegate proxy instance for interacting with various plugins that the protocol provides.
State Variables
MurePoolStorageLocation
Hash for storage location
keccak256(abi.encode(uint256(keccak256("mure.MurePool")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant MurePoolStorageLocation =
0x79bd164051f83036bb52eee1d9b6be5ba887eaf3a9d8907adbaadfa56c970700
PoolMetricsStorageLocation
Hash for storage location
keccak256(abi.encode(uint256(keccak256("mure.PoolMetrics")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PoolMetricsStorageLocation =
0x1ca3e723ed845754b3d7cf12c13e1b284ab752e694e983a627f991c98b3a0700
DEPOSIT_HASH
Struct hash for validating deposits
keccak256("Deposit(uint256 amount,string pool,address depositor,uint8 nonce,address caller,FeeConfig feeConfig,bytes permitSig)FeeConfig(uint112 amount,address recipient)")
bytes32 private constant DEPOSIT_HASH = 0xc89d53aaf3bcb1537286e629ce2d0d2490185593558793ccb9d770ed5a9b85ba
DEPOSIT_PERMIT_HASH
Struct hash for validating deposit permits
keccak256("DepositPermit(uint256 amount,string pool,address caller,uint256 depositorNonce)")
bytes32 private constant DEPOSIT_PERMIT_HASH = 0xc366e7e07f30c8c114e87a55f528d0226c44edffd2f25b0230dd00e3263a349c
CREATE_POOL_HASH
Struct hash for validating pool creation
keccak256("CreatePool(string pool,uint32 endTime,uint24 nonce)")
bytes32 private constant CREATE_POOL_HASH = 0x38c6f9238aff6821963f06d84f958ebb018ff9e4343c962882ef7b3308ff1b4d
MURE_CONFIG
Address for the MureConfig contract
Update config address
address constant MURE_CONFIG = 0x2b727332eF478bAe460ecF0CAb7C1487a87D68B8
INITIALIZED
Defines if the pool is initialized
uint16 constant INITIALIZED = 0x01
PAUSED
Defines if the pool is paused from any interaction
uint16 constant PAUSED = 0x02
PASSTHROUGH_FUNDS
PASSTHROUGH_FUNDS and REFUNDABLE cannot be set at the same time
Defines if deposits should pass straight to associtated raising wallet upon deposit
uint16 constant PASSTHROUGH_FUNDS = 0x04
REFUNDABLE
PASSTHROUGH_FUNDS and REFUNDABLE cannot be set at the same time
Defines if the pool is open for claiming refunds
uint16 constant REFUNDABLE = 0x08
TIERED
Defines if the pool is having tiers and gating
uint16 constant TIERED = 0x10
CROSS_CHAIN
Defines if the pool is cross-chain enabled, pooling funds across different networks
uint16 constant CROSS_CHAIN = 0x20
DELEGATED
Defines if the pool allows for use of delegated wallets for security
uint16 constant DELEGATED = 0x40
Functions
poolValid
modifier poolValid(string calldata poolName) ;
poolActive
modifier poolActive(string calldata poolName) ;
poolNotPaused
modifier poolNotPaused(string calldata poolName) ;
valid
modifier valid(PoolParameters calldata params) ;
onlyDelegateOrOperator
modifier onlyDelegateOrOperator() ;
onlyDelegate
modifier onlyDelegate() ;
notDelegated
modifier notDelegated() ;
initialize
function initialize(string calldata name, string calldata version, AppMember[] calldata members)
external
initializer;
createPool
Creates a new pool with the specified parameters.
Requires the pool to not already exist. Can only be called by a pool operator.
function createPool(string calldata poolName, PoolParameters calldata params, bytes memory sig)
external
onlyRole(POOL_OPERATOR_ROLE)
valid(params);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to create |
params | PoolParameters | the parameters for the new pool |
sig | bytes | the signature generated for pool creation for client |
updatePool
Updates the specified pool with the provided parameters.
Requires the pool to exist. Can only be called by a pool operator.
Requires the updated pool size to be greater than or equal to the total amount collected.
function updatePool(string calldata poolName, PoolParameters calldata params)
external
onlyRole(POOL_OPERATOR_ROLE)
valid(params)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
params | PoolParameters | the updated parameters for the pool |
updatePoolSize
Updates the size of the specified pool.
Requires the pool to exist. Can only be called by a pool operator.
Requires the new pool size to be greater than or equal to the total amount collected.
function updatePoolSize(string calldata poolName, uint256 poolSize)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
poolSize | uint256 | the updated size of the pool |
updatePoolEndTime
Updates the end time of the specified pool.
Requires the pool to exist. Can only be called by a pool operator.
function updatePoolEndTime(string calldata poolName, uint256 endTime)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
endTime | uint256 | the updated end time for the pool |
updatePoolSigner
Updates the signer of the specified pool.
Requires the pool to exist. Can only be called by a pool operator.
function updatePoolSigner(string calldata poolName, address _signer)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
_signer | address | the updated signer for the pool |
updatePoolPaused
Pauses or unpauses the specified pool.
Requires the pool to exist. Can only be called by a pool operator or delegate.
function updatePoolPaused(string calldata poolName, bool pause)
external
onlyDelegateOrOperator
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to pause or unpause |
pause | bool | a boolean representing whether to pause or unpause the pool |
updatePoolRefundable
Updates whether the specified pool allows refunds or not.
Requires the pool to exist. Can only be called by a pool operator.
Requires that the pool does not have the PASSTHROUGH_FUNDS flag set if enabling refunds.
function updatePoolRefundable(string calldata poolName, bool refundable)
external
onlyDelegateOrOperator
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
refundable | bool | a boolean representing whether refunds should be enabled or not |
updatePoolPassthroughFunds
Updates whether the specified pool passes funds through to the custodian directly or not.
Requires the pool to exist. Can only be called by a pool operator.
Requires that the pool does not have the REFUNDABLE flag set if enabling passthrough funds.
function updatePoolPassthroughFunds(string calldata poolName, bool passthroughFunds)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to update |
passthroughFunds | bool | a boolean representing whether to enable passthrough funds or not |
withdrawPoolFunds
Withdraws the total collected amount from the specified pool.
Requires the pool to exist. Can only be called by a pool operator or the delegate if it is set.
function withdrawPoolFunds(string calldata poolName) external onlyDelegateOrOperator poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to withdraw from |
withdrawCurrency
Withdraw any token from the contract. This should only be used in emergencies
as this can withdraw capital from any pool, be it active or not. Always prefer using withdrawPoolFunds
over this function, unless you need clean up the contract by, e.g., burning garbage tokens.
function withdrawCurrency(address receiver, address currency) external onlyRole(DEFAULT_ADMIN_ROLE);
Parameters
| Name | Type | Description |
|---|---|---|
receiver | address | the address to which the token will be transferred |
currency | address | the address of the token contract |
addDeposit
Adds a deposit of the specified amount to the pool for the designated depositor.
Requires the pool to exist. Can only be called by a pool operator.
function addDeposit(string calldata poolName, address depositor, uint256 amount)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to add the deposit to |
depositor | address | the address of the depositor |
amount | uint256 | the amount of the deposit |
deductDeposit
Deducts the specified amount from the deposit of the designated depositor in the pool.
Requires the pool to exist. Can only be called by a pool operator.
function deductDeposit(string calldata poolName, address depositor, uint256 amount)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to deduct the deposit from |
depositor | address | the address of the depositor |
amount | uint256 | the amount to deduct |
moveDeposit
Moves the specified amount from one depositor's deposit to another in the pool.
Requires the pool to exist. Can only be called by a pool operator.
function moveDeposit(string calldata poolName, address from, address to, uint256 amount)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to move the deposit in |
from | address | the address of the depositor to deduct the deposit from |
to | address | the address of the depositor to add the deposit to |
amount | uint256 | the amount to move |
batchDeposit
Adds or deducts balances on a per-depositor basis in batches.
Requires the pool to exist. Can only be called by the contract owner.
function batchDeposit(string calldata poolName, Transaction[] calldata transactions)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to move the deposit in |
transactions | Transaction[] | the set of Transactions to execute on the provided poolName |
batchDeposit
Adds or deducts balances on a per-depositor basis in batches.
Requires the pool to exist. Can only be called by the contract owner.
function batchDeposit(string calldata poolName, TransactionWithMetadata[] calldata transactions)
external
onlyRole(POOL_OPERATOR_ROLE)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to move the deposit in |
transactions | TransactionWithMetadata[] | the set of TransactionWithMetadatas to execute on the provided poolName |
deposit
Deposits amount of the relevant currency for the pool poolName.
This operation assumes that the contract is an approved spender of the depositor.
This operation is disabled for delegated pools, use depositFor instead
function deposit(string calldata poolName, DepositArgs calldata depositDetails) external notDelegated;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | bytes32 representation of the pool name |
depositDetails | DepositArgs | details of the deposit per the DepositArgs struct |
refund
Allows a user to refund their deposited amount from the specified pool. This operation is disabled for delegated pools, use refundTo instead.
Requires the pool to exist.
Requires the pool to be not paused and must have the REFUNDABLE flag set.
function refund(string calldata poolName) external notDelegated;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool from which to refund |
refund
Allows a user to refund their deposited amount from the specified pool. This operation is disabled for delegated pools, use refundTo instead.
Requires the pool to exist.
Requires the pool to be not paused and must have the REFUNDABLE flag set.
function refund(string calldata poolName, bytes calldata data) external notDelegated;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool from which to refund |
data | bytes | additional data as contextual data for off-chain validation |
refundTo
Allows a refund of the deposited amount from the specified pool.
Requires the pool to exist.
Requires the pool to be not paused and must have the REFUNDABLE flag set.
function refundTo(string calldata poolName, address depositor, uint256 amount) external onlyDelegate;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool from which to refund |
depositor | address | address of the depositor |
amount | uint256 |
depositPoolFunds
Deposits the withdrawn pool funds back. This operation assumes that the contract is an approved spender of the depositor.
Transfers the original collected funds back to the pool app
function depositPoolFunds(string calldata poolName, address depositor, uint256 amount) external onlyDelegate;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | name of the pool |
depositor | address | the address of the depositor |
amount | uint256 | the amount to be deposited back to the pool |
poolState
Retrieves the state of the specified pool.
Requires the pool to exist.
function poolState(string calldata poolName) external view poolValid(poolName) returns (PoolState memory);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to retrieve the state of |
poolMetrics
Retrieves the metrics of the specified pool.
Requires the pool to exist.
function poolMetrics(string calldata poolName) external view poolValid(poolName) returns (PoolMetrics memory);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to retrieve the metrics of |
deposited
Retrieves the amount deposited by the specified depositor in the specified pool.
Requires the pool to exist.
function deposited(string calldata poolName, address depositor)
external
view
poolValid(poolName)
returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to retrieve the deposit from |
depositor | address | the address of the depositor |
nonce
Retrieves the nonce of the specified depositor in the specified pool.
Requires the pool to exist.
function nonce(string calldata poolName, address depositor) external view poolValid(poolName) returns (uint8);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to retrieve the nonce from |
depositor | address | the address of the depositor |
nonce
Retrieves the nonce for create pool signature generation.
function nonce() external view returns (uint24);
poolExists
Checks if the specified pool exists.
function poolExists(string calldata pool) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
pool | string | the name of the pool to check for existence |
isPoolActive
Checks if the specified pool is active.
function isPoolActive(string calldata poolName) external view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to check if it is active |
withdrawableAmount
Checks if the specified pool is active.
function withdrawableAmount(string calldata poolName) external view returns (uint112);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool to check if it is active |
supportsInterface
See IERC165-supportsInterface.
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC165Upgradeable, IERC165, AccessControlUpgradeable)
returns (bool);
_grantRolesToMembers
Grants roles to the members based on their specified roles in the struct.
function _grantRolesToMembers(AppMember[] calldata members) private;
Parameters
| Name | Type | Description |
|---|---|---|
members | AppMember[] | An array of AppMember structs containing the member's address and their role to be granted. |
_deposit
Deposits amount of the relevant currency for the pool poolName.
This operation assumes that the contract is an approved spender of the depositor.
function _deposit(string calldata poolName, DepositArgs calldata depositDetails)
private
whenNotPaused
nonReentrant
poolValid(poolName)
poolActive(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | bytes32 representation of the pool name |
depositDetails | DepositArgs | the amount, depositor, payer, permitSig and additional data for the deposit |
_refund
Allows a user to refund their deposited amount from the specified pool.
Requires the pool to exist.
Requires the pool to be not paused and must have the REFUNDABLE flag set.
function _refund(string calldata poolName, address depositor, uint256 amount, bytes memory data)
private
nonReentrant
whenNotPaused
poolNotPaused(poolName)
poolValid(poolName);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool from which to refund |
depositor | address | address of the depositor to refund from |
amount | uint256 | the amount to refund |
data | bytes | additional data as contextual data for off-chain validation |
_depositPoolFunds
Deposits the withdrawn pool funds back.
Transfers the original collected funds back to the pool app
function _depositPoolFunds(string calldata poolName, address depositor, uint256 amount) private nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | name of the pool |
depositor | address | the address of the depositor |
amount | uint256 | the amount to be deposited back to the pool |
_addDeposit
Adds deposit amount to designated poolName under depositor.
As totalCollected is bound by poolSize, overflow is not possible unless poolSize
is in a disallowed state to begin with.
function _addDeposit(string calldata poolName, address depositor, uint256 amount, bytes memory data) private;
_unsafeAddDeposit
Adds deposit amount to designated poolName under depositor.
Skips pool size check. To be used for manual overrides like moveDeposit and batchDeposit
function _unsafeAddDeposit(string calldata poolName, address depositor, uint256 amount, bytes memory data) private;
_deductDeposit
Deducts deposit amount from designated poolName under depositor.
As totalCollected is the cumulative sum of all depositors under poolName,
underflow is not possible unless totalCollected is in a disallowed state to begin with.
function _deductDeposit(string calldata poolName, address depositor, uint256 amount, bytes memory data) private;
_transferUpdate
Updates the transfer between two addresses with a specified amount of a given currency.
function _transferUpdate(address from, address to, uint256 amount, address currency) private;
Parameters
| Name | Type | Description |
|---|---|---|
from | address | the address from which the transfer is initiated |
to | address | the address to which the transfer is made |
amount | uint256 | the amount of the currency being transferred |
currency | address | the address of the currency being transferred |
_poolExists
Checks whether a pool with the specified name exists.
function _poolExists(string calldata pool) private view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
pool | string | the name of the pool being checked |
_verifyParams
Verifies the validity of the specified pool parameters.
function _verifyParams(PoolParameters calldata config) private pure;
Parameters
| Name | Type | Description |
|---|---|---|
config | PoolParameters | the parameters of the pool being verified |
_poolComplete
Checks whether the specified pool has been completed.
function _poolComplete(string calldata poolName) private view returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool being checked |
_hashDeposit
Generates a hashed representation of the specified amount and pool name, along with the sender's nonce.
function _hashDeposit(
uint256 amount,
string calldata poolName,
address depositor,
address caller,
FeeConfig memory feeConfig,
bytes memory permitSig
) internal view returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | the amount of the deposit |
poolName | string | the name of the pool |
depositor | address | address of the depositor |
caller | address | |
feeConfig | FeeConfig | |
permitSig | bytes | signature to permit deposit on behalf of user |
_hashCreatePool
Generates a struct hash of the specified pool name and end time, along with the nonce.
function _hashCreatePool(string calldata poolName, uint32 endTime) private view returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | the name of the pool |
endTime | uint32 | the endtime block timestamp for the pool |
_verifyPoolSize
Verifies the validity of the pool size for an existing pool.
function _verifyPoolSize(uint112 totalCollected, uint112 newPoolSize) private pure;
Parameters
| Name | Type | Description |
|---|---|---|
totalCollected | uint112 | total collected amount for the pool being updated |
newPoolSize | uint112 | new pool size for the pool being updated |
_hasFlag
Checks whether a specific flag is activated within a set of flags.
function _hasFlag(uint16 flags, uint16 flag) private pure returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
flags | uint16 | the set of flags being checked |
flag | uint16 | the flag being checked for activation |
_activateFlag
Activates the specified flag within a set of flags.
function _activateFlag(uint16 flags, uint16 flag) private pure returns (uint16);
Parameters
| Name | Type | Description |
|---|---|---|
flags | uint16 | the set of flags being modified |
flag | uint16 | the flag being activated |
_deactivateFlag
Deactivates the specified flag within a set of flags.
function _deactivateFlag(uint16 flags, uint16 flag) private pure returns (uint16);
Parameters
| Name | Type | Description |
|---|---|---|
flags | uint16 | the set of flags being modified |
flag | uint16 | the flag being deactivated |
_getDelegateAddress
Retrieves the delegate address from config.
function _getDelegateAddress() private returns (address delegate);
_beforeDeposit
Performs delegate operations before deposit operation.
function _beforeDeposit(
address delegateAddress,
string calldata poolName,
uint256 amount,
address depositor,
bytes calldata sig
) private;
Parameters
| Name | Type | Description |
|---|---|---|
delegateAddress | address | address of the delegate contract |
poolName | string | name of the pool |
amount | uint256 | deposit amount |
depositor | address | |
sig | bytes | deposit signature |
_afterDeposit
Performs delegate operations after deposit operation.
function _afterDeposit(
address delegateAddress,
string calldata poolName,
uint256 amount,
address depositor,
bytes calldata sig
) private;
Parameters
| Name | Type | Description |
|---|---|---|
delegateAddress | address | address of the delegate contract |
poolName | string | name of the pool |
amount | uint256 | deposit amount |
depositor | address | |
sig | bytes | deposit signature |
_beforeRefund
Performs delegate operations before refund operation.
function _beforeRefund(address delegateAddress, string calldata poolName, address depositor) private;
Parameters
| Name | Type | Description |
|---|---|---|
delegateAddress | address | address of the delegate contract |
poolName | string | name of the pool |
depositor | address | address of the depositor |
_afterRefund
Performs delegate operations after refund operation.
function _afterRefund(address delegateAddress, string calldata poolName, address depositor, uint256 amount)
private;
Parameters
| Name | Type | Description |
|---|---|---|
delegateAddress | address | address of the delegate contract |
poolName | string | name of the pool |
depositor | address | address of the depositor |
amount | uint256 | the refund amount |
_consumeDepositorNonce
Increments depositor's nonce for the pool.
function _consumeDepositorNonce(string calldata poolName, address depositor, DepositRecord storage deposit_)
private;
Parameters
| Name | Type | Description |
|---|---|---|
poolName | string | |
depositor | address | |
deposit_ | DepositRecord | reference to the deposit record |
_getStorage
Retrieves the storage for the MurePool contract.
function _getStorage() private pure returns (MurePoolStorage storage $);
_getPoolMetricsStorage
Retrieves the storage for the pool metrics.
function _getPoolMetricsStorage() private pure returns (PoolMetricsStorage storage $);
_verifySignature
function _verifySignature(
DepositArgs memory depositDetails,
string calldata poolName,
address signer,
bytes calldata depositSig
) private view;
_hashDepositPermit
function _hashDepositPermit(DepositPermit memory permit) internal view returns (bytes32);
_verifyDepositPermit
function _verifyDepositPermit(DepositPermit memory permit, bytes memory permitSig) internal view;
Structs
MurePoolStorage
Note: storage-location: erc7201:mure.MurePool
struct MurePoolStorage {
mapping(string => PoolState) pools;
mapping(string => mapping(address => DepositRecord)) deposits;
uint24 nonce;
}
PoolMetricsStorage
Note: storage-location: erc7201:mure.PoolMetrics
struct PoolMetricsStorage {
mapping(string => PoolMetrics) poolMetrics;
}