Address Contract Partially Verified
Address
0x109e4749F7c429DcC8ab84fE9fD587e2acf912aF
Balance
0 ETH
Nonce
1
Code Size
23503 bytes
Creator
0x812DD698...915A at tx 0x3d634c60...4ea14b
Indexed Transactions
0
Contract Bytecode
23503 bytes
0x608060405234801561001057600080fd5b50600436106103275760003560e01c806366258068116101b8578063a7c5b41311610104578063d8697598116100a2578063e5261b1d1161007c578063e5261b1d14610872578063eec47d6014610885578063f96d7b801461088f578063fb3ee5711461089857600080fd5b8063d86975981461082e578063e2481dbd14610855578063e449f3411461085f57600080fd5b8063be864d68116100de578063be864d68146107eb578063c72460ee146107fe578063d449300d14610808578063d4570c1c1461081b57600080fd5b8063a7c5b41314610743578063ac9650d8146107b8578063bc88d7e4146107d857600080fd5b80638456cb591161017157806391d148541161014b57806391d14854146106ea578063946d9204146106fd578063a488b71e14610710578063a694fc3a1461073057600080fd5b80638456cb59146106bc5780638b0bd55b146106c457806390672ad8146106d757600080fd5b806366258068146105cd57806367b4cdb8146105e25780636fa3fbda1461060c57806372f702f31461061f57806379502c5514610631578063817b1cd2146106b357600080fd5b80633d173136116102775780634b63885a11610230578063509b6c3f1161020a578063509b6c3f146105605780635c975abb1461058b5780635f3e849f1461059357806363727fc2146105a657600080fd5b80634b63885a146105275780634e6e056f1461053a5780634f814cc51461054d57600080fd5b80633d173136146104b35780633e677297146104bc5780633ee16bf7146104cf5780633f4ba83a146104e257806342623360146104ea57806349aeb46f1461051457600080fd5b8063248a9ca3116102e457806330139280116102be578063301392801461040f578063350b5af0146104365780633a22502c146104495780633cfe9fd11461049a57600080fd5b8063248a9ca3146103c25780632772ce9d146103d55780632a7a0c68146103e857600080fd5b806301ffc9a71461032c5780631b0875a6146103545780631c03e6cc1461036a5780631d8b4c491461037f5780631e26571f14610392578063227102a61461039b575b600080fd5b61033f61033a3660046150f2565b6108ab565b60405190151581526020015b60405180910390f35b61035c6108d6565b60405190815260200161034b565b61037d610378366004615141565b6108e8565b005b61037d61038d3660046151a9565b610a72565b6101945461035c565b61035c7ff28c151dcc22c5bfb460fbc387993d6c0d1c1245ca20aca5f3cbd33f33041eb181565b61035c6103d0366004615214565b610c94565b61033f6103e3366004615214565b610d86565b61035c7f000000000000000000000000000000000000000000000000ffffffffffffffff81565b61035c7f520767f2ee41b25d23e3166443601203d348640efb766878c95999973ecd38e181565b61037d61044436600461522d565b610e49565b61045c610457366004615266565b610fb2565b6040805182516001600160c01b03191681526020808401516001600160401b031690820152918101516001600160801b03169082015260600161034b565b6101d254600160c01b90046001600160401b031661035c565b6101ca5461035c565b61035c6104ca366004615141565b610fef565b61037d6104dd366004615214565b611048565b61037d61121a565b61035c6104f8366004615141565b6001600160a01b031660009081526101cf602052604090205490565b61037d6105223660046152d0565b6113a9565b61033f610535366004615141565b6114d6565b61035c610548366004615141565b6115e0565b61037d61055b366004615324565b61166d565b61057361056e366004615214565b611a44565b6040516001600160a01b03909116815260200161034b565b61033f611a52565b61037d6105a1366004615266565b611ae6565b6105737f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf81565b61035c600080516020615ba383398151915281565b61035c6105f0366004615141565b6001600160a01b031660009081526101ce602052604090205490565b61037d61061a3660046151a9565b611c57565b6101cb546001600160a01b0316610573565b6106a660408051608081018252600080825260208201819052918101829052606081019190915250604080516080810182526101cd546001600160401b038082168352600160401b820416602083015261ffff600160801b8204811693830193909352600160901b9004909116606082015290565b60405161034b9190615363565b6101c95461035c565b61037d611dea565b61037d6106d23660046153a9565b611f76565b61037d6106e53660046151a9565b61207c565b61033f6106f83660046153ea565b61228c565b61037d61070b366004615425565b612383565b61072361071e3660046153a9565b61263e565b60405161034b9190615539565b61037d61073e366004615214565b612814565b610756610751366004615214565b612922565b60405161034b9190815165ffffffffffff9081168252602080840151909116908201526040808301516001600160a01b0316908201526060808301516001600160801b0390811691830191909152608092830151169181019190915260a00190565b6107cb6107c63660046153a9565b6129ee565b60405161034b919061559c565b6107566107e6366004615214565b612ae2565b61035c6107f9366004615214565b612b9b565b61035c6101c85481565b61035c61081636600461522d565b612c92565b61035c61082936600461522d565b612cc9565b61035c7f0b8459b722d944f0580da74c767d2dcae280ce16527c19c825b302a24e208dfd81565b61035c6101c75481565b61037d61086d3660046153a9565b612d44565b61045c6108803660046155fe565b612e67565b61035c6101935481565b6101d75461035c565b61037d6108a6366004615141565b612e9f565b60006001600160e01b0319821663941be9cf60e01b14806108d057506108d082613184565b92915050565b60006108e36101d56131a9565b905090565b33610901600080516020615ba38339815191528261228c565b8061091457506109146101c7548261228c565b6109395760405162461bcd60e51b81526004016109309061562a565b60405180910390fd5b60026001540361095b5760405162461bcd60e51b815260040161093090615657565b600260015561096c6101d5836131b3565b6109b85760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a205245574152445f544f4b454e5f455849535453000000006044820152606401610930565b60406109c56101d56131a9565b1115610a045760405162461bcd60e51b815260206004820152600e60248201526d14dd185ada5b99ce88131253525560921b6044820152606401610930565b6001600160a01b0382163b610a2b5760405162461bcd60e51b81526004016109309061568e565b610a34826131c8565b60405133906001600160a01b038416907f3344e0a0f48738979c56a1b9f2cd3425597f76766d53e83439cab3fc30b067c790600090a3505060018055565b600260015403610a945760405162461bcd60e51b815260040161093090615657565b600260015533610aa3816114d6565b610abf5760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf6020526040902085610b1c5760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a20494e56414c49445f4153534554535f4c454e47544800006044820152606401610930565b838614610b6b5760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a20494e56414c49445f494e5055545f4c454e4754485300006044820152606401610930565b60005b86811015610c86576000868683818110610b8a57610b8a6156f5565b9050602002810190610b9c919061570b565b905090506000898984818110610bb457610bb46156f5565b9050602002016020810190610bc99190615141565b90506000808311610bec5760405162461bcd60e51b815260040161093090615754565b60005b83811015610c5257610c3e8a8a87818110610c0c57610c0c6156f5565b9050602002810190610c1e919061570b565b83818110610c2e57610c2e6156f5565b90506020020135848960016131d8565b90910190610c4b816157a1565b9050610bef565b506001600160a01b03909116600090815260018501602052604090208054909101905550610c7f816157a1565b9050610b6e565b505060018055505050505050565b60007f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b03166371907f176040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d1891906157ba565b6001600160a01b031663248a9ca3836040518263ffffffff1660e01b8152600401610d4591815260200190565b602060405180830381865afa158015610d62573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d091906157d7565b6000610d96610193546106f83390565b80610dc65750610dc67ff28c151dcc22c5bfb460fbc387993d6c0d1c1245ca20aca5f3cbd33f33041eb13361228c565b610e385760405162461bcd60e51b815260206004820152603860248201527f477561726461626c653a20796f7520646f206e6f74206861766520746865207260448201527f6571756972656420726f6c657320746f20646f207468697300000000000000006064820152608401610930565b610e4182613239565b506001919050565b33610e62600080516020615ba38339815191528261228c565b80610e755750610e756101c7548261228c565b610e915760405162461bcd60e51b81526004016109309061562a565b600260015403610eb35760405162461bcd60e51b815260040161093090615657565b60026001556101c954610ec59061327e565b6001600160a01b03831660009081526101d0602052604090205480610f2c5760405162461bcd60e51b815260206004820152601f60248201527f5374616b696e673a20494e53554646494349454e545f434c41494d41424c45006044820152606401610930565b6001600160a01b03841660008181526101d06020526040812055610f519084836134c8565b336001600160a01b0316836001600160a01b0316856001600160a01b03167feb4184e6deaf4d9d0984cd22dcacac383ed3c67600403e9d48a877f32843260084604051610fa091815260200190565b60405180910390a45050600180555050565b6040805160608101825260008082526020820181905291810191909152610fd88361352b565b610fe58284866001613553565b90505b9392505050565b6101c9546000908181611003576000611018565b6110186101c95461101386613656565b613768565b6001600160a01b03851660009081526101ce60205260409020549091506110409082906157f0565b949350505050565b60026001540361106a5760405162461bcd60e51b815260040161093090615657565b600260015533611079816114d6565b6110955760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf602090815260409182902080546101c95484516080810186526101cd546001600160401b038082168352600160401b8204169582019590955261ffff600160801b8604811696820196909652600160901b9094049094166060840152909290918683101561111e5760405162461bcd60e51b815260040161093090615803565b6000871161113e5760405162461bcd60e51b81526004016109309061583a565b6111478261327e565b61115b84846111568a82615871565b61378a565b8682036101c955604081015160009061117990899061ffff16613867565b6101cb546001600160a01b031660008181526101d06020526040812080549394509192849291906111ab9084906157f0565b909155506111d09050876111bf848c615871565b6001600160a01b03841691906134c8565b604080518a81526020810184905233917f0caa32aefed7436cb5c128d4c61517c3b4fd8ca09590ecadc0545441a7954864910160405180910390a250506001805550505050505050565b6000339050806001600160a01b03167f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b031663ee97f7f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611287573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ab91906157ba565b6001600160a01b031614806113525750806001600160a01b03167f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b0316632d37ead56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611323573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134791906157ba565b6001600160a01b0316145b61139e5760405162461bcd60e51b815260206004820152601f60248201527f534f4d413a204d4153544552206f7220535542204d4153544552206f6e6c79006044820152606401610930565b6113a6613876565b50565b336113c2600080516020615ba38339815191528261228c565b806113d557506113d56101c7548261228c565b6113f15760405162461bcd60e51b81526004016109309061562a565b604080516080810182526001600160401b0387811682528616602082015261ffff8581168284015284166060820152905133907f9462329a02c37f74ff4c4fcc54801197381851fde6531472fd444620fbf0fd9d90611455906101cd908590615884565b60405180910390a280516101cd8054602084015160408501516060909501516001600160401b039485166001600160801b031990931692909217600160401b94909116939093029290921763ffffffff60801b1916600160801b61ffff9485160261ffff60901b191617600160901b93909216929092021790555050505050565b60007f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b0316637ceab3b16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611536573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155a91906157ba565b6001600160a01b031663253bd7b7836115736101945490565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156115bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d091906158f7565b6000806115ef6101d5846138c8565b9050808061160b57506101cb546001600160a01b038481169116145b6116275760405162461bcd60e51b81526004016109309061568e565b6101c9541580156116355750805b611640576000611649565b61164983613656565b6001600160a01b03841660009081526101d06020526040902054610fe891906157f0565b33611686600080516020615ba38339815191528261228c565b8061169957506116996101c7548261228c565b6116b55760405162461bcd60e51b81526004016109309061562a565b6002600154036116d75760405162461bcd60e51b815260040161093090615657565b60026001556001600160801b038211156117335760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e673a204d41585f5245574152445f414d4f554e540000000000006044820152606401610930565b4285116117825760405162461bcd60e51b815260206004820152601b60248201527f5374616b696e673a20494e56414c49445f53544152545f4441544500000000006044820152606401610930565b8385106117d15760405162461bcd60e51b815260206004820152601b60248201527f5374616b696e673a20494e56414c49445f444154455f4f5244455200000000006044820152606401610930565b65ffffffffffff8411156118275760405162461bcd60e51b815260206004820152601960248201527f5374616b696e673a20494e56414c49445f454e445f44415445000000000000006044820152606401610930565b6118308361352b565b61183c833330856138ea565b91506000821161185e5760405162461bcd60e51b81526004016109309061583a565b6101d754604081106118a35760405162461bcd60e51b815260206004820152600e60248201526d14dd185ada5b99ce88131253525560921b6044820152606401610930565b60006040518060a001604052808865ffffffffffff1681526020018765ffffffffffff168152602001866001600160a01b031681526020016118e4866139f1565b6001600160801b039081168252600060209283018190526101d780546001810182559152835160029091027f069f7b5e1776a2d4bf57d8efb3ff6de682dcba14407464b37d674a8bd8984923810180549486015160408701516001600160a01b0316600160601b026bffffffffffffffffffffffff65ffffffffffff928316600160301b026bffffffffffffffffffffffff1990981692909516919091179590951792909216939093179055606083015160808401518216600160801b029116177f069f7b5e1776a2d4bf57d8efb3ff6de682dcba14407464b37d674a8bd89849249091015590506119d96101d28389613a5e565b33606080830151604080516001600160801b039092168252602082018b905281018990526001600160a01b03928316928816917f4b43c543dc2da7e74df4d701157b31ed22b9fb6a39f9c5329fff7f250b65a872910160405180910390a35050600180555050505050565b60006108d06101d583614055565b60007f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad691906158f7565b806108e357505060655460ff1690565b7f0b8459b722d944f0580da74c767d2dcae280ce16527c19c825b302a24e208dfd611b11813361228c565b611b8d5760405162461bcd60e51b815260206004820152604160248201527f536f6d61416363657373436f6e74726f6c3a2063616c6c657220646f6573206e60448201527f6f7420686176652074686520617070726f70726961746520617574686f7269746064820152607960f81b608482015260a401610930565b611b9961015f856138c8565b15611be65760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e5265636f766572793a20494e56414c49445f544f4b454e000000006044820152606401610930565b611bfa6001600160a01b03851684846134c8565b336001600160a01b0316836001600160a01b0316856001600160a01b03167fca574176b1d34032f40f7fb0c519eae468b4535ebf7b27f986a7b6e2fa53d53885604051611c4991815260200190565b60405180910390a450505050565b600260015403611c795760405162461bcd60e51b815260040161093090615657565b600260015533611c88816114d6565b611ca45760405162461bcd60e51b8152600401610930906156be565b838214611cf35760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20494e434f4e53495354454e545f4c454e475448530000006044820152606401610930565b3360008181526101cf602090815260409182902082516080810184526101cd546001600160401b038082168352600160401b8204169382019390935261ffff600160801b8404811694820194909452600160901b909204909216606082015281546101c954611d619061327e565b611d6c83828361378a565b60005b88811015611dda57611dca84846060015161ffff16878d8d86818110611d9757611d976156f5565b9050602002016020810190611dac9190615141565b8c8c87818110611dbe57611dbe6156f5565b90506020020135614061565b611dd3816157a1565b9050611d6f565b5050600180555050505050505050565b6000339050806001600160a01b03167f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b031663ee97f7f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7b91906157ba565b6001600160a01b03161480611f225750806001600160a01b03167f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b0316632d37ead56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f1791906157ba565b6001600160a01b0316145b611f6e5760405162461bcd60e51b815260206004820152601f60248201527f534f4d413a204d4153544552206f7220535542204d4153544552206f6e6c79006044820152606401610930565b6113a66141fe565b600260015403611f985760405162461bcd60e51b815260040161093090615657565b600260015533611fa7816114d6565b611fc35760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf6020526040902080546101c95485611ff65760405162461bcd60e51b815260040161093090615754565b6101cb546001600160a01b03168260005b88811015612048576120348a8a83818110612024576120246156f5565b90506020020135848960006131d8565b90910190612041816157a1565b9050612007565b506120528361327e565b61205d85858361378a565b9182016101c955506101ca805491909103905550506001805550505050565b60026001540361209e5760405162461bcd60e51b815260040161093090615657565b6002600155336120ad816114d6565b6120c95760405162461bcd60e51b8152600401610930906156be565b6101cd543390600160401b90046001600160401b031683861461212e5760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a20494e56414c49445f494e5055545f4c454e4754485300006044820152606401610930565b60005b86811015610c8657600086868381811061214d5761214d6156f5565b905060200281019061215f919061570b565b905090506000898984818110612177576121776156f5565b905060200201602081019061218c9190615141565b905060008083116121af5760405162461bcd60e51b815260040161093090615754565b60005b83811015612216576122028a8a878181106121cf576121cf6156f5565b90506020028101906121e1919061570b565b838181106121f1576121f16156f5565b90506020020135848989600161423b565b9091019061220f816157a1565b90506121b2565b5061222b6001600160a01b03831687836134c8565b856001600160a01b0316826001600160a01b03167f7e6632ca16a0ac6cf28448500b1a17d96c8b8163ad4c4a9b44ef5386cc02779e8360405161227091815260200190565b60405180910390a350505080612285906157a1565b9050612131565b60007f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b03166371907f176040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231091906157ba565b604051632474521560e21b8152600481018590526001600160a01b03848116602483015291909116906391d1485490604401602060405180830381865afa15801561235f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe891906158f7565b600054610100900460ff16158080156123a35750600054600160ff909116105b806123bd5750303b1580156123bd575060005460ff166001145b6124205760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610930565b6000805460ff191660011790558015612443576000805461ff0019166101001790555b30600080516020615ba3833981519152604051602001612464929190615919565b60408051601f198184030181529082905280516020918201206101c7556124af9130917f520767f2ee41b25d23e3166443601203d348640efb766878c95999973ecd38e19101615919565b60408051808303601f1901815291905280516020909101206101c8556001600160a01b0383163b6125225760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a20494e56414c49445f5354414b494e475f544f4b454e00006044820152606401610930565b6101cb80546001600160a01b0319166001600160a01b03851690811790915561254a906131c8565b60005b82518110156125ca57600083828151811061256a5761256a6156f5565b60200260200101519050612587816001600160a01b03163b151590565b6125a35760405162461bcd60e51b81526004016109309061568e565b6125af6101d5826131b3565b506125b9816131c8565b506125c3816157a1565b905061254d565b506125d3614304565b6125db61433e565b6040805160008152602081019091526125f39061436b565b8015612639576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b60606002600154036126625760405162461bcd60e51b815260040161093090615657565b600260015533612671816114d6565b61268d5760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf602052604090208054856001600160401b038111156126b7576126b761540f565b6040519080825280602002602001820160405280156126e0578160200160208202803683370190505b5094506126ef6101c95461327e565b6126fa82828361378a565b60005b86811015612804576000888883818110612719576127196156f5565b905060200201602081019061272e9190615141565b6001600160a01b03811660009081526001860160205260409020549091506127558261352b565b6000811161279b5760405162461bcd60e51b81526020600482015260136024820152725374616b696e673a204e4f5f5245574152445360681b6044820152606401610930565b846001016000836001600160a01b03166001600160a01b03168152602001908152602001600020600090556127d386838360016143dd565b8884815181106127e5576127e56156f5565b6020026020010181815250505050806127fd906157a1565b90506126fd565b5050600180555091949350505050565b6002600154036128365760405162461bcd60e51b815260040161093090615657565b600260015533612845816114d6565b6128615760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf6020526040902080546101c9546101cb54612890906001600160a01b03168530896138ea565b9550600086116128b25760405162461bcd60e51b81526004016109309061583a565b6128bb8161327e565b6128ca838361115689826157f0565b6128d486826157f0565b6101c9556040518681526001600160a01b038516907f6e47dcdd359b6cd69456f0f97d394bd4540a2e7c4adc1b9da076859df53756c79060200160405180910390a250506001805550505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101829052906129596101d284614530565b5090506101d78160001c81548110612973576129736156f5565b60009182526020918290206040805160a081018252600293909302909101805465ffffffffffff8082168552600160301b82041694840194909452600160601b9093046001600160a01b0316908201526001909101546001600160801b038082166060840152600160801b9091041660808201529392505050565b6060816001600160401b03811115612a0857612a0861540f565b604051908082528060200260200182016040528015612a3b57816020015b6060815260200190600190039081612a265790505b50905060005b82811015612adb57612aab30858584818110612a5f57612a5f6156f5565b9050602002810190612a71919061593b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061463192505050565b828281518110612abd57612abd6156f5565b60200260200101819052508080612ad3906157a1565b915050612a41565b5092915050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526101d78281548110612b2157612b216156f5565b60009182526020918290206040805160a081018252600293909302909101805465ffffffffffff8082168552600160301b82041694840194909452600160601b9093046001600160a01b0316908201526001909101546001600160801b038082166060840152600160801b90910416608082015292915050565b6000600260015403612bbf5760405162461bcd60e51b815260040161093090615657565b600260015533612bce816114d6565b612bea5760405162461bcd60e51b8152600401610930906156be565b3360008181526101cf6020526040902080546101c95486821015612c205760405162461bcd60e51b815260040161093090615803565b60008711612c405760405162461bcd60e51b81526004016109309061583a565b612c498161327e565b612c5883836111568a82615871565b8681036101c9556101ca8054880190556101cb54612c839085906001600160a01b03168960006143dd565b60018055979650505050505050565b6000612c9d8261352b565b6001600160a01b03831660009081526101cf6020526040902054610fe890612cc484610fef565b614725565b6001600160a01b03821660009081526101cf60205260408120612ceb8361352b565b6001600160a01b03831660009081526002820160205260409020548154612d1590612cc486610fef565b6001600160a01b0385166000908152600184016020526040902054612d3a91906157f0565b6110409190615871565b600260015403612d665760405162461bcd60e51b815260040161093090615657565b600260015533612d75816114d6565b612d915760405162461bcd60e51b8152600401610930906156be565b6101cb546101cd5433916001600160a01b0316906001600160401b03166000805b86811015612df457612de0888883818110612dcf57612dcf6156f5565b90506020020135858786600061423b565b90910190612ded816157a1565b9050612db2565b506101ca805482900390556101cb54612e17906001600160a01b031685836134c8565b836001600160a01b03167f81b0ac4b13aab1ab3b86d524dd62924e99a9d694e94e235f627bb41589717ff782604051612e5291815260200190565b60405180910390a25050600180555050505050565b60408051606081018252600080825260208201819052918101919091526101cb54610fe89083906001600160a01b0316856000613553565b33612eca7f520767f2ee41b25d23e3166443601203d348640efb766878c95999973ecd38e18261228c565b80612edd5750612edd6101c8548261228c565b612f295760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a205345495a455f524f4c455f4f4e4c5900000000000000006044820152606401610930565b60007f0000000000000000000000000f3dc00189dbcd1d0c574e48031270cae04c4adf6001600160a01b031663ff0d1a606040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fad91906157ba565b6101c9546001600160a01b03851660009081526101cf602052604090208054929350909180612fee5760405162461bcd60e51b815260040161093090615803565b612ff78361327e565b6130038282600061378a565b8083036101c95560006130176101d56131a9565b90506000816001600160401b038111156130335761303361540f565b60405190808252806020026020018201604052801561305c578160200160208202803683370190505b50905060005b828110156131095760006130786101d583614055565b6001600160a01b03811660009081526001880160209081526040808320546101d09092528220805493945090928392906130b39084906157f0565b92505081905550808484815181106130cd576130cd6156f5565b6020908102919091018101919091526001600160a01b03909216600090815260018801909252506040812055613102816157a1565b9050613062565b506101cb546001600160a01b03166131228188866134c8565b336001600160a01b0316876001600160a01b03168a6001600160a01b03167f70de378a6bcd3fde23ad1114eabf0a3d95dc5e57733b1d1c53d987128b4a76d38786604051613171929190615981565b60405180910390a4505050505050505050565b60006001600160e01b03198216630e46e23b60e31b14806108d057506108d08261473d565b60006108d0825490565b6000610fe8836001600160a01b038416614762565b6131d461015f826131b3565b5050565b60006131e685858585613553565b60409081015160008781526101d160205282812081905591516001600160801b03909116925086917fee243f878b7fc2f54e934ca33783d4395d42bc07612e2bd4b8e0e178639f7a2891a2949350505050565b61019454604080519182526020820183905233917f53f0b6b34c97fd1733ccb4b21aea7549d7ad3a83e6316864417b8cc1a9a9a807910160405180910390a261019455565b60006132936101d2546001600160401b031690565b9050600080806132a965ffffffffffff426159b0565b90505b83156134c1576132be6101d2856147b1565b6101d7805491955091935060009190849081106132dd576132dd6156f5565b60009182526020918290206040805160a081018252600293909302909101805465ffffffffffff808216808652600160301b8304821696860196909652600160601b9091046001600160a01b031692840192909252600101546001600160801b038082166060850152600160801b9091041660808301529092508316101561336557506134c1565b60006133718242614843565b90508160800151613381826139f1565b61338b91906159c4565b6101d78054869081106133a0576133a06156f5565b6000918252602090912060016002909202010180546001600160801b03928316600160801b029216919091179055861561345b5760006133e08883613768565b905080600003613422576040808401516001600160a01b031660009081526101d060205290812080548492906134179084906157f0565b909155506134559050565b6040808401516001600160a01b031660009081526101ce602052908120805483929061344f9084906157f0565b90915550505b5061348e565b6040808301516001600160a01b031660009081526101d060205290812080548392906134889084906157f0565b90915550505b816020015165ffffffffffff168365ffffffffffff16106134b7576134b56101d2876148dc565b505b84955050506132ac565b5050505050565b6040516001600160a01b03831660248201526044810182905261263990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148e8565b6135376101d5826138c8565b6113a65760405162461bcd60e51b81526004016109309061568e565b604080516060810182526000808252602082018190529181019190915260008584868560405160200161358994939291906159e4565b60408051808303601f19018152828252805160209182012060008a81526101d183528390206060850184525460c081901b6001600160c01b0319908116808752600160401b83046001600160401b031694870194909452600160801b9091046001600160801b03169385019390935292945091925082161461364d5760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a20494e56414c49445f5245515545535400000000000000006044820152606401610930565b50949350505050565b600080600061366e6101d2546001600160401b031690565b90505b8015613761576136836101d2826147b1565b6101d78054929450909250600091849081106136a1576136a16156f5565b60009182526020918290206040805160a0810182526002909302909101805465ffffffffffff808216808652600160301b8304909116958501959095526001600160a01b03600160601b9091041691830191909152600101546001600160801b038082166060840152600160801b90910416608082015291504210156137275750613761565b846001600160a01b031681604001516001600160a01b03160361375b5761374e8142614843565b61375890856157f0565b93505b50613671565b5050919050565b6000826137806a084595161401484a00000084615a42565b610fe89190615a59565b818114613795578083555b60006137a26101d56131a9565b905060005b818110156134c15760006137bd6101d583614055565b6001600160a01b03811660009081526101ce602090815260408083205460028b0190925290912054919250906137f38783614725565b6137fd9190615871565b6001600160a01b0383166000908152600189016020526040812080549091906138279084906157f0565b9091555061383790508582614725565b6001600160a01b03909216600090815260028801602052604090209190915550613860816157a1565b90506137a7565b600061ffff6137808385615a42565b61387e6149ba565b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03811660009081526001830160205260408120541515610fe8565b6040516370a0823160e01b81526001600160a01b03838116600483015260009182918716906370a0823190602401602060405180830381865afa158015613935573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061395991906157d7565b90506139706001600160a01b038716868686614a05565b6040516370a0823160e01b81526001600160a01b0385811660048301528291908816906370a0823190602401602060405180830381865afa1580156139b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139dd91906157d7565b6139e79190615871565b9695505050505050565b60006001600160801b03821115613a5a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610930565b5090565b604080516080808201835285546001600160401b038082168452600160401b82048116602080860191909152600160801b83048216858701819052600160c01b909304821660608087019190915260019384018084166000908152948b01835293879020875195860188525460ff811615801587526101008204851693870193909352600160481b8104841697860197909752600160881b909604909116948301949094529192613b1e57613b1c86836001600160401b0316614a43565b505b6040805160c0810182526000918101828152606082018390526080820183905260a08201839052815260208101919091526040805160c0810182526000918101828152606082018390526080820183905260a082018390528152602081019190915284515b6001600160401b03811615613c1b576001600160401b0380821660009081526001808c016020908152604092839020835160c081018552815460ff81161515958201958652610100810487166060830152600160481b810487166080830152600160881b900490951660a0860152928452910154908201819052881015613c0b579250613c1b565b8051604001519092509050613b83565b604051806080016040528087600001516001600160401b03168560000151602001516001600160401b031614613c52578751613c54565b865b6001600160401b0316815260200187602001516001600160401b03168460000151602001516001600160401b031614613c91578760200151613c93565b865b6001600160401b03168152602001866001600160401b0316815260200187606001516001613cc19190615a6d565b6001600160401b03168152508960000160008201518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555060208201518160000160086101000a8154816001600160401b0302191690836001600160401b0316021790555060408201518160000160106101000a8154816001600160401b0302191690836001600160401b0316021790555060608201518160000160186101000a8154816001600160401b0302191690836001600160401b0316021790555090505087896002016000876001600160401b031681526020019081526020016000208190555060405180604001604052806040518060800160405280600115158152602001886001600160401b031681526020018660000151602001516001600160401b031681526020018560000151602001516001600160401b0316815250815260200188815250896001016000876001600160401b0316815260200190815260200160002060008201518160000160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a8154816001600160401b0302191690836001600160401b0316021790555060408201518160000160096101000a8154816001600160401b0302191690836001600160401b0316021790555060608201518160000160116101000a8154816001600160401b0302191690836001600160401b0316021790555050506020820151816001015590505081600001516000015115613f9c5781516001600160401b038681166040928301528351602080820180518416600090815260018f01909252908490208251815492519584015160609094015168ffffffffffffffffff1990931690151568ffffffffffffffff001916176101009585169590950294909417600160481b600160c81b031916600160481b9284169290920267ffffffffffffffff60881b191691909117600160881b91909216021790555b8251511561404a5782516001600160401b038087166060928301528451602080820180518416600090815260018f019092526040918290208351815492519385015194909601518516600160881b0267ffffffffffffffff60881b19948616600160481b0294909416600160481b600160c81b0319939095166101000268ffffffffffffffff00199615159690961668ffffffffffffffffff19909216919091179490941716919091171790555b505050505050505050565b6000610fe88383614d6a565b61406a8261352b565b6001600160a01b0382166000908152600186016020526040902054816140a25760405162461bcd60e51b81526004016109309061583a565b600081116140e85760405162461bcd60e51b81526020600482015260136024820152725374616b696e673a204e4f5f5245574152445360681b6044820152606401610930565b808211156141385760405162461bcd60e51b815260206004820152601f60248201527f5374616b696e673a20494e53554646494349454e545f434c41494d41424c45006044820152606401610930565b60006141448387613867565b6001600160a01b03851660009081526101d060205260408120805492935083929091906141729084906157f0565b909155506141979050856141868386615871565b6001600160a01b03871691906134c8565b6001600160a01b03848116600081815260018a01602090815260409182902087870390558151878152908101859052928816927f4b7f0bdd3e71951c1c12390f2e6777e651743b9ba7acf3a13e9507c2f4dd5e31910160405180910390a350505050505050565b614206614d94565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586138ab3390565b60008061424a87878786613553565b90508381602001516001600160401b0316426142669190615871565b10156142b45760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e673a20494e53554646494349454e545f54494d450000000000006044820152606401610930565b60008781526101d160205260408082208290555188917f1cedb001a5114ea90393cd9f134224e9e1312545ee8a9b9533d780be6a9bf8b791a2604001516001600160801b03169695505050505050565b61430c614ddc565b614314614ddc565b61431c614e03565b614324614ddc565b61432c614ddc565b614334614ddc565b61433c614e84565b565b600054610100900460ff166143655760405162461bcd60e51b815260040161093090615a8d565b60018055565b600054610100900460ff166143925760405162461bcd60e51b815260040161093090615a8d565b60005b81518110156131d4576143cc8282815181106143b3576143b36156f5565b602002602001015161015f6131b390919063ffffffff16565b506143d6816157a1565b9050614395565b60008083116143fe5760405162461bcd60e51b81526004016109309061583a565b6101cc6000815461440e906157a1565b918290555060408051606081019091529091508061443283888887608086016159e4565b604051602081830303815290604052805190602001206001600160c01b031916815260200161446042614eb7565b6001600160401b03168152602001614477856139f1565b6001600160801b0390811690915260008381526101d160209081526040918290208451815492860151958401518516600160801b026001600160401b0396909616600160401b026001600160801b031990931660c09190911c1791909117909216929092179055516001600160a01b03808716919086169083907f1dc4096620302ec2c8b0fbec0db9683e195bddeddb5e9b48a150902b3676391c906145209088908890615ad8565b60405180910390a4949350505050565b6040805160808101825283546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b900490911660608201819052600091829184106145cb5760405162461bcd60e51b815260206004820152601960248201527f536f727465644c6973743a204f55545f4f465f424f554e4453000000000000006044820152606401610930565b80516001600160401b0316915060005b8481101561461657600092835260018601602052604090922054600160481b90046001600160401b03169161460f816157a1565b90506145db565b50506000818152600290940160205260409093205493915050565b60606001600160a01b0383163b6146995760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610930565b600080846001600160a01b0316846040516146b49190615b0a565b600060405180830381855af49150503d80600081146146ef576040519150601f19603f3d011682016040523d82523d6000602084013e6146f4565b606091505b509150915061471c8282604051806060016040528060278152602001615b7c60279139614f1f565b95945050505050565b60006a084595161401484a0000006137808385615a42565b60006001600160e01b03198216638757f10760e01b14806108d057506108d082614f58565b60008181526001830160205260408120546147a9575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108d0565b5060006108d0565b6000818152600183016020526040812054819060ff1661480c5760405162461bcd60e51b815260206004820152601660248201527514dbdc9d1959131a5cdd0e881253959053125117d25160521b6044820152606401610930565b5050600090815260028201602090815260408083205460019094019091529020549091600160481b9091046001600160401b031690565b600080836020015165ffffffffffff168310156148b2578351602085015161486b9190615b26565b65ffffffffffff1684606001516001600160801b0316856000015165ffffffffffff16856148999190615871565b6148a39190615a42565b6148ad9190615a59565b6148c1565b83606001516001600160801b03165b905083608001516001600160801b0316816110409190615871565b6000610fe88383614a43565b600061493d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614f7d9092919063ffffffff16565b805190915015612639578080602001905181019061495b91906158f7565b6126395760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610930565b6149c2611a52565b61433c5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610930565b6040516001600160a01b0380851660248301528316604482015260648101829052614a3d9085906323b872dd60e01b906084016134f4565b50505050565b604080516080808201835284546001600160401b038082168452600160401b82048116602080860191909152600160801b8304821685870152600160c01b90920481166060808601918252600088815260018a018552878120885196870189525460ff8116151587526101008104851695870195909552600160481b8504841697860197909752600160881b909304821692840192909252905116614b235760405162461bcd60e51b8152602060048201526016602482015275536f727465644c6973743a204c4953545f454d50545960501b6044820152606401610930565b8051614b6a5760405162461bcd60e51b815260206004820152601660248201527514dbdc9d1959131a5cdd0e881253959053125117d25160521b6044820152606401610930565b600084815260028601602052604090205460608301519093506001600160401b0316600103614b9c5760008555614d31565b81600001516001600160401b0316846001600160401b031603614bca5760408101516001600160401b031682525b81602001516001600160401b0316846001600160401b031603614bfb5760608101516001600160401b031660208301525b60608101516001600160401b031615614c5b5760408181015160608301516001600160401b0390811660009081526001890160205292909220805470ffffffffffffffff0000000000000000001916600160481b93909216929092021790555b60408101516001600160401b031615614cb45760608101516040808301516001600160401b0390811660009081526001890160205291909120805491909216600160881b0267ffffffffffffffff60881b199091161790555b816060018051614cc390615b45565b6001600160401b03908116909152825186546020850151604086015160608701519385166001600160801b031990931692909217600160401b91851691909102176001600160801b0316600160801b918416919091026001600160c01b031617600160c01b91909216021785555b5050600091825260018084016020908152604080852080546001600160c81b031916815590920184905560029094019093529181205590565b6000826000018281548110614d8157614d816156f5565b9060005260206000200154905092915050565b614d9c611a52565b1561433c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610930565b600054610100900460ff1661433c5760405162461bcd60e51b815260040161093090615a8d565b600054610100900460ff16614e2a5760405162461bcd60e51b815260040161093090615a8d565b307ff28c151dcc22c5bfb460fbc387993d6c0d1c1245ca20aca5f3cbd33f33041eb1604051602001614e5d929190615919565b60408051601f1981840301815291905280516020909101206101935561433c600019613239565b600054610100900460ff16614eab5760405162461bcd60e51b815260040161093090615a8d565b6065805460ff19169055565b60006001600160401b03821115613a5a5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610930565b60608315614f2e575081610fe8565b825115614f3e5782518084602001fd5b8160405162461bcd60e51b81526004016109309190615b68565b60006001600160e01b0319821663b55bd4f760e01b14806108d057506108d082614f8c565b6060610fe58484600085614fc1565b60006001600160e01b0319821663d86f1ca160e01b14806108d057506301ffc9a760e01b6001600160e01b03198316146108d0565b6060824710156150225760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610930565b6001600160a01b0385163b6150795760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610930565b600080866001600160a01b031685876040516150959190615b0a565b60006040518083038185875af1925050503d80600081146150d2576040519150601f19603f3d011682016040523d82523d6000602084013e6150d7565b606091505b50915091506150e7828286614f1f565b979650505050505050565b60006020828403121561510457600080fd5b81356001600160e01b031981168114610fe857600080fd5b6001600160a01b03811681146113a657600080fd5b803561513c8161511c565b919050565b60006020828403121561515357600080fd5b8135610fe88161511c565b60008083601f84011261517057600080fd5b5081356001600160401b0381111561518757600080fd5b6020830191508360208260051b85010111156151a257600080fd5b9250929050565b600080600080604085870312156151bf57600080fd5b84356001600160401b03808211156151d657600080fd5b6151e28883890161515e565b909650945060208701359150808211156151fb57600080fd5b506152088782880161515e565b95989497509550505050565b60006020828403121561522657600080fd5b5035919050565b6000806040838503121561524057600080fd5b823561524b8161511c565b9150602083013561525b8161511c565b809150509250929050565b60008060006060848603121561527b57600080fd5b83356152868161511c565b925060208401356152968161511c565b929592945050506040919091013590565b80356001600160401b038116811461513c57600080fd5b803561ffff8116811461513c57600080fd5b600080600080608085870312156152e657600080fd5b6152ef856152a7565b93506152fd602086016152a7565b925061530b604086016152be565b9150615319606086016152be565b905092959194509250565b6000806000806080858703121561533a57600080fd5b843593506020850135925060408501356153538161511c565b9396929550929360600135925050565b608081016108d082846001600160401b0380825116835280602083015116602084015250604081015161ffff808216604085015280606084015116606085015250505050565b600080602083850312156153bc57600080fd5b82356001600160401b038111156153d257600080fd5b6153de8582860161515e565b90969095509350505050565b600080604083850312156153fd57600080fd5b82359150602083013561525b8161511c565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561543857600080fd5b82356154438161511c565b91506020838101356001600160401b038082111561546057600080fd5b818601915086601f83011261547457600080fd5b8135818111156154865761548661540f565b8060051b604051601f19603f830116810181811085821117156154ab576154ab61540f565b6040529182528482019250838101850191898311156154c957600080fd5b938501935b828510156154ee576154df85615131565b845293850193928501926154ce565b8096505050505050509250929050565b600081518084526020808501945080840160005b8381101561552e57815187529582019590820190600101615512565b509495945050505050565b602081526000610fe860208301846154fe565b60005b8381101561556757818101518382015260200161554f565b50506000910152565b6000815180845261558881602086016020860161554c565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156155f157603f198886030184526155df858351615570565b945092850192908501906001016155c3565b5092979650505050505050565b6000806040838503121561561157600080fd5b823561561c8161511c565b946020939093013593505050565b6020808252601390820152725374616b696e673a2041444d494e5f4f4e4c5960681b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526016908201527514dd185ada5b99ce881253959053125117d054d4d15560521b604082015260600190565b6020808252601b908201527f72657175697265642070726976696c65676573206e6f74206d65740000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261572257600080fd5b8301803591506001600160401b0382111561573c57600080fd5b6020019150600581901b36038213156151a257600080fd5b6020808252601b908201527f5374616b696e673a20494e56414c49445f4944535f4c454e4754480000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000600182016157b3576157b361578b565b5060010190565b6000602082840312156157cc57600080fd5b8151610fe88161511c565b6000602082840312156157e957600080fd5b5051919050565b808201808211156108d0576108d061578b565b6020808252601b908201527f5374616b696e673a20494e53554646494349454e545f5354414b450000000000604082015260600190565b60208082526017908201527f5374616b696e673a20494e56414c49445f414d4f554e54000000000000000000604082015260600190565b818103818111156108d0576108d061578b565b82546001600160401b038082168352604082811c8216602080860191909152608084811c61ffff9081168488015260909590951c851660608088019190915287518516918701919091529086015190921660a0850152840151821660c08401528301511660e08201526101008101610fe8565b60006020828403121561590957600080fd5b81518015158114610fe857600080fd5b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6000808335601e1984360301811261595257600080fd5b8301803591506001600160401b0382111561596c57600080fd5b6020019150368190038213156151a257600080fd5b828152604060208201526000610fe560408301846154fe565b634e487b7160e01b600052601260045260246000fd5b6000826159bf576159bf61599a565b500690565b6001600160801b03818116838216019080821115612adb57612adb61578b565b84815260006bffffffffffffffffffffffff19808660601b166020840152808560601b1660348401525060028310615a2c57634e487b7160e01b600052602160045260246000fd5b5060f89190911b60488201526049019392505050565b80820281158282048414176108d0576108d061578b565b600082615a6857615a6861599a565b500490565b6001600160401b03818116838216019080821115612adb57612adb61578b565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8281526040810160028310615afd57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b60008251615b1c81846020870161554c565b9190910192915050565b65ffffffffffff828116828216039080821115612adb57612adb61578b565b60006001600160401b03821680615b5e57615b5e61578b565b6000190192915050565b602081526000610fe8602083018461557056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65647512bb95d4b127c0d01d6ada748d8b883dc98517e724044a57377f61d3efce7da164736f6c6343000812000a
Verified Source Code Partial Match
Compiler: v0.8.18+commit.87f61d96
EVM: london
Optimization: Yes (200 runs)
SomaStaking.sol 798 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../utils/math/SortedList.sol";
import "../utils/math/Percent.sol";
import "../utils/DynamicArray.sol";
import "../SomaGuard/utils/GuardableUpgradeable.sol";
import "../SecurityTokens/ERC20/utils/SafeERC20Balance.sol";
import "../Lockdrop/extensions/TokenRecoveryUpgradeable.sol";
import "./SomaStakingLibrary.sol";
import "./ISomaStaking.sol";
/**
* @notice Implementation of the {ISomaStaking} interface.
*/
contract SomaStaking is ISomaStaking, ReentrancyGuardUpgradeable, TokenRecoveryUpgradeable, GuardableUpgradeable {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using SafeERC20Balance for IERC20;
using SafeERC20 for IERC20;
using SortedList for SortedList.AscendingList;
using Percent for uint256;
using SafeCastUpgradeable for uint256;
/**
* @inheritdoc ISomaStaking
*/
bytes32 public constant override GLOBAL_ADMIN_ROLE = keccak256("Staking.GLOBAL_ADMIN_ROLE");
/**
* @inheritdoc ISomaStaking
*/
bytes32 public constant override GLOBAL_SEIZE_ROLE = keccak256("Staking.GLOBAL_SEIZE_ROLE");
/**
* @inheritdoc ISomaStaking
*/
bytes32 public override LOCAL_ADMIN_ROLE;
/**
* @inheritdoc ISomaStaking
*/
bytes32 public override LOCAL_SEIZE_ROLE;
/* Amount of staked tokens globally */
uint256 private _totalStaked;
uint256 private _totalPendingUnstake;
address private _stakingToken;
uint256 private _currentRequestId;
StakingConfig private _config;
mapping(address => uint256) private _tps;
mapping(address => UserInfo) private _users;
mapping(address => uint256) private _adminClaimable;
mapping(uint256 => Request) private _requests;
SortedList.AscendingList private _pendingStrategies;
EnumerableSetUpgradeable.AddressSet private _rewardTokens;
Strategy[] private _strategies;
/**
* @notice Modifier to restrict function calls to accounts that have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
modifier onlyAdmin() {
address _sender = _msgSender();
require(hasRole(GLOBAL_ADMIN_ROLE, _sender) || hasRole(LOCAL_ADMIN_ROLE, _sender), "Staking: ADMIN_ONLY"); // TODO errors should be Staking or SomaStaking
_;
}
/**
* @notice Modifier to restrict function calls to accounts that have the GLOBAL_SEIZE_ROLE or LOCAL_SEIZE_ROLE.
*/
modifier onlySeizeRole() {
address _sender = _msgSender();
require(hasRole(GLOBAL_SEIZE_ROLE, _sender) || hasRole(LOCAL_SEIZE_ROLE, _sender), "Staking: SEIZE_ROLE_ONLY");
_;
}
/**
* @notice Checks if SomaStaking inherits a given contract interface.
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(GuardableUpgradeable, TokenRecoveryUpgradeable)
returns (bool)
{
return interfaceId == type(ISomaStaking).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc ISomaStaking
*/
function config() external view override returns (StakingConfig memory) {
return _config;
}
/**
* @inheritdoc ISomaStaking
*/
function totalStaked() external view override returns (uint256) {
return _totalStaked;
}
/**
* @inheritdoc ISomaStaking
*/
function totalPendingUnstake() external view override returns (uint256) {
return _totalPendingUnstake;
}
/**
* @inheritdoc ISomaStaking
*/
function strategy(uint256 id) external view override returns (Strategy memory) {
return _strategies[id];
}
/**
* @inheritdoc ISomaStaking
*/
function totalStrategies() external view override returns (uint256) {
return _strategies.length;
}
/**
* @inheritdoc ISomaStaking
*/
function stakingToken() external view override returns (address) {
return _stakingToken;
}
/**
* @inheritdoc ISomaStaking
*/
function rewardToken(uint256 index) external view override returns (address) {
return _rewardTokens.at(index);
}
/**
* @inheritdoc ISomaStaking
*/
function totalRewardTokens() external view override returns (uint256) {
return _rewardTokens.length();
}
/**
* @inheritdoc ISomaStaking
*/
function pendingStrategy(uint256 index) external view override returns (Strategy memory) {
(bytes32 id,) = _pendingStrategies.at(index);
return _strategies[uint256(id)];
}
/**
* @inheritdoc ISomaStaking
*/
function totalPendingStrategies() external view override returns (uint256) {
return _pendingStrategies.length();
}
/**
* @inheritdoc ISomaStaking
*/
function tps(address _asset) external view override returns (uint256) {
return _tps[_asset];
}
/**
* @inheritdoc ISomaStaking
*/
function adminClaimable(address _asset) external view override returns (uint256) {
bool _isRewardAsset = _rewardTokens.contains(_asset);
require(_isRewardAsset || _asset == _stakingToken, "Staking: INVALID_ASSET");
// add the extra rewards if there are currently no stakers
return _adminClaimable[_asset] + (_totalStaked == 0 && _isRewardAsset ? _rewardsUnlocked(_asset) : 0);
}
/**
* @inheritdoc ISomaStaking
*/
function debt(address _account, address _asset) external view override returns (uint256) {
_checkRewardToken(_asset);
return SomaStakingLibrary.stakeToRewards(_users[_account].stake, currentTPS(_asset));
}
/**
* @inheritdoc ISomaStaking
*/
function claimable(address _account, address _asset) external view override returns (uint256) {
UserInfo storage _user = _users[_account];
_checkRewardToken(_asset);
return _user.claimable[_asset] + SomaStakingLibrary.stakeToRewards(_user.stake, currentTPS(_asset))
- _user.debt[_asset];
}
/**
* @inheritdoc ISomaStaking
*/
function claimRequest(address _account, address _asset, uint256 _id)
external
view
override
returns (Request memory)
{
_checkRewardToken(_asset);
return _getRequest(_id, _asset, _account, RequestType.CLAIM);
}
/**
* @inheritdoc ISomaStaking
*/
function stakeOf(address _account) external view override returns (uint256) {
return _users[_account].stake;
}
/**
* @inheritdoc ISomaStaking
*/
function unstakeRequest(address _account, uint256 _id) external view override returns (Request memory) {
return _getRequest(_id, _stakingToken, _account, RequestType.UNSTAKE);
}
/**
* @inheritdoc ISomaStaking
*/
function initialize(address stakingToken_, address[] memory rewardTokens_) external override initializer {
LOCAL_ADMIN_ROLE = keccak256(abi.encodePacked(address(this), GLOBAL_ADMIN_ROLE));
LOCAL_SEIZE_ROLE = keccak256(abi.encodePacked(address(this), GLOBAL_SEIZE_ROLE));
require(Address.isContract(stakingToken_), "Staking: INVALID_STAKING_TOKEN");
_stakingToken = stakingToken_;
_disableTokenRecovery(_stakingToken);
for (uint256 i = 0; i < rewardTokens_.length; ++i) {
address _token = rewardTokens_[i];
require(Address.isContract(_token), "Staking: INVALID_ASSET");
_rewardTokens.add(_token);
_disableTokenRecovery(_token);
}
__Guardable__init();
__ReentrancyGuard_init_unchained();
__TokenRecovery__init_unchained(new address[](0));
}
/**
* @inheritdoc ISomaStaking
*/
function currentTPS(address token) public view override returns (uint256 tps_) {
uint256 totalStaked_ = _totalStaked;
uint256 extraTPS =
(totalStaked_ > 0) ? SomaStakingLibrary.rewardsToTPS(_totalStaked, _rewardsUnlocked(token)) : 0;
return _tps[token] + extraTPS;
}
/**
* @inheritdoc ISomaStaking
*/
function createUnstakeRequest(uint256 _amount)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
returns (uint256 _id)
{
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
uint256 _userStake = _user.stake;
uint256 totalStake_ = _totalStaked;
require(_userStake >= _amount, "Staking: INSUFFICIENT_STAKE");
require(_amount > 0, "Staking: INVALID_AMOUNT");
_update(totalStake_);
// remove this amount from the users stake amount, so that they no longer earn rewards on
_syncUser(_user, _userStake, _userStake - _amount);
// adjust the total stake balances
unchecked {
_totalStaked = totalStake_ - _amount;
_totalPendingUnstake += _amount;
}
return _createRequest(_sender, _stakingToken, _amount, RequestType.UNSTAKE);
}
/**
* @inheritdoc ISomaStaking
*/
function cancelUnstakeRequests(uint256[] calldata _ids)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
{
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
uint256 _userStake = _user.stake;
uint256 totalStake_ = _totalStaked;
require(_ids.length > 0, "Staking: INVALID_IDS_LENGTH");
address stakingToken_ = _stakingToken;
uint256 _totalAmount = _userStake;
for (uint256 i = 0; i < _ids.length; ++i) {
unchecked {
_totalAmount += _cancelRequest(_ids[i], stakingToken_, _sender, RequestType.UNSTAKE);
}
}
_update(totalStake_);
_syncUser(_user, _userStake, _totalAmount);
unchecked {
_totalStaked = totalStake_ + _totalAmount;
_totalPendingUnstake -= _totalAmount;
}
}
/**
* @inheritdoc ISomaStaking
*/
function createClaimRequests(address[] calldata _assets)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
returns (uint256[] memory _ids)
{
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
uint256 _userStake = _user.stake;
_ids = new uint256[](_assets.length);
_update(_totalStaked);
_syncUser(_user, _userStake, _userStake);
for (uint256 i = 0; i < _assets.length; ++i) {
address _asset = _assets[i];
uint256 _rewards = _user.claimable[_asset];
_checkRewardToken(_asset);
require(_rewards > 0, "Staking: NO_REWARDS");
delete _user.claimable[_asset];
_ids[i] = _createRequest(_sender, _asset, _rewards, RequestType.CLAIM);
}
}
/**
* @inheritdoc ISomaStaking
*/
function cancelClaimRequests(address[] calldata _assets, uint256[][] calldata _ids)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
{
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
require(_assets.length > 0, "Staking: INVALID_ASSETS_LENGTH");
require(_ids.length == _assets.length, "Staking: INVALID_INPUT_LENGTHS");
for (uint256 i = 0; i < _assets.length; ++i) {
uint256 _idsLength = _ids[i].length;
address _asset = _assets[i];
uint256 _totalAmount;
require(_idsLength > 0, "Staking: INVALID_IDS_LENGTH");
for (uint256 j = 0; j < _idsLength; ++j) {
unchecked {
_totalAmount += _cancelRequest(_ids[i][j], _asset, _sender, RequestType.CLAIM);
}
}
unchecked {
_user.claimable[_asset] += _totalAmount;
}
}
}
/**
* @inheritdoc ISomaStaking
*/
function claim(address[] calldata _assets, uint256[][] calldata _ids)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
{
address _sender = _msgSender();
uint256 _claimDuration = _config.claimDuration;
require(_assets.length == _ids.length, "Staking: INVALID_INPUT_LENGTHS");
for (uint256 i = 0; i < _assets.length; ++i) {
uint256 _idsLength = _ids[i].length;
address _asset = _assets[i];
uint256 _totalAmount;
require(_idsLength > 0, "Staking: INVALID_IDS_LENGTH");
for (uint256 j = 0; j < _idsLength; ++j) {
unchecked {
_totalAmount += _useRequest(_ids[i][j], _asset, _sender, _claimDuration, RequestType.CLAIM);
}
}
IERC20(_asset).safeTransfer(_sender, _totalAmount);
emit Claimed(_asset, _totalAmount, _sender);
}
}
/**
* @inheritdoc ISomaStaking
*/
function claimImmediate(address[] calldata _assets, uint256[] calldata _amounts)
external
override
nonReentrant
onlyApprovedPrivileges(_msgSender())
{
require(_assets.length == _amounts.length, "Staking: INCONSISTENT_LENGTHS");
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
StakingConfig memory config_ = _config;
uint256 _userStake = _user.stake;
_update(_totalStaked);
_syncUser(_user, _userStake, _userStake);
for (uint256 i = 0; i < _assets.length; ++i) {
_claimImmediate(_user, config_.earlyClaimFee, _sender, _assets[i], _amounts[i]);
}
}
/**
* @inheritdoc ISomaStaking
*/
function stake(uint256 _amount) external override nonReentrant onlyApprovedPrivileges(_msgSender()) {
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
uint256 _userStake = _user.stake;
uint256 totalStake_ = _totalStaked;
// slither-disable-next-line reentrancy-no-eth
_amount = SafeERC20Balance.safeTransferFrom(IERC20(_stakingToken), _sender, address(this), _amount);
require(_amount > 0, "Staking: INVALID_AMOUNT");
_update(totalStake_);
_syncUser(_user, _userStake, _userStake + _amount);
_totalStaked = totalStake_ + _amount;
emit Staked(_amount, _sender);
}
// TODO should this have an input amount?
/**
* @inheritdoc ISomaStaking
*/
function adminClaim(address _asset, address _to) external override onlyAdmin nonReentrant {
_update(_totalStaked);
uint256 _claimable = _adminClaimable[_asset];
require(_claimable > 0, "Staking: INSUFFICIENT_CLAIMABLE");
delete _adminClaimable[_asset];
IERC20(_asset).safeTransfer(_to, _claimable);
emit AdminClaimed(_asset, _claimable, _to, _msgSender());
}
/**
* @inheritdoc ISomaStaking
*/
function unstake(uint256[] calldata _ids) external override nonReentrant onlyApprovedPrivileges(_msgSender()) {
address _sender = _msgSender();
address stakingToken_ = _stakingToken;
uint256 _unstakeDuration = _config.unstakeDuration;
uint256 _totalAmount;
for (uint256 i = 0; i < _ids.length; ++i) {
unchecked {
_totalAmount += _useRequest(_ids[i], stakingToken_, _sender, _unstakeDuration, RequestType.UNSTAKE);
}
}
unchecked {
_totalPendingUnstake -= _totalAmount;
}
IERC20(_stakingToken).safeTransfer(_sender, _totalAmount);
emit Unstaked(_totalAmount, _sender);
}
/**
* @inheritdoc ISomaStaking
*/
function unstakeImmediate(uint256 _amount) external override nonReentrant onlyApprovedPrivileges(_msgSender()) {
address _sender = _msgSender();
UserInfo storage _user = _users[_sender];
uint256 _userStake = _user.stake;
uint256 totalStake_ = _totalStaked;
StakingConfig memory config_ = _config;
require(_userStake >= _amount, "Staking: INSUFFICIENT_STAKE");
require(_amount > 0, "Staking: INVALID_AMOUNT");
_update(totalStake_);
_syncUser(_user, _userStake, _userStake - _amount);
unchecked {
_totalStaked = totalStake_ - _amount;
}
uint256 _adminFee = _amount.applyPercent(config_.earlyUnstakeFee);
address _asset = _stakingToken;
_adminClaimable[_asset] += _adminFee;
IERC20(_asset).safeTransfer(_sender, _amount - _adminFee);
emit UnstakedImmediate(_amount, _adminFee, _msgSender());
}
/**
* @inheritdoc ISomaStaking
*/
function addRewardToken(address _asset) external override onlyAdmin nonReentrant {
require(_rewardTokens.add(_asset), "Staking: REWARD_TOKEN_EXISTS");
require(_rewardTokens.length() <= 64, "Staking: LIMIT");
require(Address.isContract(_asset), "Staking: INVALID_ASSET");
_disableTokenRecovery(_asset);
emit RewardTokenAdded(_asset, _msgSender());
}
/**
* @inheritdoc ISomaStaking
*/
function createStrategy(uint256 _startDate, uint256 _endDate, address _rewardToken, uint256 _rewardAmount)
external
override
onlyAdmin
nonReentrant
{
require(_rewardAmount <= type(uint128).max, "Staking: MAX_REWARD_AMOUNT");
require(_startDate > block.timestamp, "Staking: INVALID_START_DATE");
require(_startDate < _endDate, "Staking: INVALID_DATE_ORDER");
require(_endDate <= type(uint48).max, "Staking: INVALID_END_DATE");
_checkRewardToken(_rewardToken);
// slither-disable-next-line reentrancy-no-eth
_rewardAmount =
SafeERC20Balance.safeTransferFrom(IERC20(_rewardToken), _msgSender(), address(this), _rewardAmount);
require(_rewardAmount > 0, "Staking: INVALID_AMOUNT");
uint256 strategyId = _strategies.length;
require(strategyId < 64, "Staking: LIMIT");
Strategy memory _strategy = Strategy({
startDate: uint48(_startDate),
endDate: uint48(_endDate),
rewardsLocked: _rewardAmount.toUint128(),
rewardToken: _rewardToken,
rewardsUnlocked: 0
});
_strategies.push(_strategy);
_pendingStrategies.add(bytes32(strategyId), _startDate);
emit StrategyCreated(_rewardToken, _strategy.rewardsLocked, _startDate, _endDate, _msgSender());
}
/**
* @inheritdoc ISomaStaking
*/
function updateConfig(
uint64 _unstakeDuration,
uint64 _claimDuration,
uint16 _earlyUnstakeFee,
uint16 _earlyClaimFee
) external override onlyAdmin {
StakingConfig memory config_ = StakingConfig({
unstakeDuration: _unstakeDuration,
claimDuration: _claimDuration,
earlyUnstakeFee: _earlyUnstakeFee,
earlyClaimFee: _earlyClaimFee
});
emit StakingConfigUpdated(_config, config_, _msgSender());
_config = config_;
}
/**
* @inheritdoc ISomaStaking
*/
function seize(address from) external override onlySeizeRole {
address _seizeTo = SOMA.seizeTo();
uint256 totalStake_ = _totalStaked;
UserInfo storage _user = _users[from];
uint256 _userStake = _user.stake;
require(_userStake > 0, "Staking: INSUFFICIENT_STAKE");
_update(totalStake_);
_syncUser(_user, _userStake, 0);
unchecked {
_totalStaked = totalStake_ - _userStake;
}
uint256 _totalTokens = _rewardTokens.length();
uint256[] memory _seizedRewards = new uint256[](_totalTokens);
for (uint256 i = 0; i < _totalTokens; ++i) {
address _rewardToken = _rewardTokens.at(i);
uint256 _claimable = _user.claimable[_rewardToken];
_adminClaimable[_rewardToken] += _claimable;
_seizedRewards[i] = _claimable;
delete _user.claimable[_rewardToken];
}
address _asset = _stakingToken;
IERC20(_asset).safeTransfer(_seizeTo, _userStake);
emit Seized(from, _seizeTo, _userStake, _seizedRewards, _msgSender());
}
function _checkRewardToken(address _asset) private view {
require(_rewardTokens.contains(_asset), "Staking: INVALID_ASSET");
}
function _update(uint256 totalStake_) private {
uint256 curId = _pendingStrategies.head();
uint256 nextId;
bytes32 key;
// slither-disable-next-line weak-prng
uint48 curTimestamp = uint48(block.timestamp % type(uint48).max);
while (curId != 0) {
(key, nextId) = _pendingStrategies.get(curId);
Strategy memory _strategy = _strategies[uint256(key)];
if (curTimestamp < _strategy.startDate) {
break;
}
uint256 rewardsUnlocked = SomaStakingLibrary.rewardsUnlocked(_strategy, block.timestamp);
// increment how many rewards have been released
_strategies[uint256(key)].rewardsUnlocked = rewardsUnlocked.toUint128() + _strategy.rewardsUnlocked;
// if there is nobody staking, lets go ahead and return the rewards earned to the admin
if (totalStake_ > 0) {
uint256 tps_ = SomaStakingLibrary.rewardsToTPS(totalStake_, rewardsUnlocked);
if (tps_ == 0) {
_adminClaimable[_strategy.rewardToken] += rewardsUnlocked;
} else {
_tps[_strategy.rewardToken] += tps_;
}
} else {
_adminClaimable[_strategy.rewardToken] += rewardsUnlocked;
}
// if this strategy has been completed then let us remove it from the pending list
if (curTimestamp >= _strategy.endDate) {
_pendingStrategies.remove(curId);
}
// progress to the next item in the list
curId = nextId;
}
}
function _syncUser(UserInfo storage _user, uint256 _userStake, uint256 _newUserStake) private {
if (_newUserStake != _userStake) _user.stake = _newUserStake;
// sync the claimable and debt values
uint256 _totalTokens = _rewardTokens.length();
for (uint256 i = 0; i < _totalTokens; ++i) {
address _rewardToken = _rewardTokens.at(i);
uint256 tps_ = _tps[_rewardToken];
_user.claimable[_rewardToken] +=
SomaStakingLibrary.stakeToRewards(_userStake, tps_) - _user.debt[_rewardToken];
_user.debt[_rewardToken] = SomaStakingLibrary.stakeToRewards(_newUserStake, tps_);
}
}
function _claimImmediate(
UserInfo storage _user,
uint256 _earlyClaimFee,
address _sender,
address _asset,
uint256 _amount
) private {
_checkRewardToken(_asset);
uint256 _claimable = _user.claimable[_asset];
require(_amount > 0, "Staking: INVALID_AMOUNT");
require(_claimable > 0, "Staking: NO_REWARDS");
require(_amount <= _claimable, "Staking: INSUFFICIENT_CLAIMABLE");
uint256 _adminFee = _amount.applyPercent(_earlyClaimFee);
_adminClaimable[_asset] += _adminFee;
IERC20(_asset).safeTransfer(_sender, _amount - _adminFee);
unchecked {
_user.claimable[_asset] = _claimable - _amount;
}
emit ClaimedImmediate(_asset, _amount, _adminFee, _sender);
}
function _rewardsUnlocked(address token) private view returns (uint256 _totalUnlocked) {
bytes32 key;
uint256 curId = _pendingStrategies.head();
while (curId != 0) {
(key, curId) = _pendingStrategies.get(curId);
Strategy memory _strategy = _strategies[uint256(key)];
if (block.timestamp < _strategy.startDate) break;
if (_strategy.rewardToken == token) {
_totalUnlocked += SomaStakingLibrary.rewardsUnlocked(_strategy, block.timestamp);
}
}
}
function _createRequest(address _sender, address _asset, uint256 _amount, RequestType _type)
private
returns (uint256 _id)
{
require(_amount > 0, "Staking: INVALID_AMOUNT");
_id = ++_currentRequestId;
_requests[_id] = Request({
hash: bytes8(keccak256(abi.encodePacked(_id, _sender, _asset, _type))),
timestamp: block.timestamp.toUint64(),
amount: _amount.toUint128()
});
emit RequestCreated(_id, _asset, _amount, _sender, _type);
}
function _getRequest(uint256 _id, address _asset, address _sender, RequestType _type)
private
view
returns (Request memory _request)
{
bytes8 _hash = bytes8(keccak256(abi.encodePacked(_id, _sender, _asset, _type)));
_request = _requests[_id];
require(_request.hash == _hash, "Staking: INVALID_REQUEST");
}
function _useRequest(uint256 _id, address _asset, address _sender, uint256 _requiredDuration, RequestType _type)
private
returns (uint256 _amount)
{
Request memory _request = _getRequest(_id, _asset, _sender, _type);
require(block.timestamp - _request.timestamp >= _requiredDuration, "Staking: INSUFFICIENT_TIME");
delete _requests[_id];
emit RequestFulfilled(_id);
return _request.amount;
}
function _cancelRequest(uint256 _id, address _asset, address _sender, RequestType _type)
private
returns (uint256 _amount)
{
_amount = _getRequest(_id, _asset, _sender, _type).amount;
delete _requests[_id];
emit RequestCancelled(_id);
}
}
ReentrancyGuardUpgradeable.sol 75 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// 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;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_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 making 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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
SafeCastUpgradeable.sol 1135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCastUpgradeable {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248) {
require(value >= type(int248).min && value <= type(int248).max, "SafeCast: value doesn't fit in 248 bits");
return int248(value);
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240) {
require(value >= type(int240).min && value <= type(int240).max, "SafeCast: value doesn't fit in 240 bits");
return int240(value);
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232) {
require(value >= type(int232).min && value <= type(int232).max, "SafeCast: value doesn't fit in 232 bits");
return int232(value);
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224) {
require(value >= type(int224).min && value <= type(int224).max, "SafeCast: value doesn't fit in 224 bits");
return int224(value);
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216) {
require(value >= type(int216).min && value <= type(int216).max, "SafeCast: value doesn't fit in 216 bits");
return int216(value);
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208) {
require(value >= type(int208).min && value <= type(int208).max, "SafeCast: value doesn't fit in 208 bits");
return int208(value);
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200) {
require(value >= type(int200).min && value <= type(int200).max, "SafeCast: value doesn't fit in 200 bits");
return int200(value);
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192) {
require(value >= type(int192).min && value <= type(int192).max, "SafeCast: value doesn't fit in 192 bits");
return int192(value);
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184) {
require(value >= type(int184).min && value <= type(int184).max, "SafeCast: value doesn't fit in 184 bits");
return int184(value);
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176) {
require(value >= type(int176).min && value <= type(int176).max, "SafeCast: value doesn't fit in 176 bits");
return int176(value);
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168) {
require(value >= type(int168).min && value <= type(int168).max, "SafeCast: value doesn't fit in 168 bits");
return int168(value);
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160) {
require(value >= type(int160).min && value <= type(int160).max, "SafeCast: value doesn't fit in 160 bits");
return int160(value);
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152) {
require(value >= type(int152).min && value <= type(int152).max, "SafeCast: value doesn't fit in 152 bits");
return int152(value);
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144) {
require(value >= type(int144).min && value <= type(int144).max, "SafeCast: value doesn't fit in 144 bits");
return int144(value);
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136) {
require(value >= type(int136).min && value <= type(int136).max, "SafeCast: value doesn't fit in 136 bits");
return int136(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120) {
require(value >= type(int120).min && value <= type(int120).max, "SafeCast: value doesn't fit in 120 bits");
return int120(value);
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112) {
require(value >= type(int112).min && value <= type(int112).max, "SafeCast: value doesn't fit in 112 bits");
return int112(value);
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104) {
require(value >= type(int104).min && value <= type(int104).max, "SafeCast: value doesn't fit in 104 bits");
return int104(value);
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96) {
require(value >= type(int96).min && value <= type(int96).max, "SafeCast: value doesn't fit in 96 bits");
return int96(value);
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88) {
require(value >= type(int88).min && value <= type(int88).max, "SafeCast: value doesn't fit in 88 bits");
return int88(value);
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80) {
require(value >= type(int80).min && value <= type(int80).max, "SafeCast: value doesn't fit in 80 bits");
return int80(value);
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72) {
require(value >= type(int72).min && value <= type(int72).max, "SafeCast: value doesn't fit in 72 bits");
return int72(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56) {
require(value >= type(int56).min && value <= type(int56).max, "SafeCast: value doesn't fit in 56 bits");
return int56(value);
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48) {
require(value >= type(int48).min && value <= type(int48).max, "SafeCast: value doesn't fit in 48 bits");
return int48(value);
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40) {
require(value >= type(int40).min && value <= type(int40).max, "SafeCast: value doesn't fit in 40 bits");
return int40(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24) {
require(value >= type(int24).min && value <= type(int24).max, "SafeCast: value doesn't fit in 24 bits");
return int24(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
EnumerableSetUpgradeable.sol 367 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
* ====
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
SafeERC20.sol 116 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
SortedList.sol 155 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
library SortedList {
struct ListItemDetails {
bool exists;
uint64 id;
uint64 nextId;
uint64 prevId;
}
struct ListItem {
ListItemDetails details;
uint256 value;
}
struct ListDetails {
uint64 head;
uint64 tail;
uint64 current;
uint64 length;
}
struct AscendingList {
ListDetails __details;
mapping(uint256 => ListItem) __items;
mapping(uint256 => bytes32) __keys;
}
function head(AscendingList storage list) internal view returns (uint256 id) {
return list.__details.head;
}
function tail(AscendingList storage list) internal view returns (uint256 id) {
return list.__details.tail;
}
function get(AscendingList storage list, uint256 id) internal view returns (bytes32 key, uint256 nextId) {
require(list.__items[id].details.exists, "SortedList: INVALID_ID");
key = list.__keys[id];
nextId = list.__items[id].details.nextId;
}
function exists(AscendingList storage list, uint256 id) internal view returns (bool) {
return list.__items[id].details.exists;
}
function length(AscendingList storage list) internal view returns (uint256) {
return list.__details.length;
}
function at(AscendingList storage list, uint256 index) internal view returns (bytes32 key, uint256 curId) {
ListDetails memory details = list.__details;
require(index < details.length, "SortedList: OUT_OF_BOUNDS");
curId = details.head;
for (uint256 i = 0; i < index; ++i) {
curId = list.__items[curId].details.nextId;
}
key = list.__keys[curId];
}
function add(AscendingList storage list, bytes32 key, uint256 value) internal {
ListDetails memory details = list.__details;
// when it hits the end loop back around to the beginning
uint64 id;
unchecked {
id = details.current + 1;
}
ListItemDetails memory itemDetails = list.__items[id].details;
// we want to override the previous values if they exist
if (itemDetails.exists) _remove(list, id);
ListItem memory nextItem;
ListItem memory prevItem;
uint64 curId = details.head;
while (curId != 0) {
ListItem memory curListItem = list.__items[curId];
// sort until we find first value that is larger.
// then this item should go on the right. so it is ascending
if (curListItem.value > value) {
nextItem = curListItem;
break;
}
prevItem = curListItem;
curId = curListItem.details.nextId;
}
list.__details = ListDetails({
length: details.length + 1,
head: nextItem.details.id == details.head ? id : details.head,
tail: prevItem.details.id == details.tail ? id : details.tail,
current: id
});
list.__keys[id] = key;
list.__items[id] = ListItem({
value: value,
details: ListItemDetails({exists: true, id: id, prevId: prevItem.details.id, nextId: nextItem.details.id})
});
if (prevItem.details.exists) {
prevItem.details.nextId = id;
list.__items[prevItem.details.id].details = prevItem.details;
}
if (nextItem.details.exists) {
nextItem.details.prevId = id;
list.__items[nextItem.details.id].details = nextItem.details;
}
}
function remove(AscendingList storage list, uint256 id) internal returns (bytes32 key) {
return _remove(list, id);
}
function _remove(AscendingList storage list, uint256 id) private returns (bytes32 key) {
ListDetails memory listDetails = list.__details;
ListItemDetails memory itemDetails = list.__items[id].details;
require(listDetails.length > 0, "SortedList: LIST_EMPTY");
require(itemDetails.exists, "SortedList: INVALID_ID");
key = list.__keys[id];
if (listDetails.length == 1) {
delete list.__details;
} else {
if (uint64(id) == listDetails.head) {
listDetails.head = itemDetails.nextId;
}
if (uint64(id) == listDetails.tail) {
listDetails.tail = itemDetails.prevId;
}
if (itemDetails.prevId != 0) {
list.__items[itemDetails.prevId].details.nextId = itemDetails.nextId;
}
if (itemDetails.nextId != 0) {
list.__items[itemDetails.nextId].details.prevId = itemDetails.prevId;
}
--listDetails.length;
list.__details = listDetails;
}
// TODO confirm the gas of this -- does this clear all the structs?
delete list.__items[id];
delete list.__keys[id];
}
}
Percent.sol 31 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
library Percent {
uint256 internal constant BASE_PERCENT = type(uint16).max;
function isValidPercent(uint256 nb) internal pure returns (bool) {
return nb <= BASE_PERCENT;
}
function validatePercent(uint256 nb) internal pure {
require(isValidPercent(nb), "Percent: INVALID_NUMBER");
}
function applyPercent(uint256 nb, uint256 _percent) internal pure returns (uint256) {
return (nb * _percent) / BASE_PERCENT;
}
function inverseApplyPercent(uint256 nb, uint256 _percent) internal pure returns (uint256) {
return asPercent(nb) / (_percent);
}
function percentValueOf(uint256 value, uint256 total) internal pure returns (uint256) {
return asPercent(value) / total;
}
function asPercent(uint256 value) internal pure returns (uint256) {
return value * BASE_PERCENT;
}
}
DynamicArray.sol 97 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
library DynamicArray {
struct Bytes32Array {
uint256 length;
bytes __data;
}
function push(Bytes32Array memory array, bytes32 item) internal pure {
++array.length;
array.__data = abi.encodePacked(array.__data, item);
}
function toArray(Bytes32Array memory array) internal pure returns (bytes32[] memory) {
return abi.decode(abi.encodePacked(array.length, array.__data), (bytes32[]));
}
function includes(Bytes32Array memory array, bytes32 item) internal pure returns (bool) {
return indexOf(array, item) != type(uint256).max;
}
function indexOf(Bytes32Array memory array, bytes32 item) internal pure returns (uint256) {
return _indexOf(array, item);
}
// ----------------------------------------------------------------------------------------------
struct Uint256Array {
uint256 length;
bytes __data;
}
function push(Uint256Array memory array, uint256 item) internal pure {
++array.length;
array.__data = abi.encodePacked(array.__data, item);
}
function toArray(Uint256Array memory array) internal pure returns (uint256[] memory) {
return abi.decode(abi.encodePacked(array.length, array.__data), (uint256[]));
}
function includes(Uint256Array memory array, uint256 item) internal pure returns (bool) {
return indexOf(array, item) != type(uint256).max;
}
function indexOf(Uint256Array memory array, uint256 item) internal pure returns (uint256) {
return _indexOf(Bytes32Array(array.length, array.__data), bytes32(item));
}
// ----------------------------------------------------------------------------------------------
struct AddressArray {
uint256 length;
bytes __data;
}
function push(AddressArray memory array, address item) internal pure {
++array.length;
array.__data = abi.encodePacked(array.__data, abi.encode(item));
}
function toArray(AddressArray memory array) internal pure returns (address[] memory) {
return abi.decode(abi.encodePacked(array.length, array.__data), (address[]));
}
function includes(AddressArray memory array, address item) internal pure returns (bool) {
return indexOf(array, item) != type(uint256).max;
}
function indexOf(AddressArray memory array, address item) internal pure returns (uint256) {
return _indexOf(Bytes32Array(array.length, array.__data), bytes32(uint256(uint160(item)) << 96));
}
// ----------------------------------------------------------------------------------------------
function _indexOf(Bytes32Array memory array, bytes32 item) private pure returns (uint256) {
bytes memory data = array.__data;
for (uint256 i = 0; i < array.length; ++i) {
bytes32 piece;
uint256 pos;
unchecked {
pos = i * 32;
}
assembly {
piece := mload(add(data, pos))
}
if (piece == item) {
return i;
}
}
return type(uint256).max;
}
}
GuardableUpgradeable.sol 90 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "../../SomaAccessControl/utils/AccessibleUpgradeable.sol";
import "../ISomaGuard.sol";
import "./GuardHelper.sol";
import "./IGuardable.sol";
/**
* @notice Implementation of the {IGuardable} interface.
*/
abstract contract GuardableUpgradeable is IGuardable, AccessibleUpgradeable {
/**
* @notice Initializer for extended contracts.
*/
function __Guardable__init() internal {
__Context_init_unchained();
__ERC165_init_unchained();
__Guardable__init_unchained();
__SomaContract_init_unchained();
__Accessible_init_unchained();
__Multicall_init_unchained();
__Pausable_init_unchained();
}
/**
* @notice Unchained initializer for extended contracts.
*/
function __Guardable__init_unchained() internal onlyInitializing {
LOCAL_UPDATE_PRIVILEGES_ROLE = keccak256(abi.encodePacked(address(this), GLOBAL_UPDATE_PRIVILEGES_ROLE));
_updateRequiredPrivileges(bytes32(type(uint256).max));
}
bytes32 public immutable DEFAULT_PRIVILEGES = GuardHelper.DEFAULT_PRIVILEGES;
bytes32 public constant GLOBAL_UPDATE_PRIVILEGES_ROLE = keccak256("Guardable.GLOBAL_UPDATE_PRIVILEGES_ROLE");
bytes32 public LOCAL_UPDATE_PRIVILEGES_ROLE;
bytes32 private _requiredPrivileges;
/**
* @notice Modifier restricting a function call to accounts that have the required privileges.
*/
modifier onlyApprovedPrivileges(address sender) {
require(hasPrivileges(sender), "required privileges not met");
_;
}
/**
* @inheritdoc IGuardable
*/
function hasPrivileges(address account) public view virtual override returns (bool) {
return ISomaGuard(SOMA.guard()).check(account, requiredPrivileges());
}
/**
* @inheritdoc IGuardable
*/
function requiredPrivileges() public view virtual override returns (bytes32) {
return _requiredPrivileges;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IGuardable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IGuardable
*/
function updateRequiredPrivileges(bytes32 newRequiredPrivileges) external virtual override returns (bool) {
require(
hasRole(LOCAL_UPDATE_PRIVILEGES_ROLE, _msgSender()) || hasRole(GLOBAL_UPDATE_PRIVILEGES_ROLE, _msgSender()),
"Guardable: you do not have the required roles to do this"
);
_updateRequiredPrivileges(newRequiredPrivileges);
return true;
}
function _updateRequiredPrivileges(bytes32 newRequiredPrivileges) internal {
emit RequiredPrivilegesUpdated(_requiredPrivileges, newRequiredPrivileges, _msgSender());
_requiredPrivileges = newRequiredPrivileges;
}
uint256[50] private __gap;
}
SafeERC20Balance.sol 18 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
library SafeERC20Balance {
using SafeERC20 for IERC20;
function safeTransferFrom(IERC20 token, address sender, address receiver, uint256 amount)
internal
returns (uint256)
{
uint256 prevBalance = token.balanceOf(receiver);
token.safeTransferFrom(sender, receiver, amount);
return token.balanceOf(receiver) - prevBalance;
}
}
TokenRecoveryUpgradeable.sol 82 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../../SomaAccessControl/utils/AccessibleUpgradeable.sol";
import "./ITokenRecoveryUpgradeable.sol";
/**
* @notice Implementation of the {ITokenRecoveryUpgradeable} interface.
*/
abstract contract TokenRecoveryUpgradeable is ITokenRecoveryUpgradeable, AccessibleUpgradeable {
using EnumerableSet for EnumerableSet.AddressSet;
using SafeERC20 for IERC20;
/**
* @notice Initializer for the extended contracts.
*/
function __TokenRecovery__init() internal onlyInitializing {
__TokenRecovery__init(new address[](0));
}
/**
* @notice Initializer for the extended contracts.
*/
function __TokenRecovery__init(address[] memory disabledTokens) internal onlyInitializing {
__ERC165_init_unchained();
__Context_init_unchained();
__SomaContract_init_unchained();
__Multicall_init_unchained();
__Pausable_init_unchained();
__Accessible_init_unchained();
__TokenRecovery__init_unchained(disabledTokens);
}
/**
* @notice Unchained initializer.
*/
function __TokenRecovery__init_unchained(address[] memory disabledTokens) internal onlyInitializing {
for (uint256 i; i < disabledTokens.length; ++i) {
_disabledTokens.add(disabledTokens[i]);
}
}
/**
* @inheritdoc ITokenRecoveryUpgradeable
*/
bytes32 public constant override TOKEN_RECOVERY_ROLE = keccak256("TokenRecovery.TOKEN_RECOVERY_ROLE");
EnumerableSet.AddressSet private _disabledTokens;
/**
* @notice Checks if TokenRecoveryUpgradeable inherits a given contract interface.
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ITokenRecoveryUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc ITokenRecoveryUpgradeable
*/
function recoverTokens(address token, address to, uint256 amount) external override onlyRole(TOKEN_RECOVERY_ROLE) {
require(!_disabledTokens.contains(token), "TokenRecovery: INVALID_TOKEN");
IERC20(token).safeTransfer(to, amount);
emit TokensRecovered(token, to, amount, _msgSender());
}
function _disableTokenRecovery(address token) internal {
_disabledTokens.add(token);
}
function _enableTokenRecovery(address token) internal {
_disabledTokens.remove(token);
}
uint256[50] private __gap;
}
SomaStakingLibrary.sol 28 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "./ISomaStaking.sol";
library SomaStakingLibrary {
uint256 internal constant PRECISION_FACTOR = 10 ** 25;
function rewardsUnlocked(ISomaStaking.Strategy memory _strategy, uint256 timestamp)
internal
pure
returns (uint256)
{
uint256 locked = (timestamp >= _strategy.endDate)
? _strategy.rewardsLocked
: ((timestamp - _strategy.startDate) * _strategy.rewardsLocked) / (_strategy.endDate - _strategy.startDate);
return locked - _strategy.rewardsUnlocked;
}
function rewardsToTPS(uint256 totalStake, uint256 _rewardsUnlocked) internal pure returns (uint256 tps) {
return (_rewardsUnlocked * PRECISION_FACTOR) / totalStake;
}
function stakeToRewards(uint256 stake, uint256 tps) internal pure returns (uint256) {
return (stake * tps) / PRECISION_FACTOR;
}
}
ISomaStaking.sol 495 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Staking Contract.
* @author SOMA.finance.
* @notice A staking contract that supports multiple reward tokens and strategies.
*/
interface ISomaStaking {
/**
* Events ***********************************
*/
/**
* @notice Emitted when a user Stakes.
* @param amount The amount staked, denominated in the staking token.
* @param sender The address of the message sender.
*/
event Staked(uint256 amount, address indexed sender);
/**
* @notice Emitted when a user Unstakes.
* @param amount The amount unstaked, denominated in the staking token.
* @param sender The address of the message sender.
*/
event Unstaked(uint256 amount, address indexed sender);
/**
* @notice Emitted when a user Unstakes immediately.
* @param amount The amount of the staking token unstaked.
* @param fee The early unstake fee charged.
* @param sender The address of the message sender.
*/
event UnstakedImmediate(uint256 amount, uint256 fee, address indexed sender);
/**
* @notice Emitted when a user Claims.
* @param asset The address of the reward token claimed.
* @param amount The amount of the reward token claimed.
* @param sender The address of the message sender.
*/
event Claimed(address indexed asset, uint256 amount, address indexed sender);
/**
* @notice Emitted when a user Claims immediately.
* @param asset The address of the reward token claimed.
* @param amount The amount of the reward token claimed.
* @param fee The early claim fee.
* @param sender The address of the message sender.
*/
event ClaimedImmediate(address indexed asset, uint256 amount, uint256 fee, address indexed sender);
/**
* @notice Emitted when a Strategy is created.
* @param rewardToken The address of the reward token.
* @param amount The amount of the reward tokens.
* @param startDate The timestamp marking the start of the strategy.
* @param endDate The timestamp marking the end of the strategy.
* @param sender The address of the message sender.
*/
event StrategyCreated(
address indexed rewardToken, uint256 amount, uint256 startDate, uint256 endDate, address indexed sender
);
/**
* @notice Emitted when a Admin claims.
* @param asset The address of the asset claimed.
* @param amount The amount of the asset claimed.
* @param to The address that the claimed tokens is sent to.
* @param sender The address of the message sender.
*/
event AdminClaimed(address indexed asset, uint256 amount, address indexed to, address indexed sender);
/**
* @notice Emitted when the Staking Config is updated.
* @param prevConfig The previous staking configuration.
* @param newConfig The new staking configuration.
* @param sender The address of the message sender.
*/
event StakingConfigUpdated(StakingConfig prevConfig, StakingConfig newConfig, address indexed sender);
/**
* @notice Emitted when an Unstake or Claim Request is created.
* @param id The ID of the request.
* @param asset The asset of the request.
* @param amount The amount of the requested asset.
* @param sender The address of the message sender.
* @param requestType The type of request.
*/
event RequestCreated(
uint256 indexed id, address indexed asset, uint256 amount, address indexed sender, RequestType requestType
);
/**
* @notice Emitted when an Unstake or Claim Request is cancelled.
* @param id The ID of the request.
*/
event RequestCancelled(uint256 indexed id);
/**
* @notice Emitted when an Unstake or Claim Request is fulfilled.
* @param id The ID of the request.
*/
event RequestFulfilled(uint256 indexed id);
/**
* @notice Emitted when a Reward Token is added.
* @param token The address of the reward token.
* @param sender The address of the message sender.
*/
event RewardTokenAdded(address indexed token, address indexed sender);
/**
* @notice Emitted when a Staking Token is seized.
* @param from The address that is having their tokens seized.
* @param to The address to receive the seized tokens.
* @param amount The amount of tokens seized.
* @param seizedRewards The array of seized reward token amounts.
* @param sender The address of the message sender.
*/
event Seized(
address indexed from, address indexed to, uint256 amount, uint256[] seizedRewards, address indexed sender
);
/**
* Enum ***********************************
*/
/**
* @notice Request type.
*/
enum RequestType {
UNSTAKE,
CLAIM
}
/**
* Structs ***********************************
*/
/**
* @notice Staking Configuration structure. Defines the fees and unstake duration.
* @param unstakeDuration The amount of seconds that must pass before an unstake request is fulfilled.
* @param claimDuration The amount of seconds that must pass before a claim request is fulfilled.
* @param earlyUnstakeFee The fee charged for early unstakes.
* @param earlyClaimFee The fee charged for early claims.
*/
struct StakingConfig {
uint64 unstakeDuration;
uint64 claimDuration;
uint16 earlyUnstakeFee;
uint16 earlyClaimFee;
}
/**
* @notice Request Configuration structure.
* @param hash The ID of the request.
* @param timestamp The timestamp that the request was created at.
* @param amount The amount of the reward token requested.
*/
struct Request {
bytes8 hash;
uint64 timestamp;
uint128 amount;
}
/**
* @notice User Information structure.
* @param stake The amount of tokens the user has staked.
* @param claimable The mapping of reward token to the claimable rewards amount for the user.
* @param debt The mapping of reward token to rewards amount for the user.
*/
struct UserInfo {
uint256 stake; // How many tokens the user has staked
mapping(address => uint256) claimable;
mapping(address => uint256) debt;
}
/**
* @notice Strategy structure. Defines the rewards that are released over a particular amount of time for
* an asset.
* @param startDate The timestamp marking the start of the strategy.
* @param endDate The timestamp marking the end of the strategy.
* @param rewardToken The address of the reward token.
* @param rewardsLocked The amount of locked reward tokens.
* @param rewardsUnlocked The amount of unlocked reward tokens.
*/
struct Strategy {
uint48 startDate;
uint48 endDate;
address rewardToken;
uint128 rewardsLocked;
uint128 rewardsUnlocked;
}
/**
* @notice Returns the Staking Global Admin Role.
* @dev Equivalent to keccak256('Staking.GLOBAL_ADMIN_ROLE').
*/
function GLOBAL_ADMIN_ROLE() external pure returns (bytes32);
/**
* @notice Returns the Staking Local Admin Role.
*/
function LOCAL_ADMIN_ROLE() external view returns (bytes32);
/**
* @notice Returns the Staking Global Seize Role.
* @dev Equivalent to keccak256('Staking.GLOBAL_SEIZE_ROLE').
*/
function GLOBAL_SEIZE_ROLE() external pure returns (bytes32);
/**
* @notice Returns the Staking Local Seize Role.
*/
function LOCAL_SEIZE_ROLE() external view returns (bytes32);
/**
* @notice Returns the Staking Configuration.
*/
function config() external view returns (StakingConfig memory);
/**
* @notice Returns the strategy, given a strategy ID.
* @param id The ID of the strategy.
* @return The strategy with the matching ID.
*/
function strategy(uint256 id) external view returns (Strategy memory);
/**
* @notice Returns the pending strategy, given a strategy ID.
* @param index The ID of the pending strategy.
* @return The pending strategy with the matching ID.
*/
function pendingStrategy(uint256 index) external view returns (Strategy memory);
/**
* @notice Returns the total number of strategies created.
*/
function totalStrategies() external view returns (uint256);
/**
* @notice Returns the total number of pending strategies.
*/
function totalPendingStrategies() external view returns (uint256);
/**
* @notice Returns the total number of staked tokens.
*/
function totalStaked() external view returns (uint256);
/**
* @notice Returns the total number of staking tokens pending unstake.
*/
function totalPendingUnstake() external view returns (uint256);
/**
* @notice Returns the last recorded tokens per share, given a token.
* @param _asset The token to return the tokens per share of.
* @return The tokens per share of `_asset`.
*/
function tps(address _asset) external view returns (uint256);
/**
* @notice Returns the current tokens per share, given a token.
* @param token The token to return the current tokens per share of.
* @param tps_ The current tokens per share of `token`.
*/
function currentTPS(address token) external view returns (uint256 tps_);
/**
* @notice Returns the number of reward tokens.
*/
function totalRewardTokens() external view returns (uint256);
/**
* @notice Returns the address of a reward token, given an index.
* @param index The index of the reward token.
*/
function rewardToken(uint256 index) external view returns (address);
/**
* @notice Returns the address of the staking token.
*/
function stakingToken() external view returns (address);
/**
* @notice Returns the staked balance of an account.
* @param _account The account to return the staked balance of.
* @return The staked balance of the account, denominated in the staking token.
*/
function stakeOf(address _account) external view returns (uint256);
/**
* @notice Returns an Unstake Request, given an account and Request ID.
* @param _account The account to return the Request of.
* @param _id The ID of the request.
* @return The Request with the matching ID.
*/
function unstakeRequest(address _account, uint256 _id) external view returns (Request memory);
/**
* @notice Returns the debt of an account, given an asset.
* @param _account The account to return the debt of.
* @param _asset The asset to return the account's debt of.
* @return The debt of the account, denominated in the asset.
*/
function debt(address _account, address _asset) external view returns (uint256);
/**
* @notice Returns the amount of claimable tokens of an account, given an asset.
* @param _account The account to return the claimable tokens of.
* @param _asset The asset to return the claimable amount of.
* @return The number of claimable tokens.
*/
function claimable(address _account, address _asset) external view returns (uint256);
/**
* @notice Returns the Claim Request of an account, given an asset and Request ID.
* @param _account The account to return the Claim Request of.
* @param _asset The asset to return the Claim Request of.
* @param _id The ID of the Claim Request.
* @return The Claim Request.
*/
function claimRequest(address _account, address _asset, uint256 _id) external view returns (Request memory);
/**
* @notice Initializer for the Staking Contract.
* @param stakingToken_ The address of the staking token.
* @param rewardTokens_ An array of addresses of the reward tokens.
* @custom:emits Initialized
* @custom:requirement `stakingToken_` must be a contract.
* @custom:requirement Each token in `rewardTokens_` must be a contract.
*/
function initialize(address stakingToken_, address[] memory rewardTokens_) external;
/**
* @notice Stakes an amount of staking tokens.
* @param _amount The amount of tokens to stake.
* @custom:emits Staked
* @custom:requirement `_amount` must be greater than zero.
*/
function stake(uint256 _amount) external;
/**
* @notice Creates an Unstake Request. This is required before performing an unstake. Creating an
* unstake request will stop users from earning rewards on the amount that they are unstaking for.
* @param _amount The amount of tokens requested to unstake.
* @custom:emits RequestCreated
* @custom:requirement The stake of the message sender must be greater than or equal to `_amount`.
* @custom:requirement `_amount` must be greater than zero.
* @return _id The ID of the created Unstake Request.
*/
function createUnstakeRequest(uint256 _amount) external returns (uint256 _id);
/**
* @notice Cancels multiple Unstake Requests. Cancelling an unstake will return the staking tokens to
* the contract allowing the user to earn rewards on these tokens again.
* @param _ids An array of Request IDs to cancel the unstake requests for.
* @custom:emits RequestCancelled
* @custom:requirement The length of `_ids` must be greater than zero.
*/
function cancelUnstakeRequests(uint256[] calldata _ids) external;
/**
* @notice Unstakes the input requests, given that the required unstake duration has passed. This unstake has no fees
* associated with the transaction.
* @param _ids An array of Request IDs.
* @custom:emits Unstaked
* @custom:emits RequestFulfilled
* @custom:requirement The difference between the timestamp of the function call and the timestamp of the request creation
* must be greater than or equal to the Unstake required duration.
*/
function unstake(uint256[] calldata _ids) external;
/**
* @notice Unstakes tokens immediately. This incurs a fee to bypass the unstake duration required to unstake.
* @param _amount The number of staking tokens to unstake immediately.
* @custom:emits UnstakedImmediate
* @custom:requirement The staked balance of the message caller must be greater than or equal to `_amount`.
* @custom:requirement `_amount` must be greater than or equal to zero.
*/
function unstakeImmediate(uint256 _amount) external;
/**
* @notice Creates Claim Requests for multiple rewards tokens. This is required before performing a claim.
* @param _assets The array of rewards tokens to create Claim Requests for.
* @custom:emits RequestCreated
* @custom:requirement Each asset in `_assets` must be a valid reward token.
* @custom:requirement The claimable amount for the message sender, for each asset in `_assets` must be greater than zero.
* @return _ids The array of created Claim Requests IDs.
*/
function createClaimRequests(address[] calldata _assets) external returns (uint256[] memory _ids);
/**
* @notice Cancels multiple Claim Requests.
* @param _assets The array of rewards tokens to cancel Claim Requests for.
* @param _ids The 2D array of Request IDs to cancel requests of.
* @custom:emits RequestCancelled
* @custom:requirement The length of `_assets` must be greater than zero.
* @custom:requirement The length of `_ids` must be equal to the length of `_assets`.
*/
function cancelClaimRequests(address[] calldata _assets, uint256[][] calldata _ids) external;
/**
* @notice Claims an amount of reward tokens, provided that each request is ready to be claimed.
* @param _assets The array of rewards tokens to fulfill Claim Requests for.
* @param _ids The 2D array of Request IDs to fulfill requests of.
* @custom:emits Claimed
* @custom:emits RequestFulfilled
* @custom:requirement The length of `_ids` must be equal to the length of `_asset`.
*/
function claim(address[] calldata _assets, uint256[][] calldata _ids) external;
/**
* @notice Claims an amount of reward tokens immediately, bypassing the claim duration in exchange for a fee.
* @param _assets The array of rewards tokens to claim immediately.
* @param _amounts The array of amounts for each reward token to claim immediately.
* @custom:emits ClaimedImmediate
* @custom:requirement The length of `_assets` must be equal to the length of `_amounts`.
* @custom:requirement Each asset in `_assets` must be a valid reward token.
*/
function claimImmediate(address[] calldata _assets, uint256[] calldata _amounts) external;
// ********************************** ADMIN **********************************
/**
* @notice Returns the amount of admin claimable tokens originating from fees.
* @param _asset The asset to return the admin claimable balance of.
* @custom:requirement `_asset` must be a valid reward token.
* @return The amount of admin claimable tokens, denominated in `_asset`.
*/
function adminClaimable(address _asset) external view returns (uint256);
/**
* @notice Adds a reward token to contract. Once a reward token has been added, it cannot be removed.
* @param _asset The asset to add as a reward token.
* @custom:emits RewardTokenAdded
* @custom:requirement `_asset` must not be an existing reward token.
* @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function addRewardToken(address _asset) external;
/**
* @notice Claims the admin claimable amount for a reward token.
* @param _asset The reward token to claim as an admin.
* @param _to The address to send the claimed tokens to.
* @custom:emits AdminClaimed
* @custom:requirement `_asset` must not be an existing reward token.
* @custom:requirement The claimable amount of `_asset` must be greater than zero.
* @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function adminClaim(address _asset, address _to) external;
/**
* @notice Creates a Strategy.
* @param _startDate The timestamp marking the start of the strategy.
* @param _endDate The timestamp marking the end of the strategy.
* @param _rewardToken The address of the reward token.
* @param _rewardAmount The amount of the reward token.
* @custom:emits StrategyCreated
* @custom:requirement `_startDate` must be greater than the timestamp of the function call.
* @custom:requirement `_startDate` must be less than `_endDate`.
* @custom:requirement `_rewardToken` must be a valid existing reward token.
* @custom:requirement `_endDate` must be a valid uint48.
* @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function createStrategy(uint256 _startDate, uint256 _endDate, address _rewardToken, uint256 _rewardAmount)
external;
/**
* @notice Updates the Staking Configuration.
* @param _unstakeDuration The new unstake duration.
* @param _claimDuration The new claim duration.
* @param _earlyUnstakeFee The new early unstake fee.
* @param _earlyClaimFee The new early claim fee.
* @custom:emits StakingConfigUpdated
* @custom:requirement The message sender must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function updateConfig(
uint64 _unstakeDuration,
uint64 _claimDuration,
uint16 _earlyUnstakeFee,
uint16 _earlyClaimFee
) external;
/**
* @notice Seizes staking tokens from `from`.
* @param from The address to have their tokens seized.
* @custom:emits Seized
* @custom:requirement The user's staked balance must be greater than zero.
*/
function seize(address from) external;
}
Initializable.sol 138 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}
AddressUpgradeable.sol 195 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}
draft-IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
Address.sol 222 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
EnumerableSet.sol 367 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
AccessibleUpgradeable.sol 69 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts/access/IAccessControl.sol";
import "../../utils/security/IPausable.sol";
import "../../utils/SomaContractUpgradeable.sol";
import "../ISomaAccessControl.sol";
import "./IAccessible.sol";
/**
* @title SOMA Accessible Upgradeable Contract.
* @author SOMA.finance
*/
abstract contract AccessibleUpgradeable is IAccessible, SomaContractUpgradeable {
/**
* @notice Initializer for extended contracts.
*/
function __Accessible_init() internal onlyInitializing {
__ERC165_init_unchained();
__Context_init_unchained();
__SomaContract_init_unchained();
__Multicall_init_unchained();
__Pausable_init_unchained();
__Accessible_init_unchained();
}
/**
* @notice Unchained initializer for extended contracts.
*/
function __Accessible_init_unchained() internal onlyInitializing {}
/**
* @notice The modifier that restricts a function caller to accounts that have been granted `role`.
* @param role The role that an account must have to execute a function.
*/
modifier onlyRole(bytes32 role) {
require(hasRole(role, _msgSender()), "SomaAccessControl: caller does not have the appropriate authority");
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessible).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IAccessible
*/
// slither-disable-next-line external-function
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return IAccessControlUpgradeable(SOMA.access()).getRoleAdmin(role);
}
/**
* @inheritdoc IAccessible
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return IAccessControlUpgradeable(SOMA.access()).hasRole(role, account);
}
uint256[50] private __gap;
}
ISomaGuard.sol 89 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/**
* @title SOMA Guard Contract.
* @author SOMA.finance
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
* @notice A contract to batch update account privileges.
*/
interface ISomaGuard {
/**
* @notice Emitted when privileges for a 2D array of accounts are updated.
* @param accounts The 2D array of addresses.
* @param privileges The array of privileges.
* @param sender The address of the message sender.
*/
event BatchUpdate(address[][] accounts, bytes32[] privileges, address indexed sender);
/**
* @notice Emitted when privileges for an array of accounts are updated.
* @param accounts The array of addresses.
* @param access The array of privileges.
* @param sender The address of the message sender.
*/
event BatchUpdateSingle(address[] accounts, bytes32[] access, address indexed sender);
/**
* @notice Returns the default privileges of the SomaGuard contract.
* @dev Returns bytes32(uint256(2 ** 64 - 1)).
*/
function DEFAULT_PRIVILEGES() external view returns (bytes32);
/**
* @notice Returns the operator role of the SomaGuard contract.
* @dev Returns keccak256('SomaGuard.OPERATOR_ROLE').
*/
function OPERATOR_ROLE() external view returns (bytes32);
/**
* @notice Returns the privilege of an account.
* @param account The account to return the privilege of.
*/
function privileges(address account) external view returns (bytes32);
/**
* @notice Returns True if an account passes a query, where query is the desired privileges.
* @param account The account to check the privileges of.
* @param query The desired privileges to check for.
*/
function check(address account, bytes32 query) external view returns (bool);
/**
* @notice Returns the privileges for each account.
* @param accounts_ The array of accounts return the privileges of.
* @return privileges_ The array of privileges.
*/
function batchFetch(address[] calldata accounts_) external view returns (bytes32[] memory privileges_);
/**
* @notice Updates the privileges of an array of accounts.
* @param accounts_ The array of addresses to accumulate privileges of.
* @param privileges_ The array of privileges to update the array of accounts with.
* @custom:emits BatchUpdateSingle
* @custom:requirement The length of `accounts_` must be equal to the length of `privileges_`.
* @custom:requirement The length of `accounts_` must be greater than zero.
* @custom:requirement The function caller must have the OPERATOR_ROLE.
* @return True if the batch update was successful.
*/
function batchUpdate(address[] calldata accounts_, bytes32[] calldata privileges_) external returns (bool);
/**
* @notice Updates the privileges of a 2D array of accounts, where the child array of accounts are all assigned to the
* same privileges.
* @param accounts_ The array of addresses to accumulate privileges of.
* @param privileges_ The array of privileges to update the 2D array of accounts with.
* @custom:emits BatchUpdate
* @custom:requirement The length of `accounts_` must be equal to the length of `privileges_`.
* @custom:requirement The length of `accounts_` must be greater than zero.
* @custom:requirement The function caller must have the OPERATOR_ROLE.
* @return True if the batch update was successful.
*/
function batchUpdate(address[][] calldata accounts_, bytes32[] calldata privileges_) external returns (bool);
}
GuardHelper.sol 50 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "./IGuardable.sol";
library GuardHelper {
// 00000000(192 0's repeated)111(64times)
// (64 default on, 192 default off)
bytes32 internal constant DEFAULT_PRIVILEGES = bytes32(uint256(2 ** 64 - 1));
function requiredPrivileges(address account) internal view returns (bytes32 privileges) {
// call to account with no code returns true
// call to account with code and no function returns false
// call to account with code and function returns true
(bool success, bytes memory returndata) =
account.staticcall(abi.encodePacked(IGuardable.requiredPrivileges.selector));
privileges = (success && (account.code.length > 0)) ? bytes32(returndata) : DEFAULT_PRIVILEGES;
}
function check(bytes32 privileges, bytes32 query) internal pure returns (bool) {
return privileges & query == query;
}
function mergePrivileges(bytes32 privileges1, bytes32 privileges2) internal pure returns (bytes32) {
return privileges1 | privileges2;
}
function mergePrivileges(bytes32 privileges1, bytes32 privileges2, bytes32 privileges3)
internal
pure
returns (bytes32)
{
return privileges1 | privileges2 | privileges3;
}
function switchOn(uint256[] memory ids, bytes32 base) internal pure returns (bytes32 result) {
result = base;
for (uint256 i; i < ids.length; ++i) {
result = result | bytes32(2 ** ids[i]);
}
}
function switchOff(uint256[] memory ids, bytes32 base) internal pure returns (bytes32 result) {
result = base;
for (uint256 i; i < ids.length; ++i) {
result = result & bytes32(type(uint256).max - 2 ** ids[i]);
}
}
}
IGuardable.sol 40 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Guardable Upgradeable Contract.
* @author SOMA.finance
* @notice Interface of the {GuardableUpgradeable} contract.
*/
interface IGuardable {
/**
* @notice Emitted when the required privileges are updated.
* @param prevPrivileges The previous required privileges.
* @param newPrivileges The new required privileges.
* @param sender The message sender that triggered the event.
*/
event RequiredPrivilegesUpdated(bytes32 prevPrivileges, bytes32 newPrivileges, address indexed sender);
/**
* @notice Returns a boolean indicating if `account` has the required privileges.
* @param account The account to check against the required privileges.
* @return True if `account` has the required privileges, False otherwise.
*/
function hasPrivileges(address account) external view returns (bool);
/**
* @notice Returns the required privileges.
*/
function requiredPrivileges() external view returns (bytes32);
/**
* @notice Updates the required privileges.
* @param newRequiredPrivileges The new required privileges.
* @custom:emits RequiredPrivilegesUpdated
* @custom:requirement The message sender must have either the LOCAL_UPDATE_PRIVILEGES_ROLE or the
* GLOBAL_UPDATE_PRIVILEGES_ROLE role.
* @return True if the update was successful.
*/
function updateRequiredPrivileges(bytes32 newRequiredPrivileges) external returns (bool);
}
IAccessControlUpgradeable.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with 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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
IAccessControl.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
IPausable.sol 11 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IPausable {
function paused() external view returns (bool);
function pause() external;
function unpause() external;
}
SomaContractUpgradeable.sol 60 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
import "../ISOMA.sol";
import "../SOMAlib.sol";
import "./ISomaContract.sol";
contract SomaContractUpgradeable is ISomaContract, PausableUpgradeable, ERC165Upgradeable, MulticallUpgradeable {
function __SomaContract_init() internal onlyInitializing {
__ERC165_init_unchained();
__Context_init_unchained();
__SomaContract_init_unchained();
__Multicall_init_unchained();
__Pausable_init_unchained();
}
function __SomaContract_init_unchained() internal onlyInitializing {}
ISOMA public immutable override SOMA = SOMAlib.SOMA;
modifier onlyMaster() {
address sender = _msgSender();
require(SOMA.master() == sender, "SOMA: MASTER");
_;
}
modifier onlyMasterOrSubMaster() {
address sender = _msgSender();
require(SOMA.master() == sender || SOMA.subMaster() == sender, "SOMA: MASTER or SUB MASTER only");
_;
}
function pause() external virtual override onlyMasterOrSubMaster {
_pause();
}
function unpause() external virtual override onlyMasterOrSubMaster {
_unpause();
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ISomaContract).interfaceId || super.supportsInterface(interfaceId);
}
function paused() public view virtual override returns (bool) {
return PausableUpgradeable(address(SOMA)).paused() || super.paused();
}
uint256[50] private __gap;
}
ISomaAccessControl.sol 21 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Access Control Contract.
* @author SOMA.finance.
* @notice An access control contract that establishes a hierarchy of accounts and controls
* function call permissions.
*/
interface ISomaAccessControl {
/**
* @notice Sets the admin of a role.
* @dev Sets the admin for the `role` role.
* @param role The role to set the admin role of.
* @param adminRole The admin of `role`.
* @custom:emits RoleAdminChanged
* @custom:requirement The function caller must have the DEFAULT_ADMIN_ROLE.
*/
function setRoleAdmin(bytes32 role, bytes32 adminRole) external;
}
IAccessible.sol 25 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Accessible Contract.
* @author SOMA.finance
* @notice Interface of the {Accessible} contract.
*/
interface IAccessible {
/**
* @notice Returns the role admin, given a role.
* @param role The role to return the admin of.
* @return The admin of the role.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @notice Returns a boolean indicating if `account` has been granted `role`.
* @param role The role to check against `account`.
* @param account The account to check against `role`.
* @return True if `account` has been granted `role`, False otherwise.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
}
ERC165Upgradeable.sol 42 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
PausableUpgradeable.sol 117 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
MulticallUpgradeable.sol 51 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
pragma solidity ^0.8.0;
import "./AddressUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
abstract contract MulticallUpgradeable is Initializable {
function __Multicall_init() internal onlyInitializing {
}
function __Multicall_init_unchained() internal onlyInitializing {
}
/**
* @dev Receives and executes a batch of function calls on this contract.
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = _functionDelegateCall(address(this), data[i]);
}
return results;
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
ISOMA.sol 170 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./SomaAccessControl/ISomaAccessControl.sol";
import "./SomaSwap/periphery/ISomaSwapRouter.sol";
import "./SomaSwap/core/interfaces/ISomaSwapFactory.sol";
import "./SomaGuard/ISomaGuard.sol";
import "./TemplateFactory/ITemplateFactory.sol";
import "./Lockdrop/ILockdropFactory.sol";
/**
* @title SOMA Contract.
* @author SOMA.finance
* @notice Interface of the SOMA contract.
*/
interface ISOMA {
/**
* @notice Emitted when the SOMA snapshot is updated.
* @param version The version of the new snapshot.
* @param hash The hash of the new snapshot.
* @param snapshot The new snapshot.
*/
event SOMAUpgraded(bytes32 indexed version, bytes32 indexed hash, bytes snapshot);
/**
* @notice Emitted when the `seizeTo` address is updated.
* @param prevSeizeTo The address of the previous `seizeTo`.
* @param newSeizeTo The address of the new `seizeTo`.
* @param sender The address of the message sender.
*/
event SeizeToUpdated(address indexed prevSeizeTo, address indexed newSeizeTo, address indexed sender);
/**
* @notice Emitted when the `mintTo` address is updated.
* @param prevMintTo The address of the previous `mintTo`.
* @param newMintTo The address of the new `mintTo`.
* @param sender The address of the message sender.
*/
event MintToUpdated(address indexed prevMintTo, address indexed newMintTo, address indexed sender);
/**
* @notice Snapshot of the SOMA contracts.
* @param master The master address.
* @param subMaster The subMaster address.
* @param access The ISomaAccessControl contract.
* @param guard The ISomaGuard contract.
* @param factory The ITemplateFactory contract.
* @param token The IERC20 contract.
*/
struct Snapshot {
address master;
address subMaster;
address access;
address guard;
address factory;
address token;
}
/**
* @notice Returns the address that has been assigned the master role.
*/
function master() external view returns (address);
/**
* @notice Returns the address that has been assigned the subMaster role.
*/
function subMaster() external view returns (address);
/**
* @notice Returns the address of the {ISomaAccessControl} contract.
*/
function access() external view returns (address);
/**
* @notice Returns the address of the {ISomaGuard} contract.
*/
function guard() external view returns (address);
/**
* @notice Returns the address of the {ITemplateFactory} contract.
*/
function factory() external view returns (address);
/**
* @notice Returns the address of the {IERC20} contract.
*/
function token() external view returns (address);
/**
* @notice Returns the hash of the latest snapshot.
*/
function snapshotHash() external view returns (bytes32);
/**
* @notice Returns the latest snapshot version.
*/
function snapshotVersion() external view returns (bytes32);
/**
* @notice Returns the snapshot, given a snapshot hash.
* @param hash The snapshot hash.
* @return _snapshot The snapshot matching the `hash`.
*/
function snapshots(bytes32 hash) external view returns (bytes memory _snapshot);
/**
* @notice Returns the hash when given a version, returns a version when given a hash.
* @param versionOrHash The version or hash.
* @return hashOrVersion The hash or version based on the input.
*/
function versions(bytes32 versionOrHash) external view returns (bytes32 hashOrVersion);
/**
* @notice Returns the address that receives all minted tokens.
*/
function mintTo() external view returns (address);
/**
* @notice Returns the address that receives all seized tokens.
*/
function seizeTo() external view returns (address);
/**
* @notice Updates the current SOMA snapshot and is called after the proxy has been upgraded.
* @param version The version to upgrade to.
* @custom:emits SOMAUpgraded
* @custom:requirement The incoming snapshot hash cannot be equal to the contract's existing snapshot hash.
*/
function __upgrade(bytes32 version) external;
/**
* @notice Triggers the SOMA paused state. Pauses all the SOMA contracts.
* @custom:emits Paused
* @custom:requirement SOMA must be already unpaused.
* @custom:requirement The caller must be the master or subMaster.
*/
function pause() external;
/**
* @notice Triggers the SOMA unpaused state. Unpauses all the SOMA contracts.
* @custom:emits Unpaused
* @custom:requirement SOMA must be already paused.
* @custom:requirement The caller must be the master or subMaster.
*/
function unpause() external;
/**
* @notice Sets the `mintTo` address to `_mintTo`.
* @param _mintTo The address to be set as the `mintTo` address.
* @custom:emits MintToUpdated
* @custom:requirement The caller must be the master.
*/
function setMintTo(address _mintTo) external;
/**
* @notice Sets the `seizeTo` address to `_seizeTo`.
* @param _seizeTo The address to be set as the `seizeTo` address.
* @custom:emits SeizeToUpdated
* @custom:requirement The caller must be the master.
*/
function setSeizeTo(address _seizeTo) external;
/**
* @notice Returns the current snapshot of the SOMA contracts.
*/
function snapshot() external view returns (Snapshot memory _snapshot);
}
SOMAlib.sol 12 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.18;
import "./ISOMA.sol";
library SOMAlib {
/**
* @notice The fixed address where the SOMA contract will be located (this is a proxy).
*/
ISOMA public constant SOMA = ISOMA(0x0F3dC00189dbCD1D0c574e48031270cAe04C4ADF);
}
ISomaContract.sol 12 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "../ISOMA.sol";
interface ISomaContract {
function pause() external;
function unpause() external;
function SOMA() external view returns (ISOMA);
}
IERC165Upgradeable.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
ISomaSwapRouter.sol 483 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/**
* @title SOMA Swap Router Contract.
* @author SOMA.finance
* @notice Interface for the {SomaSwapRouter} contract.
*/
interface ISomaSwapRouter {
/**
* @notice Returns the address of the factory contract.
*/
function factory() external view returns (address);
/**
* @notice Returns the address of the WETH token.
*/
function WETH() external view returns (address);
/**
* @notice Adds liquidity to the pool.
* @param tokenA The token0 of the pair to add liquidity to.
* @param tokenB The token1 of the pair to add liquidity to.
* @param amountADesired The amount of token0 to add as liquidity.
* @param amountBDesired The amount of token1 to add as liquidity.
* @param amountAMin The bound of the tokenB / tokenA price can go up
* before transaction reverts.
* @param amountBMin The bound of the tokenA / tokenB price can go up
* before transaction reverts.
* @param to The address to receive the liquidity tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement `tokenA` and `tokenB` pair must already exist.
* @custom:requirement the router's expiration deadline must be greater than the timestamp of the
* function call
* @return amountA The amount of tokenA added as liquidity.
* @return amountB The amount of tokenB added as liquidity.
* @return liquidity The amount of liquidity tokens minted.
*/
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
/**
* @notice Adds liquidity to the pool with ETH.
* @param token The pool token.
* @param amountTokenDesired The amount of token to add as liquidity if WETH/token price
* is less or equal to the value of msg.value/amountTokenDesired (token depreciates).
* @param amountTokenMin The bound that WETH/token price can go up before the transactions
* reverts.
* @param amountETHMin The bound that token/WETH price can go up before the transaction reverts.
* @param to The recipient of the liquidity tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement `tokenA` and `tokenB` pair must already exist.
* @custom:requirement the router's expiration deadline must be greater than the timestamp of the
* function call
* @return amountToken The amount of token sent to the pool.
* @return amountETH The amount of ETH converted to WETH and sent to the pool.
* @return liquidity The amount of liquidity tokens minted.
*/
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
/**
* @notice Removes liquidity from the pool.
* @param tokenA The pool token.
* @param tokenB The pool token.
* @param liquidity The amount of liquidity tokens to remove.
* @param amountAMin The minimum amount of tokenA that must be received
* for the transaction not to revert.
* @param amountBMin The minimum amount of tokenB that must be received
* for the transaction not to revert.
* @param to The recipient of the underlying asset.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement `amountA` must be greater than or equal to `amountAMin`.
* @custom:requirement `amountB` must be greater than or equal to `amountBMin`.
* @return amountA The amount of tokenA received.
* @return amountB The amount of tokenB received.
*/
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
/**
* @notice Removes liquidity from the pool and the caller receives ETH.
* @param token The pool token.
* @param liquidity The amount of liquidity tokens to remove.
* @param amountTokenMin The minimum amount of tokens that must be received
* for the transaction not to revert.
* @param amountETHMin The minimum amount of ETH that must be received for the
* transaction not to revert.
* @param to The recipient of the underlying assets.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement `amountA` must be greater than or equal to `amountAMin`.
* @custom:requirement `amountB` must be greater than or equal to `amountBMin`.
* @return amountToken The amount of token received.
* @return amountETH The amount of ETH received.
*/
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
/**
* @notice Removes liquidity from the pool without pre-approval.
* @param tokenA The pool token0.
* @param tokenB The pool token1.
* @param liquidity The amount of liquidity to remove.
* @param amountAMin The minimum amount of tokenA that must be received for the
* transaction not to revert.
* @param amountBMin The minimum amount of tokenB that must be received for the
* transaction not to revert.
* @param to The recipient of the underlying asset.
* @param deadline The unix timestamp after which the transaction will revert.
* @param approveMax Boolean value indicating if the approval amount in the signature
* is for liquidity or uint(-1).
* @param v The v component of the permit signature.
* @param r The r component of the permit signature.
* @param s The s component of the permit signature.
* @custom:requirement `amountA` must be greater than or equal to `amountAMin`.
* @custom:requirement `amountB` must be greater than or equal to `amountBMin`.
* @return amountA The amount of tokenA received.
* @return amountB The amount of tokenB received.
*/
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
/**
* @notice Removes liquidity from the pool and the caller receives ETH without pre-approval.
* @param token The pool token.
* @param liquidity The amount of liquidity to remove.
* @param amountTokenMin The minimum amount of token that must be received for the transaction
* not to revert.
* @param amountETHMin The minimum amount of ETH that must be received for the transaction not
* to revert.
* @param to The recipient of the underlying asset.
* @param deadline The unix timestamp after which the transaction will revert.
* @param approveMax Boolean value indicating if the approval amount in the signature
* is for liquidity or uint(-1).
* @param v The v component of the permit signature.
* @param r The r component of the permit signature.
* @param s The s component of the permit signature.
* @return amountToken The amount fo token received.
* @return amountETH The amount of ETH received.
*/
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
/**
* @notice Swaps an exact amount of input tokens for as many output tokens as possible, along
* with the route determined by the path.
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction
* not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The value at the last index of `amounts` (from `SomaSwapLibrary.getAmountsOut()`) must be greater than or equal to `amountOutMin`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/**
* @notice Caller receives an exact amount of output tokens for as few input input tokens as possible, along
* with the route determined by the path.
* @param amountOut The amount of output tokens to receive.
* @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The value of the first index of `amounts` (from `SomaSwapLibrary.getAmountsIn()`) must be less than or equal to `amountInMax`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/**
* @notice Swaps an exact amount of ETH for as many output tokens as possible, along with the route
* determined by the path.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The first element of `path` must be equal to the WETH address.
* @custom:requirement The last element of `amounts` (from `SomaSwapLibrary.getAmountsOut()`) must be greater than or equal to `amount0Min`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
/**
* @notice Caller receives an exact amount of ETH for as few input tokens as possible, along with the route
* determined by the path.
* @param amountOut The amount of ETH to receive.
* @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The last element of `path` must be equal to the WETH address.
* @custom:requirement The first element of `amounts` (from `SomaSwapLibrary.getAmountsIn()`) must be less than or equal to `amountInMax`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/**
* @notice Swaps an exact amount of tokens for as much ETH as possible, along with the route determined
* by the path.
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The last element of `path` must be equal to the WETH address.
* @custom:requirement The last element of `amounts` (from `SomaSwapLibrary.getAmountsOut()`) must be greater than or
* equal to `amountOutMin`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
/**
* @notice Caller receives an exact amount of tokens for as little ETH as possible, along with the route determined
* by the path.
* @param amountOut The amount of tokens to receive.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The first element of `path` must be equal to the WETH address.
* @custom:requirement The first element of `amounts` (from `SomaSwapLibrary.getAmountIn()`) must be less than or equal
* to the `msg.value`.
* @return amounts The input token amount and all subsequent output token amounts.
*/
function swapETHForExactTokens(uint256 amountOut, address[] calldata path, address to, uint256 deadline)
external
payable
returns (uint256[] memory amounts);
/**
* @notice Given some asset amount and reserves, returns the amount of the other asset representing equivalent value.
* @param amountA The amount of token0.
* @param reserveA The reserves of token0.
* @param reserveB The reserves of token1.
* @custom:requirement `amountA` must be greater than zero.
* @custom:requirement `reserveA` must be greater than zero.
* @custom:requirement `reserveB` must be greater than zero.
* @return amountB The amount of token1.
*/
function quote(uint256 amountA, uint256 reserveA, uint256 reserveB) external pure returns (uint256 amountB);
/**
* @notice Given some asset amount and reserves, returns the maximum output amount of the other asset (accounting for fees).
* @param amountIn The amount of the input token.
* @param reserveIn The reserves of the input token.
* @param reserveOut The reserves of the output token.
* @custom:requirement `amountIn` must be greater than zero.
* @custom:requirement `reserveIn` must be greater than zero.
* @custom:requirement `reserveOut` must be greater than zero.
* @return amountOut The amount of the output token.
*/
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut)
external
pure
returns (uint256 amountOut);
/**
* @notice Returns the minimum input asset amount required to buy the given output asset amount (accounting for fees).
* @param amountOut The amount of the output token.
* @param reserveIn The reserves of the input token.
* @param reserveOut The reserves of the output token.
* @custom:requirement `amountOut` must be greater than zero.
* @custom:requirement `reserveIn` must be greater than zero.
* @custom:requirement `reserveOut` must be greater than zero.
* @return amountIn The required input amount of the input asset.
*/
function getAmountIn(uint256 amountOut, uint256 reserveIn, uint256 reserveOut)
external
pure
returns (uint256 amountIn);
/**
* @notice Given an input asset amount and an array of token addresses, calculates all subsequent maximum output token amounts
* calling `getReserves()` for each pair of token addresses in the path in turn, and using these to call `getAmountOut()`.
* @param amountIn The amount of the input token.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @custom:requirement `path` length must be greater than or equal to 2.
* @return amounts The maximum output amounts.
*/
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
/**
* @notice Given an output asset amount and an array of token addresses, calculates all preceding minimum input token amounts
* by calling `getReserves()` for each pair of token addresses in the path in turn, and using these to call `getAmountIn()`.
* @param amountOut The amount of the output token.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @custom:requirement `path` length must be greater than or equal to 2.
* @return amounts The required input amounts.
*/
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
/**
* @notice See {ISomaSwapRouter-removeLiquidityETH} - Identical but succeeds for tokens that take a fee on transfer.
* @param token The pool token.
* @param liquidity The amount of liquidity tokens to remove.
* @param amountTokenMin The minimum amount of token that must be received for the transaction not to revert.
* @param amountETHMin The minimum amount of ETH that must be received for the transaction not to revert.
* @param to Recipient of the underlying assets.
* @param deadline Unix timestamp after which the transaction will revert.
* @custom:requirement There must be enough liquidity for both token amounts to be removed.
* @return amountETH The amount of ETH received.
*/
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
/**
* @notice See {ISomaSwapRouter-removeLiquidityETHWithPermit} - Identical but succeeds for tokens that take a fee on transfer.
* @param token The pool token.
* @param liquidity The amount of liquidity tokens to remove.
* @param amountTokenMin The minimum amount of token that must be received for the transaction not to revert.
* @param amountETHMin The minimum amount of ETH that must be received for the transaction not to revert.
* @param to The recipient of the underlying assets.
* @param deadline The unix timestamp after which the transaction will revert.
* @param approveMax Whether or not the approval amount in the signature is for liquidity or uint(-1).
* @param v The v component of the permit signature.
* @param r The r component of the permit signature.
* @param s The s component of the permit signature.
* @custom:requirement There must be enough liquidity for both token amounts to be removed.
* @return amountETH The amount of ETH received.
*/
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
/**
* @notice See {ISomaSwapRouter-swapExactTokensForTokens} - Identical but succeeds for tokens that take a fee on transfer.
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the underlying assets.
* @param deadline The unix timestamp after which the transaction will revert.
*/
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
/**
* @notice See {ISomaSwapRouter-swapExactETHForTokens} - Identical but succeeds for tokens that take a fee on transfer.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The first element of `path` must be equal to the WETH address.
* @custom:requirement The increase in balance of the last element of `path` for the `to` address must be greater than
* or equal to `amountOutMin`.
*/
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
/**
* @notice See {ISomaSwapRouter-swapExactTokensForETH} - Identical but succeeds for tokens that take a fee on transfer.
* @param amountIn The amount of input tokens to send.
* @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
* @param path The array of token addresses, where pools for each pair of addresses must exist and
* have liquidity.
* @param to The recipient of the output tokens.
* @param deadline The unix timestamp after which the transaction will revert.
* @custom:requirement The last element of `path` must be equal to the WETH address.
* @custom:requirement The WETH balance of the router must be greater than or equal to `amountOutMin`.
*/
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
ISomaSwapFactory.sol 131 lines
// SPDX-License-Identifier: MIT
pragma solidity =0.8.18;
/**
* @title SOMA Swap Factory Contract.
* @author SOMA.finance
* @notice Interface for the {SomaSwapFactory} contract.
*/
interface ISomaSwapFactory {
/**
* @notice Emitted when a pair is created via `createPair()`.
* @param token0 The address of token0.
* @param token1 The address of token1.
* @param pair The address of the created pair.
*/
event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
/**
* @notice Emitted when the `feeTo` address is updated from `prevFeeTo` to `newFeeTo` by `sender`.
* @param prevFeeTo The address of the previous fee to.
* @param prevFeeTo The address of the new fee to.
* @param sender The address of the message sender.
*/
event FeeToUpdated(address indexed prevFeeTo, address indexed newFeeTo, address indexed sender);
/**
* @notice Emitted when a router is added by `sender`.
* @param router The address of the router added.
* @param sender The address of the message sender.
*/
event RouterAdded(address indexed router, address indexed sender);
/**
* @notice Emitted when a router is removed by `sender`.
* @param router The address of the router removed.
* @param sender The address of the message sender.
*/
event RouterRemoved(address indexed router, address indexed sender);
/**
* @notice Returns SOMA Swap Factory Create Pair Role.
* @dev Returns `keccak256('SomaSwapFactory.CREATE_PAIR_ROLE')`.
*/
function CREATE_PAIR_ROLE() external pure returns (bytes32);
/**
* @notice Returns SOMA Swap Factory Fee Setter Role.
* @dev Returns `keccak256('SomaSwapFactory.FEE_SETTER_ROLE')`.
*/
function FEE_SETTER_ROLE() external pure returns (bytes32);
/**
* @notice Returns SOMA Swap Factory Manage Router Role.
* @dev Returns `keccak256('SomaSwapFactory.MANAGE_ROUTER_ROLE')`.
*/
function MANAGE_ROUTER_ROLE() external pure returns (bytes32);
/**
* @notice Returns the address where fees from the exchange get transferred to.
*/
function feeTo() external view returns (address);
/**
* @notice Returns the address of the pair contract for tokenA and tokenB if it exists, else returns address(0).
* @dev Returns the address of the pair for `tokenA` and `tokenB` if it exists, else returns `address(0)`.
* @param tokenA The token0 of the pair.
* @param tokenB The token1 of the pair.
* @return pair The address of the pair.
*/
function getPair(address tokenA, address tokenB) external view returns (address pair);
/**
* @notice Returns the nth pair created through the factory, or address(0).
* @dev Returns the `n-th` pair (0 indexed) created through the factory, or `address(0)`.
* @return pair The address of the pair.
*/
function allPairs(uint256) external view returns (address pair);
/**
* @notice Returns the total number of pairs created through the factory so far.
*/
function allPairsLength() external view returns (uint256);
/**
* @notice Returns True if an address is an existing router, else returns False.
* @param target The address to return true if it an existing router, or false if it is not.
* @return Boolean value indicating if the address is an existing router.
*/
function isRouter(address target) external view returns (bool);
/**
* @notice Adds an address as a new router. A router is able to tell a pair who is swapping.
* @param router The address to add as a new router.
* @custom:emits RouterAdded
* @custom:requirement The function caller must have the MANAGE_ROUTER_ROLE.
*/
function addRouter(address router) external;
/**
* @notice Removes an address from the list of routers. A router is able to tell a pair who is swapping.
* @param router The address to remove from the list of routers.
* @custom:emits RouterRemoved
* @custom:requirement The function caller must have the MANAGE_ROUTER_ROLE.
*/
function removeRouter(address router) external;
/**
* @notice Creates a new pair.
* @dev Creates a pair for `tokenA` and `tokenB` if one does not exist already.
* @param tokenA The address of token0 of the pair.
* @param tokenB The address of token1 of the pair.
* @custom:emits PairCreated
* @custom:requirement The function caller must have the CREATE_PAIR_ROLE.
* @custom:requirement `tokenA` must not be equal to `tokenB`.
* @custom:requirement `tokenA` must not be equal to `address(0)`.
* @custom:requirement `tokenA` and `tokenB` must not be an existing pair.
* @custom:requirement The system must not be paused.
* @return pair The address of the pair created.
*/
function createPair(address tokenA, address tokenB) external returns (address pair);
/**
* @notice Sets a new `feeTo` address.
* @param _feeTo The new address to receive the protocol fees.
* @custom:emits FeeToUpdated
* @custom:requirement The function caller must have the FEE_SETTER_ROLE.
* @custom:requirement The system must not be paused.
*/
function setFeeTo(address _feeTo) external;
}
ITemplateFactory.sol 357 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/**
* @title SOMA Template Factory Contract.
* @author SOMA.finance.
* @notice Interface of the {TemplateFactory} contract.
*/
interface ITemplateFactory {
/**
* @notice Emitted when a template version is created.
* @param templateId The ID of the template added.
* @param version The version of the template.
* @param implementation The address of the implementation of the template.
* @param sender The address of the message sender.
*/
event TemplateVersionCreated(
bytes32 indexed templateId, uint256 indexed version, address implementation, address indexed sender
);
/**
* @notice Emitted when a deploy role is updated.
* @param templateId The ID of the template with the updated deploy role.
* @param prevRole The previous role.
* @param newRole The new role.
* @param sender The address of the message sender.
*/
event DeployRoleUpdated(bytes32 indexed templateId, bytes32 prevRole, bytes32 newRole, address indexed sender);
/**
* @notice Emitted when a template is enabled.
* @param templateId The ID of the template.
* @param sender The address of the message sender.
*/
event TemplateEnabled(bytes32 indexed templateId, address indexed sender);
/**
* @notice Emitted when a template is disabled.
* @param templateId The ID of the template.
* @param sender The address of the message sender.
*/
event TemplateDisabled(bytes32 indexed templateId, address indexed sender);
/**
* @notice Emitted when a template version is deprecated.
* @param templateId The ID of the template.
* @param version The version of the template deprecated.
* @param sender The address of the message sender.
*/
event TemplateVersionDeprecated(bytes32 indexed templateId, uint256 indexed version, address indexed sender);
/**
* @notice Emitted when a template version is undeprecated.
* @param templateId The ID of the template.
* @param version The version of the template undeprecated.
* @param sender The address of the message sender.
*/
event TemplateVersionUndeprecated(bytes32 indexed templateId, uint256 indexed version, address indexed sender);
/**
* @notice Emitted when a template is deployed.
* @param instance The instance of the deployed template.
* @param templateId The ID of the template.
* @param version The version of the template.
* @param args The abi-encoded constructor arguments.
* @param functionCalls The abi-encoded function calls.
* @param sender The address of the message sender.
*/
event TemplateDeployed(
address indexed instance,
bytes32 indexed templateId,
uint256 version,
bytes args,
bytes[] functionCalls,
address indexed sender
);
/**
* @notice Emitted when a template is cloned.
* @param instance The instance of the deployed template.
* @param templateId The ID of the template.
* @param version The version of the template.
* @param functionCalls The abi-encoded function calls.
* @param sender The address of the message sender.
*/
event TemplateCloned(
address indexed instance,
bytes32 indexed templateId,
uint256 version,
bytes[] functionCalls,
address indexed sender
);
/**
* @notice Emitted when a template function is called.
* @param target The address of the target contract.
* @param data The abi-encoded data.
* @param result The abi-encoded result.
* @param sender The address of the message sender.
*/
event FunctionCalled(address indexed target, bytes data, bytes result, address indexed sender);
/**
* @notice Structure of a template version.
* @param exists True if the version exists, False if it does not.
* @param deprecated True if the version is deprecated, False if it is not.
* @param implementation The address of the version's implementation.
* @param creationCode The abi-encoded creation code.
* @param totalParts The total number of parts of the version.
* @param partsUploaded The number of parts uploaded.
* @param instances The array of instances.
*/
struct Version {
bool deprecated;
address implementation;
bytes creationCode;
uint256 totalParts;
uint256 partsUploaded;
address[] instances;
}
/**
* @notice Structure of a template.
* @param disabled Boolean value indicating if the template is enabled.
* @param latestVersion The latest version of the template.
* @param deployRole The deployer role of the template.
* @param version The versions of the template.
* @param instances The instances of the template.
*/
struct Template {
bool disabled;
bytes32 deployRole;
Version[] versions;
address[] instances;
}
/**
* @notice Structure of deployment information.
* @param exists Boolean value indicating if the deployment information exists.
* @param templateId The id of the template.
* @param version The version of the template.
* @param args The abi-encoded arguments.
* @param functionCalls The abi-encoded function calls.
* @param cloned Boolean indicating if the deployment information is cloned.
*/
struct DeploymentInfo {
bool exists;
uint64 block;
uint64 timestamp;
address sender;
bytes32 templateId;
uint256 version;
bytes args;
bytes[] functionCalls;
bool cloned;
}
/**
* @notice Returns a version of a template.
* @param templateId The id of the template to return the version of.
* @param _version The version of the template to be returned.
* @return The version of the template.
*/
function version(bytes32 templateId, uint256 _version) external view returns (Version memory);
/**
* @notice Returns the latest version of a template.
* @param templateId The id of the template to return the latest version of.
* @return The latest version of the template.
*/
function latestVersion(bytes32 templateId) external view returns (uint256);
/**
* @notice Returns the instances of a template.
* @param templateId The id of the template to return the latest instance of.
* @return The instances of the template.
*/
function templateInstances(bytes32 templateId) external view returns (address[] memory);
/**
* @notice Returns the deployment information of an instance.
* @param instance The instance of the template to return deployment information of.
* @return The deployment information of the template.
*/
function deploymentInfo(address instance) external view returns (DeploymentInfo memory);
/**
* @notice Returns the deploy role of a template.
* @param templateId The id of the template to return the deploy role of.
* @return The deploy role of the template.
*/
function deployRole(bytes32 templateId) external view returns (bytes32);
/**
* @notice Returns True if an instance has been deployed by the template factory, else returns False.
* @dev Returns `true` if `instance` has been deployed by the template factory, else returns `false`.
* @param instance The instance of the template to return True for, if it has been deployed by the factory, else False.
* @return Boolean value indicating if the instance has been deployed by the template factory.
*/
function deployedByFactory(address instance) external view returns (bool);
/**
* @notice Uploads a new template and returns True.
* @param templateId The id of the template to upload.
* @param initialPart The initial part to upload.
* @param totalParts The number of total parts of the template.
* @param implementation The address of the implementation of the template.
* @custom:emits TemplateVersionCreated
* @custom:requirement `templateId` must not be equal to bytes32(0).
* @custom:requirement The length of `initialPart` must be greater than zero.
* @custom:requirement `totalParts` must be greater than zero.
*/
function uploadTemplate(bytes32 templateId, bytes memory initialPart, uint256 totalParts, address implementation)
external
returns (bool);
/**
* @notice Uploads a part of a template.
* @param templateId The id of the template to upload a part to.
* @param version The version of the template to upload a part to.
* @param part The part to upload to the template.
* @custom:requirement The length of part must be greater than zero.
* @custom:requirement The version of the template must already exist.
* @custom:requirement The version's number of parts uploaded must be less than the version's total number of parts.
* @return Boolean value indicating if the operation was successful.
*/
function uploadTemplatePart(bytes32 templateId, uint256 version, bytes memory part) external returns (bool);
/**
* @notice Updates the deploy role of a template.
* @param templateId The id of the template to update the deploy role for.
* @param _deployRole The deploy role to update to.
* @custom:emits DeployRoleUpdated
* @custom:requirement The template's existing deploy role cannot be equal to `deployRole`.
* @return Boolean value indicating if the operation was successful.
*/
function updateDeployRole(bytes32 templateId, bytes32 _deployRole) external returns (bool);
/**
* @notice Disables a template and returns True.
* @dev Disables a template and returns `true`.
* @param templateId The id of the template to disable.
* @custom:emits TemplateDisabled
* @custom:requirement The template must be enabled when the function call is made.
* @return Boolean value indicating if the operation was successful.
*/
function disableTemplate(bytes32 templateId) external returns (bool);
/**
* @notice Enables a template and returns True.
* @dev Enables a template and returns `true`.
* @param templateId The id of the template to enable.
* @custom:emits TemplateEnabled
* @custom:requirement The template must be disabled when the function call is made.
* @return Boolean value indicating if the operation was successful.
*/
function enableTemplate(bytes32 templateId) external returns (bool);
/**
* @notice Deprecates a version of a template. A deprecated template version cannot be deployed.
* @param templateId The id of the template to deprecate the version for.
* @param _version The version of the template to deprecate.
* @custom:emits TemplateVersionDeprecated
* @custom:requirement The version must already exist.
* @custom:requirement The version must not be deprecated already.
* @return Boolean value indicating if the operation was successful.
*/
function deprecateVersion(bytes32 templateId, uint256 _version) external returns (bool);
/**
* @notice Undeprecates a version of a template and returns True.
* @param templateId The id of the template to undeprecate a version for.
* @param _version The version of a template to undeprecate.
* @custom:emits TemplateVersionUndeprecated
* @custom:requirement The version must be deprecated already.
* @return Boolean value indicating if the operation was successful.
*/
function undeprecateVersion(bytes32 templateId, uint256 _version) external returns (bool);
/**
* @notice Returns the Init Code Hash.
* @dev Returns the keccak256 hash of `templateId`, `version` and `args`.
* @param templateId The id of the template to return the init code hash of.
* @param _version The version of the template to return the init code hash of.
* @param args The abi-encoded constructor arguments.
* @return The abi-encoded init code hash.
*/
function initCodeHash(bytes32 templateId, uint256 _version, bytes memory args) external view returns (bytes32);
/**
* @notice Overloaded predictDeployAddress function.
* @dev See {ITemplateFactory-predictDeployAddress}.
* @param templateId The id of the template to predict the deploy address for.
* @param _version The version of the template to predict the deploy address for.
* @param args The abi-encoded constructor arguments.
* @param salt The unique hash ot identify the contract.
*/
function predictDeployAddress(bytes32 templateId, uint256 _version, bytes memory args, bytes32 salt)
external
view
returns (address);
/**
* @notice Predict the clone address.
* @param templateId The id of the template to predict the clone address for.
* @param _version The version of the template to predict the clone address for.
* @param salt The unique hash ot identify the contract.
* @return The predicted clone address.
*/
function predictCloneAddress(bytes32 templateId, uint256 _version, bytes32 salt) external view returns (address);
/**
* @notice Deploys a version of a template.
* @param templateId The id of the template to deploy.
* @param _version The version of the template to deploy.
* @param args The abi-encoded constructor arguments.
* @param functionCalls The abi-encoded function calls.
* @param salt The unique hash to identify the contract.
* @custom:emits TemplateDeployed
* @custom:requirement The version's number of parts must be equal to the version's number of parts uploaded.
* @custom:requirement The length of the version's creation code must be greater than zero.
* @return instance The instance of the deployed template.
*/
function deployTemplate(
bytes32 templateId,
uint256 _version,
bytes memory args,
bytes[] memory functionCalls,
bytes32 salt
) external returns (address instance);
/**
* @notice Clones a version of a template.
* @param templateId The id of the template to clone.
* @param _version The version of the template to clone.
* @param functionCalls The abi-encoded function calls.
* @param salt The unique hash to identify the contract.
* @custom:emits TemplateCloned
* @custom:requirement The version's implementation must not equal `address(0)`.
* @return instance The address of the cloned template instance.
*/
function cloneTemplate(bytes32 templateId, uint256 _version, bytes[] memory functionCalls, bytes32 salt)
external
returns (address instance);
/**
* @notice Calls a function on the target contract.
* @param target The target address of the function call.
* @param data Miscalaneous data associated with the transfer.
* @custom:emits FunctionCalled
* @return result The result of the function call.
*/
function functionCall(address target, bytes memory data) external returns (bytes memory result);
}
ILockdropFactory.sol 38 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "./ILockdrop.sol";
/**
* @title SOMA Lockdrop Factory Contract.
* @author SOMA.finance.
* @notice A factory that produces Lockdrop contracts.
*/
interface ILockdropFactory {
/**
* @notice Emitted when a Lockdrop is created.
* @param id The ID of the Lockdrop.
* @param asset The delegation asset of the Lockdrop.
* @param instance The address of the created Lockdrop.
*/
event LockdropCreated(uint256 id, address asset, address instance);
/**
* @notice The Lockdrop's CREATE_ROLE.
* @dev Returns keccak256('Lockdrop.CREATE_ROLE').
*/
function CREATE_ROLE() external pure returns (bytes32);
/**
* @notice Creates a Lockdrop instance.
* @param asset The address of the delegation asset.
* @param withdrawTo The address that delegated assets will be withdrawn to.
* @param dateConfig The date configuration of the Lockdrop.
* @custom:emits LockdropCreated
* @custom:requirement `asset` must not be equal to address zero.
* @custom:requirement `withdrawTo` must not be equal to address zero.
* @custom:requirement The function caller must have the CREATE_ROLE.
*/
function create(address asset, address withdrawTo, ILockdrop.DateConfig calldata dateConfig) external;
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
ILockdrop.sol 271 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Lockdrop Contract.
* @author SOMA.finance
* @notice A fund raising contract for bootstrapping DEX liquidity pools.
*/
interface ILockdrop {
/**
* @notice Emitted when the {DelegationConfig} is updated.
* @param poolId The pool ID.
* @param prevLockDuration The previous lock duration.
* @param newLockDuration The new lock duration.
* @param sender The message sender that triggered the event.
*/
event LockDurationUpdated(
bytes32 poolId, uint256 prevLockDuration, uint256 newLockDuration, address indexed sender
);
/**
* @notice Emitted when the {withdrawTo} address is updated.
* @param prevTo The previous withdraw to address.
* @param newTo The new withdraw to address.
* @param sender The message sender that triggered the event.
*/
event WithdrawToUpdated(address prevTo, address newTo, address indexed sender);
/**
* @notice Emitted when a delegation is added to a pool.
* @param poolId The pool ID.
* @param amount The delegation amount denominated in the delegation asset.
* @param lockDuration The lock duration.
* @param sender The message sender that triggered the event.
*/
event DelegationAdded(bytes32 indexed poolId, uint256 amount, uint256 lockDuration, address indexed sender);
/**
* @notice Emitted when someone calls {moveDelegation}, transferring their delegation to a different pool.
* @param fromPoolId The pool ID of the source pool.
* @param toPoolId The pool ID of the destination pool.
* @param amount The amount of the delegation asset to move.
* @param sender TThe message sender that triggered the event.
*/
event DelegationMoved(bytes32 indexed fromPoolId, bytes32 indexed toPoolId, uint256 amount, address indexed sender);
/**
* @notice Emitted when the {DateConfig} is updated.
* @param prevDateConfig The previous date configuration.
* @param newDateConfig The new date configuration.
* @param sender The message sender that triggered the event.
*/
event DatesUpdated(DateConfig prevDateConfig, DateConfig newDateConfig, address indexed sender);
/**
* @notice Emitted when the {Pool} is updated.
* @param poolId The pool ID.
* @param requiredPrivileges The new required privileges.
* @param enabled Boolean indicating if the pool is enabled.
* @param sender The message sender that triggered the event.
*/
event PoolUpdated(bytes32 indexed poolId, bytes32 requiredPrivileges, bool enabled, address indexed sender);
/**
* @notice Emitted when a delegation is removed from a pool.
* @param poolId The pool ID.
* @param amount The removed delegation amount denominated in the delegation asset.
* @param sender The message sender that triggered the event.
*/
event DelegationRemoved(bytes32 indexed poolId, uint256 amount, address indexed sender);
/**
* @notice Date Configuration structure.
* @param startDate The unix timestamp marking the start of the lockdrop.
* @param removeDelegationEnd The unix timestamp marking the end of delegation removals.
* @param endDate The unix timestamp marking the end of the lockdrop.
*/
struct DateConfig {
uint48 startDate;
uint48 removeDelegationEnd;
uint48 endDate;
}
/**
* @notice Pool structure. Each pool will bootstrap liquidity for an upcoming DEX pair.
* E.g: sTSLA/USDC
* @param enabled Boolean indicating if the pool is enabled.
* @param requiredPrivileges The required privileges of the pool.
* @param balances The mapping of user addresses to delegation balances.
*/
struct Pool {
bool enabled;
bytes32 requiredPrivileges;
mapping(address => uint256) balances;
}
/**
* @notice Returns the Lockdrop Global Admin Role.
* @dev Equivalent to `keccak256('Lockdrop.GLOBAL_ADMIN_ROLE')`.
*/
function GLOBAL_ADMIN_ROLE() external pure returns (bytes32);
/**
* @notice Returns the Lockdrop Local Admin Role.
* @dev Equivalent to `keccak256(abi.encodePacked(address(this), GLOBAL_ADMIN_ROLE))`.
*/
function LOCAL_ADMIN_ROLE() external view returns (bytes32);
/**
* @notice Returns the ID of the Lockdrop.
*/
function id() external view returns (uint256);
/**
* @notice The address of the Lockdrop's delegation asset.
*/
function asset() external view returns (address);
/**
* @notice The date configuration of the Lockdrop.
*/
function dateConfig() external view returns (DateConfig memory);
/**
* @notice The address where the delegated funds will be withdrawn to.
*/
function withdrawTo() external view returns (address);
/**
* @notice Initialize function for the Lockdrop contract.
* @param _id The ID of the Lockdrop.
* @param _asset The address of the delegation asset.
* @param _withdrawTo The address that receives withdrawn assets.
* @param _initDateConfig The initial date configuration.
*/
function initialize(uint256 _id, address _asset, address _withdrawTo, DateConfig calldata _initDateConfig)
external;
/**
* @notice Updates the Lockdrop's date configuration.
* @param newConfig The updated date configuration.
* @custom:emits DatesUpdated
* @custom:requirement The function caller must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function updateDateConfig(DateConfig calldata newConfig) external;
/**
* @notice Sets the `withdrawTo` address.
* @param account The updated address to receive withdrawn funds.
* @custom:emits WithdrawToUpdated
* @custom:requirement The function caller must be the master.
* @custom:requirement `account` must not be equal to address zero.
*/
function setWithdrawTo(address account) external;
/**
* @notice Returns the delegation balance of an account, given a pool ID.
* @param poolId The pool ID to return the account's balance of.
* @param account The account to return the balance of.
* @return The delegation balance of `account` for the `poolId` pool.
*/
function balanceOf(bytes32 poolId, address account) external view returns (uint256);
/**
* @notice Returns the lock duration of an account for a pool.
* @param poolId The poolId to return the user lock duration of.
* @param account The account to return the pool lock duration of.
* @return The lock duration.
*/
function lockDuration(bytes32 poolId, address account) external view returns (uint256);
/**
* @notice Returns a boolean indicating if a pool is enabled.
* @param poolId The pool ID to check the enabled status of.
* @return True if the pool is enabled, False if the pool is disabled.
*/
function enabled(bytes32 poolId) external view returns (bool);
/**
* @notice Returns the required privileges of the pool. These privileges are required in order to
* delegate.
* @param poolId The pool ID to check the enabled status of.
* @custom:requirement The pool must be enabled.
* @return The required privileges of the pool.
*/
function requiredPrivileges(bytes32 poolId) external view returns (bytes32);
/**
* @notice Updates the lockdrop pool parameters.
* @param _poolId The ID of the pool to update.
* @param _requiredPrivileges The updated required privileges of the pool.
* @param _enabled The updated enabled or disabled state of the pool.
* @custom:emits PoolUpdated
* @custom:requirement The function caller must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function updatePool(bytes32 _poolId, bytes32 _requiredPrivileges, bool _enabled) external;
/**
* @notice Updates the delegation configuration of an account.
* @param poolId The pool ID.
* @param newLockDuration The new lock duration.
* @custom:emits LockDurationUpdated
* @custom:requirement The `poolId` pool must be enabled.
* @custom:requirement The lockdrop must have started already.
* @custom:requirement The lockdrop must not have ended yet.
* @custom:requirement The contracts must not be paused.
*/
function updateLockDuration(bytes32 poolId, uint256 newLockDuration) external;
/**
* @notice Withdraws tokens from the Lockdrop contract to the `withdrawTo` address.
* @param amount The amount of tokens to be withdrawn.
* @custom:requirement The function caller must have the GLOBAL_ADMIN_ROLE or LOCAL_ADMIN_ROLE.
*/
function withdraw(uint256 amount) external;
/**
* @notice Moves the accounts' delegated tokens from one pool to another, and sets the `toPoolId` lock duration.
* @param fromPoolId The ID of the pool that the delegation will be moved from.
* @param toPoolId The ID of the pool that the delegation will be moved to.
* @param amount The amount of tokens to be moved.
* @param toPoolLockDuration The lock duration of the user for `toPoolId`.
* @custom:emits DelegationMoved
* @custom:requirement `fromPoolId` must not be equal to `toPoolId`.
* @custom:requirement The lockdrop must have started already.
* @custom:requirement The lockdrop must not have ended yet.
* @custom:requirement `amount` must be greater than zero.
* @custom:requirement The `fromPoolId` pool must be enabled.
* @custom:requirement The `toPoolId` pool must be enabled.
* @custom:requirement The delegation balance of the caller for the `fromPoolId` pool must be greater than
* or equal to `amount`.
* @custom:requirement The function caller must have the required privileges of the `fromPoolId` pool.
* @custom:requirement The function caller must have the required privileges of the `toPoolId` pool.
* @custom:requirement The contracts must not be paused.
*/
function moveDelegation(bytes32 fromPoolId, bytes32 toPoolId, uint256 amount, uint256 toPoolLockDuration)
external;
/**
* @notice Removes the accounts' delegated tokens from the pool.
* @param poolId The ID of the pool that the delegation will be removed from.
* @param amount The amount of tokens to be removed.
* @custom:emits DelegationRemoved
* @custom:requirement The lockdrop must have started already.
* @custom:requirement The block timestamp must be less than or equal to the remove delegation end timestamp.
* @custom:requirement `amount` must be greater than zero.
* @custom:requirement `amount` must be less than the balance of the asset.
* @custom:requirement The `poolId` pool must be enabled.
* @custom:requirement The delegation balance of the caller for the `poolId` pool must be greater than
* or equal to `amount`.
* @custom:requirement The function caller must have the required privileges of the `poolId` pool.
* @custom:requirement The contracts must not be paused.
*/
function removeDelegation(bytes32 poolId, uint256 amount) external;
/**
* @notice Delegates tokens to the a specific pool.
* @param poolId The ID of the pool to receive the delegation.
* @param amount The amount of tokens to be delegated.
* @param lockDuration_ The lock duration.
* @custom:emits DelegationAdded
* @custom:requirement `amount` must be greater than zero.
* @custom:requirement The `poolId` pool must be enabled.
* @custom:requirement The lockdrop must have started already.
* @custom:requirement The lockdrop must not have ended yet.
* @custom:requirement The function caller must have the `poolId` pool's required privileges.
* @custom:requirement The contracts must not be paused.
*/
function delegate(bytes32 poolId, uint256 amount, uint256 lockDuration_) external;
}
ITokenRecoveryUpgradeable.sol 36 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/**
* @title SOMA Token Rewards Upgradeable Contract.
* @author SOMA.finance
* @notice Interface for the {TokenRecoveryUpgradeable} contract.
*/
interface ITokenRecoveryUpgradeable {
/**
* @notice Emitted when tokens are recovered.
* @param token The address of the recovered tokens.
* @param to The address that the tokens are being sent to.
* @param amount The amount of tokens recovered.
* @param sender The address of the message sender.
*/
event TokensRecovered(address indexed token, address indexed to, uint256 amount, address indexed sender);
/**
* @notice Returns the Token Recovery Upgradeable TOKEN_RECOVERY_ROLE.
* @dev Returns keccak256('TokenRecovery.TOKEN_RECOVERY_ROLE').
*/
function TOKEN_RECOVERY_ROLE() external pure returns (bytes32);
/**
* @notice Recovers tokens and transfers these tokens to `to`.
* @param token The address of the recovered tokens.
* @param to The address that the tokens are being sent to.
* @param amount The amount of tokens recovered.
* @custom:emits TokensRecovered
* @custom:requirement The function caller must have the TOKEN_RECOVERY_ROLE.
* @custom:requirement `token` must not be a disabled token.
*/
function recoverTokens(address token, address to, uint256 amount) external;
}
Read Contract
DEFAULT_PRIVILEGES 0x2a7a0c68 → bytes32
GLOBAL_ADMIN_ROLE 0x66258068 → bytes32
GLOBAL_SEIZE_ROLE 0x30139280 → bytes32
GLOBAL_UPDATE_PRIVILEGES_ROLE 0x227102a6 → bytes32
LOCAL_ADMIN_ROLE 0xe2481dbd → bytes32
LOCAL_SEIZE_ROLE 0xc72460ee → bytes32
LOCAL_UPDATE_PRIVILEGES_ROLE 0xeec47d60 → bytes32
SOMA 0x63727fc2 → address
TOKEN_RECOVERY_ROLE 0xd8697598 → bytes32
adminClaimable 0x4e6e056f → uint256
claimRequest 0x3a22502c → tuple
claimable 0xd4570c1c → uint256
config 0x79502c55 → tuple
currentTPS 0x3e677297 → uint256
debt 0xd449300d → uint256
getRoleAdmin 0x248a9ca3 → bytes32
hasPrivileges 0x4b63885a → bool
hasRole 0x91d14854 → bool
paused 0x5c975abb → bool
pendingStrategy 0xa7c5b413 → tuple
requiredPrivileges 0x1e26571f → bytes32
rewardToken 0x509b6c3f → address
stakeOf 0x42623360 → uint256
stakingToken 0x72f702f3 → address
strategy 0xbc88d7e4 → tuple
supportsInterface 0x01ffc9a7 → bool
totalPendingStrategies 0x3cfe9fd1 → uint256
totalPendingUnstake 0x3d173136 → uint256
totalRewardTokens 0x1b0875a6 → uint256
totalStaked 0x817b1cd2 → uint256
totalStrategies 0xf96d7b80 → uint256
tps 0x67b4cdb8 → uint256
unstakeRequest 0xe5261b1d → tuple
Write Contract 20 functions
These functions modify contract state and require a wallet transaction to execute.
addRewardToken 0x1c03e6cc
address _asset
adminClaim 0x350b5af0
address _asset
address _to
cancelClaimRequests 0x1d8b4c49
address[] _assets
uint256[][] _ids
cancelUnstakeRequests 0x8b0bd55b
uint256[] _ids
claim 0x90672ad8
address[] _assets
uint256[][] _ids
claimImmediate 0x6fa3fbda
address[] _assets
uint256[] _amounts
createClaimRequests 0xa488b71e
address[] _assets
returns: uint256[]
createStrategy 0x4f814cc5
uint256 _startDate
uint256 _endDate
address _rewardToken
uint256 _rewardAmount
createUnstakeRequest 0xbe864d68
uint256 _amount
returns: uint256
initialize 0x946d9204
address stakingToken_
address[] rewardTokens_
multicall 0xac9650d8
bytes[] data
returns: bytes[]
pause 0x8456cb59
No parameters
recoverTokens 0x5f3e849f
address token
address to
uint256 amount
seize 0xfb3ee571
address from
stake 0xa694fc3a
uint256 _amount
unpause 0x3f4ba83a
No parameters
unstake 0xe449f341
uint256[] _ids
unstakeImmediate 0x3ee16bf7
uint256 _amount
updateConfig 0x49aeb46f
uint64 _unstakeDuration
uint64 _claimDuration
uint16 _earlyUnstakeFee
uint16 _earlyClaimFee
updateRequiredPrivileges 0x2772ce9d
bytes32 newRequiredPrivileges
returns: bool
Recent Transactions
No transactions found for this address