Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xE1e697Fd7EC9b3675808Ba8Ad508fD51cac756a3
Balance 0 ETH
Nonce 1
Code Size 21245 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

21245 bytes
0x608060405234801561001057600080fd5b50600436106104055760003560e01c80637f472e541161021a578063d2010fb411610135578063e1ba95d2116100c8578063f2a8d34911610097578063f77e34d11161007c578063f77e34d1146109a8578063facefb64146109bb578063fff6cae9146109ce57600080fd5b8063f2a8d3491461098c578063f2caeb1e1461099557600080fd5b8063e1ba95d21461095f578063e7f3058214610967578063ebe2b12b1461097a578063f288baf61461098357600080fd5b8063d7400d5611610104578063d7400d56146108fb578063d9f96e8d1461090e578063de1a655114610944578063e01f62bf1461095757600080fd5b8063d2010fb4146108b9578063d2fbdc0d146108c2578063d42fc9b4146108d5578063d5e1a9c6146108e857600080fd5b8063aa1d4fce116101ad578063c35438261161017c578063c35438261461085e578063c8f33c9114610871578063ca6df29d1461087a578063cdc82e80146108b057600080fd5b8063aa1d4fce14610826578063b85efd061461082f578063b94c4dcb14610842578063c00007b01461084b57600080fd5b80638da5cb5b116101e95780638da5cb5b146107d357806391cf600a146107f35780639637927f14610806578063a0f234761461081357600080fd5b80637f472e541461076a5780638980f11f1461077d57806389b5f00b146107905780638bad86a7146107a557600080fd5b806341a16f3f116103255780636c430dbb116102b8578063774d4ae7116102875780637970833e1161026c5780637970833e1461070857806379ba5097146107435780637d6ef08e1461074b57600080fd5b8063774d4ae7146106e25780637910d17b146106f557600080fd5b80636c430dbb1461068c5780636e27cef9146106ac57806370641a36146106b557806372f702f3146106bd57600080fd5b806354fd4d50116102f457806354fd4d50146106545780635bfd92581461065c57806364f2c06014610664578063693392451461066c57600080fd5b806341a16f3f146105d657806341edbdf01461060c5780634fd2b5361461062157806353a47bb71461063457600080fd5b80631face8561161039d5780632df079f11161036c5780632df079f11461057057806336f89af214610583578063386a9525146105b9578063387edc86146105c357600080fd5b80631face856146104cc578063231b68dc146104df57806328408bab146105025780632c0c2a0a1461055d57600080fd5b80631627540c116103d95780631627540c1461047c57806317b18c89146104915780631c1f78eb146104a45780631e090f01146104ac57600080fd5b80628cc2621461040a5780630238b936146104335780630d7bac4f1461045457806312edb24c14610467575b600080fd5b61041d610418366004614ce7565b6109d6565b60405161042a9190614d02565b60405180910390f35b610446610441366004614d54565b610b4b565b60405190815260200161042a565b610446610462366004614d94565b610c4c565b61046f610c78565b60405161042a9190614dad565b61048f61048a366004614ce7565b610ce7565b005b61044661049f366004614dfb565b610e07565b61041d610e91565b6104bf6104ba366004614ce7565b610f28565b60405161042a9190614e1d565b6104466104da366004614ce7565b610fdc565b6104f26104ed366004614e8b565b611021565b604051901515815260200161042a565b610538610510366004614ce7565b60216020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161042a565b61044661056b366004614ce7565b611107565b61048f61057e366004614ebe565b6113f3565b610446610591366004614ce7565b73ffffffffffffffffffffffffffffffffffffffff166000908152601f602052604090205490565b61044662093a8081565b61048f6105d1366004614ce7565b61156c565b6105386105e4366004614ce7565b600f6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6106146116cb565b60405161042a9190614f3e565b61044661062f366004614ce7565b611759565b6001546105389073ffffffffffffffffffffffffffffffffffffffff1681565b61061461177a565b610446611787565b601d54610446565b61044661067a366004614ce7565b60156020526000908152604090205481565b61044661069a366004614ce7565b60196020526000908152604090205481565b61044660085481565b61041d61182c565b60245461053890610100900473ffffffffffffffffffffffffffffffffffffffff1681565b6104466106f0366004614f8f565b611981565b61041d610703366004614fb9565b611b8d565b61071b610716366004614f8f565b611c09565b604080519586526020860194909452928401919091526060830152608082015260a00161042a565b61048f611c57565b610446610759366004614ce7565b602080526000908152604090205481565b610446610778366004614ce7565b611da2565b61048f61078b366004614f8f565b611db9565b6022546104f290640100000000900460ff1681565b6107b86107b3366004614ce7565b611f4a565b6040805193845260208401929092529082015260600161042a565b6000546105389073ffffffffffffffffffffffffffffffffffffffff1681565b61048f610801366004614ce7565b612177565b6022546104f29060ff1681565b610446610821366004614ce7565b61226a565b61044660095481565b61048f61083d366004614dfb565b612334565b61044660075481565b61041d610859366004614ce7565b6125d0565b61053861086c366004614ce7565b612658565b61044660055481565b610446610888366004614ce7565b73ffffffffffffffffffffffffffffffffffffffff1660009081526025602052604090205490565b61044660065481565b61044660035481565b61048f6108d0366004614dfb565b6126bb565b6104466108e3366004614ce7565b612b08565b61048f6108f6366004614ff0565b612b44565b61048f610909366004614ce7565b612d33565b61044661091c366004614ce7565b73ffffffffffffffffffffffffffffffffffffffff166000908152601e602052604090205490565b61048f610952366004614e8b565b612f4d565b601c54610446565b61048f613034565b61048f610975366004614ce7565b613105565b61044660045481565b610446600a5481565b610446600b5481565b6104466109a3366004614d94565b613265565b61048f6109b636600461503d565b61337c565b61048f6109c9366004615089565b613548565b61048f613708565b606060006109e261182c565b60105490915067ffffffffffffffff811115610a0057610a0061505a565b604051908082528060200260200182016040528015610a29578160200160208202803683370190505b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601f602052604090205490925015610b455760005b601054811015610b435773ffffffffffffffffffffffffffffffffffffffff84166000818152601860209081526040808320858452825280832054938352601782528083208584529091529020548351670de0b6b3a76400009190859085908110610ac857610ac861512e565b6020026020010151610ada919061518c565b73ffffffffffffffffffffffffffffffffffffffff87166000908152601f6020526040902054610b0a919061519f565b610b1491906151b6565b610b1e91906151f1565b838281518110610b3057610b3061512e565b6020908102919091010152600101610a5b565b505b50919050565b60006002805403610bbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60028055602254610100900460ff1615610c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f5769746864726177616c732070617573656400000000000000000000000000006044820152606401610bb4565b610c3f338486856137ad565b6001600255949350505050565b600654600754600091610c7291610c63828661519f565b610c6d91906151b6565b61396c565b92915050565b60606010805480602002602001604051908101604052809291908181526020018280548015610cdd57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610cb2575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610bb4565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60006002805403610e74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b60028055610e853380858542613984565b60016002559392505050565b60135460609067ffffffffffffffff811115610eaf57610eaf61505a565b604051908082528060200260200182016040528015610ed8578160200160208202803683370190505b50905060005b601354811015610f245762093a80610ef582613265565b610eff919061519f565b828281518110610f1157610f1161512e565b6020908102919091010152600101610ede565b5090565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602560209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610fd157838290600052602060002090600502016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081526020019060010190610f6d565b505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812054600354670de0b6b3a7640000916110179161519f565b610c7291906151b6565b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604081205460ff1661105657506000610c72565b73ffffffffffffffffffffffffffffffffffffffff8316158061108d575073ffffffffffffffffffffffffffffffffffffffff8216155b1561109a57506000610c72565b60005473ffffffffffffffffffffffffffffffffffffffff908116908416036110c557506001610c72565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f60205260409020548185169116036110fe57506001610c72565b50600092915050565b6000808061111484612658565b905073ffffffffffffffffffffffffffffffffffffffff8116156111d9576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015273c8418af6358ffdda74e09ca9cc3fe03ca6adc5b0906370a0823190602401602060405180830381865afa1580156111b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d49190615204565b61127b565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273c8418af6358ffdda74e09ca9cc3fe03ca6adc5b0906370a0823190602401602060405180830381865afa158015611257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127b9190615204565b91506000670de0b6b3a764000073c8418af6358ffdda74e09ca9cc3fe03ca6adc5b073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130b9190615204565b611315919061519f565b600954600a54611325908661519f565b61132f919061519f565b61133991906151b6565b905060008073ffffffffffffffffffffffffffffffffffffffff8416156113685761136384611da2565b611371565b61137187611759565b905080156113c35760008161138e670de0b6b3a76400008861519f565b61139891906151b6565b9050670de0b6b3a7640000600a54826113b1919061519f565b6113bb91906151b6565b9250506113c8565b600091505b508082116113d657806113d8565b815b9450600a548511156113ea57600a5494505b50505050919050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061142c5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b611492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bb4565b602280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff00ff166301000000861515027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010085151502177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000841515021790558080156115315750602254640100000000900460ff16155b1561156657602280547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff166401000000001790555b50505050565b60028054036115d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b60028055602254640100000000900460ff1615611650576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b60225462010000900460ff16156116c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610bb4565b506001600255565b602680546116d89061521d565b80601f01602080910402602001604051908101604052809291908181526020018280546117049061521d565b80156117515780601f1061172657610100808354040283529160200191611751565b820191906000526020600020905b81548152906001019060200180831161173457829003601f168201915b505050505081565b6000670de0b6b3a7640000600b5461177084612b08565b611017919061519f565b602380546116d89061521d565b602480546040517f07a2d13a000000000000000000000000000000000000000000000000000000008152670de0b6b3a7640000600482015260009261010090920473ffffffffffffffffffffffffffffffffffffffff16916307a2d13a9101602060405180830381865afa158015611803573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118279190615204565b905090565b6060601c546000148061183f5750601d54155b15611899576016805480602002602001604051908101604052809291908181526020018280548015610cdd57602002820191906000526020600020905b81548152602001906001019080831161187c575050505050905090565b60105467ffffffffffffffff8111156118b4576118b461505a565b6040519080825280602002602001820160405280156118dd578160200160208202803683370190505b50905060005b601654811015610f2457601d546118f982613265565b600554611904613d48565b61190e919061518c565b611918919061519f565b61192a90670de0b6b3a764000061519f565b61193491906151b6565b601682815481106119475761194761512e565b906000526020600020015461195c91906151f1565b82828151811061196e5761196e61512e565b60209081029190910101526001016118e3565b73ffffffffffffffffffffffffffffffffffffffff821660009081526025602052604081208054829190849081106119bb576119bb61512e565b600091825260208083206040805160a081018252600590940290910180548452600181015484840181905260028201548584015260038201546060860152600490910154608085015273ffffffffffffffffffffffffffffffffffffffff8916855260199092528320549193501115611a3957506020810151611a61565b5073ffffffffffffffffffffffffffffffffffffffff84166000908152601960205260409020545b42826060015111611b2157606082015173ffffffffffffffffffffffffffffffffffffffff86166000908152601960205260409020541015611b18576000818360600151611aaf919061518c565b90506000836060015142611ac3919061518c565b90506000611ad56104626002856151b6565b90506000611ae3838261519f565b611aed858461519f565b611af791906151f1565b9050611b0383856151f1565b611b0d90826151b6565b965050505050611b71565b60009250611b71565b600080828460600151611b34919061518c565b90506000428560600151611b48919061518c565b90506002611b5682846151f1565b611b6091906151b6565b92505050611b6d81610c4c565b9350505b8160800151831115611b8557816080015192505b505092915050565b60606002805403611bfa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b60028055610e85338484613d56565b60256020528160005260406000208181548110611c2557600080fd5b600091825260209091206005909102018054600182015460028301546003840154600490940154929550909350919085565b60015473ffffffffffffffffffffffffffffffffffffffff163314611cfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610bb4565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6000670de0b6b3a7640000600b5461177084610fdc565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480611de65750611de63382611021565b611e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bb4565b73ffffffffffffffffffffffffffffffffffffffff831660009081526014602052604090205460ff16808015611ea8575073ffffffffffffffffffffffffffffffffffffffff8481166000908152600f60205260409020541633145b80611ed3575080158015611ed3575060005473ffffffffffffffffffffffffffffffffffffffff1633145b15611ee35761156684338561408f565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4e6f2076616c696420746f6b656e7320746f207265636f7665720000000000006044820152606401610bb4565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601f60205260408120549080611f7b84611107565b73ffffffffffffffffffffffffffffffffffffffff85166000908152601e602052604081205491935090158015611fd5575073ffffffffffffffffffffffffffffffffffffffff85166000908152601f6020526040902054155b80612005575073ffffffffffffffffffffffffffffffffffffffff85166000908152600c60205260409020548310155b15612011575081612051565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600c602052604090205460029061204490856151f1565b61204e91906151b6565b90505b6000915060005b73ffffffffffffffffffffffffffffffffffffffff861660009081526025602052604090205481101561216e5773ffffffffffffffffffffffffffffffffffffffff861660009081526025602052604081208054839081106120bc576120bc61512e565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006121158884611981565b60408301519091506000670de0b6b3a764000061213287856151f1565b61213c908461519f565b61214691906151b6565b61215090836151f1565b905061215c81886151f1565b96505060019093019250612058915050565b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff163314806121b05750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b612216576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bb4565b73ffffffffffffffffffffffffffffffffffffffff166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000600354600b5461227c919061519f565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152670de0b6b3a764000090819073c8418af6358ffdda74e09ca9cc3fe03ca6adc5b0906370a0823190602401602060405180830381865afa158015612306573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232a9190615204565b611770919061519f565b600280540361239f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b600280556022546301000000900460ff1615612417576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610bb4565b602254640100000000900460ff161561248c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b61249833336001613d56565b506000806124a633856141ff565b9150915060008383604001516124bc91906151f1565b90506024546124e890610100900473ffffffffffffffffffffffffffffffffffffffff163330876143cd565b6040805160a08101825286815260208581015181830152818301849052606080870151908301526080808701519083015233600090815260259091529190912080548490811061253a5761253a61512e565b906000526020600020906005020160008201518160000155602082015181600101556040820151816002015560608201518160030155608082015181600401559050506125893385600161456b565b604080518681526020810186905233917f2640b32e7e5d0fa2a21ea06b22fbd75fda0fda384a895a5fdeef43646de47a0c910160405180910390a250506001600255505050565b6060600280540361263d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b6002805561264d33836001613d56565b600160025592915050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604081205460ff161561268a575090565b5073ffffffffffffffffffffffffffffffffffffffff9081166000908152602160205260409020541690565b919050565b6002805403612726576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb4565b600280556022546301000000900460ff161561279e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610bb4565b602254640100000000900460ff1615612813576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b61281f33336001613d56565b5060008061282d33856141ff565b9150915042831161289a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d75737420626520696e207468652066757475726500000000000000000000006044820152606401610bb4565b6000428360600151116128ae5760006128be565b4283606001516128be919061518c565b905060006128cc428661518c565b9050818111612937576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e6e6f742073686f7274656e206c6f636b2074696d6500000000000000006044820152606401610bb4565b6008548110156129a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610bb4565b600754811115612a0f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610bb4565b6040518060a0016040528087815260200142815260200185604001518152602001868152602001612a3f83610c4c565b9052336000908152602560205260409020805485908110612a6257612a6261512e565b90600052602060002090600502016000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040155905050612ab233600060016146da565b6040805187815260208101839052428183015260608101879052905133917fc2cf1aae6decacbc52f96b4e4fec96d4ebab5236e4ed987165537bc463014a43919081900360800190a25050600160025550505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e6020526040812054600354670de0b6b3a7640000916110179161519f565b600054849073ffffffffffffffffffffffffffffffffffffffff16331480612b715750612b713382611021565b612bd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bb4565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260156020526040902054601380548692908110612c1257612c1261512e565b9060005260206000200181905550826011601560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481548110612c7357612c7361512e565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918716815260159091526040902054601280548492908110612ce457612ce461512e565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16612dc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bb4565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600e6020908152604080832033845290915290205460ff16612e5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f50726f787920686173206e6f7420616c6c6f77656420796f75207965740000006044820152606401610bb4565b3360009081526021602052604090205473ffffffffffffffffffffffffffffffffffffffff168015612ed057336000908152601e602090815260408083205473ffffffffffffffffffffffffffffffffffffffff851684529180528220805491929091612eca90849061518c565b90915550505b33600090815260216020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155601e8352818420549084529180528220805491929091612f449084906151f1565b90915550505050565b600054829073ffffffffffffffffffffffffffffffffffffffff16331480612f7a5750612f7a3382611021565b612fe0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f74206f776e6572206f7220746b6e206d67720000000000000000000000006044820152606401610bb4565b5073ffffffffffffffffffffffffffffffffffffffff9182166000908152600f6020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061306d5750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b6130d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bb4565b602280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b336000908152600d602052604090205460ff1661317e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642070726f7879000000000000000000000000000000000000006044820152606401610bb4565b336000818152600e6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8681168552908352818420805460ff8116157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911617905560219092529091205416036132625773ffffffffffffffffffffffffffffffffffffffff8116600090815260216020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055601e825280832054338452918052822080549192909161325c90849061518c565b90915550505b50565b6000806011838154811061327b5761327b61512e565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561335657670de0b6b3a7640000601a84815481106132c1576132c161512e565b90600052602060002001548273ffffffffffffffffffffffffffffffffffffffff16630a3be7576040518163ffffffff1660e01b8152600401602060405180830381865afa158015613317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061333b9190615204565b613345919061519f565b61334f91906151b6565b9150610b45565b601383815481106133695761336961512e565b9060005260206000200154915050919050565b60005b6011548110156135445760006011828154811061339e5761339e61512e565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561353b5782806133f05750601b82815481106133e2576133e261512e565b906000526020600020015442115b1561353b576040517f6472eee100000000000000000000000000000000000000000000000000000000815230600482015242602482015273ffffffffffffffffffffffffffffffffffffffff821690636472eee1906044016020604051808303816000875af1158015613467573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348b9190615204565b601a838154811061349e5761349e61512e565b90600052602060002001819055508073ffffffffffffffffffffffffffffffffffffffff1663513872bd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156134f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351b9190615204565b601b838154811061352e5761352e61512e565b6000918252602090912001555b5060010161337f565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806135815750738412ebf45bac1b340bbe8f318b928c466c4e39ca33145b6135e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610bb4565b8051670de0b6b3a7640000111561365a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d757374206265203e3d204d554c2050524543000000000000000000000000006044820152606401610bb4565b6080810151600111801590613674575060a0810151600111155b6136da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d757374206265203e3d203100000000000000000000000000000000000000006044820152606401610bb4565b80516006556020810151600a556040810151600b556060810151600955608081015160075560a00151600855565b602254640100000000900460ff161561377d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b613787600061337c565b61378f611787565b60035560045442106137a5576137a3614859565b565b6137a3614b6e565b602254600090640100000000900460ff166137d0576137ce85856001613d56565b505b6000806137dd87866141ff565b915091508160600151421015806137fb575060225460ff1615156001145b613861576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b65206973207374696c6c206c6f636b656421000000000000000000006044820152606401610bb4565b604082015180156139615760245461389590610100900473ffffffffffffffffffffffffffffffffffffffff16888361408f565b73ffffffffffffffffffffffffffffffffffffffff881660009081526025602052604090208054839081106138cc576138cc61512e565b600091825260208220600590910201818155600181018290556002810182905560038101829055600401819055613906908990839061456b565b604080518281526020810188905273ffffffffffffffffffffffffffffffffffffffff898116828401529151918a16917f1d9308f6b22a2754a1c622bb30889e8f8f956c83e524d039e9d65d5f052eb9089181900360600190a25b979650505050505050565b600081831061397b578161397d565b825b9392505050565b6000856001613995828260006146da565b602254640100000000900460ff1615613a0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b6022546301000000900460ff1615613a7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5374616b696e67207061757365640000000000000000000000000000000000006044820152606401610bb4565b600854851015613aea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d696e696d756d207374616b652074696d65206e6f74206d65740000000000006044820152606401610bb4565b600754851115613b56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f547279696e6720746f206c6f636b20666f7220746f6f206c6f6e6700000000006044820152606401610bb4565b602454613b8090610100900473ffffffffffffffffffffffffffffffffffffffff168830896143cd565b6000613b8b86610c4c565b73ffffffffffffffffffffffffffffffffffffffff8a166000908152601e602090815260408083205490517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608f901b169281019290925260348201899052605482018b9052607482015291925090609401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012073ffffffffffffffffffffffffffffffffffffffff8e1660009081526025835283902060a0850184528185529184018a90529183018b90529092509060608101613c7e8a8a6151f1565b81526020908101859052825460018181018555600094855293829020835160059092020190815590820151818401556040820151600282015560608201516003820155608090910151600490910155613cda908b908a9061456b565b604080518981526020810189905290810182905273ffffffffffffffffffffffffffffffffffffffff8a811660608301528b16907ff400e72e69ef4402819dfc57eeddc66f5eb69bf405e0e8098b1946ec1ac14a229060800160405180910390a29998505050505050505050565b60006118274260045461396c565b6060836001613d67828260006146da565b602254640100000000900460ff1615613ddc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f6e6c79207769746864726177616c7320616c6c6f77656400000000000000006044820152606401610bb4565b60225462010000900460ff1615613e4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5265776172647320636f6c6c656374696f6e20706175736564000000000000006044820152606401610bb4565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260196020526040902042905560105467ffffffffffffffff811115613e9257613e9261505a565b604051908082528060200260200182016040528015613ebb578160200160208202803683370190505b50925060005b6010548110156140855773ffffffffffffffffffffffffffffffffffffffff871660009081526018602090815260408083208484529091529020548451859083908110613f1057613f1061512e565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff881660009081526018825260408082208483529092529081208190558451859083908110613f6457613f6461512e565b6020026020010151111561407d57613fd360108281548110613f8857613f8861512e565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1687868481518110613fc657613fc661512e565b602002602001015161408f565b8673ffffffffffffffffffffffffffffffffffffffff167f1d2f2ca53af5d2f333bd32fdd45f9c52ad8ebe31414f7792912077fcb3876dff85838151811061401d5761401d61512e565b6020026020010151601084815481106140385761403861512e565b600091825260209182902001546040805193845273ffffffffffffffffffffffffffffffffffffffff918216928401929092528a169082015260600160405180910390a25b600101613ec1565b5050509392505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691614126919061526a565b6000604051808303816000865af19150503d8060008114614163576040519150601f19603f3d011682016040523d82523d6000602084013e614168565b606091505b50915091508180156141925750805115806141925750808060200190518101906141929190615286565b6141f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610bb4565b5050505050565b6142346040518060a0016040528060008019168152602001600081526020016000815260200160008152602001600081525090565b600082156143515760005b73ffffffffffffffffffffffffffffffffffffffff851660009081526025602052604090205481101561434f5773ffffffffffffffffffffffffffffffffffffffff851660009081526025602052604090208054829081106142a3576142a361512e565b90600052602060002090600502016000015484036143475773ffffffffffffffffffffffffffffffffffffffff851660009081526025602052604090208054829081106142f2576142f261512e565b90600052602060002090600502016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050925080915061434f565b60010161423f565b505b82158015906143605750815183145b6143c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5374616b65206e6f7420666f756e6400000000000000000000000000000000006044820152606401610bb4565b9250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161446c919061526a565b6000604051808303816000865af19150503d80600081146144a9576040519150601f19603f3d011682016040523d82523d6000602084013e6144ae565b606091505b50915091508180156144d85750805115806144d85750808060200190518101906144d89190615286565b614563576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610bb4565b505050505050565b600061457684612658565b9050811561462a5782601c600082825461459091906151f1565b909155505073ffffffffffffffffffffffffffffffffffffffff84166000908152601e6020526040812080548592906145ca9084906151f1565b909155505073ffffffffffffffffffffffffffffffffffffffff8116156146255773ffffffffffffffffffffffffffffffffffffffff811660009081526020805260408120805485929061461f9084906151f1565b90915550505b6146d1565b82601c600082825461463c919061518c565b909155505073ffffffffffffffffffffffffffffffffffffffff84166000908152601e60205260408120805485929061467690849061518c565b909155505073ffffffffffffffffffffffffffffffffffffffff8116156146d15773ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040812080548592906146cb90849061518c565b90915550505b61156684600060015b602254640100000000900460ff166146fa5781156146fa576146fa613708565b80156147305761470983611107565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c60205260409020555b73ffffffffffffffffffffffffffffffffffffffff831615611f4557600080600061475a86611f4a565b6022549295509093509150640100000000900460ff1661477d5761477d86614bd7565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600c602052604090208290558281106148015760006147b8848361518c565b905080601d546147c891906151f1565b601d556147d581856151f1565b73ffffffffffffffffffffffffffffffffffffffff88166000908152601f602052604090205550614563565b600061480d828561518c565b905080601d5461481d919061518c565b601d5561482a818561518c565b73ffffffffffffffffffffffffffffffffffffffff88166000908152601f602052604090205550505050505050565b614861614b6e565b60005b601254811015614948576000601282815481106148835761488361512e565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050801561493f576040517f092193ab00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82169063092193ab9060240160408051808303816000875af1158015614918573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061493c91906152a3565b50505b50600101614864565b50600062093a806004544261495d919061518c565b61496791906151b6565b905060005b601054811015614b4057601081815481106149895761498961512e565b6000918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015614a00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a249190615204565b614a2f8360016151f1565b62093a80614a3c84613265565b614a46919061519f565b614a50919061519f565b111560108281548110614a6557614a6561512e565b60009182526020918290200154604080517f4e6f7420656e6f7567682072657761726420746f6b656e7320617661696c6162938101939093527f6c653a20000000000000000000000000000000000000000000000000000000009083015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604482015260580160405160208183030381529060405290614b37576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb49190614f3e565b5060010161496c565b5062093a80614b508260016151f1565b614b5a919061519f565b600454614b6791906151f1565b6004556132625b6000614b7861182c565b905060005b601654811015614bc857818181518110614b9957614b9961512e565b602002602001015160168281548110614bb457614bb461512e565b600091825260209091200155600101614b7d565b50614bd1613d48565b60055550565b73ffffffffffffffffffffffffffffffffffffffff811615613262576000614bfe826109d6565b905060005b8151811015614c6257818181518110614c1e57614c1e61512e565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff851660009081526018835260408082208583529093529190912055600101614c03565b5060005b8151811015611f455760168181548110614c8257614c8261512e565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff86168352601782526040808420858552909252912055600101614c66565b803573ffffffffffffffffffffffffffffffffffffffff811681146126b657600080fd5b600060208284031215614cf957600080fd5b61397d82614cc3565b6020808252825182820181905260009190848201906040850190845b81811015614d3a57835183529284019291840191600101614d1e565b50909695505050505050565b801515811461326257600080fd5b600080600060608486031215614d6957600080fd5b83359250614d7960208501614cc3565b91506040840135614d8981614d46565b809150509250925092565b600060208284031215614da657600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015614d3a57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614dc9565b60008060408385031215614e0e57600080fd5b50508035926020909101359150565b602080825282518282018190526000919060409081850190868401855b82811015614e7e5781518051855286810151878601528581015186860152606080820151908601526080908101519085015260a09093019290850190600101614e3a565b5091979650505050505050565b60008060408385031215614e9e57600080fd5b614ea783614cc3565b9150614eb560208401614cc3565b90509250929050565b60008060008060808587031215614ed457600080fd5b8435614edf81614d46565b93506020850135614eef81614d46565b92506040850135614eff81614d46565b91506060850135614f0f81614d46565b939692955090935050565b60005b83811015614f35578181015183820152602001614f1d565b50506000910152565b6020815260008251806020840152614f5d816040850160208701614f1a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008060408385031215614fa257600080fd5b614fab83614cc3565b946020939093013593505050565b60008060408385031215614fcc57600080fd5b614fd583614cc3565b91506020830135614fe581614d46565b809150509250929050565b6000806000806080858703121561500657600080fd5b61500f85614cc3565b93506020850135925061502460408601614cc3565b915061503260608601614cc3565b905092959194509250565b60006020828403121561504f57600080fd5b813561397d81614d46565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060c0828403121561509b57600080fd5b82601f8301126150aa57600080fd5b60405160c0810181811067ffffffffffffffff821117156150f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528060c084018581111561510957600080fd5b845b8181101561512357803583526020928301920161510b565b509195945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610c7257610c7261515d565b8082028115828204841417610c7257610c7261515d565b6000826151ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b80820180821115610c7257610c7261515d565b60006020828403121561521657600080fd5b5051919050565b600181811c9082168061523157607f821691505b602082108103610b45577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000825161527c818460208701614f1a565b9190910192915050565b60006020828403121561529857600080fd5b815161397d81614d46565b600080604083850312156152b657600080fd5b50508051602090910151909290915056fea2646970667358221220136292d73fa0d5c1542e8129b18b22e0bee7d83eb30bc7f086ae0148341aa9ab64736f6c63430008170033

Verified Source Code Partial Match

Compiler: v0.8.23+commit.f704f362 EVM: paris Optimization: Yes (100000 runs)
FraxUnifiedFarm_ERC20_Other.sol 2559 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

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


// File contracts/Common/Context.sol

// Original license: SPDX_License_Identifier: MIT

/*
 * @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

// Original license: SPDX_License_Identifier: MIT

/**
 * @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

// Original license: SPDX_License_Identifier: MIT


/**
 * @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/Misc_AMOs/morpho/IMetaMorpho.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later


interface IMetaMorpho {

    struct MarketParams {
        address loanToken;
        address collateralToken;
        address oracle;
        address irm;
        uint256 lltv;
    }

    struct MarketAllocation {
        /// @notice The market to allocate.
        MarketParams marketParams;
        /// @notice The amount of assets to allocate.
        uint256 assets;
    }

    function DECIMALS_OFFSET (  ) external view returns ( uint8 );
    function DOMAIN_SEPARATOR (  ) external view returns ( bytes32 );
    function MORPHO (  ) external view returns ( address );
    function acceptCap ( MarketParams memory marketParams ) external;
    function acceptGuardian (  ) external;
    function acceptOwnership (  ) external;
    function acceptTimelock (  ) external;
    function allowance ( address owner, address spender ) external view returns ( uint256 );
    function approve ( address spender, uint256 value ) external returns ( bool );
    function asset (  ) external view returns ( address );
    function balanceOf ( address account ) external view returns ( uint256 );
    function config ( bytes32 ) external view returns ( uint184 cap, bool enabled, uint64 removableAt );
    function convertToAssets ( uint256 shares ) external view returns ( uint256 );
    function convertToShares ( uint256 assets ) external view returns ( uint256 );
    function curator (  ) external view returns ( address );
    function decimals (  ) external view returns ( uint8 );
    function deposit ( uint256 assets, address receiver ) external returns ( uint256 shares );
    function eip712Domain (  ) external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions );
    function fee (  ) external view returns ( uint96 );
    function feeRecipient (  ) external view returns ( address );
    function guardian (  ) external view returns ( address );
    function isAllocator ( address ) external view returns ( bool );
    function lastTotalAssets (  ) external view returns ( uint256 );
    function maxDeposit ( address ) external view returns ( uint256 );
    function maxMint ( address ) external view returns ( uint256 );
    function maxRedeem ( address owner ) external view returns ( uint256 );
    function maxWithdraw ( address owner ) external view returns ( uint256 assets );
    function mint ( uint256 shares, address receiver ) external returns ( uint256 assets );
    function multicall ( bytes[] memory data ) external returns ( bytes[] memory results );
    function name (  ) external view returns ( string memory );
    function nonces ( address owner ) external view returns ( uint256 );
    function owner (  ) external view returns ( address );
    function pendingCap ( bytes32 ) external view returns ( uint192 value, uint64 validAt );
    function pendingGuardian (  ) external view returns ( address value, uint64 validAt );
    function pendingOwner (  ) external view returns ( address );
    function pendingTimelock (  ) external view returns ( uint192 value, uint64 validAt );
    function permit ( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external;
    function previewDeposit ( uint256 assets ) external view returns ( uint256 );
    function previewMint ( uint256 shares ) external view returns ( uint256 );
    function previewRedeem ( uint256 shares ) external view returns ( uint256 );
    function previewWithdraw ( uint256 assets ) external view returns ( uint256 );
    function reallocate ( MarketAllocation[] memory allocations ) external;
    function redeem ( uint256 shares, address receiver, address owner ) external returns ( uint256 assets );
    function renounceOwnership (  ) external;
    function revokePendingCap ( bytes32 id ) external;
    function revokePendingGuardian (  ) external;
    function revokePendingMarketRemoval ( bytes32 id ) external;
    function revokePendingTimelock (  ) external;
    function setCurator ( address newCurator ) external;
    function setFee ( uint256 newFee ) external;
    function setFeeRecipient ( address newFeeRecipient ) external;
    function setIsAllocator ( address newAllocator, bool newIsAllocator ) external;
    function setSkimRecipient ( address newSkimRecipient ) external;
    function setSupplyQueue ( bytes32[] memory newSupplyQueue ) external;
    function skim ( address token ) external;
    function skimRecipient (  ) external view returns ( address );
    function submitCap ( MarketParams memory marketParams, uint256 newSupplyCap ) external;
    function submitGuardian ( address newGuardian ) external;
    function submitMarketRemoval ( MarketParams memory marketParams ) external;
    function submitTimelock ( uint256 newTimelock ) external;
    function supplyQueue ( uint256 ) external view returns ( bytes32 );
    function supplyQueueLength (  ) external view returns ( uint256 );
    function symbol (  ) external view returns ( string memory );
    function timelock (  ) external view returns ( uint256 );
    function totalAssets (  ) external view returns ( uint256 assets );
    function totalSupply (  ) external view returns ( uint256 );
    function transfer ( address to, uint256 value ) external returns ( bool );
    function transferFrom ( address from, address to, uint256 value ) external returns ( bool );
    function transferOwnership ( address newOwner ) external;
    function updateWithdrawQueue ( uint256[] memory indexes ) external;
    function withdraw ( uint256 assets, address receiver, address owner ) external returns ( uint256 shares );
    function withdrawQueue ( uint256 ) external view returns ( bytes32 );
    function withdrawQueueLength (  ) external view returns ( uint256 );
}


// File contracts/Curve/IFraxGaugeController.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

// 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

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

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/Curve/IveFXS.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

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/Math/Math.sol

// Original license: SPDX_License_Identifier: MIT

/**
 * @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/Misc_AMOs/convex/IConvexBaseRewardPool.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

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/Owned.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

// 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/Uniswap/TransferHelper.sol

// Original license: SPDX_License_Identifier: MIT

// 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

// Original license: SPDX_License_Identifier: MIT

/**
 * @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/FraxUnifiedFarmTemplate.sol

// Original license: SPDX_License_Identifier: GPL-2.0-or-later

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ====================== 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
// Balancer
// ====================
// import "../Misc_AMOs/balancer/IAuraDeposit.sol";
// import "../Misc_AMOs/balancer/IAuraDepositVault.sol";

// BUNNI
// ====================
// import "../Misc_AMOs/bunni/IBunniGauge.sol";
// import "../Misc_AMOs/bunni/IBunniLens.sol";
// import "../Misc_AMOs/bunni/IBunniMinter.sol";

// CONVEX
// ====================

contract FraxUnifiedFarmTemplate is Owned, ReentrancyGuard {


    // -------------------- VARIES --------------------

    // Balancer
    // IAuraDeposit public stakingToken;
    // IAuraDepositVault public aura_deposit_vault = IAuraDepositVault(0xE557658e3D13d074961265756dC2eFB6c903A763);

    // Bunni
    // IBunniGauge public stakingToken;
    // IBunniLens public lens = IBunniLens(0xb73F303472C4fD4FF3B9f59ce0F9b13E47fbfD19);
    // IBunniMinter public minter = IBunniMinter(0xF087521Ffca0Fa8A43F5C445773aB37C5f574DA0);

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

    // Instances
    IveFXS private constant veFXS = IveFXS(0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0);
    
    // Frax related
    address internal constant frax_address = 0x853d955aCEf822Db058eb8505911ED77F175b99e;
    /// @notice fraxPerLPToken is a public view function, although doesn't show the stored value
    uint256 public fraxPerLPStored;

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

    // Time tracking
    /// @notice Ending timestamp for the current period
    uint256 public periodFinish;
    /// @notice Timestamp of the last update - when this period started
    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 * 1095 * 86400; // 3 years
    // uint256 public lock_time_for_max_multiplier = 2 * 86400; // 2 days
    uint256 public lock_time_min = 1; // 1 seconds. If 0, calcCurrLockMultiplier could div by 0

    // 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
    /// @notice token addr -> manager addr
    mapping(address => address) public rewardManagers; 
    address[] internal rewardTokens;
    address[] internal gaugeControllers;
    address[] internal rewardDistributors;
    uint256[] internal rewardRatesManual;
    mapping(address => bool) internal isRewardToken;
    /// @notice token addr -> token index
    mapping(address => uint256) public rewardTokenAddrToIdx;
    
    // 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;
    /// @notice Keeps track of LP balances proxy-wide. Needed to make sure the proxy boost is kept in line
    mapping(address => uint256) public proxy_lp_balances; 


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

    // 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

    // For emergencies if a token is overemitted or something else. Only callable once.
    // Bypasses certain logic, which will cause reward calculations to be off
    // But the goal is for the users to recover LP, and they couldn't claim the erroneous rewards anyways.
    // Reward reimbursement claims would be handled with pre-issue earned() snapshots and a claim contract, or similar.
    bool public withdrawalOnlyShutdown; 

    // Version
    string public version = "1.0.6";

    /* ========== 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, false);
        _;
    }

    /* ========== 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;

            // Add to the mapping
            isRewardToken[_rewardTokens[i]] = true;

            // 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;

        // Sync the first period finish here with the gauge's 
        // periodFinish = IFraxGaugeController(gaugeControllers[0]).time_total();
        periodFinish = IFraxGaugeController(0x3669C421b77340B2979d1A00a792CC2ee0FcE737).time_total();
        
    }

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

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

    /// @notice Checks if the caller is a manager for the reward token
    /// @param caller_addr The address of the caller
    /// @param reward_token_addr The address of the reward token
    /// @return bool True if the caller is a manager for the reward token
    function isTokenManagerFor(address caller_addr, address reward_token_addr) public view returns (bool){
        if (!isRewardToken[reward_token_addr]) return false;
        else if (caller_addr == address(0) || reward_token_addr == address(0)) return false;
        else if (caller_addr == owner) return true; // Contract owner
        else if (rewardManagers[reward_token_addr] == caller_addr) return true; // Reward manager
        return false; 
    }

    /// @notice Gets all the reward tokens this contract handles
    /// @return rewardTokens_ The reward tokens array
    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);
    }

    /// @notice The amount of reward tokens being paid out per second this period
    /// @param token_idx The index of the reward token
    /// @return rwd_rate The reward rate
    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;
        }
    }

    /// @notice The amount of reward tokens an account has earned / accrued
    /// @dev In the edge-case of one of the account's stake expiring since the last claim, this will
    /// @param account The account to check
    /// @return new_earned Array of reward token amounts earned by the account
    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];
            }
        }
    }

    /// @notice The total reward tokens emitted in the given period
    /// @return rewards_per_duration_arr Array of reward token amounts emitted in the current 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 ------

    /// @notice The farm's total locked liquidity / LP tokens
    /// @return The total locked liquidity
    function totalLiquidityLocked() external view returns (uint256) {
        return _total_liquidity_locked;
    }

    /// @notice A user's locked liquidity / LP tokens
    /// @param account The address of the account
    /// @return The locked liquidity
    function lockedLiquidityOf(address account) external view returns (uint256) {
        return _locked_liquidity[account];
    }

    /// @notice The farm's total combined weight of all users
    /// @return The total combined weight
    function totalCombinedWeight() external view returns (uint256) {
        return _total_combined_weight;
    }

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

    /// @notice Calculates the combined weight for an account
    /// @notice Must be overriden by the child contract
    /// @dev account The address of the 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 ------

    /// @notice Reads the lock boost multiplier for a given duration
    /// @param secs The duration of the lock in seconds
    /// @return The multiplier amount
    function lockMultiplier(uint256 secs) public view returns (uint256) {
        return Math.min(
            lock_max_multiplier,
            (secs * lock_max_multiplier) / lock_time_for_max_multiplier
        ) ;
    }

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

    /// @notice The amount of FRAX denominated value being boosted that an address has staked
    /// @param account The address to check
    /// @return The amount of FRAX value boosted
    function userStakedFrax(address account) public view returns (uint256) {
        return (fraxPerLPStored * _locked_liquidity[account]) / MULTIPLIER_PRECISION;
    }

    /// @notice The amount of FRAX denominated value being boosted that a proxy address has staked
    /// @param proxy_address The address to check
    /// @return The amount of FRAX value boosted
    function proxyStakedFrax(address proxy_address) public view returns (uint256) {
        return (fraxPerLPStored * proxy_lp_balances[proxy_address]) / MULTIPLIER_PRECISION;
    }

    /// @notice The maximum LP that can get max veFXS boosted for a given address at its current veFXS balance
    /// @param account The address to check
    /// @return The maximum 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);
    }

    /// @notice Must be overriden to return the current FRAX per LP token
    /// @return The current number of FRAX per LP token
    function fraxPerLPToken() public virtual view returns (uint256) {
        revert("Need fPLPT logic");
    }

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

    /// @notice The minimum veFXS required to get max boost for a given address
    /// @param account The address to check
    /// @return The minimum veFXS required to get max boost
    function minVeFXSForMaxBoost(address account) public view returns (uint256) {
        return (userStakedFrax(account) * vefxs_per_frax_for_max_boost) / MULTIPLIER_PRECISION;
    }

    /// @notice The minimum veFXS required to get max boost for a given proxy
    /// @param proxy_address The proxy address
    /// @re...

// [truncated — 107695 bytes total]

Read Contract

calcCurCombinedWeight 0x8bad86a7 → uint256, uint256, uint256
calcCurrLockMultiplier 0x774d4ae7 → uint256
combinedWeightOf 0x36f89af2 → uint256
earned 0x008cc262 → uint256[]
farm_type 0x41edbdf0 → string
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
version 0x54fd4d50 → string
withdrawalOnlyShutdown 0x89b5f00b → bool

Write Contract 20 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 0x2df079f1
bool _stakingPaused
bool _withdrawalsPaused
bool _rewardsCollectionPaused
bool _withdrawalOnlyShutdown
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
withdrawLocked 0x0238b936
bytes32 kek_id
address destination_address
bool claim_rewards_deprecated
returns: uint256

Recent Transactions

No transactions found for this address