Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xb324b2BD8a3Dc55b04111E84d5cce0c3771F8889
Balance 0 ETH
Nonce 1
Code Size 20267 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

20267 bytes
0x608060405234801561001057600080fd5b50600436106104055760003560e01c80638980f11f1161021a578063d2fbdc0d11610135578063e44b9fa5116100c8578063f2a8d34911610097578063f77e34d11161007c578063f77e34d1146109d9578063facefb64146109ec578063fff6cae9146109ff57600080fd5b8063f2a8d349146109bd578063f2caeb1e146109c657600080fd5b8063e44b9fa514610985578063e7f3058214610998578063ebe2b12b146109ab578063f288baf6146109b457600080fd5b8063d9f96e8d11610104578063d9f96e8d1461092c578063de1a655114610962578063e01f62bf14610975578063e1ba95d21461097d57600080fd5b8063d2fbdc0d146108e0578063d42fc9b4146108f3578063d5e1a9c614610906578063d7400d561461091957600080fd5b8063b94c4dcb116101ad578063ca6df29d1161017c578063ca6df29d14610885578063cc2abd64146108bb578063cdc82e80146108ce578063d2010fb4146108d757600080fd5b8063b94c4dcb1461084d578063c00007b014610856578063c354382614610869578063c8f33c911461087c57600080fd5b80639637927f116101e95780639637927f14610811578063a0f234761461081e578063aa1d4fce14610831578063b85efd061461083a57600080fd5b80638980f11f1461079d5780638bad86a7146107b05780638da5cb5b146107de57806391cf600a146107fe57600080fd5b80634f39059c116103255780636e27cef9116102b85780637910d17b1161028757806379ba50971161026c57806379ba5097146107625780637d6ef08e1461076a5780637f472e541461078a57600080fd5b80637910d17b146107145780637970833e1461072757600080fd5b80636e27cef9146106c957806370641a36146106d257806372f702f3146106da578063774d4ae71461070157600080fd5b80635bfd9258116102f45780635bfd92581461067957806364f2c0601461068157806369339245146106895780636c430dbb146106a957600080fd5b80634f39059c1461060c5780634fd2b5361461063357806353a47bb714610646578063551897731461066657600080fd5b8063218751b21161039d57806336f89af21161036c57806336f89af214610583578063386a9525146105b9578063387edc86146105c357806341a16f3f146105d657600080fd5b8063218751b2146104cc578063231b68dc1461051857806328408bab1461053b5780632c0c2a0a1461057057600080fd5b806317b18c89116103d957806317b18c891461047e5780631c1f78eb146104915780631e090f01146104995780631face856146104b957600080fd5b80628cc2621461040a5780630d7bac4f1461043357806312edb24c146104545780631627540c14610469575b600080fd5b61041d610418366004614921565b610a07565b60405161042a919061493c565b60405180910390f35b610446610441366004614980565b610b86565b60405190815260200161042a565b61045c610bb2565b60405161042a9190614999565b61047c610477366004614921565b610c21565b005b61044661048c3660046149e7565b610d46565b61041d610dd0565b6104ac6104a7366004614921565b610e71565b60405161042a9190614a09565b6104466104c7366004614921565b610f25565b6104f37f00000000000000000000000033baeda08b8afacc4d3d07cf31d49fc1f1f3e89381565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161042a565b61052b610526366004614a77565b610f6b565b604051901515815260200161042a565b6104f3610549366004614921565b602080526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61044661057e366004614921565b610fd9565b610446610591366004614921565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b61044662093a8081565b61047c6105d1366004614921565b6112ed565b6104f36105e4366004614921565b600f6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6104f37f00000000000000000000000033baeda08b8afacc4d3d07cf31d49fc1f1f3e89381565b610446610641366004614921565b6113d7565b6001546104f39073ffffffffffffffffffffffffffffffffffffffff1681565b61047c610674366004614ab8565b6113f8565b61044661151c565b601c54610446565b610446610697366004614921565b60146020526000908152604090205481565b6104466106b7366004614921565b60186020526000908152604090205481565b61044660085481565b61041d6115b0565b6104f37f00000000000000000000000032fa492ac1f729e0ee9eddfcbacc3ef72b234e2781565b61044661070f366004614aef565b61170f565b61041d610722366004614ab8565b61191b565b61073a610735366004614aef565b611997565b604080519586526020860194909452928401919091526060830152608082015260a00161042a565b61047c6119e5565b610446610778366004614921565b601f6020526000908152604090205481565b610446610798366004614921565b611b30565b61047c6107ab366004614aef565b611b47565b6107c36107be366004614921565b611d30565b6040805193845260208401929092529082015260600161042a565b6000546104f39073ffffffffffffffffffffffffffffffffffffffff1681565b61047c61080c366004614921565b611f64565b60215461052b9060ff1681565b61044661082c366004614921565b612057565b61044660095481565b61047c6108483660046149e7565b61212f565b61044660075481565b61041d610864366004614921565b612386565b6104f3610877366004614921565b61240e565b61044660055481565b610446610893366004614921565b73ffffffffffffffffffffffffffffffffffffffff1660009081526022602052604090205490565b61047c6108c9366004614b19565b612470565b61044660065481565b61044660035481565b61047c6108ee3660046149e7565b6125a6565b610446610901366004614921565b61290a565b61047c610914366004614b64565b612946565b61047c610927366004614921565b612b35565b61044661093a366004614921565b73ffffffffffffffffffffffffffffffffffffffff166000908152601d602052604090205490565b61047c610970366004614a77565b612d50565b601b54610446565b61047c612e37565b610446610993366004614bb1565b612f08565b61047c6109a6366004614921565b612ff6565b61044660045481565b610446600a5481565b610446600b5481565b6104466109d4366004614980565b613154565b61047c6109e7366004614bd4565b61326b565b61047c6109fa366004614c20565b61343d565b61047c6135fd565b60606000610a136115b0565b60105490915067ffffffffffffffff811115610a3157610a31614bf1565b604051908082528060200260200182016040528015610a5a578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601e602052604090205490925015610b805760005b601054811015610b7e5773ffffffffffffffffffffffffffffffffffffffff84166000818152601760209081526040808320858452825280832054938352601682528083208584529091529020548351670de0b6b3a76400009190859085908110610af957610af9614cc5565b6020026020010151610b0b9190614d23565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902054610b3b9190614d3a565b610b459190614d77565b610b4f9190614db2565b838281518110610b6157610b61614cc5565b602090810291909101015280610b7681614dca565b915050610a8c565b505b50919050565b600654600754600091610bac91610b9d8286614d3a565b610ba79190614d77565b61362d565b92915050565b60606010805480602002602001604051908101604052809291908181526020018280548015610c1757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610bec575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ccd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60006002805403610db3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b60028055610dc43380858542613645565b60016002559392505050565b60135460609067ffffffffffffffff811115610dee57610dee614bf1565b604051908082528060200260200182016040528015610e17578160200160208202803683370190505b50905060005b601354811015610e6d5762093a80610e3482613154565b610e3e9190614d3a565b828281518110610e5057610e50614cc5565b602090810291909101015280610e6581614dca565b915050610e1d565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610f1a57838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610eb6565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812054600354670de0b6b3a764000091610f6191614d3a565b610bac9190614d77565b6000805473ffffffffffffffffffffffffffffffffffffffff90811690841603610f9757506001610bac565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f6020526040902054818516911603610fd057506001610bac565b50600092915050565b60008080610fe68461240e565b905073ffffffffffffffffffffffffffffffffffffffff8116156110b9576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301527f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b49190614e02565b611169565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301527f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa158015611145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111699190614e02565b91506000670de0b6b3a76400007f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112059190614e02565b61120f9190614d3a565b600954600a5461121f9086614d3a565b6112299190614d3a565b6112339190614d77565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156112625761125d84611b30565b61126b565b61126b876113d7565b905080156112bd57600081611288670de0b6b3a764000088614d3a565b6112929190614d77565b9050670de0b6b3a7640000600a54826112ab9190614d3a565b6112b59190614d77565b9250506112c2565b600091505b508082116112d057806112d2565b815b9450600a548511156112e457600a5494505b50505050919050565b6002805403611358576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b6002805560215462010000900460ff16156113cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610cc4565b506001600255565b6000670de0b6b3a7640000600b546113ee8461290a565b610f619190614d3a565b8015611406576114066135fd565b73ffffffffffffffffffffffffffffffffffffffff82161561151857600080600061143085611d30565b92509250925061143f85613a4b565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c602052604090208290558281106114c357600061147a8483614d23565b905080601c5461148a9190614db2565b601c556114978185614db2565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e602052604090205550611514565b60006114cf8285614d23565b905080601c546114df9190614d23565b601c556114ec8185614d23565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601e6020526040902055505b5050505b5050565b60008060047f00000000000000000000000033baeda08b8afacc4d3d07cf31d49fc1f1f3e89373ffffffffffffffffffffffffffffffffffffffff1663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa15801561158c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f619190614e02565b6060601b54600014806115c35750601c54155b1561161d576015805480602002602001604051908101604052809291908181526020018280548015610c1757602002820191906000526020600020905b815481526020019060010190808311611600575050505050905090565b60105467ffffffffffffffff81111561163857611638614bf1565b604051908082528060200260200182016040528015611661578160200160208202803683370190505b50905060005b601554811015610e6d57601c5461167d82613154565b600554611688613b4b565b6116929190614d23565b61169c9190614d3a565b6116ae90670de0b6b3a7640000614d3a565b6116b89190614d77565b601582815481106116cb576116cb614cc5565b90600052602060002001546116e09190614db2565b8282815181106116f2576116f2614cc5565b60209081029190910101528061170781614dca565b915050611667565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260226020526040812080548291908490811061174957611749614cc5565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff89168552601890925283205491935011156117c7575060208101516117ef565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601860205260409020545b428260600151116118af57606082015173ffffffffffffffffffffffffffffffffffffffff861660009081526018602052604090205410156118a657600081836060015161183d9190614d23565b905060008360600151426118519190614d23565b90506000611863610441600285614d77565b905060006118718382614d3a565b61187b8584614d3a565b6118859190614db2565b90506118918385614db2565b61189b9082614d77565b9650505050506118ff565b600092506118ff565b6000808284606001516118c29190614d23565b905060004285606001516118d69190614d23565b905060026118e48284614db2565b6118ee9190614d77565b925050506118fb81610b86565b9350505b816080015183111561191357816080015192505b505092915050565b60606002805403611988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b60028055610dc4338484613b5e565b602260205281600052604060002081815481106119b357600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff163314611a8c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610cc4565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600b546113ee84610f25565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480611b745750611b743382610f6b565b611bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610cc4565b6000805b601054811015611c54578473ffffffffffffffffffffffffffffffffffffffff1660108281548110611c1257611c12614cc5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603611c425760019150611c54565b80611c4c81614dca565b915050611bde565b50808015611c88575073ffffffffffffffffffffffffffffffffffffffff8481166000908152600f60205260409020541633145b80611cb3575080158015611cb3575060005473ffffffffffffffffffffffffffffffffffffffff1633145b15611cc957611cc3843385613e2a565b50505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610cc4565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e60205260408120549080611d6184610fd9565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601d602052604081205491935090158015611dbb575073ffffffffffffffffffffffffffffffffffffffff85166000908152601e6020526040902054155b80611deb575073ffffffffffffffffffffffffffffffffffffffff85166000908152600c60205260409020548310155b15611df7575081611e37565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c6020526040902054600290611e2a9085614db2565b611e349190614d77565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff8616600090815260226020526040902054811015611f5b5773ffffffffffffffffffffffffffffffffffffffff86166000908152602260205260408120805483908110611ea257611ea2614cc5565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000611efb888461170f565b60408301519091506000670de0b6b3a7640000611f188785614db2565b611f229084614d3a565b611f2c9190614d77565b611f369083614db2565b9050611f428188614db2565b9650505050508080611f5390614dca565b915050611e3e565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611f9d5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610cc4565b73ffffffffffffffffffffffffffffffffffffffff166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600354600b546120699190614d3a565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152670de0b6b3a76400009182917f000000000000000000000000c8418af6358ffdda74e09ca9cc3fe03ca6adc5b016906370a0823190602401602060405180830381865afa158015612101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121259190614e02565b6113ee9190614d3a565b600280540361219a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b600280553360016121ab82826113f8565b6000806121b83387613f93565b9150915060008583604001516121ce9190614db2565b90506121fc7f00000000000000000000000032fa492ac1f729e0ee9eddfcbacc3ef72b234e27333089614158565b6040805160a08101825288815260208581015181830152818301849052606080870151908301526080808701519083015233600090815260229091529190912080548490811061224e5761224e614cc5565b9060005260206000209060050201600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015590505085601b60008282546122a39190614db2565b9091555050336000908152601d6020526040812080548892906122c7908490614db2565b90915550600090506122d83361240e565b905073ffffffffffffffffffffffffffffffffffffffff8116156123315773ffffffffffffffffffffffffffffffffffffffff81166000908152601f60205260408120805489929061232b908490614db2565b90915550505b5061233d3360006113f8565b604080518881526020810188905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a2505060016002555050505050565b606060028054036123f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b6002805561240333836001613b5e565b600160025592915050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604081205460ff1615612440575090565b5073ffffffffffffffffffffffffffffffffffffffff90811660009081526020805260409020541690565b919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806124a95750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b61250f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610cc4565b6021805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff931515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515630100000002959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ff909316929092179390931791909116179055565b6002805403612611576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b6002805533600161262282826113f8565b60008061262f3387613f93565b9150915042851161269c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610cc4565b6000428360600151116126b05760006126c0565b4283606001516126c09190614d23565b905060006126ce4288614d23565b9050818111612739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610cc4565b6008548110156127a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610cc4565b600754811115612811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610cc4565b6040518060a001604052808981526020014281526020018560400151815260200188815260200161284183610b86565b905233600090815260226020526040902080548590811061286457612864614cc5565b906000526020600020906005020160008201518160000155602082015181600101556040820151816002015560608201518160030155608082015181600401559050506128b23360006113f8565b6040805189815260208101839052428183015260608101899052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a250506001600255505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601d6020526040812054600354670de0b6b3a764000091610f6191614d3a565b600054849073ffffffffffffffffffffffffffffffffffffffff1633148061297357506129733382610f6b565b6129d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610cc4565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260146020526040902054601380548692908110612a1457612a14614cc5565b9060005260206000200181905550826011601460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481548110612a7557612a75614cc5565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918716815260149091526040902054601280548492908110612ae657612ae6614cc5565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16612bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610cc4565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e6020908152604080832033845290915290205460ff16612c5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610cc4565b33600090815260208052604090205473ffffffffffffffffffffffffffffffffffffffff168015612cd357336000908152601d602090815260408083205473ffffffffffffffffffffffffffffffffffffffff85168452601f9092528220805491929091612ccd908490614d23565b90915550505b3360009081526020808052604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155601d835281842054908452601f9092528220805491929091612d47908490614db2565b90915550505050565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480612d7d5750612d7d3382610f6b565b612de3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610cc4565b5073ffffffffffffffffffffffffffffffffffffffff9182166000908152600f6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612e705750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612ed6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610cc4565b602180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b60006002805403612f75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cc4565b60028055602154610100900460ff1615612feb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610cc4565b610dc43383856142f6565b336000908152600d602052604090205460ff1661306f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610cc4565b336000818152600e6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161790559180529091205416036131515773ffffffffffffffffffffffffffffffffffffffff811660009081526020808052604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601d825280832054338452601f909252822080549192909161314b908490614d23565b90915550505b50565b6000806011838154811061316a5761316a614cc5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561324557670de0b6b3a7640000601984815481106131b0576131b0614cc5565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa158015613206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322a9190614e02565b6132349190614d3a565b61323e9190614d77565b9150610b80565b6013838154811061325857613258614cc5565b9060005260206000200154915050919050565b60005b6011548110156115185760006011828154811061328d5761328d614cc5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561342a5782806132df5750601a82815481106132d1576132d1614cc5565b906000526020600020015442115b1561342a576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af1158015613356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337a9190614e02565b6019838154811061338d5761338d614cc5565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340a9190614e02565b601a838154811061341d5761341d614cc5565b6000918252602090912001555b508061343581614dca565b91505061326e565b60005473ffffffffffffffffffffffffffffffffffffffff163314806134765750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b6134dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610cc4565b8051670de0b6b3a7640000111561354f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610cc4565b6080810151600111801590613569575060a0810151600111155b6135cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610cc4565b80516006556020810151600a556040810151600b556060810151600955608081015160075560a00151600855565b613607600061326b565b61360f61151c565b600355600454421061362557613623614557565b565b61362361488a565b600081831061363c578161363e565b825b9392505050565b600085600161365482826113f8565b6021546301000000900460ff16156136c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610cc4565b600854851015613734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610cc4565b6007548511156137a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610cc4565b6137cc7f00000000000000000000000032fa492ac1f729e0ee9eddfcbacc3ef72b234e27883089614158565b60006137d786610b86565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601d602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608f901b169281019290925260348201899052605482018b9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8e1660009081526022835283902060a0850184528185529184018a90529183018b905290925090606081016138ca8a8a614db2565b815260209081018590528254600181810185556000948552828520845160059093020191825591830151918101919091556040820151600282015560608201516003820155608090910151600490910155601b80548a929061392d908490614db2565b909155505073ffffffffffffffffffffffffffffffffffffffff8a166000908152601d6020526040812080548a9290613967908490614db2565b90915550600090506139788b61240e565b905073ffffffffffffffffffffffffffffffffffffffff8116156139d15773ffffffffffffffffffffffffffffffffffffffff81166000908152601f6020526040812080548b92906139cb908490614db2565b90915550505b506139dd8a60006113f8565b604080518981526020810189905290810182905273ffffffffffffffffffffffffffffffffffffffff8a811660608301528b16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a29998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff811615613151576000613a7282610a07565b905060005b8151811015613ae057818181518110613a9257613a92614cc5565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff85166000908152601783526040808220858352909352919091205580613ad881614dca565b915050613a77565b5060005b8151811015611d2b5760158181548110613b0057613b00614cc5565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8616835260168252604080842085855290925291205580613b4381614dca565b915050613ae4565b6000613b594260045461362d565b905090565b6060836001613b6d82826113f8565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260186020526040902042905560215462010000900460ff1615613c08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610cc4565b60105467ffffffffffffffff811115613c2357613c23614bf1565b604051908082528060200260200182016040528015613c4c578160200160208202803683370190505b50925060005b601054811015613e205773ffffffffffffffffffffffffffffffffffffffff871660009081526017602090815260408083208484529091529020548451859083908110613ca157613ca1614cc5565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff881660009081526017825260408082208483529092529081208190558451859083908110613cf557613cf5614cc5565b60200260200101511115613e0e57613d6460108281548110613d1957613d19614cc5565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1687868481518110613d5757613d57614cc5565b6020026020010151613e2a565b8673ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff858381518110613dae57613dae614cc5565b602002602001015160108481548110613dc957613dc9614cc5565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff918216928401929092528a169082015260600160405180910390a25b80613e1881614dca565b915050613c52565b5050509392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691613ec19190614e47565b6000604051808303816000865af19150503d8060008114613efe576040519150601f19603f3d011682016040523d82523d6000602084013e613f03565b606091505b5091509150818015613f2d575080511580613f2d575080806020019051810190613f2d9190614e63565b611514576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610cc4565b613fc86040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b6000805b73ffffffffffffffffffffffffffffffffffffffff85166000908152602260205260409020548110156140e65773ffffffffffffffffffffffffffffffffffffffff8516600090815260226020526040902080548290811061403057614030614cc5565b90600052602060002090600502016000015484036140d45773ffffffffffffffffffffffffffffffffffffffff8516600090815260226020526040902080548290811061407f5761407f614cc5565b90600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505092508091506140e6565b806140de81614dca565b915050613fcc565b5081518314614151576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610cc4565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916141f79190614e47565b6000604051808303816000865af19150503d8060008114614234576040519150601f19603f3d011682016040523d82523d6000602084013e614239565b606091505b50915091508180156142635750805115806142635750808060200190518101906142639190614e63565b6142ee576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610cc4565b505050505050565b600061430484846001613b5e565b506000806143128685613f93565b91509150816060015142101580614330575060215460ff1615156001145b614396576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610cc4565b6040820151801561454d576143cc7f00000000000000000000000032fa492ac1f729e0ee9eddfcbacc3ef72b234e278783613e2a565b80601b60008282546143de9190614d23565b909155505073ffffffffffffffffffffffffffffffffffffffff87166000908152601d602052604081208054839290614418908490614d23565b90915550600090506144298861240e565b905073ffffffffffffffffffffffffffffffffffffffff8116156144825773ffffffffffffffffffffffffffffffffffffffff81166000908152601f60205260408120805484929061447c908490614d23565b90915550505b5073ffffffffffffffffffffffffffffffffffffffff871660009081526022602052604090208054839081106144ba576144ba614cc5565b6000918252602082206005909102018181556001810182905560028101829055600381018290556004018190556144f29088906113f8565b604080518281526020810187905273ffffffffffffffffffffffffffffffffffffffff888116828401529151918916917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b9695505050505050565b60005b6012548110156146485760006012828154811061457957614579614cc5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015614635576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af115801561460e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146329190614e80565b50505b508061464081614dca565b91505061455a565b50600062093a806004544261465d9190614d23565b6146679190614d77565b905060005b60105481101561484a576010818154811061468957614689614cc5565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614700573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147249190614e02565b61472f836001614db2565b62093a8061473c84613154565b6147469190614d3a565b6147509190614d3a565b11156010828154811061476557614765614cc5565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604482015260580160405160208183030381529060405290614837576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc49190614ea4565b508061484281614dca565b91505061466c565b5062093a8061485a826001614db2565b6148649190614d3a565b6004546148719190614db2565b60045561487c61488a565b61488461151c565b60035550565b60006148946115b0565b905060005b6015548110156148ee578181815181106148b5576148b5614cc5565b6020026020010151601582815481106148d0576148d0614cc5565b600091825260209091200155806148e681614dca565b915050614899565b506148f7613b4b565b60055550565b803573ffffffffffffffffffffffffffffffffffffffff8116811461246b57600080fd5b60006020828403121561493357600080fd5b61363e826148fd565b6020808252825182820181905260009190848201906040850190845b8181101561497457835183529284019291840191600101614958565b50909695505050505050565b60006020828403121561499257600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b8181101561497457835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016149b5565b600080604083850312156149fa57600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b82811015614a6a5781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614a26565b5091979650505050505050565b60008060408385031215614a8a57600080fd5b614a93836148fd565b9150614aa1602084016148fd565b90509250929050565b801515811461315157600080fd5b60008060408385031215614acb57600080fd5b614ad4836148fd565b91506020830135614ae481614aaa565b809150509250929050565b60008060408385031215614b0257600080fd5b614b0b836148fd565b946020939093013593505050565b600080600060608486031215614b2e57600080fd5b8335614b3981614aaa565b92506020840135614b4981614aaa565b91506040840135614b5981614aaa565b809150509250925092565b60008060008060808587031215614b7a57600080fd5b614b83856148fd565b935060208501359250614b98604086016148fd565b9150614ba6606086016148fd565b905092959194509250565b60008060408385031215614bc457600080fd5b82359150614aa1602084016148fd565b600060208284031215614be657600080fd5b813561363e81614aaa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c08284031215614c3257600080fd5b82601f830112614c4157600080fd5b60405160c0810181811067ffffffffffffffff82111715614c8b577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c0840185811115614ca057600080fd5b845b81811015614cba578035835260209283019201614ca2565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015614d3557614d35614cf4565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d7257614d72614cf4565b500290565b600082614dad577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008219821115614dc557614dc5614cf4565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dfb57614dfb614cf4565b5060010190565b600060208284031215614e1457600080fd5b5051919050565b60005b83811015614e36578181015183820152602001614e1e565b83811115611cc35750506000910152565b60008251614e59818460208701614e1b565b9190910192915050565b600060208284031215614e7557600080fd5b815161363e81614aaa565b60008060408385031215614e9357600080fd5b505080516020909101519092909150565b6020815260008251806020840152614ec3816040850160208701614e1b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212205aebb569aae77c355e348f8cc000f795c11b91d0812e5743988160eafc0efd4864736f6c634300080f0033

Verified Source Code Partial Match

Compiler: v0.8.15+commit.e14f2714 EVM: london Optimization: Yes (100000 runs)
FraxUnifiedFarm_ERC20_Convex_stkcvxTUSDFRAXBP.sol 2126 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// Sources flattened with hardhat v2.10.1 https://hardhat.org

// File contracts/Math/Math.sol


/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}


// File contracts/Curve/IveFXS.sol

pragma abicoder v2;

interface IveFXS {

    struct LockedBalance {
        int128 amount;
        uint256 end;
    }

    function commit_transfer_ownership(address addr) external;
    function apply_transfer_ownership() external;
    function commit_smart_wallet_checker(address addr) external;
    function apply_smart_wallet_checker() external;
    function toggleEmergencyUnlock() external;
    function recoverERC20(address token_addr, uint256 amount) external;
    function get_last_user_slope(address addr) external view returns (int128);
    function user_point_history__ts(address _addr, uint256 _idx) external view returns (uint256);
    function locked__end(address _addr) external view returns (uint256);
    function checkpoint() external;
    function deposit_for(address _addr, uint256 _value) external;
    function create_lock(uint256 _value, uint256 _unlock_time) external;
    function increase_amount(uint256 _value) external;
    function increase_unlock_time(uint256 _unlock_time) external;
    function withdraw() external;
    function balanceOf(address addr) external view returns (uint256);
    function balanceOf(address addr, uint256 _t) external view returns (uint256);
    function balanceOfAt(address addr, uint256 _block) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function totalSupply(uint256 t) external view returns (uint256);
    function totalSupplyAt(uint256 _block) external view returns (uint256);
    function totalFXSSupply() external view returns (uint256);
    function totalFXSSupplyAt(uint256 _block) external view returns (uint256);
    function changeController(address _newController) external;
    function token() external view returns (address);
    function supply() external view returns (uint256);
    function locked(address addr) external view returns (LockedBalance memory);
    function epoch() external view returns (uint256);
    function point_history(uint256 arg0) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxs_amt);
    function user_point_history(address arg0, uint256 arg1) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxs_amt);
    function user_point_epoch(address arg0) external view returns (uint256);
    function slope_changes(uint256 arg0) external view returns (int128);
    function controller() external view returns (address);
    function transfersEnabled() external view returns (bool);
    function emergencyUnlockActive() external view returns (bool);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function version() external view returns (string memory);
    function decimals() external view returns (uint256);
    function future_smart_wallet_checker() external view returns (address);
    function smart_wallet_checker() external view returns (address);
    function admin() external view returns (address);
    function future_admin() external view returns (address);
}


// File contracts/Curve/IFraxGaugeController.sol


// https://github.com/swervefi/swerve/edit/master/packages/swerve-contracts/interfaces/IGaugeController.sol

interface IFraxGaugeController {
    struct Point {
        uint256 bias;
        uint256 slope;
    }

    struct VotedSlope {
        uint256 slope;
        uint256 power;
        uint256 end;
    }

    // Public variables
    function admin() external view returns (address);
    function future_admin() external view returns (address);
    function token() external view returns (address);
    function voting_escrow() external view returns (address);
    function n_gauge_types() external view returns (int128);
    function n_gauges() external view returns (int128);
    function gauge_type_names(int128) external view returns (string memory);
    function gauges(uint256) external view returns (address);
    function vote_user_slopes(address, address)
        external
        view
        returns (VotedSlope memory);
    function vote_user_power(address) external view returns (uint256);
    function last_user_vote(address, address) external view returns (uint256);
    function points_weight(address, uint256)
        external
        view
        returns (Point memory);
    function time_weight(address) external view returns (uint256);
    function points_sum(int128, uint256) external view returns (Point memory);
    function time_sum(uint256) external view returns (uint256);
    function points_total(uint256) external view returns (uint256);
    function time_total() external view returns (uint256);
    function points_type_weight(int128, uint256)
        external
        view
        returns (uint256);
    function time_type_weight(uint256) external view returns (uint256);

    // Getter functions
    function gauge_types(address) external view returns (int128);
    function gauge_relative_weight(address) external view returns (uint256);
    function gauge_relative_weight(address, uint256) external view returns (uint256);
    function get_gauge_weight(address) external view returns (uint256);
    function get_type_weight(int128) external view returns (uint256);
    function get_total_weight() external view returns (uint256);
    function get_weights_sum_per_type(int128) external view returns (uint256);

    // External functions
    function commit_transfer_ownership(address) external;
    function apply_transfer_ownership() external;
    function add_gauge(
        address,
        int128,
        uint256
    ) external;
    function checkpoint() external;
    function checkpoint_gauge(address) external;
    function global_emission_rate() external view returns (uint256);
    function gauge_relative_weight_write(address)
        external
        returns (uint256);
    function gauge_relative_weight_write(address, uint256)
        external
        returns (uint256);
    function add_type(string memory, uint256) external;
    function change_type_weight(int128, uint256) external;
    function change_gauge_weight(address, uint256) external;
    function change_global_emission_rate(uint256) external;
    function vote_for_gauge_weights(address, uint256) external;
}


// File contracts/Curve/IFraxGaugeFXSRewardsDistributor.sol


interface IFraxGaugeFXSRewardsDistributor {
  function acceptOwnership() external;
  function curator_address() external view returns(address);
  function currentReward(address gauge_address) external view returns(uint256 reward_amount);
  function distributeReward(address gauge_address) external returns(uint256 weeks_elapsed, uint256 reward_tally);
  function distributionsOn() external view returns(bool);
  function gauge_whitelist(address) external view returns(bool);
  function is_middleman(address) external view returns(bool);
  function last_time_gauge_paid(address) external view returns(uint256);
  function nominateNewOwner(address _owner) external;
  function nominatedOwner() external view returns(address);
  function owner() external view returns(address);
  function recoverERC20(address tokenAddress, uint256 tokenAmount) external;
  function setCurator(address _new_curator_address) external;
  function setGaugeController(address _gauge_controller_address) external;
  function setGaugeState(address _gauge_address, bool _is_middleman, bool _is_active) external;
  function setTimelock(address _new_timelock) external;
  function timelock_address() external view returns(address);
  function toggleDistributions() external;
}


// File contracts/Common/Context.sol


/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return payable(msg.sender);
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}


// File contracts/Math/SafeMath.sol


/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}


// File contracts/ERC20/IERC20.sol



/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


// File contracts/Uniswap/TransferHelper.sol


// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}


// File contracts/Utils/ReentrancyGuard.sol


/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}


// File contracts/Staking/Owned.sol


// https://docs.synthetix.io/contracts/Owned
contract Owned {
    address public owner;
    address public nominatedOwner;

    constructor (address _owner) public {
        require(_owner != address(0), "Owner address cannot be 0");
        owner = _owner;
        emit OwnerChanged(address(0), _owner);
    }

    function nominateNewOwner(address _owner) external onlyOwner {
        nominatedOwner = _owner;
        emit OwnerNominated(_owner);
    }

    function acceptOwnership() external {
        require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
        emit OwnerChanged(owner, nominatedOwner);
        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner {
        require(msg.sender == owner, "Only the contract owner may perform this action");
        _;
    }

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);
}


// File contracts/Misc_AMOs/convex/IConvexBaseRewardPool.sol


interface IConvexBaseRewardPool {
  function addExtraReward(address _reward) external returns (bool);
  function balanceOf(address account) external view returns (uint256);
  function clearExtraRewards() external;
  function currentRewards() external view returns (uint256);
  function donate(uint256 _amount) external returns (bool);
  function duration() external view returns (uint256);
  function earned(address account) external view returns (uint256);
  function extraRewards(uint256) external view returns (address);
  function extraRewardsLength() external view returns (uint256);
  function getReward() external returns (bool);
  function getReward(address _account, bool _claimExtras) external returns (bool);
  function historicalRewards() external view returns (uint256);
  function lastTimeRewardApplicable() external view returns (uint256);
  function lastUpdateTime() external view returns (uint256);
  function newRewardRatio() external view returns (uint256);
  function operator() external view returns (address);
  function periodFinish() external view returns (uint256);
  function pid() external view returns (uint256);
  function queueNewRewards(uint256 _rewards) external returns (bool);
  function queuedRewards() external view returns (uint256);
  function rewardManager() external view returns (address);
  function rewardPerToken() external view returns (uint256);
  function rewardPerTokenStored() external view returns (uint256);
  function rewardRate() external view returns (uint256);
  function rewardToken() external view returns (address);
  function rewards(address) external view returns (uint256);
  function stake(uint256 _amount) external returns (bool);
  function stakeAll() external returns (bool);
  function stakeFor(address _for, uint256 _amount) external returns (bool);
  function stakingToken() external view returns (address);
  function totalSupply() external view returns (uint256);
  function userRewardPerTokenPaid(address) external view returns (uint256);
  function withdraw(uint256 amount, bool claim) external returns (bool);
  function withdrawAll(bool claim) external;
  function withdrawAllAndUnwrap(bool claim) external;
  function withdrawAndUnwrap(uint256 amount, bool claim) external returns (bool);
}


// File contracts/Staking/FraxUnifiedFarmTemplate.sol


// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ====================== FraxUnifiedFarmTemplate =====================
// ====================================================================
// Farming contract that accounts for veFXS
// Overrideable for UniV3, ERC20s, etc
// New for V2
//      - Multiple reward tokens possible
//      - Can add to existing locked stakes
//      - Contract is aware of proxied veFXS
//      - veFXS multiplier formula changed
// Apes together strong

// Frax Finance: https://github.com/FraxFinance

// Primary Author(s)
// Travis Moore: https://github.com/FortisFortuna

// Reviewer(s) / Contributor(s)
// Jason Huan: https://github.com/jasonhuan
// Sam Kazemian: https://github.com/samkazemian
// Dennis: github.com/denett

// Originally inspired by Synthetix.io, but heavily modified by the Frax team
// (Locked, veFXS, and UniV3 portions are new)
// https://raw.githubusercontent.com/Synthetixio/synthetix/develop/contracts/StakingRewards.sol








// Extra rewards

contract FraxUnifiedFarmTemplate is Owned, ReentrancyGuard {

    /* ========== STATE VARIABLES ========== */

    // Instances
    IveFXS private immutable veFXS = IveFXS(0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0);
    
    // Frax related
    address internal immutable frax_address = 0x853d955aCEf822Db058eb8505911ED77F175b99e;
    uint256 public fraxPerLPStored;

    // Constant for various precisions
    uint256 internal constant MULTIPLIER_PRECISION = 1e18;

    // Time tracking
    uint256 public periodFinish;
    uint256 public lastUpdateTime;

    // Lock time and multiplier settings
    uint256 public lock_max_multiplier = uint256(2e18); // E18. 1x = e18
    uint256 public lock_time_for_max_multiplier = 1 * 365 * 86400; // 1 year
    // uint256 public lock_time_for_max_multiplier = 2 * 86400; // 2 days
    uint256 public lock_time_min = 594000; // 6.875 * 86400 (~7 day)

    // veFXS related
    uint256 public vefxs_boost_scale_factor = uint256(4e18); // E18. 4x = 4e18; 100 / scale_factor = % vefxs supply needed for max boost
    uint256 public vefxs_max_multiplier = uint256(2e18); // E18. 1x = 1e18
    uint256 public vefxs_per_frax_for_max_boost = uint256(4e18); // E18. 2e18 means 2 veFXS must be held by the staker per 1 FRAX
    mapping(address => uint256) internal _vefxsMultiplierStored;
    mapping(address => bool) internal valid_vefxs_proxies;
    mapping(address => mapping(address => bool)) internal proxy_allowed_stakers;

    // Reward addresses, gauge addresses, reward rates, and reward managers
    mapping(address => address) public rewardManagers; // token addr -> manager addr
    address[] internal rewardTokens;
    address[] internal gaugeControllers;
    address[] internal rewardDistributors;
    uint256[] internal rewardRatesManual;
    mapping(address => uint256) public rewardTokenAddrToIdx; // token addr -> token index
    
    // Reward period
    uint256 public constant rewardsDuration = 604800; // 7 * 86400  (7 days)

    // Reward tracking
    uint256[] private rewardsPerTokenStored;
    mapping(address => mapping(uint256 => uint256)) private userRewardsPerTokenPaid; // staker addr -> token id -> paid amount
    mapping(address => mapping(uint256 => uint256)) private rewards; // staker addr -> token id -> reward amount
    mapping(address => uint256) public lastRewardClaimTime; // staker addr -> timestamp
    
    // Gauge tracking
    uint256[] private last_gauge_relative_weights;
    uint256[] private last_gauge_time_totals;

    // Balance tracking
    uint256 internal _total_liquidity_locked;
    uint256 internal _total_combined_weight;
    mapping(address => uint256) internal _locked_liquidity;
    mapping(address => uint256) internal _combined_weights;
    mapping(address => uint256) public proxy_lp_balances; // Keeps track of LP balances proxy-wide. Needed to make sure the proxy boost is kept in line


    // Stakers set which proxy(s) they want to use
    mapping(address => address) public staker_designated_proxies; // Keep public so users can see on the frontend if they have a proxy

    // Admin booleans for emergencies and overrides
    bool public stakesUnlocked; // Release locked stakes in case of emergency
    bool internal withdrawalsPaused; // For emergencies
    bool internal rewardsCollectionPaused; // For emergencies
    bool internal stakingPaused; // For emergencies

    /* ========== STRUCTS ========== */
    // In children...


    /* ========== MODIFIERS ========== */

    modifier onlyByOwnGov() {
        require(msg.sender == owner || msg.sender == 0x8412ebf45bAC1B340BbE8F318b928C466c4E39CA, "Not owner or timelock");
        _;
    }

    modifier onlyTknMgrs(address reward_token_address) {
        require(msg.sender == owner || isTokenManagerFor(msg.sender, reward_token_address), "Not owner or tkn mgr");
        _;
    }

    modifier updateRewardAndBalanceMdf(address account, bool sync_too) {
        updateRewardAndBalance(account, sync_too);
        _;
    }

    /* ========== CONSTRUCTOR ========== */

    constructor (
        address _owner,
        address[] memory _rewardTokens,
        address[] memory _rewardManagers,
        uint256[] memory _rewardRatesManual,
        address[] memory _gaugeControllers,
        address[] memory _rewardDistributors
    ) Owned(_owner) {

        // Address arrays
        rewardTokens = _rewardTokens;
        gaugeControllers = _gaugeControllers;
        rewardDistributors = _rewardDistributors;
        rewardRatesManual = _rewardRatesManual;

        for (uint256 i = 0; i < _rewardTokens.length; i++){ 
            // For fast token address -> token ID lookups later
            rewardTokenAddrToIdx[_rewardTokens[i]] = i;

            // Initialize the stored rewards
            rewardsPerTokenStored.push(0);

            // Initialize the reward managers
            rewardManagers[_rewardTokens[i]] = _rewardManagers[i];

            // Push in empty relative weights to initialize the array
            last_gauge_relative_weights.push(0);

            // Push in empty time totals to initialize the array
            last_gauge_time_totals.push(0);
        }

        // Other booleans
        stakesUnlocked = false;

        // Initialization
        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp + rewardsDuration;
    }

    /* ============= VIEWS ============= */

    // ------ REWARD RELATED ------

    // See if the caller_addr is a manager for the reward token 
    function isTokenManagerFor(address caller_addr, address reward_token_addr) public view returns (bool){
        if (caller_addr == owner) return true; // Contract owner
        else if (rewardManagers[reward_token_addr] == caller_addr) return true; // Reward manager
        return false; 
    }

    // All the reward tokens
    function getAllRewardTokens() external view returns (address[] memory) {
        return rewardTokens;
    }

    // Last time the reward was applicable
    function lastTimeRewardApplicable() internal view returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }

    function rewardRates(uint256 token_idx) public view returns (uint256 rwd_rate) {
        address gauge_controller_address = gaugeControllers[token_idx];
        if (gauge_controller_address != address(0)) {
            rwd_rate = (IFraxGaugeController(gauge_controller_address).global_emission_rate() * last_gauge_relative_weights[token_idx]) / 1e18;
        }
        else {
            rwd_rate = rewardRatesManual[token_idx];
        }
    }

    // Amount of reward tokens per LP token / liquidity unit
    function rewardsPerToken() public view returns (uint256[] memory newRewardsPerTokenStored) {
        if (_total_liquidity_locked == 0 || _total_combined_weight == 0) {
            return rewardsPerTokenStored;
        }
        else {
            newRewardsPerTokenStored = new uint256[](rewardTokens.length);
            for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){ 
                newRewardsPerTokenStored[i] = rewardsPerTokenStored[i] + (
                    ((lastTimeRewardApplicable() - lastUpdateTime) * rewardRates(i) * 1e18) / _total_combined_weight
                );
            }
            return newRewardsPerTokenStored;
        }
    }

    // Amount of reward tokens an account has earned / accrued
    // Note: In the edge-case of one of the account's stake expiring since the last claim, this will
    // return a slightly inflated number
    function earned(address account) public view returns (uint256[] memory new_earned) {
        uint256[] memory reward_arr = rewardsPerToken();
        new_earned = new uint256[](rewardTokens.length);

        if (_combined_weights[account] > 0){
            for (uint256 i = 0; i < rewardTokens.length; i++){ 
                new_earned[i] = ((_combined_weights[account] * (reward_arr[i] - userRewardsPerTokenPaid[account][i])) / 1e18)
                                + rewards[account][i];
            }
        }
    }

    // Total reward tokens emitted in the given period
    function getRewardForDuration() external view returns (uint256[] memory rewards_per_duration_arr) {
        rewards_per_duration_arr = new uint256[](rewardRatesManual.length);

        for (uint256 i = 0; i < rewardRatesManual.length; i++){ 
            rewards_per_duration_arr[i] = rewardRates(i) * rewardsDuration;
        }
    }


    // ------ LIQUIDITY AND WEIGHTS ------

    // User locked liquidity / LP tokens
    function totalLiquidityLocked() external view returns (uint256) {
        return _total_liquidity_locked;
    }

    // Total locked liquidity / LP tokens
    function lockedLiquidityOf(address account) external view returns (uint256) {
        return _locked_liquidity[account];
    }

    // Total combined weight
    function totalCombinedWeight() external view returns (uint256) {
        return _total_combined_weight;
    }

    // Total 'balance' used for calculating the percent of the pool the account owns
    // Takes into account the locked stake time multiplier and veFXS multiplier
    function combinedWeightOf(address account) external view returns (uint256) {
        return _combined_weights[account];
    }

    // Calculated the combined weight for an account
    function calcCurCombinedWeight(address account) public virtual view 
        returns (
            uint256 old_combined_weight,
            uint256 new_vefxs_multiplier,
            uint256 new_combined_weight
        )
    {
        revert("Need cCCW logic");
    }

    // ------ LOCK RELATED ------

    // Multiplier amount, given the length of the lock
    function lockMultiplier(uint256 secs) public view returns (uint256) {
        // return Math.min(
        //     lock_max_multiplier,
        //     uint256(MULTIPLIER_PRECISION) + (
        //         (secs * (lock_max_multiplier - MULTIPLIER_PRECISION)) / lock_time_for_max_multiplier
        //     )
        // ) ;
        return Math.min(
            lock_max_multiplier,
            (secs * lock_max_multiplier) / lock_time_for_max_multiplier
        ) ;
    }

    // ------ FRAX RELATED ------

    function userStakedFrax(address account) public view returns (uint256) {
        return (fraxPerLPStored * _locked_liquidity[account]) / MULTIPLIER_PRECISION;
    }

    function proxyStakedFrax(address proxy_address) public view returns (uint256) {
        return (fraxPerLPStored * proxy_lp_balances[proxy_address]) / MULTIPLIER_PRECISION;
    }

    // Max LP that can get max veFXS boosted for a given address at its current veFXS balance
    function maxLPForMaxBoost(address account) external view returns (uint256) {
        return (veFXS.balanceOf(account) * MULTIPLIER_PRECISION * MULTIPLIER_PRECISION) / (vefxs_per_frax_for_max_boost * fraxPerLPStored);
    }

    // Meant to be overridden
    function fraxPerLPToken() public virtual view returns (uint256) {
        revert("Need fPLPT logic");
    }

    // ------ veFXS RELATED ------

    function minVeFXSForMaxBoost(address account) public view returns (uint256) {
        return (userStakedFrax(account) * vefxs_per_frax_for_max_boost) / MULTIPLIER_PRECISION;
    }

    function minVeFXSForMaxBoostProxy(address proxy_address) public view returns (uint256) {
        return (proxyStakedFrax(proxy_address) * vefxs_per_frax_for_max_boost) / MULTIPLIER_PRECISION;
    }

    function getProxyFor(address addr) public view returns (address){
        if (valid_vefxs_proxies[addr]) {
            // If addr itself is a proxy, return that.
            // If it farms itself directly, it should use the shared LP tally in proxyStakedFrax
            return addr;
        }
        else {
            // Otherwise, return the proxy, or address(0)
            return staker_designated_proxies[addr];
        }
    }

    function veFXSMultiplier(address account) public view returns (uint256 vefxs_multiplier) {
        // Use either the user's or their proxy's veFXS balance
        uint256 vefxs_bal_to_use = 0;
        address the_proxy = getProxyFor(account);
        vefxs_bal_to_use = (the_proxy == address(0)) ? veFXS.balanceOf(account) : veFXS.balanceOf(the_proxy);

        // First option based on fraction of total veFXS supply, with an added scale factor
        uint256 mult_optn_1 = (vefxs_bal_to_use * vefxs_max_multiplier * vefxs_boost_scale_factor) 
                            / (veFXS.totalSupply() * MULTIPLIER_PRECISION);
        
        // Second based on old method, where the amount of FRAX staked comes into play
        uint256 mult_optn_2;
        {
            uint256 veFXS_needed_for_max_boost;

            // Need to use proxy-wide FRAX balance if applicable, to prevent exploiting
            veFXS_needed_for_max_boost = (the_proxy == address(0)) ? minVeFXSForMaxBoost(account) : minVeFXSForMaxBoostProxy(the_proxy);

            if (veFXS_needed_for_max_boost > 0){ 
                uint256 user_vefxs_fraction = (vefxs_bal_to_use * MULTIPLIER_PRECISION) / veFXS_needed_for_max_boost;
                
                mult_optn_2 = (user_vefxs_fraction * vefxs_max_multiplier) / MULTIPLIER_PRECISION;
            }
            else mult_optn_2 = 0; // This will happen with the first stake, when user_staked_frax is 0
        }

        // Select the higher of the two
        vefxs_multiplier = (mult_optn_1 > mult_optn_2 ? mult_optn_1 : mult_optn_2);

        // Cap the boost to the vefxs_max_multiplier
        if (vefxs_multiplier > vefxs_max_multiplier) vefxs_multiplier = vefxs_max_multiplier;
    }

    /* =============== MUTATIVE FUNCTIONS =============== */


    // Proxy can allow a staker to use their veFXS balance (the staker will have to reciprocally toggle them too)
    // Must come before stakerSetVeFXSProxy
    // CALLED BY PROXY
    function proxyToggleStaker(address staker_address) external {
        require(valid_vefxs_proxies[msg.sender], "Invalid proxy");
        proxy_allowed_stakers[msg.sender][staker_address] = !proxy_allowed_stakers[msg.sender][staker_address]; 

        // Disable the staker's set proxy if it was the toggler and is currently on
        if (staker_designated_proxies[staker_address] == msg.sender){
            staker_designated_proxies[staker_address] = address(0); 

            // Remove the LP as well
            proxy_lp_balances[msg.sender] -= _locked_liquidity[staker_address];
        }
    }

    // Staker can allow a veFXS proxy (the proxy will have to toggle them first)
    // CALLED BY STAKER
    function stakerSetVeFXSProxy(address proxy_address) external {
        require(valid_vefxs_proxies[proxy_address], "Invalid proxy");
        require(proxy_allowed_stakers[proxy_address][msg.sender], "Proxy has not allowed you yet");
        
        // Corner case sanity check to make sure LP isn't double counted
        address old_proxy_addr = staker_designated_proxies[msg.sender];
        if (old_proxy_addr != address(0)) {
            // Remove the LP count from the old proxy
            proxy_lp_balances[old_proxy_addr] -= _locked_liquidity[msg.sender];
        }

        // Set the new proxy
        staker_designated_proxies[msg.sender] = proxy_address; 

        // Add the the LP as well
        proxy_lp_balances[proxy_address] += _locked_liquidity[msg.sender];
    }

    // ------ STAKING ------
    // In children...


    // ------ WITHDRAWING ------
    // In children...


    // ------ REWARDS SYNCING ------

    function updateRewardAndBalance(address account, bool sync_too) public {
        // Need to retro-adjust some things if the period hasn't been renewed, then start a new one
        if (sync_too){
            sync();
        }
        
        if (account != address(0)) {
            // To keep the math correct, the user's combined weight must be recomputed to account for their
            // ever-changing veFXS balance.
            (   
                uint256 old_combined_weight,
                uint256 new_vefxs_multiplier,
                uint256 new_combined_weight
            ) = calcCurCombinedWeight(account);

            // Calculate the earnings first
            _syncEarned(account);

            // Update the user's stored veFXS multipliers
            _vefxsMultiplierStored[account] = new_vefxs_multiplier;

            // Update the user's and the global combined weights
            if (new_combined_weight >= old_combined_weight) {
                uint256 weight_diff = new_combined_weight - old_combined_weight;
                _total_combined_weight = _total_combined_weight + weight_diff;
                _combined_weights[account] = old_combined_weight + weight_diff;
            } else {
                uint256 weight_diff = old_combined_weight - new_combined_weight;
                _total_combined_weight = _total_combined_weight - weight_diff;
                _combined_weights[account] = old_combined_weight - weight_diff;
            }

        }
    }

    function _syncEarned(address account) internal {
        if (account != address(0)) {
            // Calculate the earnings
            uint256[] memory earned_arr = earned(account);

            // Update the rewards array
            for (uint256 i = 0; i < earned_arr.length; i++){ 
                rewards[account][i] = earned_arr[i];
            }

            // Update the rewards paid array
            for (uint256 i = 0; i < earned_arr.length; i++){ 
                userRewardsPerTokenPaid[account][i] = rewardsPerTokenStored[i];
            }
        }
    }


    // ------ REWARDS CLAIMING ------

    function getRewardExtraLogic(address destination_address) public nonReentrant {
        require(rewardsCollectionPaused == false, "Rewards collection paused");
        return _getRewardExtraLogic(msg.sender, destination_address);
    }

    function _getRewardExtraLogic(address rewardee, address destination_address) internal virtual {
        revert("Need gREL logic");
    }

    // Two different getReward functions are needed because of delegateCall and msg.sender issues
    // For backwards-compatibility
    function getReward(address destination_address) external nonReentrant returns (uint256[] memory) {
        return _getReward(msg.sender, destination_address, true);
    }

    function getReward2(address destination_address, bool claim_extra_too) external nonReentrant returns (uint256[] memory) {
        return _getReward(msg.sender, destination_address, claim_extra_too);
    }

    // No withdrawer == msg.sender check needed since this is only internally callable
    function _getReward(address rewardee, address destination_address, bool do_extra_logic) internal updateRewardAndBalanceMdf(rewardee, true) returns (uint256[] memory rewards_before) {
        // Update the last reward claim time first, as an extra reentrancy safeguard
        lastRewardClaimTime[rewardee] = block.timestamp;
        
        // Make sure rewards collection isn't paused
        require(rewardsCollectionPaused == false, "Rewards collection paused");
        
        // Update the rewards array and distribute rewards
        rewards_before = new uint256[](rewardTokens.length);

        for (uint256 i = 0; i < rewardTokens.length; i++){ 
            rewards_before[i] = rewards[rewardee][i];
            rewards[rewardee][i] = 0;
            if (rewards_before[i] > 0) {
                TransferHelper.safeTransfer(rewardTokens[i], destination_address, rewards_before[i]);

                emit RewardPaid(rewardee, rewards_before[i], rewardTokens[i], destination_address);
            }
        }

        // Handle additional reward logic
        if (do_extra_logic) {
            _getRewardExtraLogic(rewardee, destination_address);
        }
    }


    // ------ FARM SYNCING ------

    // If the period expired, renew it
    function retroCatchUp() internal {
        // Pull in rewards from the rewards distributor, if applicable
        for (uint256 i = 0; i < rewardDistributors.length; i++){ 
            address reward_distributor_address = rewardDistributors[i];
            if (reward_distributor_address != address(0)) {
                IFraxGaugeFXSRewardsDistributor(reward_distributor_address).distributeReward(address(this));
            }
        }

        // Ensure the provided reward amount is not more than the balance in the contract.
        // This keeps the reward rate in the right range, preventing overflows due to
        // very high values of rewardRate in the earned and rewardsPerToken functions;
        // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
        uint256 num_periods_elapsed = uint256(block.timestamp - periodFinish) / rewardsDuration; // Floor division to the nearest period
        
        // Make sure there are enough tokens to renew the reward period
        for (uint256 i = 0; i < rewardTokens.length; i++){ 
            require((rewardRates(i) * rewardsDuration * (num_periods_elapsed + 1)) <= IERC20(rewardTokens[i]).balanceOf(address(this)), string(abi.encodePacked("Not enough reward tokens available: ", rewardTokens[i])) );
        }
        
        // uint256 old_lastUpdateTime = lastUpdateTime;
        // uint256 new_lastUpdateTime = block.timestamp;

        // lastUpdateTime = periodFinish;
        periodFinish = periodFinish + ((num_periods_elapsed + 1) * rewardsDuration);

        // Update the rewards and time
        _updateStoredRewardsAndTime();

        // Update the fraxPerLPStored
        fraxPerLPStored = fraxPerLPToken();

        // Pull in rewards and set the reward rate for one week, based off of that
        // If the rewards get messed up for some reason, set this to 0 and it will skip
        // if (rewardRatesManual[1] != 0 && rewardRatesManual[2] != 0) {
        //     // CRV & CVX
        //     // ===========================...

// [truncated — 89507 bytes total]

Read Contract

calcCurCombinedWeight 0x8bad86a7 → uint256, uint256, uint256
calcCurrLockMultiplier 0x774d4ae7 → uint256
combinedWeightOf 0x36f89af2 → uint256
curvePool 0x218751b2 → address
curveToken 0x4f39059c → address
earned 0x008cc262 → uint256[]
fraxPerLPStored 0xd2010fb4 → uint256
fraxPerLPToken 0x5bfd9258 → uint256
getAllRewardTokens 0x12edb24c → address[]
getProxyFor 0xc3543826 → address
getRewardForDuration 0x1c1f78eb → uint256[]
isTokenManagerFor 0x231b68dc → bool
lastRewardClaimTime 0x6c430dbb → uint256
lastUpdateTime 0xc8f33c91 → uint256
lockMultiplier 0x0d7bac4f → uint256
lock_max_multiplier 0xcdc82e80 → uint256
lock_time_for_max_multiplier 0xb94c4dcb → uint256
lock_time_min 0x6e27cef9 → uint256
lockedLiquidityOf 0xd9f96e8d → uint256
lockedStakes 0x7970833e → bytes32, uint256, uint256, uint256, uint256
lockedStakesOf 0x1e090f01 → tuple[]
lockedStakesOfLength 0xca6df29d → uint256
maxLPForMaxBoost 0xa0f23476 → uint256
minVeFXSForMaxBoost 0x4fd2b536 → uint256
minVeFXSForMaxBoostProxy 0x7f472e54 → uint256
nominatedOwner 0x53a47bb7 → address
owner 0x8da5cb5b → address
periodFinish 0xebe2b12b → uint256
proxyStakedFrax 0x1face856 → uint256
proxy_lp_balances 0x7d6ef08e → uint256
rewardManagers 0x41a16f3f → address
rewardRates 0xf2caeb1e → uint256
rewardTokenAddrToIdx 0x69339245 → uint256
rewardsDuration 0x386a9525 → uint256
rewardsPerToken 0x70641a36 → uint256[]
staker_designated_proxies 0x28408bab → address
stakesUnlocked 0x9637927f → bool
stakingToken 0x72f702f3 → address
totalCombinedWeight 0x64f2c060 → uint256
totalLiquidityLocked 0xe01f62bf → uint256
userStakedFrax 0xd42fc9b4 → uint256
veFXSMultiplier 0x2c0c2a0a → uint256
vefxs_boost_scale_factor 0xaa1d4fce → uint256
vefxs_max_multiplier 0xf288baf6 → uint256
vefxs_per_frax_for_max_boost 0xf2a8d349 → uint256

Write Contract 21 functions

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

acceptOwnership 0x79ba5097
No parameters
changeTokenManager 0xde1a6551
address reward_token_address
address new_manager_address
getReward 0xc00007b0
address destination_address
returns: uint256[]
getReward2 0x7910d17b
address destination_address
bool claim_extra_too
returns: uint256[]
getRewardExtraLogic 0x387edc86
address destination_address
lockAdditional 0xb85efd06
bytes32 kek_id
uint256 addl_liq
lockLonger 0xd2fbdc0d
bytes32 kek_id
uint256 new_ending_ts
nominateNewOwner 0x1627540c
address _owner
proxyToggleStaker 0xe7f30582
address staker_address
recoverERC20 0x8980f11f
address tokenAddress
uint256 tokenAmount
setMiscVariables 0xfacefb64
uint256[6] _misc_vars
setPauses 0xcc2abd64
bool _stakingPaused
bool _withdrawalsPaused
bool _rewardsCollectionPaused
setRewardVars 0xd5e1a9c6
address reward_token_address
uint256 _new_rate
address _gauge_controller_address
address _rewards_distributor_address
stakeLocked 0x17b18c89
uint256 liquidity
uint256 secs
returns: bytes32
stakerSetVeFXSProxy 0xd7400d56
address proxy_address
sync 0xfff6cae9
No parameters
sync_gauge_weights 0xf77e34d1
bool force_update
toggleValidVeFXSProxy 0x91cf600a
address _proxy_addr
unlockStakes 0xe1ba95d2
No parameters
updateRewardAndBalance 0x55189773
address account
bool sync_too
withdrawLocked 0xe44b9fa5
bytes32 kek_id
address destination_address
returns: uint256

Recent Transactions

No transactions found for this address