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",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"remappings": []
},
"sources": {
"contracts/swap/CurvePoolRegistry.sol": {
"content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.30;\r
\r
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";\r
\r
/**\r
*⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\r
*⠀⠀⠀⠀⠈⢻⣿⠛⠻⢷⣄⠀⠀ ⣴⡟⠛⠛⣷⠀ ⠘⣿⡿⠛⠛⢿⡇⠀⠀⠀⠀\r
*⠀⠀⠀⠀⠀⢸⣿⠀⠀ ⠈⣿⡄⠀⠿⣧⣄⡀ ⠉⠀⠀ ⣿⣧⣀⣀⡀⠀⠀⠀⠀⠀\r
*⠀⠀⠀⠀⠀⢸⣿⠀⠀ ⢀⣿⠃ ⣀ ⠈⠉⠻⣷⡄⠀ ⣿⡟⠉⠉⠁⠀⠀⠀⠀⠀\r
*⠀⠀⠀⠀⢠⣼⣿⣤⣴⠿⠋⠀ ⠀⢿⣦⣤⣴⡿⠁ ⢠⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\r
*\r
* - Defining Successful Future -\r
*\r
* @title CurvePoolRegistry\r
* @author Andrei Averin — CTO dsf.finance\r
* @notice Centralized, owner-controlled registry for whitelisting safe and verified Curve pools.\r
* @dev\r
* - Intended to be consumed by aggregator modules (e.g., CurveDexModule).\r
* - Stores:\r
* (1) Per-(tokenA, tokenB) allowlist of pools (strict routing allowlist).\r
* (2) Minimal per-pool call profile for `exchange(...)` (non-underlying branch).\r
* - Pair allowlist is keyed by `keccak256(sorted(tokenA, tokenB))`.\r
* - Admin (owner) can atomically set/clear allowlists and update per-pool profiles.\r
* - The profile exposes three booleans:\r
* `exIndexUint` : true => `exchange(uint256,uint256,...)`, false => `exchange(int128,int128,...)`\r
* `exHasEthFlag` : true => non-underlying `exchange(..., bool use_eth)` (5-arg/6-arg forms)\r
* `exHasReceiver` : true => presence of receiver overloads `exchange(..., address)` / `exchange(..., bool, address)`\r
* `exHasReceiverUnderlying` : true => underlying receiver overloads exist\r
* - The registry also provides view-only probe helpers to heuristically detect a profile off-chain.\r
*/\r
\r
/**\r
* @title IPoolRegistry\r
* @notice Interface for accessing whitelisted pools and their call profiles.\r
*/\r
interface IPoolRegistry {\r
/**\r
* @notice Minimal call profile for non-underlying `exchange(...)`.\r
* @dev\r
* - `exIndexUint` selects indices type: uint256 vs int128.\r
* - `exHasEthFlag` indicates existence of a trailing `bool use_eth` argument in non-underlying exchange.\r
* - `exHasReceiver` indicates presence of receiver overloads (`..., address)` or `(..., bool, address)`.\r
* - `exHasReceiverUnderlying` covers `exchange_underlying(..., address)`/`(..., bool, address)` presence.\r
*/\r
struct PoolProfile {\r
// exchange signatures (non-underlying branch)\r
bool exIndexUint; // true: exchange(uint256,uint256,...) ; false: exchange(int128,int128,...)\r
bool exHasEthFlag; // true: non-underlying exchange has trailing `bool use_eth`\r
bool exHasReceiver; // true: non-underlying exchange has overloads with `address receiver`\r
bool exHasReceiverUnderlying; // underlying: has receiver overloads\r
}\r
\r
/**\r
* @notice Get allowlisted pools for a (tokenA, tokenB) pair.\r
* @param tokenA First token.\r
* @param tokenB Second token.\r
* @return Array of allowlisted pool addresses under the canonical pair key.\r
*/\r
function getVerifiedPools(address tokenA, address tokenB) external view returns (address[] memory);\r
\r
/**\r
* @notice Get a saved profile for a pool.\r
* @param pool Pool address.\r
* @return exists True if a profile is set in the registry.\r
* @return profile The stored PoolProfile ({exIndexUint, exHasEthFlag, exHasReceiver}).\r
*/\r
function getPoolProfile(address pool) external view returns (bool exists, PoolProfile memory profile);\r
\r
/**\r
* @notice Returns stored profile flags for a pool as separate booleans (gas-cheaper in some cases).\r
* @param pool Pool address.\r
* @return exists True if an explicit profile exists.\r
* @return exIndexUint See `PoolProfile.exIndexUint`.\r
* @return exHasEthFlag See `PoolProfile.exHasEthFlag`.\r
* @return exHasReceiver See `PoolProfile.exHasReceiver`.\r
* @return exHasReceiverUnderlying See `PoolProfile.exHasReceiverUnderlying`.\r
*/\r
function getPoolProfileFlags(address pool)\r
external\r
view\r
returns (\r
bool exists,\r
bool exIndexUint,\r
bool exHasEthFlag,\r
bool exHasReceiver,\r
bool exHasReceiverUnderlying\r
);\r
}\r
\r
/**\r
* @title CurvePoolRegistry\r
* @notice Stores and manages the list of officially verified Curve pools for specific token pairs.\r
* @dev Owner is the only actor allowed to mutate storage (allowlists and profiles).\r
*/\r
contract CurvePoolRegistry is Ownable, IPoolRegistry {\r
// events \r
event VerifiedPoolsSet(bytes32 indexed pairKey, address tokenA, address tokenB, address[] pools);\r
event VerifiedPoolsCleared(bytes32 indexed pairKey, address tokenA, address tokenB);\r
event PoolProfileSet(\r
address indexed pool,\r
bool exIndexUint,\r
bool exHasEthFlag,\r
bool exHasReceiver,\r
bool exHasReceiverUnderlying\r
);\r
event PoolProfileCleared(address indexed pool);\r
event DefaultProfileSet(PoolProfile profile);\r
\r
// probe constants\r
uint256 private constant DX = 1;\r
uint256 private constant MIN = 0;\r
\r
// selectors\r
// coins(...)\r
bytes4 private constant COINS_U256 = bytes4(keccak256("coins(uint256)"));\r
bytes4 private constant COINS_I128 = bytes4(keccak256("coins(int128)"));\r
// non-underlying exchange base\r
bytes4 private constant EX_U256_ETH = bytes4(keccak256("exchange(uint256,uint256,uint256,uint256,bool)"));\r
bytes4 private constant EX_U256 = bytes4(keccak256("exchange(uint256,uint256,uint256,uint256)"));\r
bytes4 private constant EX_I128_ETH = bytes4(keccak256("exchange(int128,int128,uint256,uint256,bool)"));\r
bytes4 private constant EX_I128 = bytes4(keccak256("exchange(int128,int128,uint256,uint256)"));\r
// non-underlying exchange with receiver\r
bytes4 private constant EX_U256_RCV = bytes4(keccak256("exchange(uint256,uint256,uint256,uint256,address)"));\r
bytes4 private constant EX_U256_ETH_RCV = bytes4(keccak256("exchange(uint256,uint256,uint256,uint256,bool,address)"));\r
bytes4 private constant EX_I128_RCV = bytes4(keccak256("exchange(int128,int128,uint256,uint256,address)"));\r
\r
\r
// key: keccak256(sorted(tokenA, tokenB)) => allowlisted pools\r
mapping(bytes32 => address[]) public verifiedPools;\r
\r
// per-pool profile\r
mapping(address => bool) internal exIndexUintOf; // true => exchange(uint256,...)\r
mapping(address => bool) internal exHasEthFlagOf; // true => has trailing `bool use_eth`\r
mapping(address => bool) internal exHasReceiverOf; // true => has overloads with `address receiver`\r
mapping(address => bool) internal exHasReceiverUnderlyingOf;\r
mapping(address => bool) internal hasProfile;\r
\r
PoolProfile private _defaultProfile = PoolProfile({\r
exIndexUint: true,\r
exHasEthFlag: true,\r
exHasReceiver: false,\r
exHasReceiverUnderlying: false\r
});\r
\r
constructor() Ownable(msg.sender) {}\r
\r
/**\r
* @inheritdoc IPoolRegistry\r
*/\r
function getVerifiedPools(address tokenA, address tokenB) \r
external \r
view \r
override \r
returns (address[] memory) \r
{\r
return verifiedPools[_pairKey(tokenA, tokenB)];\r
}\r
\r
/**\r
* @inheritdoc IPoolRegistry\r
*/\r
function getPoolProfile(address pool)\r
external\r
view\r
override\r
returns (bool exists, PoolProfile memory profile)\r
{\r
if (hasProfile[pool]) {\r
profile = PoolProfile({\r
exIndexUint: exIndexUintOf[pool],\r
exHasEthFlag: exHasEthFlagOf[pool],\r
exHasReceiver: exHasReceiverOf[pool],\r
exHasReceiverUnderlying: exHasReceiverUnderlyingOf[pool]\r
});\r
return (true, profile);\r
}\r
return (false, _defaultProfile);\r
}\r
\r
/**\r
* @inheritdoc IPoolRegistry\r
*/\r
function getPoolProfileFlags(address pool)\r
external\r
view\r
override\r
returns (\r
bool exists,\r
bool exIndexUint,\r
bool exHasEthFlag,\r
bool exHasReceiver,\r
bool exHasReceiverUnderlying\r
)\r
{\r
if (hasProfile[pool]) {\r
return (\r
true,\r
exIndexUintOf[pool],\r
exHasEthFlagOf[pool],\r
exHasReceiverOf[pool],\r
exHasReceiverUnderlyingOf[pool]\r
);\r
}\r
IPoolRegistry.PoolProfile memory p = _defaultProfile;\r
return (false, p.exIndexUint, p.exHasEthFlag, p.exHasReceiver, p.exHasReceiverUnderlying);\r
}\r
\r
\r
/**\r
* @notice Returns the current default profile that is used when a pool has no explicit profile.\r
* @return profile The default `PoolProfile`.\r
*/\r
function getDefaultProfile() external view returns (PoolProfile memory) {\r
return _defaultProfile;\r
}\r
\r
/**\r
* @notice Add/replace the allowlist of pools for a (tokenA, tokenB) pair.\r
* @dev Replaces the full list atomically.\r
* @param tokenA First token\r
* @param tokenB Second token\r
* @param pools New full list of allowlisted pools (non-empty)\r
*/\r
function setVerifiedPools(address tokenA, address tokenB, address[] calldata pools)\r
external\r
onlyOwner\r
{\r
require(pools.length > 0, "Registry: empty list");\r
bytes32 key = _pairKey(tokenA, tokenB);\r
verifiedPools[key] = pools;\r
emit VerifiedPoolsSet(key, tokenA, tokenB, pools);\r
}\r
\r
/**\r
* @notice Clear the allowlist for a (tokenA, tokenB) pair.\r
* @param tokenA First token\r
* @param tokenB Second token\r
*/\r
function clearVerifiedPools(address tokenA, address tokenB)\r
external\r
onlyOwner\r
{\r
bytes32 key = _pairKey(tokenA, tokenB);\r
delete verifiedPools[key];\r
emit VerifiedPoolsCleared(key, tokenA, tokenB);\r
}\r
\r
/**\r
* @notice Set/update a pool profile (three flags).\r
* @param pool Pool address (non-zero)\r
* @param exIndexUint true => `exchange(uint256,...)`; false => `exchange(int128,...)`\r
* @param exHasEthFlag true => non-underlying has trailing `bool use_eth`\r
* @param exHasReceiver true => receiver overloads exist (`..., address)` / `(..., bool, address)`\r
* @param exHasReceiverUnderlying true => underlying receiver overloads exist\r
*/\r
function setPoolProfile(\r
address pool,\r
bool exIndexUint,\r
bool exHasEthFlag,\r
bool exHasReceiver,\r
bool exHasReceiverUnderlying\r
)\r
external\r
onlyOwner\r
{\r
require(pool != address(0), "Registry: zero pool");\r
exIndexUintOf[pool] = exIndexUint;\r
exHasEthFlagOf[pool] = exHasEthFlag;\r
exHasReceiverOf[pool] = exHasReceiver;\r
exHasReceiverUnderlyingOf[pool] = exHasReceiverUnderlying;\r
hasProfile[pool] = true;\r
emit PoolProfileSet(pool, exIndexUint, exHasEthFlag, exHasReceiver, exHasReceiverUnderlying);\r
}\r
\r
/**\r
* @notice Batch set/update pool profiles (arrays must be aligned).\r
* @param pools Pool addresses\r
* @param exIndexUint Flags for indices type per pool\r
* @param exHasEthFlag Flags for `use_eth` presence per pool\r
* @param exHasReceiver Flags for receiver overloads per pool\r
* @param exHasReceiverUnderlying Flags for presence of receiver overloads per pool (underlying).\r
*/\r
function setPoolProfiles(\r
address[] calldata pools,\r
bool[] calldata exIndexUint,\r
bool[] calldata exHasEthFlag,\r
bool[] calldata exHasReceiver,\r
bool[] calldata exHasReceiverUnderlying\r
)\r
external\r
onlyOwner\r
{\r
uint256 n = pools.length;\r
require(n > 0, "Registry: empty arrays");\r
require(\r
exIndexUint.length == n &&\r
exHasEthFlag.length == n &&\r
exHasReceiver.length == n &&\r
exHasReceiverUnderlying.length == n,\r
"Registry: bad arrays"\r
);\r
\r
for (uint256 i; i < n; ++i) {\r
address pool = pools[i];\r
require(pool != address(0), "Registry: zero pool");\r
exIndexUintOf[pool] = exIndexUint[i];\r
exHasEthFlagOf[pool] = exHasEthFlag[i];\r
exHasReceiverOf[pool] = exHasReceiver[i];\r
exHasReceiverUnderlyingOf[pool] = exHasReceiverUnderlying[i];\r
hasProfile[pool] = true;\r
emit PoolProfileSet(pool, exIndexUint[i], exHasEthFlag[i], exHasReceiver[i], exHasReceiverUnderlying[i]);\r
}\r
}\r
\r
/**\r
* @notice Delete a saved profile for a pool.\r
* @dev After deletion, calling modules may fall back to defaults or skip routing.\r
* @param pool Pool address\r
*/\r
function clearPoolProfile(address pool) external onlyOwner {\r
delete exIndexUintOf[pool];\r
delete exHasEthFlagOf[pool];\r
delete exHasReceiverOf[pool];\r
delete exHasReceiverUnderlyingOf[pool]; // NEW\r
delete hasProfile[pool];\r
emit PoolProfileCleared(pool);\r
}\r
\r
/**\r
* @notice Sets the global default profile returned when a pool lacks an explicit profile.\r
* @dev Emits {DefaultProfileSet}. Parameter order matches {setPoolProfile} to reduce misconfiguration risk.\r
* @param exIndexUint true => `exchange(uint256,...)`; false => `exchange(int128,...)`\r
* @param exHasEthFlag true => non-underlying has trailing `bool use_eth`\r
* @param exHasReceiver true => non-underlying receiver overloads exist\r
* @param exHasReceiverUnderlying true => underlying receiver overloads exist\r
*/\r
function setDefaultProfile(\r
bool exIndexUint,\r
bool exHasEthFlag,\r
bool exHasReceiver,\r
bool exHasReceiverUnderlying\r
) external onlyOwner {\r
_defaultProfile = PoolProfile({\r
exIndexUint: exIndexUint,\r
exHasEthFlag: exHasEthFlag,\r
exHasReceiver: exHasReceiver,\r
exHasReceiverUnderlying: exHasReceiverUnderlying\r
});\r
emit DefaultProfileSet(_defaultProfile);\r
}\r
\r
/**\r
* @notice Canonical pair key, order-independent.\r
* @param a Token address\r
* @param b Token address\r
* @return Pair key `keccak256(sorted(a, b))`\r
*/\r
function _pairKey(address a, address b) internal pure returns (bytes32) {\r
return a < b ? keccak256(abi.encodePacked(a, b))\r
: keccak256(abi.encodePacked(b, a));\r
}\r
}"
},
"@openzeppelin/contracts/access/Ownable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
}
"
}
}
}}
Submitted on: 2025-11-01 14:17:43
Comments
Log in to comment.
No comments yet.