Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x4f1C53F096533C04d8157EFB6Bca3eb22ddC6360
Balance 0 ETH
Nonce 1165
Code Size 17969 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

17969 bytes
0x60806040523480156200001157600080fd5b5060043610620002445760003560e01c806372eb5f2b1162000141578063b8f8a84c11620000bd578063df369ba71162000087578063df369ba714620004d3578063ebb3d58914620004ea578063ed9eeb7f14620004f4578063efcde9e3146200050b578063ff84571814620005225762000244565b8063b8f8a84c1462000465578063c83980dd146200047c578063cebffb5814620004a3578063d5189add14620004bc5762000244565b806393a2ecd9116200010b57806393a2ecd9146200041957806398f0d4bb14620004235780639c9d48da146200042d5780639f9df7851462000444578063ac259456146200045b5762000244565b806372eb5f2b14620003c8578063749cc8f514620003ee578063893d20e814620003f85780638c500ea314620004025762000244565b80634140d60711620001d1578063575403dc116200019b578063575403dc146200036f578063682cea1914620003865780636c579e5714620003905780636ea2114314620003a75780636f2b757414620003b15762000244565b80634140d60714620003135780634348ab62146200032a5780634bacc5f7146200034157806354391f0914620003585762000244565b806338b3eb1b116200021357806338b3eb1b14620002b45780633b30dce714620002cb5780633d0d4abb14620002e25780633f84c12c14620002fc5762000244565b80630d2fcd7614620002495780630ee2cb101462000262578063164dd2d4146200028457806336b4ea4f146200028e575b600080fd5b620002606200025a36600462002da6565b62000539565b005b6200026c6200060c565b6040516200027b919062003dd1565b60405180910390f35b6200026062000631565b620002a56200029f3660046200307e565b62000778565b6040516200027b919062003f2e565b62000260620002c53660046200303f565b620007d1565b62000260620002dc3660046200338e565b620009af565b620002ec62000a2e565b6040516200027b9291906200417a565b620002606200030d3660046200331b565b62000a4c565b620002606200032436600462002da6565b62000b3f565b6200026c6200033b36600462002eb8565b62000bfd565b6200026062000352366004620031ef565b62000e8e565b620002a56200036936600462002da6565b62000fda565b6200026062000380366004620033af565b62000ff8565b6200026c620010dd565b620002a5620003a136600462002da6565b620010ec565b6200026c6200110c565b62000260620003c2366004620031ef565b62001205565b620003df620003d936600462002da6565b62001336565b6040516200027b91906200415a565b6200026c6200137d565b6200026c6200138c565b620002a5620004133660046200307e565b620013f2565b6200026c6200148b565b620002a56200149a565b620002606200043e3660046200303f565b620014aa565b620002606200045536600462002da6565b62001529565b6200026c620015e7565b6200026c6200047636600462002f71565b6200160b565b620004936200048d366004620030d2565b620018ab565b6040516200027b92919062003de1565b620004ad62001b07565b6040516200027b91906200416a565b62000260620004cd36600462002da6565b62001b0d565b62000260620004e436600462002df0565b62001c0f565b6200026c62001cb5565b620002606200050536600462003234565b62001cd9565b620002606200051c36600462003234565b62001f60565b620002606200053336600462002da6565b62002192565b620005436200138c565b6001600160a01b0316336001600160a01b0316146200057f5760405162461bcd60e51b8152600401620005769062003ff2565b60405180910390fd5b620005896200148b565b6001600160a01b03811615620005b35760405162461bcd60e51b8152600401620005769062003fce565b600080546001600160a01b0319166001600160a01b0384161790556040517f38e37d5fdf60e4358769c3b616594ad451626b1e023c65eaa1062116feadacf8906200060090849062003dd1565b60405180910390a15050565b7f00000000000000000000000087a60129375d22489bbd287ec0d23129ef9290ef5b90565b6200063b6200060c565b6001600160a01b0316336001600160a01b0316146200066e5760405162461bcd60e51b8152600401620005769062004124565b620006786200149a565b15620006985760405162461bcd60e51b815260040162000576906200405e565b6000620006a46200148b565b6001600160a01b03161415620006ce5760405162461bcd60e51b8152600401620005769062003fbc565b6000620006da6200137d565b6001600160a01b03161415620007045760405162461bcd60e51b81526004016200057690620040a6565b600062000710620010dd565b6001600160a01b031614156200073a5760405162461bcd60e51b8152600401620005769062003f98565b6002805460ff60e01b1916600160e01b1790556040517f0356d4f8f825c1c2803d9e1f15724b6b8eea8992d04fad04da8bcbe6ff30296f90600090a1565b60006005600085856040516020016200079392919062003da7565b60408051601f1981840301815291815281516020928301208352828201939093529082016000908120858252909152205460ff1690505b9392505050565b81620007de813362002560565b6000620007ea62001cb5565b90506000816001600160a01b0316637dad9fc8866040518263ffffffff1660e01b81526004016200081c919062003dd1565b60806040518083038186803b1580156200083557600080fd5b505afa1580156200084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000870919062002e5a565b50506040516338b3eb1b60e01b81529092506001600160a01b03841691506338b3eb1b90620008a6908890889060040162003ef0565b600060405180830381600087803b158015620008c157600080fd5b505af1158015620008d6573d6000803e3d6000fd5b505060405163ce5e84a360e01b81526001600160a01b038416925063ce5e84a39150620009099060019060040162003f2e565b600060405180830381600087803b1580156200092457600080fd5b505af115801562000939573d6000803e3d6000fd5b50505050620009476200137d565b6001600160a01b0316630a48e041866040518263ffffffff1660e01b815260040162000974919062003dd1565b600060405180830381600087803b1580156200098f57600080fd5b505af1158015620009a4573d6000803e3d6000fd5b505050505050505050565b620009b96200138c565b6001600160a01b0316336001600160a01b031614620009ec5760405162461bcd60e51b8152600401620005769062003ff2565b60038190556040517fa12f25dbb69b970318f8cc02d37f8cfe5bb3fec3a55630fd7e419d6dc42f1d919062000a239083906200416a565b60405180910390a150565b60025463ffffffff600160a01b8204811691600160c01b9004169091565b336001600160a01b037f000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab32161462000a975760405162461bcd60e51b815260040162000576906200403a565b600285600481111562000aa657fe5b1462000ab25762000b38565b6000846001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b15801562000aee57600080fd5b505afa15801562000b03573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b29919062002dcf565b905062000b368162002605565b505b5050505050565b62000b496200138c565b6001600160a01b0316336001600160a01b03161462000b7c5760405162461bcd60e51b8152600401620005769062003ff2565b62000b86620010dd565b6001600160a01b0381161562000bb05760405162461bcd60e51b8152600401620005769062003fce565b600280546001600160a01b0319166001600160a01b0384161790556040517f1e01982aac1b1376985c41ed48c69e04ff4c75107bfe0b8a4827693d2ddba04e906200060090849062003dd1565b60008062000c0a62002647565b905062000c18898262002560565b3062000c2362001cb5565b6001600160a01b0316633d7c74f88b6040518263ffffffff1660e01b815260040162000c50919062003dd1565b60206040518083038186803b15801562000c6957600080fd5b505afa15801562000c7e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ca4919062002dcf565b6001600160a01b03161462000ccd5760405162461bcd60e51b8152600401620005769062004004565b62000cd889620010ec565b1562000cf85760405162461bcd60e51b8152600401620005769062004112565b62000d0581898962002690565b60405163397bfe5560e01b81529092506001600160a01b0383169063397bfe559062000d36908c9060040162003dd1565b600060405180830381600087803b15801562000d5157600080fd5b505af115801562000d66573d6000803e3d6000fd5b5050505062000de1828a88888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152506200278292505050565b600062000ded62001b07565b6040805180820182526001600160a01b038681168252429390930160208083018281528f86166000818152600690935291859020935184546001600160a01b031916908716178455516001909301929092559151919350918416907fbc4a5bba58d663a7e6752f3a72d2737260a60caeec28e0bf880ee25711f7fe1e9062000e79908790869062003f0f565b60405180910390a35050979650505050505050565b62000e986200138c565b6001600160a01b0316336001600160a01b03161462000ecb5760405162461bcd60e51b8152600401620005769062003ff2565b60005b8181101562000fd55762000eff83838381811062000ee857fe5b905060200201602081019062000369919062002da6565b62000f1e5760405162461bcd60e51b81526004016200057690620040ca565b60006004600085858581811062000f3157fe5b905060200201602081019062000f48919062002da6565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557fe49a33dc7a73a9833a0358b29ef8d5fecbfff419af0c4fd9219f57a7147009c683838381811062000f9e57fe5b905060200201602081019062000fb5919062002da6565b60405162000fc4919062003dd1565b60405180910390a160010162000ece565b505050565b6001600160a01b031660009081526004602052604090205460ff1690565b620010026200138c565b6001600160a01b0316336001600160a01b031614620010355760405162461bcd60e51b8152600401620005769062003ff2565b60008263ffffffff1611801562001052575060008163ffffffff16115b620010715760405162461bcd60e51b8152600401620005769062004082565b6002805463ffffffff838116600160c01b0263ffffffff60c01b19918616600160a01b0263ffffffff60a01b1990931692909217161790556040517f09069ba7f5bded3e9f9f7d353e606ae6ee8496309d9cbe09241d1c741e1dceed906200060090849084906200418a565b6002546001600160a01b031690565b6001600160a01b0390811660009081526006602052604090205416151590565b600062001118620015e7565b6001600160a01b03166398a7c4c76040518163ffffffff1660e01b815260040160206040518083038186803b1580156200115157600080fd5b505afa15801562001166573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200118c919062002dcf565b6001600160a01b0316637da0a8776040518163ffffffff1660e01b815260040160206040518083038186803b158015620011c557600080fd5b505afa158015620011da573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001200919062002dcf565b905090565b6200120f6200138c565b6001600160a01b0316336001600160a01b031614620012425760405162461bcd60e51b8152600401620005769062003ff2565b60005b8181101562000fd5576200125f83838381811062000ee857fe5b156200127f5760405162461bcd60e51b8152600401620005769062003fe0565b6001600460008585858181106200129257fe5b9050602002016020810190620012a9919062002da6565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790557f7b322f508cd6b0cc569822d5a028bb23e6698192d88a7b9669ab48fd68916eda838383818110620012ff57fe5b905060200201602081019062001316919062002da6565b60405162001325919062003dd1565b60405180910390a160010162001245565b6200134062002bee565b506001600160a01b039081166000908152600660209081526040918290208251808401909352805490931682526001909201549181019190915290565b6001546001600160a01b031690565b6000620013986200149a565b620013af57620013a76200060c565b90506200062e565b620013b962001cb5565b6001600160a01b031663893d20e86040518163ffffffff1660e01b815260040160206040518083038186803b158015620011c557600080fd5b60008084846040516020016200140a92919062003da7565b60408051601f19818403018152918152815160209283012060008181526005845282812087825290935291205490915060ff168062001482575060008181526005602090815260408083207f5bf1898dd28c4d29f33c4c1bb9b8a7e2f6322847d70be63e8f89de024d08a669845290915290205460ff165b95945050505050565b6000546001600160a01b031690565b600254600160e01b900460ff1690565b81620014b7813362002560565b620014c162001cb5565b6001600160a01b0316639c9d48da84846040518363ffffffff1660e01b8152600401620014f092919062003ef0565b600060405180830381600087803b1580156200150b57600080fd5b505af115801562001520573d6000803e3d6000fd5b50505050505050565b620015336200138c565b6001600160a01b0316336001600160a01b031614620015665760405162461bcd60e51b8152600401620005769062003ff2565b620015706200137d565b6001600160a01b038116156200159a5760405162461bcd60e51b8152600401620005769062003fce565b600180546001600160a01b0319166001600160a01b0384161790556040517f1a8919bc714742db0ed6eb86960768bdd5103c1dabb914651aaec5796907db15906200060090849062003dd1565b7f000000000000000000000000846bbe1925047023651de7ec289f329c24ded3a890565b6000620016176200149a565b620016365760405162461bcd60e51b8152600401620005769062004094565b8862001643813362002560565b6200164d62001cb5565b6001600160a01b031663d0449d3d8b6040518263ffffffff1660e01b81526004016200167a919062003dd1565b60206040518083038186803b1580156200169357600080fd5b505afa158015620016a8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620016ce9190620032d9565b15620016ee5760405162461bcd60e51b815260040162000576906200404c565b620016fb338a8a62002690565b60405163397bfe5560e01b81529092506001600160a01b0383169063397bfe55906200172c908d9060040162003dd1565b600060405180830381600087803b1580156200174757600080fd5b505af11580156200175c573d6000803e3d6000fd5b50505050620017d7828b89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284376000920191909152506200278292505050565b620017e162001cb5565b6001600160a01b031663d15f9b9c8b84620017fb620010dd565b876040518563ffffffff1660e01b81526004016200181d949392919062003e00565b600060405180830381600087803b1580156200183857600080fd5b505af11580156200184d573d6000803e3d6000fd5b50505050896001600160a01b0316336001600160a01b03167f7cb609d1845028175b74ce1b27f0b41ba93711f8699a747463f0cf89c5c95b818460405162001896919062003dd1565b60405180910390a35098975050505050505050565b600080620018b86200149a565b620018d75760405162461bcd60e51b8152600401620005769062004094565b6000620018e362002647565b9050620018f2818a8a62002690565b9250620019048e848f8f8f8f62002ad6565b60405163397bfe5560e01b815290925083906001600160a01b0382169063397bfe55906200193790869060040162003dd1565b600060405180830381600087803b1580156200195257600080fd5b505af115801562001967573d6000803e3d6000fd5b50505050620019e284848a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b90819084018382808284376000920191909152506200278292505050565b60405163ce5e84a360e01b81526001600160a01b0382169063ce5e84a39062001a119060009060040162003f2e565b600060405180830381600087803b15801562001a2c57600080fd5b505af115801562001a41573d6000803e3d6000fd5b5050505062001a4f6200137d565b6001600160a01b0316630a48e041846040518263ffffffff1660e01b815260040162001a7c919062003dd1565b600060405180830381600087803b15801562001a9757600080fd5b505af115801562001aac573d6000803e3d6000fd5b50505050816001600160a01b03167f04dab3bc63cc7e4b52aa28a026644559e2937d78dbf7b81e26dfecdd8bbe33b9848660405162001aed92919062003de1565b60405180910390a250509b509b9950505050505050505050565b60035490565b8062001b238162001b1d62002647565b62002560565b6001600160a01b03808316600090815260066020526040902054168062001b5e5760405162461bcd60e51b8152600401620005769062003f86565b806001600160a01b031663e53a73b96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562001b9a57600080fd5b505af115801562001baf573d6000803e3d6000fd5b505050506001600160a01b0383811660008181526006602052604080822080546001600160a01b031916815560010182905551928416927f8eae645f408f18cb738736a49846a7ccb7a4ed8cdf9b960624ea965ffbe96e919190a3505050565b336001600160a01b037f000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab32161462001c5a5760405162461bcd60e51b815260040162000576906200403a565b816001600160a01b031663e53a73b96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562001c9657600080fd5b505af115801562001cab573d6000803e3d6000fd5b5050505050505050565b7f000000000000000000000000c3dc853dd716bd5754f421ef94fdcbac3902ab3290565b62001ce36200138c565b6001600160a01b0316336001600160a01b03161462001d165760405162461bcd60e51b8152600401620005769062003ff2565b8362001d365760405162461bcd60e51b8152600401620005769062004100565b838214801562001d465750805184145b62001d655760405162461bcd60e51b8152600401620005769062004148565b60005b8481101562000b365762001dd886868381811062001d8257fe5b905060200201602081019062001d99919062002da6565b85858481811062001da657fe5b905060200201602081019062001dbd9190620032fa565b84848151811062001dca57fe5b602002602001015162000778565b62001df75760405162461bcd60e51b8152600401620005769062004016565b60006005600088888581811062001e0a57fe5b905060200201602081019062001e21919062002da6565b87878681811062001e2e57fe5b905060200201602081019062001e459190620032fa565b60405160200162001e5892919062003da7565b604051602081830303815290604052805190602001208152602001908152602001600020600084848151811062001e8b57fe5b6020026020010151815260200190815260200160002060006101000a81548160ff02191690831515021790555085858281811062001ec557fe5b905060200201602081019062001edc919062002da6565b6001600160a01b03167f845c9ef356cc5570a54e9eb6be3e6d95a2aaad4c4c7d7b2c0cf8c7cdd78d614d85858481811062001f1357fe5b905060200201602081019062001f2a9190620032fa565b84848151811062001f3757fe5b602002602001015160405162001f4f92919062003f3e565b60405180910390a260010162001d68565b62001f6a6200138c565b6001600160a01b0316336001600160a01b03161462001f9d5760405162461bcd60e51b8152600401620005769062003ff2565b8362001fbd5760405162461bcd60e51b81526004016200057690620040b8565b838214801562001fcd5750805184145b62001fec5760405162461bcd60e51b81526004016200057690620040ee565b60005b8481101562000b36576200200986868381811062001d8257fe5b15620020295760405162461bcd60e51b81526004016200057690620040dc565b6001600560008888858181106200203c57fe5b905060200201602081019062002053919062002da6565b8787868181106200206057fe5b9050602002016020810190620020779190620032fa565b6040516020016200208a92919062003da7565b6040516020818303038152906040528051906020012081526020019081526020016000206000848481518110620020bd57fe5b6020026020010151815260200190815260200160002060006101000a81548160ff021916908315150217905550858582818110620020f757fe5b90506020020160208101906200210e919062002da6565b6001600160a01b03167fb1fbe377864edcbf521713f906125bd99a3638c7a9e4087f6a70019686a741d18585848181106200214557fe5b90506020020160208101906200215c9190620032fa565b8484815181106200216957fe5b60200260200101516040516200218192919062003f3e565b60405180910390a260010162001fef565b80620021a28162001b1d62002647565b620021ac62002bee565b620021b78362001336565b80519091506001600160a01b0316620021e45760405162461bcd60e51b8152600401620005769062003faa565b80602001514210156200220b5760405162461bcd60e51b8152600401620005769062004136565b306200221662001cb5565b6001600160a01b0316633d7c74f8856040518263ffffffff1660e01b815260040162002243919062003dd1565b60206040518083038186803b1580156200225c57600080fd5b505afa15801562002271573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002297919062002dcf565b6001600160a01b031614620022c05760405162461bcd60e51b8152600401620005769062004070565b6000836001600160a01b0316635a53e3486040518163ffffffff1660e01b815260040160206040518083038186803b158015620022fc57600080fd5b505afa15801562002311573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002337919062002dcf565b90506000816001600160a01b031663faf9096b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200237557600080fd5b505afa1580156200238a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023b0919062002dcf565b9050620023bd8262002605565b8251604051633a0795ad60e11b81526001600160a01b0387169163740f2b5a91620023ec919060040162003dd1565b600060405180830381600087803b1580156200240757600080fd5b505af11580156200241c573d6000803e3d6000fd5b5050845160405163ce5e84a360e01b81526001600160a01b03909116925063ce5e84a39150620024529060019060040162003f2e565b600060405180830381600087803b1580156200246d57600080fd5b505af115801562002482573d6000803e3d6000fd5b505050506001600160a01b03811615620024fc5782516040516373eecf4760e01b81526001600160a01b03909116906373eecf4790620024c790849060040162003dd1565b600060405180830381600087803b158015620024e257600080fd5b505af1158015620024f7573d6000803e3d6000fd5b505050505b6001600160a01b0380861660008181526006602052604080822080546001600160a01b03191681556001018290558651905190841693861692917fa587629d93edeac6431610facaeec919890c8bc040ef849f720e42315148d7d991a45050505050565b604051633ef03e7560e11b81526001600160a01b03831690637de07cea906200258e90849060040162003dd1565b60206040518083038186803b158015620025a757600080fd5b505afa158015620025bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025e29190620032d9565b620026015760405162461bcd60e51b8152600401620005769062004028565b5050565b6000806200261262000a2e565b60405163495abadb60e11b815291935091506001600160a01b038416906392b575b690620014f090859085906004016200417a565b600060183610801590620026755750620026606200110c565b6001600160a01b0316336001600160a01b0316145b156200268b575060131936013560601c6200062e565b503390565b6000606063399ae72460e01b8484604051602401620026b192919062003f0f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905080620026f06200148b565b604051620026fe9062002c05565b6200270b92919062003f4e565b604051809103906000f08015801562002728573d6000803e3d6000fd5b509150836001600160a01b0316856001600160a01b03167f19dbe5ac5bcfdc5074f78d1e907e1dce6f6e3b50a56b50d990926abaf9c5505784866040516200277292919062003f0f565b60405180910390a3509392505050565b8151156200286557836001600160a01b031663f2d638266040518163ffffffff1660e01b815260040160206040518083038186803b158015620027c457600080fd5b505afa158015620027d9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620027ff919062002dcf565b6001600160a01b031663f067cc118585856040518463ffffffff1660e01b8152600401620028309392919062003e8b565b600060405180830381600087803b1580156200284b57600080fd5b505af115801562002860573d6000803e3d6000fd5b505050505b836001600160a01b031663b3fc38e96040518163ffffffff1660e01b815260040160206040518083038186803b1580156200289f57600080fd5b505afa158015620028b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620028da919062002dcf565b6001600160a01b031663f067cc1185856040518363ffffffff1660e01b81526004016200290992919062003ebe565b600060405180830381600087803b1580156200292457600080fd5b505af115801562002939573d6000803e3d6000fd5b50505050836001600160a01b031663e7c456906040518163ffffffff1660e01b815260040160206040518083038186803b1580156200297757600080fd5b505afa1580156200298c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620029b2919062002dcf565b6001600160a01b031663f067cc1185856040518363ffffffff1660e01b8152600401620029e192919062003ebe565b600060405180830381600087803b158015620029fc57600080fd5b505af115801562002a11573d6000803e3d6000fd5b50505050836001600160a01b031663d44ad6cb6040518163ffffffff1660e01b815260040160206040518083038186803b15801562002a4f57600080fd5b505afa15801562002a64573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002a8a919062002dcf565b6001600160a01b031663f067cc118585846040518463ffffffff1660e01b815260040162002abb9392919062003e8b565b600060405180830381600087803b15801562001c9657600080fd5b600062002ae262001cb5565b6001600160a01b03166322a0c08b62002afa620010dd565b898989896040518663ffffffff1660e01b815260040162002b2095949392919062003e3d565b602060405180830381600087803b15801562002b3b57600080fd5b505af115801562002b50573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002b76919062002dcf565b9050811562002be457604051635c26412360e11b81526001600160a01b0382169063b84c82469062002baf908690869060040162003f72565b600060405180830381600087803b15801562002bca57600080fd5b505af115801562002bdf573d6000803e3d6000fd5b505050505b9695505050505050565b604080518082019091526000808252602082015290565b61030980620042f383390190565b803562002c20816200429e565b92915050565b805162002c20816200429e565b60008083601f84011262002c4657600080fd5b5081356001600160401b0381111562002c5e57600080fd5b60208301915083602082028301111562002c7757600080fd5b9250929050565b600082601f83011262002c9057600080fd5b813562002ca762002ca182620041d0565b620041a9565b9150818183526020840193506020810190508385602084028201111562002ccd57600080fd5b60005b8381101562002cfd578162002ce6888262002d21565b845250602092830192919091019060010162002cd0565b5050505092915050565b803562002c2081620042b8565b805162002c2081620042b8565b803562002c2081620042c3565b803562002c2081620042ce565b60008083601f84011262002d4e57600080fd5b5081356001600160401b0381111562002d6657600080fd5b60208301915083600182028301111562002c7757600080fd5b803562002c2081620042d9565b805162002c2081620042c3565b803562002c2081620042e7565b60006020828403121562002db957600080fd5b600062002dc7848462002c13565b949350505050565b60006020828403121562002de257600080fd5b600062002dc7848462002c26565b6000806000806080858703121562002e0757600080fd5b600062002e15878762002c13565b945050602062002e288782880162002c13565b935050604062002e3b8782880162002c13565b925050606062002e4e8782880162002c13565b91505092959194509250565b6000806000806080858703121562002e7157600080fd5b600062002e7f878762002c26565b945050602062002e928782880162002c26565b935050604062002ea58782880162002c26565b925050606062002e4e8782880162002d8c565b600080600080600080600060a0888a03121562002ed457600080fd5b600062002ee28a8a62002c13565b975050602062002ef58a828b0162002c13565b965050604062002f088a828b0162002d21565b95505060608801356001600160401b0381111562002f2557600080fd5b62002f338a828b0162002d3b565b945094505060808801356001600160401b0381111562002f5257600080fd5b62002f608a828b0162002d3b565b925092505092959891949750929550565b60008060008060008060008060c0898b03121562002f8e57600080fd5b600062002f9c8b8b62002c13565b985050602062002faf8b828c0162002c13565b975050604062002fc28b828c0162002d21565b96505060608901356001600160401b0381111562002fdf57600080fd5b62002fed8b828c0162002d3b565b955095505060808901356001600160401b038111156200300c57600080fd5b6200301a8b828c0162002d3b565b935093505060a06200302f8b828c0162002d07565b9150509295985092959890939650565b600080604083850312156200305357600080fd5b600062003061858562002c13565b9250506020620030748582860162002d07565b9150509250929050565b6000806000606084860312156200309457600080fd5b6000620030a2868662002c13565b9350506020620030b58682870162002d2e565b9250506040620030c88682870162002d21565b9150509250925092565b600080600080600080600080600080600060e08c8e031215620030f457600080fd5b6000620031028e8e62002c13565b9b505060208c01356001600160401b038111156200311f57600080fd5b6200312d8e828f0162002d3b565b9a509a505060408c01356001600160401b038111156200314c57600080fd5b6200315a8e828f0162002d3b565b985098505060606200316f8e828f0162002c13565b9650506080620031828e828f0162002d21565b95505060a08c01356001600160401b038111156200319f57600080fd5b620031ad8e828f0162002d3b565b945094505060c08c01356001600160401b03811115620031cc57600080fd5b620031da8e828f0162002d3b565b92509250509295989b509295989b9093969950565b600080602083850312156200320357600080fd5b82356001600160401b038111156200321a57600080fd5b620032288582860162002c33565b92509250509250929050565b6000806000806000606086880312156200324d57600080fd5b85356001600160401b038111156200326457600080fd5b620032728882890162002c33565b955095505060208601356001600160401b038111156200329157600080fd5b6200329f8882890162002c33565b935093505060408601356001600160401b03811115620032be57600080fd5b620032cc8882890162002c7e565b9150509295509295909350565b600060208284031215620032ec57600080fd5b600062002dc7848462002d14565b6000602082840312156200330d57600080fd5b600062002dc7848462002d2e565b600080600080600060a086880312156200333457600080fd5b600062003342888862002d7f565b9550506020620033558882890162002c13565b9450506040620033688882890162002c13565b93505060606200337b8882890162002c13565b9250506080620032cc8882890162002c13565b600060208284031215620033a157600080fd5b600062002dc7848462002d21565b60008060408385031215620033c357600080fd5b6000620033d1858562002d99565b9250506020620030748582860162002d99565b620033ef81620041fe565b82525050565b620033ef6200340482620041fe565b6200427a565b620033ef816200420b565b620033ef816200062e565b620033ef8162004210565b620033ef6200343a8262004210565b6200062e565b60006200344d82620041f1565b620034598185620041f5565b93506200346b8185602086016200424b565b62003476816200428e565b9093019392505050565b60006200348e8385620041f5565b93506200349d8385846200423f565b62003476836200428e565b6000620034b7604883620041f5565b7f63616e63656c5265636f6e66696775726174696f6e3a204e6f207265636f6e6681527f696775726174696f6e20726571756573742065786973747320666f72205f7661602082015267756c7450726f787960c01b604082015260600192915050565b600062003529602383620041f5565b7f73657452656c656173654c6976653a207661756c744c6962206973206e6f74208152621cd95d60ea1b602082015260400192915050565b600062003570604983620041f5565b7f657865637574655265636f6e66696775726174696f6e3a204e6f207265636f6e81527f66696775726174696f6e20726571756573742065786973747320666f72205f7660208201526861756c7450726f787960b81b604082015260600192915050565b6000620035e3602983620041f5565b7f73657452656c656173654c6976653a20636f6d7074726f6c6c65724c696220698152681cc81b9bdd081cd95d60ba1b602082015260400192915050565b600062003630601f83620041f5565b7f546869732076616c75652063616e206f6e6c7920626520736574206f6e636500815260200192915050565b60006200366b603b83620041f5565b7f72656769737465724275795368617265734f6e426568616c6643616c6c65727381527f3a2043616c6c657220616c726561647920726567697374657265640000000000602082015260400192915050565b6000620036cc602e83620041f5565b7f4f6e6c792074686520636f6e7472616374206f776e65722063616e2063616c6c81526d103a3434b990333ab731ba34b7b760911b602082015260400192915050565b60006200371e603c83620041f5565b7f6372656174655265636f6e66696775726174696f6e526571756573743a20566181527f756c7450726f7879206e6f74206f6e20746869732072656c6561736500000000602082015260400192915050565b60006200377f602983620041f5565b7f646572656769737465725661756c7443616c6c733a2043616c6c206e6f7420728152681959da5cdd195c995960ba1b602082015260400192915050565b6000620037cc603383620041f5565b7f4f6e6c792061207065726d697373696f6e6564206d69677261746f722063616e8152721031b0b636103a3434b990333ab731ba34b7b760691b602082015260400192915050565b600062003823602683620041f5565b7f4f6e6c7920446973706174636865722063616e2063616c6c20746869732066758152653731ba34b7b760d11b602082015260400192915050565b60006200386d603983620041f5565b7f6372656174654d6967726174696f6e526571756573743a2041204d696772617481527f696f6e5265717565737420616c72656164792065786973747300000000000000602082015260400192915050565b6000620038ce601c83620041f5565b7f73657452656c656173654c6976653a20416c7265616479206c69766500000000815260200192915050565b600062003909604083620041f5565b7f657865637574655265636f6e66696775726174696f6e3a205f7661756c74507281527f6f7879206973206e6f206c6f6e676572206f6e20746869732072656c65617365602082015260400192915050565b60006200396a603383620041f5565b7f7365744761734c696d697473466f72446573747275637443616c6c3a205a65728152721bc81d985b1d59481b9bdd08185b1b1bddd959606a1b602082015260400192915050565b6000620039c1601783620041f5565b7f52656c65617365206973206e6f7420796574206c697665000000000000000000815260200192915050565b6000620039fc602d83620041f5565b7f73657452656c656173654c6976653a2070726f746f636f6c466565547261636b81526c195c881a5cc81b9bdd081cd95d609a1b602082015260400192915050565b600062003a4d602483620041f5565b7f72656769737465725661756c7443616c6c733a20456d707479205f636f6e74728152636163747360e01b602082015260400192915050565b600062002c20600083620041f5565b600062003aa4603983620041f5565b7f646572656769737465724275795368617265734f6e426568616c6643616c6c6581527f72733a2043616c6c6572206e6f74207265676973746572656400000000000000602082015260400192915050565b600062003b05602b83620041f5565b7f72656769737465725661756c7443616c6c733a2043616c6c20616c726561647981526a081c9959da5cdd195c995960aa1b602082015260400192915050565b600062003b54602783620041f5565b7f72656769737465725661756c7443616c6c733a20556e6576656e20696e7075748152662061727261797360c81b602082015260400192915050565b600062003b9f602683620041f5565b7f646572656769737465725661756c7443616c6c733a20456d707479205f636f6e81526574726163747360d01b602082015260400192915050565b600062003be9604e83620041f5565b7f6372656174655265636f6e66696775726174696f6e526571756573743a20566181527f756c7450726f78792068617320612070656e64696e67207265636f6e6669677560208201526d1c985d1a5bdb881c995c5d595cdd60921b604082015260600192915050565b600062003c61603783620041f5565b7f73657452656c656173654c6976653a204f6e6c79207468652063726561746f7281527f2063616e2063616c6c20746869732066756e6374696f6e000000000000000000602082015260400192915050565b600062003cc2604483620041f5565b7f657865637574655265636f6e66696775726174696f6e3a20546865207265636f81527f6e66696775726174696f6e2074696d656c6f636b20686173206e6f7420656c616020820152631c1cd95960e21b604082015260600192915050565b600062003d30602983620041f5565b7f646572656769737465725661756c7443616c6c733a20556e6576656e20696e7081526875742061727261797360b81b602082015260400192915050565b8051604083019062003d818482620033e4565b50602082015162003d96602085018262003415565b50505050565b620033ef8162004232565b600062003db58285620033f5565b60148201915062003dc782846200342b565b5060040192915050565b6020810162002c208284620033e4565b6040810162003df18285620033e4565b620007ca6020830184620033e4565b6080810162003e108287620033e4565b62003e1f6020830186620033e4565b62003e2e6040830185620033e4565b6200148260608301846200340a565b6080810162003e4d8288620033e4565b62003e5c6020830187620033e4565b62003e6b6040830186620033e4565b818103606083015262003e8081848662003480565b979650505050505050565b6060810162003e9b8286620033e4565b62003eaa6020830185620033e4565b818103604083015262001482818462003440565b6060810162003ece8285620033e4565b62003edd6020830184620033e4565b818103604083015262002dc78162003a86565b6040810162003f008285620033e4565b620007ca60208301846200340a565b6040810162003f1f8285620033e4565b620007ca602083018462003415565b6020810162002c2082846200340a565b6040810162003f1f828562003420565b6040808252810162003f61818562003440565b9050620007ca6020830184620033e4565b6020808252810162002dc781848662003480565b6020808252810162002c2081620034a8565b6020808252810162002c20816200351a565b6020808252810162002c208162003561565b6020808252810162002c2081620035d4565b6020808252810162002c208162003621565b6020808252810162002c20816200365c565b6020808252810162002c2081620036bd565b6020808252810162002c20816200370f565b6020808252810162002c208162003770565b6020808252810162002c2081620037bd565b6020808252810162002c208162003814565b6020808252810162002c20816200385e565b6020808252810162002c2081620038bf565b6020808252810162002c2081620038fa565b6020808252810162002c20816200395b565b6020808252810162002c2081620039b2565b6020808252810162002c2081620039ed565b6020808252810162002c208162003a3e565b6020808252810162002c208162003a95565b6020808252810162002c208162003af6565b6020808252810162002c208162003b45565b6020808252810162002c208162003b90565b6020808252810162002c208162003bda565b6020808252810162002c208162003c52565b6020808252810162002c208162003cb3565b6020808252810162002c208162003d21565b6040810162002c20828462003d6e565b6020810162002c20828462003415565b6040810162003f1f828562003415565b604081016200419a828562003d9c565b620007ca602083018462003d9c565b6040518181016001600160401b0381118282101715620041c857600080fd5b604052919050565b60006001600160401b03821115620041e757600080fd5b5060209081020190565b5190565b90815260200190565b600062002c20826200421d565b151590565b6001600160e01b03191690565b6001600160a01b031690565b63ffffffff1690565b600062002c208262004229565b82818337506000910152565b60005b83811015620042685781810151838201526020016200424e565b8381111562003d965750506000910152565b600062002c2082600062002c208262004298565b601f01601f191690565b60601b90565b620042a981620041fe565b8114620042b557600080fd5b50565b620042a9816200420b565b620042a9816200062e565b620042a98162004210565b60058110620042b557600080fd5b620042a9816200422956fe60a060405234801561001057600080fd5b506040516103093803806103098339818101604052604081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b50604052602001805190602001909291905050508181806001600160a01b03166080816001600160a01b031660601b81525050807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5560006060826001600160a01b0316846040518082805190602001908083835b602083106101705780518252601f199092019160209182019101610151565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146101d0576040519150601f19603f3d011682016040523d82523d6000602084013e6101d5565b606091505b50915091508181906102655760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561022a578181015183820152602001610212565b50505050905090810190601f1680156102575780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5050505050505060805160601c6083610286600039806006525060836000f3fe60806040527f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000846127105a03f43d806000803e818015604857816000f35b816000fdfea2646970667358221220af3fa506b4585d3105feda3d44f2fc3c9f0ebf4c6a5e5924e3a86b53bce8828564736f6c634300060c0033a2646970667358221220d9b62d9b60679c4b6382580270964cc4183cf3513320f3be13c4e15ba22da2dd64736f6c634300060c0033

Verified Source Code Full Match

Compiler: v0.6.12+commit.27d51765 EVM: istanbul
IGsnTypes.sol 35 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./IGsnForwarder.sol";

/// @title IGsnTypes Interface
/// @author Enzyme Council <[email protected]>
interface IGsnTypes {
    struct RelayData {
        uint256 gasPrice;
        uint256 pctRelayFee;
        uint256 baseRelayFee;
        address relayWorker;
        address paymaster;
        address forwarder;
        bytes paymasterData;
        uint256 clientId;
    }

    struct RelayRequest {
        IGsnForwarder.ForwardRequest request;
        RelayData relayData;
    }
}
IExtension.sol 33 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IExtension Interface
/// @author Enzyme Council <[email protected]>
/// @notice Interface for all extensions
interface IExtension {
    function activateForFund(bool _isMigration) external;

    function deactivateForFund() external;

    function receiveCallFromComptroller(
        address _caller,
        uint256 _actionId,
        bytes calldata _callArgs
    ) external;

    function setConfigForFund(
        address _comptrollerProxy,
        address _vaultProxy,
        bytes calldata _configData
    ) external;
}
IVault.sol 87 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

import "../../../../persistent/vault/interfaces/IExternalPositionVault.sol";
import "../../../../persistent/vault/interfaces/IFreelyTransferableSharesVault.sol";
import "../../../../persistent/vault/interfaces/IMigratableVault.sol";

/// @title IVault Interface
/// @author Enzyme Council <[email protected]>
interface IVault is IMigratableVault, IFreelyTransferableSharesVault, IExternalPositionVault {
    enum VaultAction {
        None,
        // Shares management
        BurnShares,
        MintShares,
        TransferShares,
        // Asset management
        AddTrackedAsset,
        ApproveAssetSpender,
        RemoveTrackedAsset,
        WithdrawAssetTo,
        // External position management
        AddExternalPosition,
        CallOnExternalPosition,
        RemoveExternalPosition
    }

    function addTrackedAsset(address) external;

    function burnShares(address, uint256) external;

    function buyBackProtocolFeeShares(
        uint256,
        uint256,
        uint256
    ) external;

    function callOnContract(address, bytes calldata) external returns (bytes memory);

    function canManageAssets(address) external view returns (bool);

    function canRelayCalls(address) external view returns (bool);

    function getAccessor() external view returns (address);

    function getOwner() external view returns (address);

    function getActiveExternalPositions() external view returns (address[] memory);

    function getTrackedAssets() external view returns (address[] memory);

    function isActiveExternalPosition(address) external view returns (bool);

    function isTrackedAsset(address) external view returns (bool);

    function mintShares(address, uint256) external;

    function payProtocolFee() external;

    function receiveValidatedVaultAction(VaultAction, bytes calldata) external;

    function setAccessorForFundReconfiguration(address) external;

    function setSymbol(string calldata) external;

    function transferShares(
        address,
        address,
        uint256
    ) external;

    function withdrawAssetTo(
        address,
        address,
        uint256
    ) external;
}
IGsnForwarder.sol 26 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IGsnForwarder interface
/// @author Enzyme Council <[email protected]>
interface IGsnForwarder {
    struct ForwardRequest {
        address from;
        address to;
        uint256 value;
        uint256 gas;
        uint256 nonce;
        bytes data;
        uint256 validUntil;
    }
}
IGsnPaymaster.sol 50 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./IGsnTypes.sol";

/// @title IGsnPaymaster interface
/// @author Enzyme Council <[email protected]>
interface IGsnPaymaster {
    struct GasAndDataLimits {
        uint256 acceptanceBudget;
        uint256 preRelayedCallGasLimit;
        uint256 postRelayedCallGasLimit;
        uint256 calldataSizeLimit;
    }

    function getGasAndDataLimits() external view returns (GasAndDataLimits memory limits);

    function getHubAddr() external view returns (address);

    function getRelayHubDeposit() external view returns (uint256);

    function preRelayedCall(
        IGsnTypes.RelayRequest calldata relayRequest,
        bytes calldata signature,
        bytes calldata approvalData,
        uint256 maxPossibleGas
    ) external returns (bytes memory context, bool rejectOnRecipientRevert);

    function postRelayedCall(
        bytes calldata context,
        bool success,
        uint256 gasUseWithoutPost,
        IGsnTypes.RelayData calldata relayData
    ) external;

    function trustedForwarder() external view returns (address);

    function versionPaymaster() external view returns (string memory);
}
NonUpgradableProxy.sol 63 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title NonUpgradableProxy Contract
/// @author Enzyme Council <[email protected]>
/// @notice A proxy contract for use with non-upgradable libs
/// @dev The recommended constructor-fallback pattern of a proxy in EIP-1822, updated for solc 0.6.12,
/// and using an immutable lib value to save on gas (since not upgradable).
/// The EIP-1967 storage slot for the lib is still assigned,
/// for ease of referring to UIs that understand the pattern, i.e., Etherscan.
abstract contract NonUpgradableProxy {
    address private immutable CONTRACT_LOGIC;

    constructor(bytes memory _constructData, address _contractLogic) public {
        CONTRACT_LOGIC = _contractLogic;

        assembly {
            // EIP-1967 slot: `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
            sstore(
                0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
                _contractLogic
            )
        }
        (bool success, bytes memory returnData) = _contractLogic.delegatecall(_constructData);
        require(success, string(returnData));
    }

    // solhint-disable-next-line no-complex-fallback
    fallback() external payable {
        address contractLogic = CONTRACT_LOGIC;

        assembly {
            calldatacopy(0x0, 0x0, calldatasize())
            let success := delegatecall(
                sub(gas(), 10000),
                contractLogic,
                0x0,
                calldatasize(),
                0,
                0
            )
            let retSz := returndatasize()
            returndatacopy(0, 0, retSz)
            switch success
                case 0 {
                    revert(0, retSz)
                }
                default {
                    return(0, retSz)
                }
        }
    }
}
IDispatcher.sol 86 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IDispatcher Interface
/// @author Enzyme Council <[email protected]>
interface IDispatcher {
    function cancelMigration(address _vaultProxy, bool _bypassFailure) external;

    function claimOwnership() external;

    function deployVaultProxy(
        address _vaultLib,
        address _owner,
        address _vaultAccessor,
        string calldata _fundName
    ) external returns (address vaultProxy_);

    function executeMigration(address _vaultProxy, bool _bypassFailure) external;

    function getCurrentFundDeployer() external view returns (address currentFundDeployer_);

    function getFundDeployerForVaultProxy(address _vaultProxy)
        external
        view
        returns (address fundDeployer_);

    function getMigrationRequestDetailsForVaultProxy(address _vaultProxy)
        external
        view
        returns (
            address nextFundDeployer_,
            address nextVaultAccessor_,
            address nextVaultLib_,
            uint256 executableTimestamp_
        );

    function getMigrationTimelock() external view returns (uint256 migrationTimelock_);

    function getNominatedOwner() external view returns (address nominatedOwner_);

    function getOwner() external view returns (address owner_);

    function getSharesTokenSymbol() external view returns (string memory sharesTokenSymbol_);

    function getTimelockRemainingForMigrationRequest(address _vaultProxy)
        external
        view
        returns (uint256 secondsRemaining_);

    function hasExecutableMigrationRequest(address _vaultProxy)
        external
        view
        returns (bool hasExecutableRequest_);

    function hasMigrationRequest(address _vaultProxy)
        external
        view
        returns (bool hasMigrationRequest_);

    function removeNominatedOwner() external;

    function setCurrentFundDeployer(address _nextFundDeployer) external;

    function setMigrationTimelock(uint256 _nextTimelock) external;

    function setNominatedOwner(address _nextNominatedOwner) external;

    function setSharesTokenSymbol(string calldata _nextSymbol) external;

    function signalMigration(
        address _vaultProxy,
        address _nextVaultAccessor,
        address _nextVaultLib,
        bool _bypassFailure
    ) external;
}
IBeacon.sol 18 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IBeacon interface
/// @author Enzyme Council <[email protected]>
interface IBeacon {
    function getCanonicalLib() external view returns (address);
}
FundDeployer.sol 917 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "../../../persistent/dispatcher/IDispatcher.sol";
import "../../../persistent/dispatcher/IMigrationHookHandler.sol";
import "../../extensions/IExtension.sol";
import "../../infrastructure/gas-relayer/GasRelayRecipientMixin.sol";
import "../../infrastructure/protocol-fees/IProtocolFeeTracker.sol";
import "../fund/comptroller/ComptrollerProxy.sol";
import "../fund/comptroller/IComptroller.sol";
import "../fund/vault/IVault.sol";
import "./IFundDeployer.sol";

/// @title FundDeployer Contract
/// @author Enzyme Council <[email protected]>
/// @notice The top-level contract of the release.
/// It primarily coordinates fund deployment and fund migration, but
/// it is also deferred to for contract access control and for allowed calls
/// that can be made with a fund's VaultProxy as the msg.sender.
contract FundDeployer is IFundDeployer, IMigrationHookHandler, GasRelayRecipientMixin {
    event BuySharesOnBehalfCallerDeregistered(address caller);

    event BuySharesOnBehalfCallerRegistered(address caller);

    event ComptrollerLibSet(address comptrollerLib);

    event ComptrollerProxyDeployed(
        address indexed creator,
        address comptrollerProxy,
        address indexed denominationAsset,
        uint256 sharesActionTimelock
    );

    event GasLimitsForDestructCallSet(
        uint256 nextDeactivateFeeManagerGasLimit,
        uint256 nextPayProtocolFeeGasLimit
    );

    event MigrationRequestCreated(
        address indexed creator,
        address indexed vaultProxy,
        address comptrollerProxy
    );

    event NewFundCreated(address indexed creator, address vaultProxy, address comptrollerProxy);

    event ProtocolFeeTrackerSet(address protocolFeeTracker);

    event ReconfigurationRequestCancelled(
        address indexed vaultProxy,
        address indexed nextComptrollerProxy
    );

    event ReconfigurationRequestCreated(
        address indexed creator,
        address indexed vaultProxy,
        address comptrollerProxy,
        uint256 executableTimestamp
    );

    event ReconfigurationRequestExecuted(
        address indexed vaultProxy,
        address indexed prevComptrollerProxy,
        address indexed nextComptrollerProxy
    );

    event ReconfigurationTimelockSet(uint256 nextTimelock);

    event ReleaseIsLive();

    event VaultCallDeregistered(
        address indexed contractAddress,
        bytes4 selector,
        bytes32 dataHash
    );

    event VaultCallRegistered(address indexed contractAddress, bytes4 selector, bytes32 dataHash);

    event VaultLibSet(address vaultLib);

    struct ReconfigurationRequest {
        address nextComptrollerProxy;
        uint256 executableTimestamp;
    }

    // Constants
    // keccak256(abi.encodePacked("mln.vaultCall.any")
    bytes32
        private constant ANY_VAULT_CALL = 0x5bf1898dd28c4d29f33c4c1bb9b8a7e2f6322847d70be63e8f89de024d08a669;

    address private immutable CREATOR;
    address private immutable DISPATCHER;

    // Pseudo-constants (can only be set once)
    address private comptrollerLib;
    address private protocolFeeTracker;
    address private vaultLib;

    // Storage
    uint32 private gasLimitForDestructCallToDeactivateFeeManager; // Can reduce to uint16
    uint32 private gasLimitForDestructCallToPayProtocolFee; // Can reduce to uint16
    bool private isLive;
    uint256 private reconfigurationTimelock;

    mapping(address => bool) private acctToIsAllowedBuySharesOnBehalfCaller;
    mapping(bytes32 => mapping(bytes32 => bool)) private vaultCallToPayloadToIsAllowed;
    mapping(address => ReconfigurationRequest) private vaultProxyToReconfigurationRequest;

    modifier onlyDispatcher() {
        require(msg.sender == DISPATCHER, "Only Dispatcher can call this function");
        _;
    }

    modifier onlyLiveRelease() {
        require(releaseIsLive(), "Release is not yet live");
        _;
    }

    modifier onlyMigrator(address _vaultProxy) {
        __assertIsMigrator(_vaultProxy, __msgSender());
        _;
    }

    modifier onlyMigratorNotRelayable(address _vaultProxy) {
        __assertIsMigrator(_vaultProxy, msg.sender);
        _;
    }

    modifier onlyOwner() {
        require(msg.sender == getOwner(), "Only the contract owner can call this function");
        _;
    }

    modifier pseudoConstant(address _storageValue) {
        require(_storageValue == address(0), "This value can only be set once");
        _;
    }

    function __assertIsMigrator(address _vaultProxy, address _who) private view {
        require(
            IVault(_vaultProxy).canMigrate(_who),
            "Only a permissioned migrator can call this function"
        );
    }

    constructor(address _dispatcher, address _gasRelayPaymasterFactory)
        public
        GasRelayRecipientMixin(_gasRelayPaymasterFactory)
    {
        // Validate constants
        require(
            ANY_VAULT_CALL == keccak256(abi.encodePacked("mln.vaultCall.any")),
            "constructor: Incorrect ANY_VAULT_CALL"
        );

        CREATOR = msg.sender;
        DISPATCHER = _dispatcher;

        // Estimated base call cost: 17k
        // Per fee that uses shares outstanding (default recipient): 33k
        // 300k accommodates up to 8 such fees
        gasLimitForDestructCallToDeactivateFeeManager = 300000;
        // Estimated cost: 50k
        gasLimitForDestructCallToPayProtocolFee = 200000;

        reconfigurationTimelock = 2 days;
    }

    //////////////////////////////////////
    // PSEUDO-CONSTANTS (only set once) //
    //////////////////////////////////////

    /// @notice Sets the ComptrollerLib
    /// @param _comptrollerLib The ComptrollerLib contract address
    function setComptrollerLib(address _comptrollerLib)
        external
        onlyOwner
        pseudoConstant(getComptrollerLib())
    {
        comptrollerLib = _comptrollerLib;

        emit ComptrollerLibSet(_comptrollerLib);
    }

    /// @notice Sets the ProtocolFeeTracker
    /// @param _protocolFeeTracker The ProtocolFeeTracker contract address
    function setProtocolFeeTracker(address _protocolFeeTracker)
        external
        onlyOwner
        pseudoConstant(getProtocolFeeTracker())
    {
        protocolFeeTracker = _protocolFeeTracker;

        emit ProtocolFeeTrackerSet(_protocolFeeTracker);
    }

    /// @notice Sets the VaultLib
    /// @param _vaultLib The VaultLib contract address
    function setVaultLib(address _vaultLib) external onlyOwner pseudoConstant(getVaultLib()) {
        vaultLib = _vaultLib;

        emit VaultLibSet(_vaultLib);
    }

    /////////////
    // GENERAL //
    /////////////

    /// @notice Gets the current owner of the contract
    /// @return owner_ The contract owner address
    /// @dev The owner is initially the contract's creator, for convenience in setting up configuration.
    /// Ownership is handed-off when the creator calls setReleaseLive().
    function getOwner() public view override returns (address owner_) {
        if (!releaseIsLive()) {
            return getCreator();
        }

        return IDispatcher(getDispatcher()).getOwner();
    }

    /// @notice Sets the amounts of gas to forward to each of the ComptrollerLib.destructActivated() external calls
    /// @param _nextDeactivateFeeManagerGasLimit The amount of gas to forward to deactivate the FeeManager
    /// @param _nextPayProtocolFeeGasLimit The amount of gas to forward to pay the protocol fee
    function setGasLimitsForDestructCall(
        uint32 _nextDeactivateFeeManagerGasLimit,
        uint32 _nextPayProtocolFeeGasLimit
    ) external onlyOwner {
        require(
            _nextDeactivateFeeManagerGasLimit > 0 && _nextPayProtocolFeeGasLimit > 0,
            "setGasLimitsForDestructCall: Zero value not allowed"
        );

        gasLimitForDestructCallToDeactivateFeeManager = _nextDeactivateFeeManagerGasLimit;
        gasLimitForDestructCallToPayProtocolFee = _nextPayProtocolFeeGasLimit;

        emit GasLimitsForDestructCallSet(
            _nextDeactivateFeeManagerGasLimit,
            _nextPayProtocolFeeGasLimit
        );
    }

    /// @notice Sets the release as live
    /// @dev A live release allows funds to be created and migrated once this contract
    /// is set as the Dispatcher.currentFundDeployer
    function setReleaseLive() external {
        require(
            msg.sender == getCreator(),
            "setReleaseLive: Only the creator can call this function"
        );
        require(!releaseIsLive(), "setReleaseLive: Already live");

        // All pseudo-constants should be set
        require(getComptrollerLib() != address(0), "setReleaseLive: comptrollerLib is not set");
        require(
            getProtocolFeeTracker() != address(0),
            "setReleaseLive: protocolFeeTracker is not set"
        );
        require(getVaultLib() != address(0), "setReleaseLive: vaultLib is not set");

        isLive = true;

        emit ReleaseIsLive();
    }

    /// @dev Helper to call ComptrollerProxy.destructActivated() with the correct params
    function __destructActivatedComptrollerProxy(address _comptrollerProxy) private {
        (
            uint256 deactivateFeeManagerGasLimit,
            uint256 payProtocolFeeGasLimit
        ) = getGasLimitsForDestructCall();
        IComptroller(_comptrollerProxy).destructActivated(
            deactivateFeeManagerGasLimit,
            payProtocolFeeGasLimit
        );
    }

    ///////////////////
    // FUND CREATION //
    ///////////////////

    /// @notice Creates a fully-configured ComptrollerProxy instance for a VaultProxy and signals the migration process
    /// @param _vaultProxy The VaultProxy to migrate
    /// @param _denominationAsset The contract address of the denomination asset for the fund
    /// @param _sharesActionTimelock The minimum number of seconds between any two "shares actions"
    /// (buying or selling shares) by the same user
    /// @param _feeManagerConfigData Bytes data for the fees to be enabled for the fund
    /// @param _policyManagerConfigData Bytes data for the policies to be enabled for the fund
    /// @param _bypassPrevReleaseFailure True if should override a failure in the previous release while signaling migration
    /// @return comptrollerProxy_ The address of the ComptrollerProxy deployed during this action
    function createMigrationRequest(
        address _vaultProxy,
        address _denominationAsset,
        uint256 _sharesActionTimelock,
        bytes calldata _feeManagerConfigData,
        bytes calldata _policyManagerConfigData,
        bool _bypassPrevReleaseFailure
    )
        external
        onlyLiveRelease
        onlyMigratorNotRelayable(_vaultProxy)
        returns (address comptrollerProxy_)
    {
        // Bad _vaultProxy value is validated by Dispatcher.signalMigration()

        require(
            !IDispatcher(getDispatcher()).hasMigrationRequest(_vaultProxy),
            "createMigrationRequest: A MigrationRequest already exists"
        );

        comptrollerProxy_ = __deployComptrollerProxy(
            msg.sender,
            _denominationAsset,
            _sharesActionTimelock
        );

        IComptroller(comptrollerProxy_).setVaultProxy(_vaultProxy);

        __configureExtensions(
            comptrollerProxy_,
            _vaultProxy,
            _feeManagerConfigData,
            _policyManagerConfigData
        );

        IDispatcher(getDispatcher()).signalMigration(
            _vaultProxy,
            comptrollerProxy_,
            getVaultLib(),
            _bypassPrevReleaseFailure
        );

        emit MigrationRequestCreated(msg.sender, _vaultProxy, comptrollerProxy_);

        return comptrollerProxy_;
    }

    /// @notice Creates a new fund
    /// @param _fundOwner The address of the owner for the fund
    /// @param _fundName The name of the fund's shares token
    /// @param _fundSymbol The symbol of the fund's shares token
    /// @param _denominationAsset The contract address of the denomination asset for the fund
    /// @param _sharesActionTimelock The minimum number of seconds between any two "shares actions"
    /// (buying or selling shares) by the same user
    /// @param _feeManagerConfigData Bytes data for the fees to be enabled for the fund
    /// @param _policyManagerConfigData Bytes data for the policies to be enabled for the fund
    /// @return comptrollerProxy_ The address of the ComptrollerProxy deployed during this action
    function createNewFund(
        address _fundOwner,
        string calldata _fundName,
        string calldata _fundSymbol,
        address _denominationAsset,
        uint256 _sharesActionTimelock,
        bytes calldata _feeManagerConfigData,
        bytes calldata _policyManagerConfigData
    ) external onlyLiveRelease returns (address comptrollerProxy_, address vaultProxy_) {
        // _fundOwner is validated by VaultLib.__setOwner()
        address canonicalSender = __msgSender();

        comptrollerProxy_ = __deployComptrollerProxy(
            canonicalSender,
            _denominationAsset,
            _sharesActionTimelock
        );

        vaultProxy_ = __deployVaultProxy(_fundOwner, comptrollerProxy_, _fundName, _fundSymbol);

        IComptroller comptrollerContract = IComptroller(comptrollerProxy_);
        comptrollerContract.setVaultProxy(vaultProxy_);

        __configureExtensions(
            comptrollerProxy_,
            vaultProxy_,
            _feeManagerConfigData,
            _policyManagerConfigData
        );

        comptrollerContract.activate(false);

        IProtocolFeeTracker(getProtocolFeeTracker()).initializeForVault(vaultProxy_);

        emit NewFundCreated(canonicalSender, vaultProxy_, comptrollerProxy_);

        return (comptrollerProxy_, vaultProxy_);
    }

    /// @notice Creates a fully-configured ComptrollerProxy instance for a VaultProxy and signals the reconfiguration process
    /// @param _vaultProxy The VaultProxy to reconfigure
    /// @param _denominationAsset The contract address of the denomination asset for the fund
    /// @param _sharesActionTimelock The minimum number of seconds between any two "shares actions"
    /// (buying or selling shares) by the same user
    /// @param _feeManagerConfigData Bytes data for the fees to be enabled for the fund
    /// @param _policyManagerConfigData Bytes data for the policies to be enabled for the fund
    /// @return comptrollerProxy_ The address of the ComptrollerProxy deployed during this action
    function createReconfigurationRequest(
        address _vaultProxy,
        address _denominationAsset,
        uint256 _sharesActionTimelock,
        bytes calldata _feeManagerConfigData,
        bytes calldata _policyManagerConfigData
    ) external returns (address comptrollerProxy_) {
        address canonicalSender = __msgSender();
        __assertIsMigrator(_vaultProxy, canonicalSender);
        require(
            IDispatcher(getDispatcher()).getFundDeployerForVaultProxy(_vaultProxy) ==
                address(this),
            "createReconfigurationRequest: VaultProxy not on this release"
        );
        require(
            !hasReconfigurationRequest(_vaultProxy),
            "createReconfigurationRequest: VaultProxy has a pending reconfiguration request"
        );

        comptrollerProxy_ = __deployComptrollerProxy(
            canonicalSender,
            _denominationAsset,
            _sharesActionTimelock
        );

        IComptroller(comptrollerProxy_).setVaultProxy(_vaultProxy);

        __configureExtensions(
            comptrollerProxy_,
            _vaultProxy,
            _feeManagerConfigData,
            _policyManagerConfigData
        );

        uint256 executableTimestamp = block.timestamp + getReconfigurationTimelock();
        vaultProxyToReconfigurationRequest[_vaultProxy] = ReconfigurationRequest({
            nextComptrollerProxy: comptrollerProxy_,
            executableTimestamp: executableTimestamp
        });

        emit ReconfigurationRequestCreated(
            canonicalSender,
            _vaultProxy,
            comptrollerProxy_,
            executableTimestamp
        );

        return comptrollerProxy_;
    }

    /// @dev Helper function to configure the Extensions for a given ComptrollerProxy
    function __configureExtensions(
        address _comptrollerProxy,
        address _vaultProxy,
        bytes memory _feeManagerConfigData,
        bytes memory _policyManagerConfigData
    ) private {
        // Since fees can only be set in this step, if there are no fees, there is no need to set the validated VaultProxy
        if (_feeManagerConfigData.length > 0) {
            IExtension(IComptroller(_comptrollerProxy).getFeeManager()).setConfigForFund(
                _comptrollerProxy,
                _vaultProxy,
                _feeManagerConfigData
            );
        }

        // For all other extensions, we call to cache the validated VaultProxy, for simplicity.
        // In the future, we can consider caching conditionally.
        IExtension(IComptroller(_comptrollerProxy).getExternalPositionManager()).setConfigForFund(
            _comptrollerProxy,
            _vaultProxy,
            ""
        );
        IExtension(IComptroller(_comptrollerProxy).getIntegrationManager()).setConfigForFund(
            _comptrollerProxy,
            _vaultProxy,
            ""
        );
        IExtension(IComptroller(_comptrollerProxy).getPolicyManager()).setConfigForFund(
            _comptrollerProxy,
            _vaultProxy,
            _policyManagerConfigData
        );
    }

    /// @dev Helper function to deploy a configured ComptrollerProxy
    function __deployComptrollerProxy(
        address _canonicalSender,
        address _denominationAsset,
        uint256 _sharesActionTimelock
    ) private returns (address comptrollerProxy_) {
        // _denominationAsset is validated by ComptrollerLib.init()

        bytes memory constructData = abi.encodeWithSelector(
            IComptroller.init.selector,
            _denominationAsset,
            _sharesActionTimelock
        );
        comptrollerProxy_ = address(new ComptrollerProxy(constructData, getComptrollerLib()));

        emit ComptrollerProxyDeployed(
            _canonicalSender,
            comptrollerProxy_,
            _denominationAsset,
            _sharesActionTimelock
        );

        return comptrollerProxy_;
    }

    /// @dev Helper to deploy a new VaultProxy instance during fund creation.
    /// Avoids stack-too-deep error.
    function __deployVaultProxy(
        address _fundOwner,
        address _comptrollerProxy,
        string calldata _fundName,
        string calldata _fundSymbol
    ) private returns (address vaultProxy_) {
        vaultProxy_ = IDispatcher(getDispatcher()).deployVaultProxy(
            getVaultLib(),
            _fundOwner,
            _comptrollerProxy,
            _fundName
        );
        if (bytes(_fundSymbol).length != 0) {
            IVault(vaultProxy_).setSymbol(_fundSymbol);
        }

        return vaultProxy_;
    }

    ///////////////////////////////////////////////
    // RECONFIGURATION (INTRA-RELEASE MIGRATION) //
    ///////////////////////////////////////////////

    /// @notice Cancels a pending reconfiguration request
    /// @param _vaultProxy The VaultProxy contract for which to cancel the reconfiguration request
    function cancelReconfiguration(address _vaultProxy) external onlyMigrator(_vaultProxy) {
        address nextComptrollerProxy = vaultProxyToReconfigurationRequest[_vaultProxy]
            .nextComptrollerProxy;
        require(
            nextComptrollerProxy != address(0),
            "cancelReconfiguration: No reconfiguration request exists for _vaultProxy"
        );

        // Destroy the nextComptrollerProxy
        IComptroller(nextComptrollerProxy).destructUnactivated();

        // Remove the reconfiguration request
        delete vaultProxyToReconfigurationRequest[_vaultProxy];

        emit ReconfigurationRequestCancelled(_vaultProxy, nextComptrollerProxy);
    }

    /// @notice Executes a pending reconfiguration request
    /// @param _vaultProxy The VaultProxy contract for which to execute the reconfiguration request
    /// @dev ProtocolFeeTracker.initializeForVault() does not need to be included in a reconfiguration,
    /// as it refers to the vault and not the new ComptrollerProxy
    function executeReconfiguration(address _vaultProxy) external onlyMigrator(_vaultProxy) {
        ReconfigurationRequest memory request = getReconfigurationRequestForVaultProxy(
            _vaultProxy
        );
        require(
            request.nextComptrollerProxy != address(0),
            "executeReconfiguration: No reconfiguration request exists for _vaultProxy"
        );
        require(
            block.timestamp >= request.executableTimestamp,
            "executeReconfiguration: The reconfiguration timelock has not elapsed"
        );
        // Not technically necessary, but a nice assurance
        require(
            IDispatcher(getDispatcher()).getFundDeployerForVaultProxy(_vaultProxy) ==
                address(this),
            "executeReconfiguration: _vaultProxy is no longer on this release"
        );

        // Unwind and destroy the prevComptrollerProxy before setting the nextComptrollerProxy as the VaultProxy.accessor
        address prevComptrollerProxy = IVault(_vaultProxy).getAccessor();
        address paymaster = IComptroller(prevComptrollerProxy).getGasRelayPaymaster();
        __destructActivatedComptrollerProxy(prevComptrollerProxy);

        // Execute the reconfiguration
        IVault(_vaultProxy).setAccessorForFundReconfiguration(request.nextComptrollerProxy);

        // Activate the new ComptrollerProxy
        IComptroller(request.nextComptrollerProxy).activate(true);
        if (paymaster != address(0)) {
            IComptroller(request.nextComptrollerProxy).setGasRelayPaymaster(paymaster);
        }

        // Remove the reconfiguration request
        delete vaultProxyToReconfigurationRequest[_vaultProxy];

        emit ReconfigurationRequestExecuted(
            _vaultProxy,
            prevComptrollerProxy,
            request.nextComptrollerProxy
        );
    }

    /// @notice Sets a new reconfiguration timelock
    /// @param _nextTimelock The number of seconds for the new timelock
    function setReconfigurationTimelock(uint256 _nextTimelock) external onlyOwner {
        reconfigurationTimelock = _nextTimelock;

        emit ReconfigurationTimelockSet(_nextTimelock);
    }

    //////////////////
    // MIGRATION IN //
    //////////////////

    /// @notice Cancels fund migration
    /// @param _vaultProxy The VaultProxy for which to cancel migration
    /// @param _bypassPrevReleaseFailure True if should override a failure in the previous release while canceling migration
    function cancelMigration(address _vaultProxy, bool _bypassPrevReleaseFailure)
        external
        onlyMigratorNotRelayable(_vaultProxy)
    {
        IDispatcher(getDispatcher()).cancelMigration(_vaultProxy, _bypassPrevReleaseFailure);
    }

    /// @notice Executes fund migration
    /// @param _vaultProxy The VaultProxy for which to execute the migration
    /// @param _bypassPrevReleaseFailure True if should override a failure in the previous release while executing migration
    function executeMigration(address _vaultProxy, bool _bypassPrevReleaseFailure)
        external
        onlyMigratorNotRelayable(_vaultProxy)
    {
        IDispatcher dispatcherContract = IDispatcher(getDispatcher());

        (, address comptrollerProxy, , ) = dispatcherContract
            .getMigrationRequestDetailsForVaultProxy(_vaultProxy);

        dispatcherContract.executeMigration(_vaultProxy, _bypassPrevReleaseFailure);

        IComptroller(comptrollerProxy).activate(true);

        IProtocolFeeTracker(getProtocolFeeTracker()).initializeForVault(_vaultProxy);
    }

    /// @notice Executes logic when a migration is canceled on the Dispatcher
    /// @param _nextComptrollerProxy The ComptrollerProxy created on this release
    function invokeMigrationInCancelHook(
        address,
        address,
        address _nextComptrollerProxy,
        address
    ) external override onlyDispatcher {
        IComptroller(_nextComptrollerProxy).destructUnactivated();
    }

    ///////////////////
    // MIGRATION OUT //
    ///////////////////

    /// @notice Allows "hooking into" specific moments in the migration pipeline
    /// to execute arbitrary logic during a migration out of this release
    /// @param _vaultProxy The VaultProxy being migrated
    function invokeMigrationOutHook(
        MigrationOutHook _hook,
        address _vaultProxy,
        address,
        address,
        address
    ) external override onlyDispatcher {
        if (_hook != MigrationOutHook.PreMigrate) {
            return;
        }

        // Must use PreMigrate hook to get the ComptrollerProxy from the VaultProxy
        address comptrollerProxy = IVault(_vaultProxy).getAccessor();

        // Wind down fund and destroy its config
        __destructActivatedComptrollerProxy(comptrollerProxy);
    }

    //////////////
    // REGISTRY //
    //////////////

    // BUY SHARES CALLERS

    /// @notice Deregisters allowed callers of ComptrollerProxy.buySharesOnBehalf()
    /// @param _callers The callers to deregister
    function deregisterBuySharesOnBehalfCallers(address[] calldata _callers) external onlyOwner {
        for (uint256 i; i < _callers.length; i++) {
            require(
                isAllowedBuySharesOnBehalfCaller(_callers[i]),
                "deregisterBuySharesOnBehalfCallers: Caller not registered"
            );

            acctToIsAllowedBuySharesOnBehalfCaller[_callers[i]] = false;

            emit BuySharesOnBehalfCallerDeregistered(_callers[i]);
        }
    }

    /// @notice Registers allowed callers of ComptrollerProxy.buySharesOnBehalf()
    /// @param _callers The allowed callers
    /// @dev Validate that each registered caller only forwards requests to buy shares that
    /// originate from the same _buyer passed into buySharesOnBehalf(). This is critical
    /// to the integrity of VaultProxy.freelyTransferableShares.
    function registerBuySharesOnBehalfCallers(address[] calldata _callers) external onlyOwner {
        for (uint256 i; i < _callers.length; i++) {
            require(
                !isAllowedBuySharesOnBehalfCaller(_callers[i]),
                "registerBuySharesOnBehalfCallers: Caller already registered"
            );

            acctToIsAllowedBuySharesOnBehalfCaller[_callers[i]] = true;

            emit BuySharesOnBehalfCallerRegistered(_callers[i]);
        }
    }

    // VAULT CALLS

    /// @notice De-registers allowed arbitrary contract calls that can be sent from the VaultProxy
    /// @param _contracts The contracts of the calls to de-register
    /// @param _selectors The selectors of the calls to de-register
    /// @param _dataHashes The keccak call data hashes of the calls to de-register
    /// @dev ANY_VAULT_CALL is a wildcard that allows any payload
    function deregisterVaultCalls(
        address[] calldata _contracts,
        bytes4[] calldata _selectors,
        bytes32[] memory _dataHashes
    ) external onlyOwner {
        require(_contracts.length > 0, "deregisterVaultCalls: Empty _contracts");
        require(
            _contracts.length == _selectors.length && _contracts.length == _dataHashes.length,
            "deregisterVaultCalls: Uneven input arrays"
        );

        for (uint256 i; i < _contracts.length; i++) {
            require(
                isRegisteredVaultCall(_contracts[i], _selectors[i], _dataHashes[i]),
                "deregisterVaultCalls: Call not registered"
            );

            vaultCallToPayloadToIsAllowed[keccak256(
                abi.encodePacked(_contracts[i], _selectors[i])
            )][_dataHashes[i]] = false;

            emit VaultCallDeregistered(_contracts[i], _selectors[i], _dataHashes[i]);
        }
    }

    /// @notice Registers allowed arbitrary contract calls that can be sent from the VaultProxy
    /// @param _contracts The contracts of the calls to register
    /// @param _selectors The selectors of the calls to register
    /// @param _dataHashes The keccak call data hashes of the calls to register
    /// @dev ANY_VAULT_CALL is a wildcard that allows any payload
    function registerVaultCalls(
        address[] calldata _contracts,
        bytes4[] calldata _selectors,
        bytes32[] memory _dataHashes
    ) external onlyOwner {
        require(_contracts.length > 0, "registerVaultCalls: Empty _contracts");
        require(
            _contracts.length == _selectors.length && _contracts.length == _dataHashes.length,
            "registerVaultCalls: Uneven input arrays"
        );

        for (uint256 i; i < _contracts.length; i++) {
            require(
                !isRegisteredVaultCall(_contracts[i], _selectors[i], _dataHashes[i]),
                "registerVaultCalls: Call already registered"
            );

            vaultCallToPayloadToIsAllowed[keccak256(
                abi.encodePacked(_contracts[i], _selectors[i])
            )][_dataHashes[i]] = true;

            emit VaultCallRegistered(_contracts[i], _selectors[i], _dataHashes[i]);
        }
    }

    ///////////////////
    // STATE GETTERS //
    ///////////////////

    // EXTERNAL FUNCTIONS

    /// @notice Checks if a contract call is allowed
    /// @param _contract The contract of the call to check
    /// @param _selector The selector of the call to check
    /// @param _dataHash The keccak call data hash of the call to check
    /// @return isAllowed_ True if the call is allowed
    /// @dev A vault call is allowed if the _dataHash is specifically allowed,
    /// or if any _dataHash is allowed
    function isAllowedVaultCall(
        address _contract,
        bytes4 _selector,
        bytes32 _dataHash
    ) external view override returns (bool isAllowed_) {
        bytes32 contractFunctionHash = keccak256(abi.encodePacked(_contract, _selector));

        return
            vaultCallToPayloadToIsAllowed[contractFunctionHash][_dataHash] ||
            vaultCallToPayloadToIsAllowed[contractFunctionHash][ANY_VAULT_CALL];
    }

    // PUBLIC FUNCTIONS

    /// @notice Gets the `comptrollerLib` variable value
    /// @return comptrollerLib_ The `comptrollerLib` variable value
    function getComptrollerLib() public view returns (address comptrollerLib_) {
        return comptrollerLib;
    }

    /// @notice Gets the `CREATOR` variable value
    /// @return creator_ The `CREATOR` variable value
    function getCreator() public view returns (address creator_) {
        return CREATOR;
    }

    /// @notice Gets the `DISPATCHER` variable value
    /// @return dispatcher_ The `DISPATCHER` variable value
    function getDispatcher() public view returns (address dispatcher_) {
        return DISPATCHER;
    }

    /// @notice Gets the amounts of gas to forward to each of the ComptrollerLib.destructActivated() external calls
    /// @return deactivateFeeManagerGasLimit_ The amount of gas to forward to deactivate the FeeManager
    /// @return payProtocolFeeGasLimit_ The amount of gas to forward to pay the protocol fee
    function getGasLimitsForDestructCall()
        public
        view
        returns (uint256 deactivateFeeManagerGasLimit_, uint256 payProtocolFeeGasLimit_)
    {
        return (
            gasLimitForDestructCallToDeactivateFeeManager,
            gasLimitForDestructCallToPayProtocolFee
        );
    }

    /// @notice Gets the `protocolFeeTracker` variable value
    /// @return protocolFeeTracker_ The `protocolFeeTracker` variable value
    function getProtocolFeeTracker() public view returns (address protocolFeeTracker_) {
        return protocolFeeTracker;
    }

    /// @notice Gets the pending ReconfigurationRequest for a given VaultProxy
    /// @param _vaultProxy The VaultProxy instance
    /// @return reconfigurationRequest_ The pending ReconfigurationRequest
    function getReconfigurationRequestForVaultProxy(address _vaultProxy)
        public
        view
        returns (ReconfigurationRequest memory reconfigurationRequest_)
    {
        return vaultProxyToReconfigurationRequest[_vaultProxy];
    }

    /// @notice Gets the amount of time that must pass before executing a ReconfigurationRequest
    /// @return reconfigurationTimelock_ The timelock value (in seconds)
    function getReconfigurationTimelock() public view returns (uint256 reconfigurationTimelock_) {
        return reconfigurationTimelock;
    }

    /// @notice Gets the `vaultLib` variable value
    /// @return vaultLib_ The `vaultLib` variable value
    function getVaultLib() public view returns (address vaultLib_) {
        return vaultLib;
    }

    /// @notice Checks whether a ReconfigurationRequest exists for a given VaultProxy
    /// @param _vaultProxy The VaultProxy instance
    /// @return hasReconfigurationRequest_ True if a ReconfigurationRequest exists
    function hasReconfigurationRequest(address _vaultProxy)
        public
        view
        override
        returns (bool hasReconfigurationRequest_)
    {
        return vaultProxyToReconfigurationRequest[_vaultProxy].nextComptrollerProxy != address(0);
    }

    /// @notice Checks if an account is an allowed caller of ComptrollerProxy.buySharesOnBehalf()
    /// @param _who The account to check
    /// @return isAllowed_ True if the account is an allowed caller
    function isAllowedBuySharesOnBehalfCaller(address _who)
        public
        view
        override
        returns (bool isAllowed_)
    {
        return acctToIsAllowedBuySharesOnBehalfCaller[_who];
    }

    /// @notice Checks if a contract call is registered
    /// @param _contract The contract of the call to check
    /// @param _selector The selector of the call to check
    /// @param _dataHash The keccak call data hash of the call to check
    /// @return isRegistered_ True if the call is registered
    function isRegisteredVaultCall(
        address _contract,
        bytes4 _selector,
        bytes32 _dataHash
    ) public view returns (bool isRegistered_) {
        return
            vaultCallToPayloadToIsAllowed[keccak256(
                abi.encodePacked(_contract, _selector)
            )][_dataHash];
    }

    /// @notice Gets the `isLive` variable value
    /// @return isLive_ The `isLive` variable value
    function releaseIsLive() public view returns (bool isLive_) {
        return isLive;
    }
}
IFundDeployer.sol 28 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IFundDeployer Interface
/// @author Enzyme Council <[email protected]>
interface IFundDeployer {
    function getOwner() external view returns (address);

    function hasReconfigurationRequest(address) external view returns (bool);

    function isAllowedBuySharesOnBehalfCaller(address) external view returns (bool);

    function isAllowedVaultCall(
        address,
        bytes4,
        bytes32
    ) external view returns (bool);
}
IComptroller.sol 66 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

import "../vault/IVault.sol";

/// @title IComptroller Interface
/// @author Enzyme Council <[email protected]>
interface IComptroller {
    function activate(bool) external;

    function calcGav() external returns (uint256);

    function calcGrossShareValue() external returns (uint256);

    function callOnExtension(
        address,
        uint256,
        bytes calldata
    ) external;

    function destructActivated(uint256, uint256) external;

    function destructUnactivated() external;

    function getDenominationAsset() external view returns (address);

    function getExternalPositionManager() external view returns (address);

    function getFeeManager() external view returns (address);

    function getFundDeployer() external view returns (address);

    function getGasRelayPaymaster() external view returns (address);

    function getIntegrationManager() external view returns (address);

    function getPolicyManager() external view returns (address);

    function getVaultProxy() external view returns (address);

    function init(address, uint256) external;

    function permissionedVaultAction(IVault.VaultAction, bytes calldata) external;

    function preTransferSharesHook(
        address,
        address,
        uint256
    ) external;

    function preTransferSharesHookFreelyTransferable(address) external view;

    function setGasRelayPaymaster(address) external;

    function setVaultProxy(address) external;
}
IMigrationHookHandler.sol 33 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IMigrationHookHandler Interface
/// @author Enzyme Council <[email protected]>
interface IMigrationHookHandler {
    enum MigrationOutHook {PreSignal, PostSignal, PreMigrate, PostMigrate, PostCancel}

    function invokeMigrationInCancelHook(
        address _vaultProxy,
        address _prevFundDeployer,
        address _nextVaultAccessor,
        address _nextVaultLib
    ) external;

    function invokeMigrationOutHook(
        MigrationOutHook _hook,
        address _vaultProxy,
        address _nextFundDeployer,
        address _nextVaultAccessor,
        address _nextVaultLib
    ) external;
}
IMigratableVault.sol 29 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IMigratableVault Interface
/// @author Enzyme Council <[email protected]>
/// @dev DO NOT EDIT CONTRACT
interface IMigratableVault {
    function canMigrate(address _who) external view returns (bool canMigrate_);

    function init(
        address _owner,
        address _accessor,
        string calldata _fundName
    ) external;

    function setAccessor(address _nextAccessor) external;

    function setVaultLib(address _nextVaultLib) external;
}
ComptrollerProxy.sol 24 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

import "../../../utils/NonUpgradableProxy.sol";

/// @title ComptrollerProxy Contract
/// @author Enzyme Council <[email protected]>
/// @notice A proxy contract for all ComptrollerProxy instances
contract ComptrollerProxy is NonUpgradableProxy {
    constructor(bytes memory _constructData, address _comptrollerLib)
        public
        NonUpgradableProxy(_constructData, _comptrollerLib)
    {}
}
IBeaconProxyFactory.sol 22 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

import "./IBeacon.sol";

pragma solidity 0.6.12;

/// @title IBeaconProxyFactory interface
/// @author Enzyme Council <[email protected]>
interface IBeaconProxyFactory is IBeacon {
    function deployProxy(bytes memory _constructData) external returns (address proxy_);

    function setCanonicalLib(address _canonicalLib) external;
}
IExternalPositionVault.sol 19 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IExternalPositionVault interface
/// @author Enzyme Council <[email protected]>
/// Provides an interface to get the externalPositionLib for a given type from the Vault
interface IExternalPositionVault {
    function getExternalPositionLibForType(uint256) external view returns (address);
}
IGasRelayPaymaster.sol 23 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "../../interfaces/IGsnPaymaster.sol";

/// @title IGasRelayPaymaster Interface
/// @author Enzyme Council <[email protected]>
interface IGasRelayPaymaster is IGsnPaymaster {
    function deposit() external;

    function withdrawBalance() external;
}
IProtocolFeeTracker.sol 20 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IProtocolFeeTracker Interface
/// @author Enzyme Council <[email protected]>
interface IProtocolFeeTracker {
    function initializeForVault(address) external;

    function payFee() external returns (uint256);
}
GasRelayRecipientMixin.sol 65 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

import "../../utils/beacon-proxy/IBeaconProxyFactory.sol";
import "./IGasRelayPaymaster.sol";

pragma solidity 0.6.12;

/// @title GasRelayRecipientMixin Contract
/// @author Enzyme Council <[email protected]>
/// @notice A mixin that enables receiving GSN-relayed calls
/// @dev IMPORTANT: Do not use storage var in this contract,
/// unless it is no longer inherited by the VaultLib
abstract contract GasRelayRecipientMixin {
    address internal immutable GAS_RELAY_PAYMASTER_FACTORY;

    constructor(address _gasRelayPaymasterFactory) internal {
        GAS_RELAY_PAYMASTER_FACTORY = _gasRelayPaymasterFactory;
    }

    /// @dev Helper to parse the canonical sender of a tx based on whether it has been relayed
    function __msgSender() internal view returns (address payable canonicalSender_) {
        if (msg.data.length >= 24 && msg.sender == getGasRelayTrustedForwarder()) {
            assembly {
                canonicalSender_ := shr(96, calldataload(sub(calldatasize(), 20)))
            }

            return canonicalSender_;
        }

        return msg.sender;
    }

    ///////////////////
    // STATE GETTERS //
    ///////////////////

    /// @notice Gets the `GAS_RELAY_PAYMASTER_FACTORY` variable
    /// @return gasRelayPaymasterFactory_ The `GAS_RELAY_PAYMASTER_FACTORY` variable value
    function getGasRelayPaymasterFactory()
        public
        view
        returns (address gasRelayPaymasterFactory_)
    {
        return GAS_RELAY_PAYMASTER_FACTORY;
    }

    /// @notice Gets the trusted forwarder for GSN relaying
    /// @return trustedForwarder_ The trusted forwarder
    function getGasRelayTrustedForwarder() public view returns (address trustedForwarder_) {
        return
            IGasRelayPaymaster(
                IBeaconProxyFactory(getGasRelayPaymasterFactory()).getCanonicalLib()
            )
                .trustedForwarder();
    }
}
IFreelyTransferableSharesVault.sol 24 lines
// SPDX-License-Identifier: GPL-3.0

/*
    This file is part of the Enzyme Protocol.

    (c) Enzyme Council <[email protected]>

    For the full license information, please view the LICENSE
    file that was distributed with this source code.
*/

pragma solidity 0.6.12;

/// @title IFreelyTransferableSharesVault Interface
/// @author Enzyme Council <[email protected]>
/// @notice Provides the interface for determining whether a vault's shares
/// are guaranteed to be freely transferable.
/// @dev DO NOT EDIT CONTRACT
interface IFreelyTransferableSharesVault {
    function sharesAreFreelyTransferable()
        external
        view
        returns (bool sharesAreFreelyTransferable_);
}

Read Contract

getComptrollerLib 0x93a2ecd9 → address
getCreator 0x0ee2cb10 → address
getDispatcher 0xebb3d589 → address
getGasLimitsForDestructCall 0x3d0d4abb → uint256, uint256
getGasRelayPaymasterFactory 0xac259456 → address
getGasRelayTrustedForwarder 0x6ea21143 → address
getOwner 0x893d20e8 → address
getProtocolFeeTracker 0x749cc8f5 → address
getReconfigurationRequestForVaultProxy 0x72eb5f2b → tuple
getReconfigurationTimelock 0xcebffb58 → uint256
getVaultLib 0x682cea19 → address
hasReconfigurationRequest 0x6c579e57 → bool
isAllowedBuySharesOnBehalfCaller 0x54391f09 → bool
isAllowedVaultCall 0x8c500ea3 → bool
isRegisteredVaultCall 0x36b4ea4f → bool
releaseIsLive 0x98f0d4bb → bool

Write Contract 19 functions

These functions modify contract state and require a wallet transaction to execute.

cancelMigration 0x9c9d48da
address _vaultProxy
bool _bypassPrevReleaseFailure
cancelReconfiguration 0xd5189add
address _vaultProxy
createMigrationRequest 0xb8f8a84c
address _vaultProxy
address _denominationAsset
uint256 _sharesActionTimelock
bytes _feeManagerConfigData
bytes _policyManagerConfigData
bool _bypassPrevReleaseFailure
returns: address
createNewFund 0xc83980dd
address _fundOwner
string _fundName
string _fundSymbol
address _denominationAsset
uint256 _sharesActionTimelock
bytes _feeManagerConfigData
bytes _policyManagerConfigData
returns: address, address
createReconfigurationRequest 0x4348ab62
address _vaultProxy
address _denominationAsset
uint256 _sharesActionTimelock
bytes _feeManagerConfigData
bytes _policyManagerConfigData
returns: address
deregisterBuySharesOnBehalfCallers 0x4bacc5f7
address[] _callers
deregisterVaultCalls 0xed9eeb7f
address[] _contracts
bytes4[] _selectors
bytes32[] _dataHashes
executeMigration 0x38b3eb1b
address _vaultProxy
bool _bypassPrevReleaseFailure
executeReconfiguration 0xff845718
address _vaultProxy
invokeMigrationInCancelHook 0xdf369ba7
address
address
address _nextComptrollerProxy
address
invokeMigrationOutHook 0x3f84c12c
uint8 _hook
address _vaultProxy
address
address
address
registerBuySharesOnBehalfCallers 0x6f2b7574
address[] _callers
registerVaultCalls 0xefcde9e3
address[] _contracts
bytes4[] _selectors
bytes32[] _dataHashes
setComptrollerLib 0x0d2fcd76
address _comptrollerLib
setGasLimitsForDestructCall 0x575403dc
uint32 _nextDeactivateFeeManagerGasLimit
uint32 _nextPayProtocolFeeGasLimit
setProtocolFeeTracker 0x9f9df785
address _protocolFeeTracker
setReconfigurationTimelock 0x3b30dce7
uint256 _nextTimelock
setReleaseLive 0x164dd2d4
No parameters
setVaultLib 0x4140d607
address _vaultLib

Recent Transactions

No transactions found for this address