文件 1 的 1:LSVProxyRegistry.sol
pragma solidity =0.8.10;
contract MainnetActionsUtilAddresses {
address internal constant DFS_REG_CONTROLLER_ADDR = 0xF8f8B3C98Cf2E63Df3041b73f80F362a4cf3A576;
address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b;
address internal constant DFS_LOGGER_ADDR = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3;
address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90;
address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
address internal constant LSV_PROXY_REGISTRY_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant TRANSIENT_STORAGE = 0x2F7Ef2ea5E8c97B8687CA703A0e50Aa5a49B7eb2;
}
contract ActionsUtilHelper is MainnetActionsUtilAddresses {
}
contract MainnetAuthAddresses {
address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD;
address internal constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9;
}
contract AuthHelper is MainnetAuthAddresses {
}
contract AdminVault is AuthHelper {
address public owner;
address public admin;
error SenderNotAdmin();
constructor() {
owner = msg.sender;
admin = ADMIN_ADDR;
}
function changeOwner(address _owner) public {
if (admin != msg.sender){
revert SenderNotAdmin();
}
owner = _owner;
}
function changeAdmin(address _admin) public {
if (admin != msg.sender){
revert SenderNotAdmin();
}
admin = _admin;
}
}
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint256 digits);
function totalSupply() external view returns (uint256 supply);
function balanceOf(address _owner) external view returns (uint256 balance);
function transfer(address _to, uint256 _value) external returns (bool success);
function transferFrom(
address _from,
address _to,
uint256 _value
) external returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
library Address {
error InsufficientBalance(uint256 available, uint256 required);
error SendingValueFail();
error InsufficientBalanceForCall(uint256 available, uint256 required);
error NonContractCall();
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
uint256 balance = address(this).balance;
if (balance < amount){
revert InsufficientBalance(balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!(success)){
revert SendingValueFail();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return
functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
uint256 balance = address(this).balance;
if (balance < value){
revert InsufficientBalanceForCall(balance, value);
}
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint256 weiValue,
string memory errorMessage
) private returns (bytes memory) {
if (!(isContract(target))){
revert NonContractCall();
}
(bool success, bytes memory returndata) = target.call{value: weiValue}(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(
value,
"SafeERC20: decreased allowance below zero"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(
data,
"SafeERC20: low-level call failed"
);
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
contract AdminAuth is AuthHelper {
using SafeERC20 for IERC20;
AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR);
error SenderNotOwner();
error SenderNotAdmin();
modifier onlyOwner() {
if (adminVault.owner() != msg.sender){
revert SenderNotOwner();
}
_;
}
modifier onlyAdmin() {
if (adminVault.admin() != msg.sender){
revert SenderNotAdmin();
}
_;
}
function withdrawStuckFunds(address _token, address _receiver, uint256 _amount) public onlyOwner {
if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
payable(_receiver).transfer(_amount);
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
function kill() public onlyAdmin {
selfdestruct(payable(msg.sender));
}
}
abstract contract DSAuthority {
function canCall(
address src,
address dst,
bytes4 sig
) public view virtual returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority(address indexed authority);
event LogSetOwner(address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
constructor() {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_) public auth {
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_) public auth {
authority = authority_;
emit LogSetAuthority(address(authority));
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig), "Not authorized");
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(address(0))) {
return false;
} else {
return authority.canCall(src, address(this), sig);
}
}
}
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint256 wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
abstract contract DSProxy is DSAuth, DSNote {
DSProxyCache public cache;
constructor(address _cacheAddr) {
if (!(setCache(_cacheAddr))){
require(isAuthorized(msg.sender, msg.sig), "Not authorized");
}
}
receive() external payable {}
function execute(bytes memory _code, bytes memory _data)
public
payable
virtual
returns (address target, bytes32 response);
function execute(address _target, bytes memory _data)
public
payable
virtual
returns (bytes32 response);
function setCache(address _cacheAddr) public payable virtual returns (bool);
}
contract DSProxyCache {
mapping(bytes32 => address) cache;
function read(bytes memory _code) public view returns (address) {
bytes32 hash = keccak256(_code);
return cache[hash];
}
function write(bytes memory _code) public returns (address target) {
assembly {
target := create(0, add(_code, 0x20), mload(_code))
switch iszero(extcodesize(target))
case 1 {
revert(0, 0)
}
}
bytes32 hash = keccak256(_code);
cache[hash] = target;
}
}
abstract contract DSProxyFactoryInterface {
function build(address owner) public virtual returns (DSProxy proxy);
function build() public virtual returns (DSProxy proxy);
}
contract MainnetUtilAddresses {
address internal refillCaller = 0x33fDb79aFB4456B604f376A45A546e7ae700e880;
address internal feeAddr = 0x76720aC2574631530eC8163e4085d6F98513fb27;
address internal constant BOT_REGISTRY_ADDRESS = 0x637726f8b08a7ABE3aE3aCaB01A80E2d8ddeF77B;
address internal constant UNI_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address internal constant MKR_PROXY_REGISTRY = 0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4;
address internal constant AAVE_MARKET = 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5;
address internal constant PROXY_FACTORY_ADDR = 0xA26e15C895EFc0616177B7c1e7270A4C7D51C997;
address internal constant DFS_PROXY_REGISTRY_ADDR = 0x29474FdaC7142f9aB7773B8e38264FA15E3805ed;
address internal constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant WSTETH_ADDR = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
address internal constant STETH_ADDR = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
address internal constant WBTC_ADDR = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address internal constant CHAINLINK_WBTC_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
address internal constant DAI_ADDR = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address internal constant FEE_RECEIVER_ADMIN_ADDR = 0xA74e9791D7D66c6a14B2C571BdA0F2A1f6D64E06;
address internal constant UNI_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address internal constant UNI_V3_QUOTER = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6;
address internal constant FEE_RECIPIENT = 0x39C4a92Dc506300c3Ea4c67ca4CA611102ee6F2A;
address internal constant DEFAULT_BOT = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public constant CHAINLINK_FEED_REGISTRY = 0x47Fb2585D2C56Fe188D0E6ec628a38b74fCeeeDf;
}
contract UtilHelper is MainnetUtilAddresses{
}
contract LSVProxyRegistry is AdminAuth, UtilHelper, ActionsUtilHelper {
mapping(address => address[]) public proxies;
address[] public proxyPool;
event NewProxy(address, address);
event ChangedOwner(address oldOwner, address newOwner, address proxy);
function addNewProxy() public returns (address) {
address newProxy = getFromPoolOrBuild(msg.sender);
proxies[msg.sender].push(newProxy);
emit NewProxy(msg.sender, newProxy);
return newProxy;
}
function updateRegistry(address _proxyAddr, address _oldOwner, uint256 _indexNumInOldOwnerProxiesArr) public {
require(DSProxy(payable(_proxyAddr)).owner() == msg.sender);
require(proxies[_oldOwner][_indexNumInOldOwnerProxiesArr] == _proxyAddr);
uint256 oldOwnersProxyCount = proxies[_oldOwner].length;
if (oldOwnersProxyCount > 1 && _indexNumInOldOwnerProxiesArr < (oldOwnersProxyCount - 1)) {
proxies[_oldOwner][_indexNumInOldOwnerProxiesArr] = proxies[_oldOwner][oldOwnersProxyCount - 1];
}
proxies[_oldOwner].pop();
proxies[msg.sender].push(_proxyAddr);
}
function addToPool(uint256 _numNewProxies) public {
for (uint256 i = 0; i < _numNewProxies; ++i) {
DSProxy newProxy = DSProxyFactoryInterface(PROXY_FACTORY_ADDR).build();
proxyPool.push(address(newProxy));
}
}
function getProxies(address _user) public view returns (address[] memory){
address[] memory resultProxies = new address[](proxies[_user].length);
for (uint256 i = 0; i < proxies[_user].length; i++){
resultProxies[i] = proxies[_user][i];
}
return resultProxies;
}
function getProxyPoolCount() public view returns (uint256) {
return proxyPool.length;
}
function getFromPoolOrBuild(address _user) internal returns (address) {
if (proxyPool.length > 0) {
address newProxy = proxyPool[proxyPool.length - 1];
proxyPool.pop();
DSAuth(newProxy).setOwner(_user);
return newProxy;
} else {
DSProxy newProxy = DSProxyFactoryInterface(PROXY_FACTORY_ADDR).build(_user);
return address(newProxy);
}
}
}