Address Contract Verified
Address
0xDC9718E7704f10DB1aFaad737f8A04bcd14C20AA
Balance
0 ETH
Nonce
293
Code Size
7603 bytes
Creator
0x000755Fb...ff62 at tx 0x1d99eb13...ad43e9
Indexed Transactions
0
Contract Bytecode
7603 bytes
0x608060405234801561001057600080fd5b50600436106101215760003560e01c8063918f8674116100ad578063bba48a9011610071578063bba48a90146102d7578063d4bba87b146102fe578063f7a6bc7b14610325578063f7c618c114610362578063fb7049cd1461038957600080fd5b8063918f8674146102425780639ed9331814610259578063a77f02451461027a578063a8c62e7614610295578063ba32c619146102bc57600080fd5b80634e8090ce116100f45780634e8090ce146101af57806358a13f08146101d657806362810e1a146101f1578063759cb53b1461020c57806375b0ffd11461022757600080fd5b80631326c2471461012657806322884e2c1461015e578063401c9eec1461017957806348fc3c2d14610194575b600080fd5b61014173baf05d7aa4129ca14ec45cc9d4103a9ab9a9ff6081565b6040516001600160a01b0390911681526020015b60405180910390f35b610141732f50d538606fa9edd2b11e2446beb18c9d5846bb81565b61014173d67bdbeff01fc492f1864e61756e5fbb3f17350681565b610141730c30476f66034e11782938df8e4384970b6c9e8a81565b6101417f000000000000000000000000c1e4775b3a589784aacd15265ac39d3b3c13ca3c81565b610141739c99dffc1de1aff7e7c1f36fcdd49063a281e18c81565b61014173539e65190a371ce73244a98dec42ba635cca512c81565b610141734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b61014173f403c135812408bfbe8713b5a23a04b3d48aae3181565b61024b61271081565b604051908152602001610155565b61026c61026736600461192e565b61039e565b604051610155929190611952565b610141734e795a6f991e305e3f28a3b1b2b4b9789d2cd5a181565b6101417f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd81565b6101417373968b9a57c6e53d41345fd57a6e6ae27d6cdb2f81565b6101417f0000000000000000000000005940611b5d6f16ea670f032f13e8a09567a8dff581565b6101417f000000000000000000000000d24d1fa18605006d222fbfe8476858b2dfc9a04e81565b61033861033336600461197a565b6103b3565b604080516001600160a01b0394851681529284166020840152921691810191909152606001610155565b6101417f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5281565b61039c61039736600461192e565b610921565b005b6000806103aa836109d2565b91509150915091565b600080600080600073f403c135812408bfbe8713b5a23a04b3d48aae316001600160a01b0316631526fe27896040518263ffffffff1660e01b81526004016103fd91815260200190565b60c060405180830381865afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e91906119bc565b505050925050915085156104d457604051630ecaea7360e01b81526001600160a01b038316600482015260248101899052734e795a6f991e305e3f28a3b1b2b4b9789d2cd5a190630ecaea73906044016020604051808303816000875af11580156104ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d19190611a43565b92505b861561054a576104e3816109d2565b604080516001600160a01b03848116825283811660208301528681168284015285811660608301528716608082015290519297509095507fb9b8d50b80f9a41ca6bb6a3e3e8fc694fe041d8059f91a504be694b820cd0573919081900360a00190a1610916565b604051632a704bc360e21b81526001600160a01b0382811660048301526000917f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd9091169063a9c12f0c90602401602060405180830381865afa1580156105b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d99190611a43565b604051636eb1769f60e11b8152909150734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b9063dd62ed3e90610635907f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd908590600401611952565b602060405180830381865afa158015610652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106769190611a60565b600003610772576040516001600160a01b03828116602483015260001960448301527f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd169063b61d27f690734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b9060009060640160408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b1790525160e085901b6001600160e01b031916815261072893929190600401611ac9565b6000604051808303816000875af1158015610747573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261076f9190810190611b83565b50505b604051632474e32f60e11b8152734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b60048201526000906001600160a01b038316906348e9c65e9060240160c060405180830381865afa1580156107cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f19190611be8565b6020015190506001600160a01b038116610913577f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd6001600160a01b031663b61d27f6836000734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b7f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd60405160240161087e929190611952565b60408051601f198184030181529181526020820180516001600160e01b031663e8de0d4d60e01b1790525160e085901b6001600160e01b03191681526108c993929190600401611ac9565b6000604051808303816000875af11580156108e8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109109190810190611b83565b50505b50505b505093509350939050565b604051632a704bc360e21b81526001600160a01b0382811660048301526000917f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd9091169063a9c12f0c90602401602060405180830381865afa15801561098c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b09190611a43565b90506001600160a01b0381166109c4575050565b6109ce828261101b565b5050565b6000806109de836112ff565b6109fb57604051633859027960e21b815260040160405180910390fd5b604051632a704bc360e21b81526001600160a01b0384811660048301526000917f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd9091169063a9c12f0c90602401602060405180830381865afa158015610a66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8a9190611a43565b6001600160a01b031614610ab1576040516345f0cd7160e01b815260040160405180910390fd5b6000610abc84611401565b9050610ae77f000000000000000000000000c1e4775b3a589784aacd15265ac39d3b3c13ca3c611465565b60408051606084811b6bffffffffffffffffffffffff1990811660208085018290528a841b8316603486015285516028818703018152604886018752805191012060688501919091527f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd831b8216607c8501529185901b1660908301528251608481840301815260a490920190925291935090610bae7f0000000000000000000000005940611b5d6f16ea670f032f13e8a09567a8dff56001600160a01b03168284611472565b94506000610bbb84611489565b60405163819dc9fb60e01b81529092506001600160a01b038716915063819dc9fb90610c4990899030907373968b9a57c6e53d41345fd57a6e6ae27d6cdb2f90730c30476f66034e11782938df8e4384970b6c9e8a9073d67bdbeff01fc492f1864e61756e5fbb3f17350690739c99dffc1de1aff7e7c1f36fcdd49063a281e18c9086908b90600401611c74565b600060405180830381600087803b158015610c6357600080fd5b505af1158015610c77573d6000803e3d6000fd5b50505050856001600160a01b0316638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610cb657600080fd5b505af1158015610cca573d6000803e3d6000fd5b5050604051631370877b60e11b81526001600160a01b0389811660048301527f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd1692506326e10ef69150602401600060405180830381600087803b158015610d3157600080fd5b505af1158015610d45573d6000803e3d6000fd5b50506040516308df9b5960e21b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd16925063237e6d649150610d979087908b90600401611952565b600060405180830381600087803b158015610db157600080fd5b505af1158015610dc5573d6000803e3d6000fd5b50506040516314f3279560e21b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd1692506353cc9e549150610e17908a908990600401611952565b600060405180830381600087803b158015610e3157600080fd5b505af1158015610e45573d6000803e3d6000fd5b50506040516329de95bf60e01b815273539e65190a371ce73244a98dec42ba635cca512c60048201526001600160a01b03881692506329de95bf9150602401600060405180830381600087803b158015610e9e57600080fd5b505af1158015610eb2573d6000803e3d6000fd5b50506040516301ad106960e61b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd8116600483015288169250636b441a409150602401600060405180830381600087803b158015610f1957600080fd5b505af1158015610f2d573d6000803e3d6000fd5b5050604051631cb2800b60e01b81526001600160a01b0388811660048301527f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd169250631cb2800b9150602401600060405180830381600087803b158015610f9457600080fd5b505af1158015610fa8573d6000803e3d6000fd5b50505050610fb587611561565b610fbf878661101b565b604080516001600160a01b0388811682528781166020830152868116828401528916606082015290517f5f7560a5797edc6f72421362defa094d690eb9f7ced3cc5a5c13383502e4fcc59181900360800190a150505050915091565b6040516000602482018190529060440160408051601f198184030181529181526020820180516001600160e01b03166354c49fe960e01b179052519091506000906001600160a01b03851690611072908490611cd8565b6000604051808303816000865af19150503d80600081146110af576040519150601f19603f3d011682016040523d82523d6000602084013e6110b4565b606091505b505090508061114557604051635afc6e4760e11b81526001600160a01b038581166004830152600160248301527f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd169063b5f8dc8e90604401600060405180830381600087803b15801561112757600080fd5b505af115801561113b573d6000803e3d6000fd5b5050505050505050565b60005b60088160ff1610156112f8576040516354c49fe960e01b815260ff821660048201526000906001600160a01b038716906354c49fe990602401602060405180830381865afa15801561119e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c29190611a43565b90506001600160a01b0381166111d857506112f8565b604051632474e32f60e11b81526001600160a01b038281166004830152600091908716906348e9c65e9060240160c060405180830381865afa158015611222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112469190611be8565b60200151905061125582611691565b801561126857506001600160a01b038116155b156112ee5760405163023cb23960e41b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd16906323cb2390906112bb908a908690600401611952565b600060405180830381600087803b1580156112d557600080fd5b505af11580156112e9573d6000803e3d6000fd5b505050505b5050600101611148565b5050505050565b604051633f9095b760e01b81526001600160a01b03821660048201526000908190732f50d538606fa9edd2b11e2446beb18c9d5846bb90633f9095b790602401602060405180830381865afa925050508015611378575060408051601f3d908101601f1916820190925261137591810190611cf4565b60015b6113855750600092915050565b5060019050826001600160a01b0316639c868ac06040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156113e4575060408051601f3d908101601f191682019092526113e191810190611d17565b60015b156113fb5780156113f9575060009392505050565b505b92915050565b6000816001600160a01b03166382c630666040518163ffffffff1660e01b8152600401602060405180830381865afa158015611441573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fb9190611a43565b60006113fb6000836117d3565b60006114816000858585611828565b949350505050565b606080826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156114ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114f29190810190611d34565b9150826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261155a9190810190611d34565b9050915091565b60405163023cb23960e41b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd16906323cb2390906115cf9084907f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5290600401611952565b600060405180830381600087803b1580156115e957600080fd5b505af11580156115fd573d6000803e3d6000fd5b505060405163023cb23960e41b81526001600160a01b037f00000000000000000000000069d61428d089c2f35bf6a472f540d0f82d1ea2cd1692506323cb23909150611663908490734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b90600401611952565b600060405180830381600087803b15801561167d57600080fd5b505af11580156112f8573d6000803e3d6000fd5b60007f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd526001600160a01b0316826001600160a01b031614806116ef57506001600160a01b03821673baf05d7aa4129ca14ec45cc9d4103a9ab9a9ff60145b8061171657506001600160a01b0382167373968b9a57c6e53d41345fd57a6e6ae27d6cdb2f145b8061173d57506001600160a01b038216734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b145b1561174a57506000919050565b604051633f9095b760e01b81526001600160a01b0383166004820152732f50d538606fa9edd2b11e2446beb18c9d5846bb90633f9095b790602401602060405180830381865afa9250505080156117be575060408051601f3d908101601f191682019092526117bb91810190611cf4565b60015b6117ca57506001919050565b50600092915050565b60006c5af43d3d93803e602a57fd5bf36021528160145273602c3d8160093d39f33d3d3d3d363d3d37363d736000526035600c84f090508061181d5763301164256000526004601cfd5b600060215292915050565b600060608303516040840351602085035185518060208801018051600283016c5af43d3d93803e606057fd5bf38a528a600d8b035278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b1760218b03527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff603a8b035272fd6100003d81600a3d39f336602c57343d527f6062820160781b1761ff9e82106059018b03528060f01b835288606c8201604c8c038ef5975050866118f55763301164256000526004601cfd5b90528652601f19860152603f19850152605f19909301929092525092915050565b6001600160a01b038116811461192b57600080fd5b50565b60006020828403121561194057600080fd5b813561194b81611916565b9392505050565b6001600160a01b0392831681529116602082015260400190565b801515811461192b57600080fd5b60008060006060848603121561198f57600080fd5b8335925060208401356119a18161196c565b915060408401356119b18161196c565b809150509250925092565b60008060008060008060c087890312156119d557600080fd5b86516119e081611916565b60208801519096506119f181611916565b6040880151909550611a0281611916565b6060880151909450611a1381611916565b6080880151909350611a2481611916565b60a0880151909250611a358161196c565b809150509295509295509295565b600060208284031215611a5557600080fd5b815161194b81611916565b600060208284031215611a7257600080fd5b5051919050565b60005b83811015611a94578181015183820152602001611a7c565b50506000910152565b60008151808452611ab5816020860160208601611a79565b601f01601f19169290920160200192915050565b60018060a01b0384168152826020820152606060408201526000611af06060830184611a9d565b95945050505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611b2a57611b2a611af9565b604051601f8501601f19908116603f01168101908282118183101715611b5257611b52611af9565b81604052809350858152868686011115611b6b57600080fd5b611b79866020830187611a79565b5050509392505050565b60008060408385031215611b9657600080fd5b8251611ba18161196c565b602084015190925067ffffffffffffffff811115611bbe57600080fd5b8301601f81018513611bcf57600080fd5b611bde85825160208401611b0f565b9150509250929050565b600060c08284031215611bfa57600080fd5b60405160c0810181811067ffffffffffffffff82111715611c1d57611c1d611af9565b6040528251611c2b81611916565b81526020830151611c3b81611916565b8060208301525060408301516040820152606083015160608201526080830151608082015260a083015160a08201528091505092915050565b6001600160a01b038981168252888116602083015287811660408301528681166060830152858116608083015284811660a0830152831660c082015261010060e08201819052600090611cc983820185611a9d565b9b9a5050505050505050505050565b60008251611cea818460208701611a79565b9190910192915050565b600060208284031215611d0657600080fd5b815180600f0b811461194b57600080fd5b600060208284031215611d2957600080fd5b815161194b8161196c565b600060208284031215611d4657600080fd5b815167ffffffffffffffff811115611d5d57600080fd5b8201601f81018413611d6e57600080fd5b61148184825160208401611b0f56fea26469706673582212207edead2c1abc9842c639e73d73320b0cc48d235619fd3a6a1e2b02c5e276a15364736f6c63430008130033
Verified Source Code Full Match
Compiler: v0.8.19+commit.7dd6d404
EVM: paris
Optimization: Yes (200 runs)
IVault.sol 9 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface IVault {
function deposit(address _recipient, uint256 _amount, bool _earn) external;
function withdraw(uint256 _shares) external;
function initialize() external;
}
ERC20.sol 546 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
/// minting and transferring zero tokens, as well as self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
/// the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The total supply has overflowed.
error TotalSupplyOverflow();
/// @dev The allowance has overflowed.
error AllowanceOverflow();
/// @dev The allowance has underflowed.
error AllowanceUnderflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Insufficient allowance.
error InsufficientAllowance();
/// @dev The permit is invalid.
error InvalidPermit();
/// @dev The permit has expired.
error PermitExpired();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
event Transfer(address indexed from, address indexed to, uint256 amount);
/// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
event Approval(address indexed owner, address indexed spender, uint256 amount);
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The storage slot for the total supply.
uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
/// @dev The balance slot of `owner` is given by:
/// ```
/// mstore(0x0c, _BALANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
/// @dev The allowance slot of (`owner`, `spender`) is given by:
/// ```
/// mstore(0x20, spender)
/// mstore(0x0c, _ALLOWANCE_SLOT_SEED)
/// mstore(0x00, owner)
/// let allowanceSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
/// @dev The nonce slot of `owner` is given by:
/// ```
/// mstore(0x0c, _NONCES_SLOT_SEED)
/// mstore(0x00, owner)
/// let nonceSlot := keccak256(0x0c, 0x20)
/// ```
uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
/// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
bytes32 private constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
/// @dev `keccak256("1")`.
bytes32 private constant _VERSION_HASH =
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
/// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
bytes32 private constant _PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the name of the token.
function name() public view virtual returns (string memory);
/// @dev Returns the symbol of the token.
function symbol() public view virtual returns (string memory);
/// @dev Returns the decimals places of the token.
function decimals() public view virtual returns (uint8) {
return 18;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of tokens in existence.
function totalSupply() public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_TOTAL_SUPPLY_SLOT)
}
}
/// @dev Returns the amount of tokens owned by `owner`.
function balanceOf(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
function allowance(address owner, address spender)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
///
/// Emits a {Approval} event.
function approve(address spender, uint256 amount) public virtual returns (bool) {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
}
return true;
}
/// @dev Transfer `amount` tokens from the caller to `to`.
///
/// Requirements:
/// - `from` must at least have `amount`.
///
/// Emits a {Transfer} event.
function transfer(address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(msg.sender, to, amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Transfers `amount` tokens from `from` to `to`.
///
/// Note: Does not update the allowance if it is the maximum uint256 value.
///
/// Requirements:
/// - `from` must at least have `amount`.
/// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the allowance slot and load its value.
mstore(0x20, caller())
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
return true;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EIP-2612 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev For more performance, override to return the constant value
/// of `keccak256(bytes(name()))` if `name()` will never change.
function _constantNameHash() internal view virtual returns (bytes32 result) {}
/// @dev Returns the current nonce for `owner`.
/// This value is used to compute the signature for EIP-2612 permit.
function nonces(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// Compute the nonce slot and load its value.
mstore(0x0c, _NONCES_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
/// authorized by a signed approval by `owner`.
///
/// Emits a {Approval} event.
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
// Revert if the block timestamp is greater than `deadline`.
if gt(timestamp(), deadline) {
mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
revert(0x1c, 0x04)
}
let m := mload(0x40) // Grab the free memory pointer.
// Clean the upper 96 bits.
owner := shr(96, shl(96, owner))
spender := shr(96, shl(96, spender))
// Compute the nonce slot and load its value.
mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
mstore(0x00, owner)
let nonceSlot := keccak256(0x0c, 0x20)
let nonceValue := sload(nonceSlot)
// Prepare the domain separator.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
mstore(0x2e, keccak256(m, 0xa0))
// Prepare the struct hash.
mstore(m, _PERMIT_TYPEHASH)
mstore(add(m, 0x20), owner)
mstore(add(m, 0x40), spender)
mstore(add(m, 0x60), value)
mstore(add(m, 0x80), nonceValue)
mstore(add(m, 0xa0), deadline)
mstore(0x4e, keccak256(m, 0xc0))
// Prepare the ecrecover calldata.
mstore(0x00, keccak256(0x2c, 0x42))
mstore(0x20, and(0xff, v))
mstore(0x40, r)
mstore(0x60, s)
let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
// If the ecrecover fails, the returndatasize will be 0x00,
// `owner` will be checked if it equals the hash at 0x00,
// which evaluates to false (i.e. 0), and we will revert.
// If the ecrecover succeeds, the returndatasize will be 0x20,
// `owner` will be compared against the returned address at 0x20.
if iszero(eq(mload(returndatasize()), owner)) {
mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
revert(0x1c, 0x04)
}
// Increment and store the updated nonce.
sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
// Compute the allowance slot and store the value.
// The `owner` is already at slot 0x20.
mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
sstore(keccak256(0x2c, 0x34), value)
// Emit the {Approval} event.
log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero pointer.
}
}
/// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
bytes32 nameHash = _constantNameHash();
// We simply calculate it on-the-fly to allow for cases where the `name` may change.
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Grab the free memory pointer.
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
result := keccak256(m, 0xa0)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` tokens to `to`, increasing the total supply.
///
/// Emits a {Transfer} event.
function _mint(address to, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), to, amount);
/// @solidity memory-safe-assembly
assembly {
let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
let totalSupplyAfter := add(totalSupplyBefore, amount)
// Revert if the total supply overflows.
if lt(totalSupplyAfter, totalSupplyBefore) {
mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
revert(0x1c, 0x04)
}
// Store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
}
_afterTokenTransfer(address(0), to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Burns `amount` tokens from `from`, reducing the total supply.
///
/// Emits a {Transfer} event.
function _burn(address from, uint256 amount) internal virtual {
_beforeTokenTransfer(from, address(0), amount);
/// @solidity memory-safe-assembly
assembly {
// Compute the balance slot and load its value.
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, from)
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Subtract and store the updated total supply.
sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
// Emit the {Transfer} event.
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
}
_afterTokenTransfer(from, address(0), amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Moves `amount` of tokens from `from` to `to`.
function _transfer(address from, address to, uint256 amount) internal virtual {
_beforeTokenTransfer(from, to, amount);
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
// Compute the balance slot and load its value.
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))
// Compute the balance slot of `to`.
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
// Add and store the updated balance of `to`.
// Will not overflow because the sum of all user balances
// cannot exceed the maximum uint256 value.
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
// Emit the {Transfer} event.
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL ALLOWANCE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the allowance slot and load its value.
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
// If the allowance is not the maximum uint256 value.
if add(allowance_, 1) {
// Revert if the amount to be transferred exceeds the allowance.
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated allowance.
sstore(allowanceSlot, sub(allowance_, amount))
}
}
}
/// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
///
/// Emits a {Approval} event.
function _approve(address owner, address spender, uint256 amount) internal virtual {
/// @solidity memory-safe-assembly
assembly {
let owner_ := shl(96, owner)
// Compute the allowance slot and store the amount.
mstore(0x20, spender)
mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
sstore(keccak256(0x0c, 0x34), amount)
// Emit the {Approval} event.
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS TO OVERRIDE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any transfer of tokens.
/// This includes minting and burning.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/// @dev Hook that is called after any transfer of tokens.
/// This includes minting and burning.
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
PoolFactory.sol 219 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
import {ERC20} from "solady/tokens/ERC20.sol";
import {IVault} from "src/base/interfaces/IVault.sol";
import {LibClone} from "solady/utils/LibClone.sol";
import {IBooster} from "src/base/interfaces/IBooster.sol";
import {IStrategy} from "src/base/interfaces/IStrategy.sol";
import {IFallback} from "src/base/interfaces/IFallback.sol";
import {ILiquidityGauge} from "src/base/interfaces/ILiquidityGauge.sol";
import {ISDLiquidityGauge} from "src/base/interfaces/ISDLiquidityGauge.sol";
/// @notice Factory built to be compatible with CRV gauges but can be overidden to support other gauges/protocols.
abstract contract PoolFactory {
using LibClone for address;
/// @notice Denominator for fixed point math.
uint256 public constant DENOMINATOR = 10_000;
/// @notice Stake DAO strategy contract address.
IStrategy public immutable strategy;
/// @notice Reward token address.
address public immutable rewardToken;
/// @notice Staking Deposit implementation address.
address public immutable vaultImplementation;
/// @notice Reward Receiver implementation address.
address public immutable rewardReceiverImplementation;
/// @notice Liquidity Gauge implementation address.
address public immutable liquidityGaugeImplementation;
/// @notice Stake DAO token address.
address public constant SDT = 0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F;
/// @notice Voting Escrow Stake DAO token address.
address public constant VESDT = 0x0C30476f66034E11782938DF8e4384970B6c9e8a;
/// @notice SDT VEBoost proxy address.
address public constant VE_BOOST_PROXY = 0xD67bdBefF01Fc492f1864E61756E5FBB3f173506;
/// @notice Claim helper contract address for LiquidityGauges.
address public constant CLAIM_HELPER = 0x539e65190a371cE73244A98DEc42BA635cCa512c;
/// @notice Stake DAO token distributor address.
address public constant SDT_DISTRIBUTOR = 0x9C99dffC1De1AfF7E7C1F36fCdD49063A281e18C;
/// @notice Throwed if the gauge is not valid candidate.
error INVALID_GAUGE();
/// @notice Throwed if the token is not valid.
error INVALID_TOKEN();
/// @notice Throwed if the gauge has been already used.
error GAUGE_ALREADY_USED();
/// @notice Emitted when a new pool is deployed.
event PoolDeployed(address vault, address rewardDistributor, address token, address gauge);
/// @notice Constructor.
/// @param _strategy Address of the strategy contract. This contract should have the ability to add new reward tokens.
/// @param _rewardToken Address of the main reward token.
/// @param _vaultImplementation Address of the staking deposit implementation. Main entry point.
/// @param _liquidityGaugeImplementation Address of the liquidity gauge implementation.
constructor(
address _strategy,
address _rewardToken,
address _vaultImplementation,
address _liquidityGaugeImplementation,
address _rewardReceiverImplementation
) {
rewardToken = _rewardToken;
strategy = IStrategy(_strategy);
vaultImplementation = _vaultImplementation;
liquidityGaugeImplementation = _liquidityGaugeImplementation;
rewardReceiverImplementation = _rewardReceiverImplementation;
}
/// @notice Add new staking gauge to Stake DAO Locker.
/// @param _gauge Address of the liquidity gauge.
/// @return vault Address of the staking deposit.
/// @return rewardDistributor Address of the reward distributor to claim rewards.
function create(address _gauge) public virtual returns (address vault, address rewardDistributor) {
return _create(_gauge);
}
/// @notice Add new staking gauge to Stake DAO Locker.
function _create(address _gauge) internal returns (address vault, address rewardDistributor) {
/// Perform checks on the gauge to make sure it's valid and can be used.
if (!_isValidGauge(_gauge)) revert INVALID_GAUGE();
/// Perform checks on the strategy to make sure it's not already used.
if (strategy.rewardDistributors(_gauge) != address(0)) revert GAUGE_ALREADY_USED();
/// Retrieve the staking token.
address lp = _getGaugeStakingToken(_gauge);
/// Clone the Reward Distributor.
rewardDistributor = LibClone.clone(liquidityGaugeImplementation);
/// We use the LP token and the gauge address as salt to generate the vault address.
bytes32 salt = keccak256(abi.encodePacked(lp, _gauge));
/// We use CWIA setup. We encode the LP token, the strategy address and the reward distributor address as data
/// to be passed as immutable args to the vault.
bytes memory vaultData = abi.encodePacked(lp, address(strategy), rewardDistributor);
/// Clone the Vault.
vault = vaultImplementation.cloneDeterministic(vaultData, salt);
/// Retrieve the symbol to be used on the reward distributor.
(, string memory _symbol) = _getNameAndSymbol(lp);
/// Initialize the Reward Distributor.
ISDLiquidityGauge(rewardDistributor).initialize(
vault, address(this), SDT, VESDT, VE_BOOST_PROXY, SDT_DISTRIBUTOR, vault, _symbol
);
/// Initialize Vault.
IVault(vault).initialize();
/// Allow the vault to stake the LP token in the locker trough the strategy.
strategy.toggleVault(vault);
/// Map in the strategy the staking token to it's corresponding gauge.
strategy.setGauge(lp, _gauge);
/// Map the gauge to the reward distributor that should receive the rewards.
strategy.setRewardDistributor(_gauge, rewardDistributor);
/// Set ClaimHelper as claimer.
ISDLiquidityGauge(rewardDistributor).set_claimer(CLAIM_HELPER);
/// Transfer ownership of the reward distributor to the strategy.
ISDLiquidityGauge(rewardDistributor).commit_transfer_ownership(address(strategy));
/// Accept ownership of the reward distributor.
strategy.acceptRewardDistributorOwnership(rewardDistributor);
/// Add the reward token to the reward distributor.
_addRewardToken(_gauge);
/// Add extra rewards if any.
_addExtraRewards(_gauge, rewardDistributor);
emit PoolDeployed(vault, rewardDistributor, lp, _gauge);
}
/// @notice Add the main reward token to the reward distributor.
/// @param _gauge Address of the gauge.
function _addRewardToken(address _gauge) internal virtual {
/// The strategy should claim through the locker the reward token,
/// and distribute it to the reward distributor every harvest.
strategy.addRewardToken(_gauge, rewardToken);
}
/// @notice Add extra reward tokens to the reward distributor.
/// @param _gauge Address of the liquidity gauge.
function _addExtraRewards(address _gauge, address _rewardDistributor) internal virtual {
/// Check if the gauge supports extra rewards.
/// This function is not supported on all gauges, depending on when they were deployed.
bytes memory data = abi.encodeWithSignature("reward_tokens(uint256)", 0);
/// Hence the call to the function is wrapped in a try catch.
(bool success,) = _gauge.call(data);
if (!success) {
/// If it fails, we set the LGtype to 1 to indicate that the gauge doesn't support extra rewards.
/// So the harvest would skip the extra rewards.
strategy.setLGtype(_gauge, 1);
return;
}
/// Loop through the extra reward tokens.
/// 8 is the maximum number of extra reward tokens supported by the gauges.
for (uint8 i = 0; i < 8;) {
/// Get the extra reward token address.
address _extraRewardToken = ISDLiquidityGauge(_gauge).reward_tokens(i);
/// If the address is 0, it means there are no more extra reward tokens.
if (_extraRewardToken == address(0)) break;
/// Performs checks on the extra reward token.
/// Checks like if the token is also an lp token that can be staked in the locker, these tokens are not supported.
address distributor = ILiquidityGauge(_rewardDistributor).reward_data(_extraRewardToken).distributor;
if (_isValidToken(_extraRewardToken) && distributor == address(0)) {
/// Then we add the extra reward token to the reward distributor through the strategy.
strategy.addRewardToken(_gauge, _extraRewardToken);
}
unchecked {
++i;
}
}
}
/// @notice Perform checks on the gauge to make sure it's valid and can be used.
function _isValidGauge(address _gauge) internal view virtual returns (bool) {}
/// @notice Perform checks on the token to make sure it's valid and can be used.
function _isValidToken(address _token) internal view virtual returns (bool) {}
/// @notice Retrieve the staking token from the gauge.
/// @param _gauge Address of the liquidity gauge.
function _getGaugeStakingToken(address _gauge) internal view virtual returns (address lp) {
lp = ILiquidityGauge(_gauge).lp_token();
}
/// @notice Retrieve the name and symbol of the staking token.
/// @param _lp Address of the staking token.
function _getNameAndSymbol(address _lp) internal view virtual returns (string memory name, string memory symbol) {
name = ERC20(_lp).name();
symbol = ERC20(_lp).symbol();
}
}
IBooster.sol 22 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface IBooster {
function poolLength() external view returns (uint256);
function poolInfo(uint256 pid)
external
view
returns (address lpToken, address token, address gauge, address crvRewards, address stash, bool shutdown);
function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns (bool);
function earmarkRewards(uint256 _pid) external returns (bool);
function depositAll(uint256 _pid, bool _stake) external returns (bool);
function withdraw(uint256 _pid, uint256 _amount) external returns (bool);
function claimRewards(uint256 _pid, address gauge) external returns (bool);
}
LibClone.sol 1210 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Minimal proxy library.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
/// @author Minimal proxy by 0age (https://github.com/0age)
/// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
/// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
/// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy)
///
/// @dev Minimal proxy:
/// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
/// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
/// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
///
/// @dev Minimal proxy (PUSH0 variant):
/// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai.
/// It is optimized first for minimal runtime gas, then for minimal bytecode.
/// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as
/// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai.
/// Please use with caution.
///
/// @dev Clones with immutable args (CWIA):
/// The implementation of CWIA here implements a `receive()` method that emits the
/// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata,
/// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards
/// composability. The minimal proxy implementation does not offer this feature.
///
/// @dev Minimal ERC1967 proxy:
/// An minimal ERC1967 proxy, intended to be upgraded with UUPS.
/// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.
///
/// @dev ERC1967I proxy:
/// An variant of the minimal ERC1967 proxy, with a special code path that activates
/// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the
/// `implementation` address. The returned implementation is guaranteed to be valid if the
/// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`.
library LibClone {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The keccak256 of the deployed code for the ERC1967 proxy.
bytes32 internal constant ERC1967_CODE_HASH =
0xaaa52c8cc8a0e3fd27ce756cc6b4e70c51423e9b597b11f32d3e49f8b1fc890d;
/// @dev The keccak256 of the deployed code for the ERC1967I proxy.
bytes32 internal constant ERC1967I_CODE_HASH =
0xce700223c0d4cea4583409accfc45adac4a093b3519998a9cbbe1504dadba6f7;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unable to deploy the clone.
error DeploymentFailed();
/// @dev The salt must start with either the zero address or `by`.
error SaltDoesNotStartWith();
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Deploys a clone of `implementation`.
function clone(address implementation) internal returns (address instance) {
instance = clone(0, implementation);
}
/// @dev Deploys a clone of `implementation`.
/// Deposits `value` ETH during deployment.
function clone(uint256 value, address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
/**
* --------------------------------------------------------------------------+
* CREATION (9 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* --------------------------------------------------------------------------|
* RUNTIME (44 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* |
* ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | |
* 3d | RETURNDATASIZE | 0 0 | |
* 3d | RETURNDATASIZE | 0 0 0 | |
* 3d | RETURNDATASIZE | 0 0 0 0 | |
* |
* ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 0 0 | |
* 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | |
* 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | |
* 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata |
* |
* ::: delegate call to the implementation contract :::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata |
* 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata |
* 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata |
* f4 | DELEGATECALL | success 0 0 | [0..cds): calldata |
* |
* ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata |
* 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata |
* 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata |
* 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata |
* |
* 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata |
* 57 | JUMPI | 0 rds | [0..rds): returndata |
* |
* ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* --------------------------------------------------------------------------+
*/
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
instance := create(value, 0x0c, 0x35)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Deploys a deterministic clone of `implementation` with `salt`.
function cloneDeterministic(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic(0, implementation, salt);
}
/// @dev Deploys a deterministic clone of `implementation` with `salt`.
/// Deposits `value` ETH during deployment.
function cloneDeterministic(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
instance := create2(value, 0x0c, 0x35, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the initialization code of the clone of `implementation`.
function initCode(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(add(result, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000)
mstore(add(result, 0x28), implementation)
mstore(add(result, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
mstore(result, 0x35) // Store the length.
mstore(0x40, add(result, 0x60)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x21, 0x5af43d3d93803e602a57fd5bf3)
mstore(0x14, implementation)
mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73)
hash := keccak256(0x0c, 0x35)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the address of the deterministic clone of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
bytes32 hash = initCodeHash(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Deploys a PUSH0 clone of `implementation`.
function clone_PUSH0(address implementation) internal returns (address instance) {
instance = clone_PUSH0(0, implementation);
}
/// @dev Deploys a PUSH0 clone of `implementation`.
/// Deposits `value` ETH during deployment.
function clone_PUSH0(uint256 value, address implementation)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
/**
* --------------------------------------------------------------------------+
* CREATION (9 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 5f | PUSH0 | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 5f | PUSH0 | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* --------------------------------------------------------------------------|
* RUNTIME (45 bytes) |
* --------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* |
* ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: |
* 5f | PUSH0 | 0 | |
* 5f | PUSH0 | 0 0 | |
* |
* ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 | |
* 5f | PUSH0 | 0 cds 0 0 | |
* 5f | PUSH0 | 0 0 cds 0 0 | |
* 37 | CALLDATACOPY | 0 0 | [0..cds): calldata |
* |
* ::: delegate call to the implementation contract :::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds 0 0 | [0..cds): calldata |
* 5f | PUSH0 | 0 cds 0 0 | [0..cds): calldata |
* 73 addr | PUSH20 addr | addr 0 cds 0 0 | [0..cds): calldata |
* 5a | GAS | gas addr 0 cds 0 0 | [0..cds): calldata |
* f4 | DELEGATECALL | success | [0..cds): calldata |
* |
* ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success | [0..cds): calldata |
* 5f | PUSH0 | 0 rds success | [0..cds): calldata |
* 5f | PUSH0 | 0 0 rds success | [0..cds): calldata |
* 3e | RETURNDATACOPY | success | [0..rds): returndata |
* |
* 60 0x29 | PUSH1 0x29 | 0x29 success | [0..rds): returndata |
* 57 | JUMPI | | [0..rds): returndata |
* |
* ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds | [0..rds): returndata |
* 5f | PUSH0 | 0 rds | [0..rds): returndata |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | [0..rds): returndata |
* 3d | RETURNDATASIZE | rds | [0..rds): returndata |
* 5f | PUSH0 | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* --------------------------------------------------------------------------+
*/
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
instance := create(value, 0x0e, 0x36)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
function cloneDeterministic_PUSH0(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic_PUSH0(0, implementation, salt);
}
/// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`.
/// Deposits `value` ETH during deployment.
function cloneDeterministic_PUSH0(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
instance := create2(value, 0x0e, 0x36, salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the initialization code of the PUSH0 clone of `implementation`.
function initCode_PUSH0(address implementation) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(add(result, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16
mstore(add(result, 0x26), implementation) // 20
mstore(add(result, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
mstore(result, 0x36) // Store the length.
mstore(0x40, add(result, 0x60)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16
mstore(0x14, implementation) // 20
mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9
hash := keccak256(0x0e, 0x36)
mstore(0x24, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the address of the deterministic PUSH0 clone of `implementation`,
/// with `salt` by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress_PUSH0(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHash_PUSH0(implementation);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CLONES WITH IMMUTABLE ARGS OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: This implementation of CWIA differs from the original implementation.
// If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`.
/// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`.
function clone(address implementation, bytes memory data) internal returns (address instance) {
instance = clone(0, implementation, data);
}
/// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`.
/// Deposits `value` ETH during deployment.
function clone(uint256 value, address implementation, bytes memory data)
internal
returns (address instance)
{
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
// The `creationSize` is `extraLength + 108`
// The `runSize` is `creationSize - 10`.
/**
* ---------------------------------------------------------------------------------------------------+
* CREATION (10 bytes) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* 61 runSize | PUSH2 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------------------------|
* RUNTIME (98 bytes + extraLength) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* |
* ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 60 0x2c | PUSH1 0x2c | 0x2c cds | |
* 57 | JUMPI | | |
* 34 | CALLVALUE | cv | |
* 3d | RETURNDATASIZE | 0 cv | |
* 52 | MSTORE | | [0..0x20): callvalue |
* 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue |
* 59 | MSIZE | 0x20 sig | [0..0x20): callvalue |
* 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue |
* a1 | LOG1 | | [0..0x20): callvalue |
* 00 | STOP | | [0..0x20): callvalue |
* 5b | JUMPDEST | | |
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..cds): calldata |
* |
* ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata |
* 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata |
* |
* ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata |
* 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata |
* 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata |
* 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata |
* |
* 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata |
* 57 | JUMPI | 0 rds | [0..rds): returndata |
* |
* ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* ---------------------------------------------------------------------------------------------------+
*/
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
// Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
// The actual EVM limit may be smaller and may change over time.
sub(data, add(0x59, lt(extraLength, 0xff9e))),
or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
instance := create(value, sub(data, 0x4c), add(extraLength, 0x6c))
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Deploys a deterministic clone of `implementation`
/// with immutable arguments encoded in `data` and `salt`.
function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
internal
returns (address instance)
{
instance = cloneDeterministic(0, implementation, data, salt);
}
/// @dev Deploys a deterministic clone of `implementation`
/// with immutable arguments encoded in `data` and `salt`.
function cloneDeterministic(
uint256 value,
address implementation,
bytes memory data,
bytes32 salt
) internal returns (address instance) {
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
// Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e.
// The actual EVM limit may be smaller and may change over time.
sub(data, add(0x59, lt(extraLength, 0xff9e))),
or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
instance := create2(value, sub(data, 0x4c), add(extraLength, 0x6c), salt)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`
/// using immutable arguments encoded in `data`.
function initCode(address implementation, bytes memory data)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let dataLength := mload(data)
// Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b))
let o := add(result, 0x8c)
let end := add(o, dataLength)
// Copy the `data` into `result`.
for { let d := sub(add(data, 0x20), o) } 1 {} {
mstore(o, mload(add(o, d)))
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(add(result, 0x6c), 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(add(result, 0x5f), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
add(result, 0x4b),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
add(result, 0x32),
0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
add(result, 0x12),
or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
)
mstore(end, shl(0xf0, extraLength))
mstore(add(end, 0x02), 0) // Zeroize the slot after the result.
mstore(result, add(extraLength, 0x6c)) // Store the length.
mstore(0x40, add(0x22, end)) // Allocate memory.
}
}
/// @dev Returns the initialization code hash of the clone of `implementation`
/// using immutable arguments encoded in `data`.
/// Used for mining vanity addresses with create2crunch.
function initCodeHash(address implementation, bytes memory data)
internal
pure
returns (bytes32 hash)
{
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore3 := mload(sub(data, 0x60))
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b))
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data.
mstore(sub(data, 0x0d), implementation) // Write the address of the implementation.
// Write the rest of the bytecode.
mstore(
sub(data, 0x21),
or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)
)
// `keccak256("ReceiveETH(uint256)")`
mstore(
sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff
)
mstore(
sub(data, 0x5a),
or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)
)
mstore(dataEnd, shl(0xf0, extraLength))
hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c))
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
mstore(sub(data, 0x60), mBefore3)
}
}
/// @dev Returns the address of the deterministic clone of
/// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
/// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
function predictDeterministicAddress(
address implementation,
bytes memory data,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes32 hash = initCodeHash(implementation, data);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MINIMAL ERC1967 PROXY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: The ERC1967 proxy here is intended to be upgraded with UUPS.
// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic.
/// @dev Deploys a minimal ERC1967 proxy with `implementation`.
function deployERC1967(address implementation) internal returns (address instance) {
instance = deployERC1967(0, implementation);
}
/// @dev Deploys a minimal ERC1967 proxy with `implementation`.
/// Deposits `value` ETH during deployment.
function deployERC1967(uint256 value, address implementation)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
/**
* ---------------------------------------------------------------------------------+
* CREATION (34 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* 60 runSize | PUSH1 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code |
* 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code |
* 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code |
* 55 | SSTORE | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------|
* RUNTIME (61 bytes) |
* ---------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------|
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..calldatasize): calldata |
* |
* ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | |
* 3d | RETURNDATASIZE | 0 0 | |
* 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata |
* 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata |
* 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata |
* 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata |
* 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata |
* f4 | DELEGATECALL | succ | [0..calldatasize): calldata |
* |
* ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata |
* 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata |
* 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata |
* 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata |
* |
* ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: |
* 60 0x38 | PUSH1 0x38 | dest succ | [0..returndatasize): returndata |
* 57 | JUMPI | | [0..returndatasize): returndata |
* |
* ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* fd | REVERT | | [0..returndatasize): returndata |
* |
* ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | | [0..returndatasize): returndata |
* 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata |
* 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata |
* f3 | RETURN | | [0..returndatasize): returndata |
* ---------------------------------------------------------------------------------+
*/
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223d3973)
instance := create(value, 0x21, 0x5f)
if iszero(instance) {
mstore(0x00, 0x30116425) // `DeploymentFailed()`.
revert(0x1c, 0x04)
}
mstore(0x40, m) // Restore the free memory pointer.
mstore(0x60, 0) // Restore the zero slot.
}
}
/// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
function deployDeterministicERC1967(address implementation, bytes32 salt)
internal
returns (address instance)
{
instance = deployDeterministicERC1967(0, implementation, salt);
}
/// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`.
/// Deposits `value` ETH during deployment.
function deployDeterministicERC1967(uint256 value, address implementation, bytes32 salt)
internal
returns (address instance)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3)
mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076)
mstore(0x20, 0x6009)
mstore(0x1e, implementation)
mstore(0x0a, 0x603d3d8160223...
// [truncated — 73026 bytes total]
IFallback.sol 13 lines
/// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
interface IFallback {
function initialize() external;
function claim(bool _claimExtraRewards)
external
returns (uint256 rewardTokenAmount, uint256 fallbackRewardTokenAmount, uint256 protocolFees);
function balanceOf(address _asset) external view returns (uint256);
function deposit(address _asset, uint256 _amount) external;
function withdraw(address _asset, uint256 _amount) external;
function fallbackRewardToken() external view returns (address);
}
IStrategy.sol 27 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface IStrategy {
function locker() external view returns (address);
function deposit(address _token, uint256 amount) external;
function withdraw(address _token, uint256 amount) external;
function claimProtocolFees() external;
function claimNativeRewards() external;
function harvest(address _asset, bool _distributeSDT, bool _claimExtra) external;
function rewardReceivers(address _gauge) external view returns (address);
function rewardDistributors(address _gauge) external view returns (address);
/// Factory functions
function toggleVault(address vault) external;
function setGauge(address token, address gauge) external;
function setLGtype(address gauge, uint256 gaugeType) external;
function addRewardToken(address _token, address _rewardDistributor) external;
function acceptRewardDistributorOwnership(address rewardDistributor) external;
function setRewardDistributor(address gauge, address rewardDistributor) external;
function addRewardReceiver(address gauge, address rewardReceiver) external;
function execute(address _to, uint256 _value, bytes calldata _data) external returns (bool, bytes memory);
}
CRVPoolFactory.sol 146 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
import "src/base/factory/PoolFactory.sol";
import {IBooster} from "src/base/interfaces/IBooster.sol";
import {IConvexFactory} from "src/base/interfaces/IConvexFactory.sol";
import {IGaugeController} from "src/base/interfaces/IGaugeController.sol";
/// @notice Inherit from PoolFactory to deploy a pool compatible with CRV gauges and check if the token is a valid extra rewards to add.
contract CRVPoolFactory is PoolFactory {
/// @notice Ve Funder is a special gauge not valid to be deployed as a pool.
address public constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;
/// @notice Convex Booster.
address public constant BOOSTER = 0xF403C135812408BFbE8713b5A23a04b3D48AAE31;
/// @notice Ve Funder is a special gauge not valid to be deployed as a pool.
address public constant VE_FUNDER = 0xbAF05d7aa4129CA14eC45cC9d4103a9aB9A9fF60;
/// @notice Convex Minimal Proxy Factory for Only Boost.
address public constant CONVEX_MINIMAL_PROXY_FACTORY = 0x4E795A6f991e305e3f28A3b1b2B4B9789d2CD5A1;
/// @notice Curve Gauge Controller.
IGaugeController public constant GAUGE_CONTROLLER = IGaugeController(0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB);
/// @notice Event emitted when a pool is deployed with Only Boost.
event PoolDeployed(address vault, address rewardDistributor, address lp, address gauge, address stakingConvex);
constructor(
address _strategy,
address _rewardToken,
address _vaultImplementation,
address _liquidityGaugeImplementation,
address _rewardReceiverImplementation
)
PoolFactory(
_strategy,
_rewardToken,
_vaultImplementation,
_liquidityGaugeImplementation,
_rewardReceiverImplementation
)
{}
/// @notice Create a new pool for a given pid on the Convex platform.
/// @param _pid Pool id.
/// @param _deployPool To deploy the pool.
/// @param _deployConvex To deploy the convex staking.
/// @return vault Address of the vault.
/// @return rewardDistributor Address of the reward distributor.
/// @return stakingConvex Address of the staking convex.
function create(uint256 _pid, bool _deployPool, bool _deployConvex)
external
returns (address vault, address rewardDistributor, address stakingConvex)
{
(address _token,, address _gauge,,,) = IBooster(BOOSTER).poolInfo(_pid);
if (_deployConvex) {
stakingConvex = IConvexFactory(CONVEX_MINIMAL_PROXY_FACTORY).create(_token, _pid);
}
if (_deployPool) {
/// Create Stake DAO pool.
(vault, rewardDistributor) = _create(_gauge);
emit PoolDeployed(vault, rewardDistributor, _token, _gauge, stakingConvex);
} else {
address _rewardDistributor = strategy.rewardDistributors(_gauge);
/// We go through the execute function because if the pool is already deployed and have extra rewards,
/// We do not want CVX be distributed by the Reward Receiver.
/// Approve the reward distributor to spend the reward token.
if (ERC20(CVX).allowance(address(strategy), _rewardDistributor) == 0) {
strategy.execute(
CVX, 0, abi.encodeWithSignature("approve(address,uint256)", _rewardDistributor, type(uint256).max)
);
}
/// Add CVX in the case where Only Boost is enabled.
address distributor = ILiquidityGauge(_rewardDistributor).reward_data(CVX).distributor;
if (distributor == address(0)) {
strategy.execute(
_rewardDistributor,
0,
abi.encodeWithSignature("add_reward(address,address)", CVX, address(strategy))
);
}
}
}
function syncExtraRewards(address _gauge) external {
address _rewardDistributor = strategy.rewardDistributors(_gauge);
if (_rewardDistributor == address(0)) return;
_addExtraRewards(_gauge, _rewardDistributor);
}
/// @notice Add the main reward token to the reward distributor.
/// @param _gauge Address of the _gauge.
function _addRewardToken(address _gauge) internal override {
/// The strategy should claim through the locker the reward token,
/// and distribute it to the reward distributor every harvest.
strategy.addRewardToken(_gauge, rewardToken);
/// Add CVX in the case where Only Boost is enabled.
strategy.addRewardToken(_gauge, CVX);
}
/// @inheritdoc PoolFactory
function _isValidToken(address _token) internal view override returns (bool) {
/// We can't add the reward token as extra reward.
/// We can't add special pools like the Ve Funder.
/// We can't add SDT as extra reward, as it's already added by default.
/// We can't add CVX as extra reward, as it's already added by default.
if (_token == rewardToken || _token == VE_FUNDER || _token == SDT || _token == CVX) return false;
/// If the token is available as an inflation receiver, it's not valid.
try GAUGE_CONTROLLER.gauge_types(_token) {
return false;
} catch {
return true;
}
}
/// inheritdoc PoolFactory
function _isValidGauge(address _gauge) internal view override returns (bool) {
bool isValid;
/// Check if the gauge is a valid candidate and available as an inflation receiver.
/// This call always reverts if the gauge is not valid.
try GAUGE_CONTROLLER.gauge_types(_gauge) {
isValid = true;
} catch {
return false;
}
/// Check if the gauge is not killed.
/// Not all the pools, but most of them, have this function.
try ILiquidityGauge(_gauge).is_killed() returns (bool isKilled) {
if (isKilled) return false;
} catch {}
/// If the gauge doesn't support the is_killed function, but is unofficially killed, it can be deployed.
return isValid;
}
}
IConvexFactory.sol 8 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface IConvexFactory {
function protocolFeesPercent() external view returns (uint256);
function fallbacks(address gauge) external view returns (address);
function create(address token, uint256 pid) external returns (address);
}
ILiquidityGauge.sol 55 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface ILiquidityGauge {
struct Reward {
address token;
address distributor;
uint256 period_finish;
uint256 rate;
uint256 last_update;
uint256 integral;
}
function deposit_reward_token(address _rewardToken, uint256 _amount) external;
function claim_rewards_for(address _user, address _recipient) external;
function working_balances(address _address) external view returns (uint256);
function deposit(uint256 _value, address _addr) external;
function reward_tokens(uint256 _i) external view returns (address);
function reward_data(address _tokenReward) external view returns (Reward memory);
function balanceOf(address) external view returns (uint256);
function totalSupply() external view returns (uint256);
function claimable_reward(address _user, address _reward_token) external view returns (uint256);
function claimable_tokens(address _user) external returns (uint256);
function user_checkpoint(address _user) external returns (bool);
function commit_transfer_ownership(address) external;
function apply_transfer_ownership() external;
function claim_rewards(address) external;
function add_reward(address, address) external;
function set_claimer(address) external;
function admin() external view returns (address);
function set_reward_distributor(address _rewardToken, address _newDistrib) external;
function lp_token() external view returns (address);
function is_killed() external view returns (bool);
function staking_token() external view returns (address);
}
IGaugeController.sol 50 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface IGaugeController {
struct VotedSlope {
uint256 slope;
uint256 power;
uint256 end;
}
function admin() external view returns (address);
function gauges(uint256) external view returns (address);
//solhint-disable-next-line
function gauge_types(address addr) external view returns (int128);
//solhint-disable-next-line
function gauge_relative_weight_write(address addr, uint256 timestamp) external returns (uint256);
//solhint-disable-next-line
function gauge_relative_weight(address addr) external view returns (uint256);
//solhint-disable-next-line
function gauge_relative_weight(address addr, uint256 timestamp) external view returns (uint256);
//solhint-disable-next-line
function get_total_weight() external view returns (uint256);
//solhint-disable-next-line
function get_gauge_weight(address addr) external view returns (uint256);
function get_type_weight(int128) external view returns (uint256);
function vote_for_gauge_weights(address, uint256) external;
function vote_user_slopes(address, address) external returns (VotedSlope memory);
function last_user_vote(address _user, address _gauge) external view returns (uint256);
function checkpoint_gauge(address _gauge) external;
function add_gauge(address, int128, uint256) external;
function add_type(string memory, uint256) external;
function commit_transfer_ownership(address) external;
function accept_transfer_ownership() external;
}
ISDLiquidityGauge.sol 83 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
/// Modified version of the liquidity for Stake DAO needs.
interface ISDLiquidityGauge {
struct Reward {
address token;
address distributor;
uint256 period_finish;
uint256 rate;
uint256 last_update;
uint256 integral;
}
// solhint-disable-next-line
function deposit_reward_token(address _rewardToken, uint256 _amount) external;
// solhint-disable-next-line
function claim_rewards_for(address _user, address _recipient) external;
function claim_rewards() external;
function claim_rewards(address _user) external;
function claim_rewards(address _user, address _receiver) external;
// // solhint-disable-next-line
// function claim_rewards_for(address _user) external;
// solhint-disable-next-line
function deposit(uint256 _value, address _addr) external;
// solhint-disable-next-line
function reward_tokens(uint256 _i) external view returns (address);
function withdraw(uint256 _value, address _addr, bool _claim_rewards) external;
function withdraw(uint256 _value, address _addr) external;
function staking_token() external view returns (address);
function vault() external view returns (address);
// solhint-disable-next-line
function reward_data(address _tokenReward) external view returns (Reward memory);
function reward_count() external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address) external returns (uint256);
function claimable_reward(address _user, address _reward_token) external view returns (uint256);
function user_checkpoint(address _user) external returns (bool);
function commit_transfer_ownership(address) external;
function initialize(
address _staking_token,
address _admin,
address _SDT,
address _voting_escrow,
address _veBoost_proxy,
address _distributor,
address _vault,
string memory _symbol
) external;
function add_reward(address, address) external;
function set_claimer(address) external;
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function transfer(address _to, uint256 _value) external returns (bool);
function working_balances(address _address) external returns (uint256);
function set_reward_distributor(address _rewardToken, address _newDistrib) external;
}
Read Contract
BOOSTER 0x75b0ffd1 → address
CLAIM_HELPER 0x62810e1a → address
CONVEX_MINIMAL_PROXY_FACTORY 0xa77f0245 → address
CVX 0x759cb53b → address
DENOMINATOR 0x918f8674 → uint256
GAUGE_CONTROLLER 0x22884e2c → address
SDT 0xba32c619 → address
SDT_DISTRIBUTOR 0x58a13f08 → address
VESDT 0x48fc3c2d → address
VE_BOOST_PROXY 0x401c9eec → address
VE_FUNDER 0x1326c247 → address
liquidityGaugeImplementation 0x4e8090ce → address
rewardReceiverImplementation 0xd4bba87b → address
rewardToken 0xf7c618c1 → address
strategy 0xa8c62e76 → address
vaultImplementation 0xbba48a90 → address
Write Contract 3 functions
These functions modify contract state and require a wallet transaction to execute.
create 0x9ed93318
address _gauge
returns: address, address
create 0xf7a6bc7b
uint256 _pid
bool _deployPool
bool _deployConvex
returns: address, address, address
syncExtraRewards 0xfb7049cd
address _gauge
Recent Transactions
No transactions found for this address