Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xfb55F43fB9F48F63f9269DB7Dde3BbBe1ebDC0dE
Balance 0 ETH
Nonce 1
Code Size 18038 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

18038 bytes
0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80638ea2f2ab116100ee578063b9a3c84c11610097578063da03b36e11610071578063da03b36e1461071b578063e39dfd7f1461072a578063f2fde38b1461073d578063fe4e19831461075057600080fd5b8063b9a3c84c146105a1578063d509b017146105c8578063d60715b5146105ef57600080fd5b8063a8655785116100c8578063a86557851461054e578063ac9650d814610561578063afedba4f1461058157600080fd5b80638ea2f2ab14610508578063a6a22b431461051b578063a7af2d0f1461052e57600080fd5b8063530dd3921161015b578063715018a611610135578063715018a6146102df57806382762520146102e757806388302884146102fa5780638da5cb5b146104e557600080fd5b8063530dd392146102555780636457c97914610288578063707621571461029b57600080fd5b806336b13af41161018c57806336b13af41461021a5780634124beef1461022d5780634360af3d1461024257600080fd5b806308e7c3e6146101b357806320402e1d146101cf57806329cb924d14610214575b600080fd5b6101bc60055481565b6040519081526020015b60405180910390f35b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b426101bc565b6101bc610228366004613a49565b610795565b61024061023b366004613acc565b61084c565b005b6101bc610250366004613ae5565b610e41565b610278610263366004613acc565b60036020526000908152604090205460ff1681565b60405190151581526020016101c6565b6101bc610296366004613bde565b610e89565b6102c86102a9366004613ae5565b6002602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016101c6565b6102406116ef565b6102406102f5366004613ccf565b611782565b6104d8610308366004613acc565b6040805161022081018252600061018082018181526101a083018290526101c083018290526101e083018290526102008301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250600090815260046020818152604092839020835161022081018552815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169685019690965267ffffffffffffffff740100000000000000000000000000000000000000008088048216998601999099527c010000000000000000000000000000000000000000000000000000000096879004831615156060860152600386015480851660808701529889041660a085015294909604909516151560c08201529281015460e08401526005810154918301919091526006810154610120830152600781015483166101408301526008015490911661016082015290565b6040516101c69190613d0d565b600054610100900473ffffffffffffffffffffffffffffffffffffffff166101ef565b610278610516366004613acc565b6119de565b610240610529366004613e29565b611a2f565b6001546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b61024061055c366004613e29565b611e24565b61057461056f366004613e59565b6121a9565b6040516101c69190613f3c565b61059461058f366004613acc565b61231b565b6040516101c69190613fbc565b6101ef7f00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c381565b6101bc7f4153534552545f5452555448000000000000000000000000000000000000000081565b6107036105fd366004613acc565b600460208181526000928352604092839020835160a081018552815460ff8082161515835261010082048116151594830194909452620100008104841615159582019590955273ffffffffffffffffffffffffffffffffffffffff630100000090950485166060820152600182015485166080820152600282015460038301549483015460058401546006850154600786015460089096015494988481169867ffffffffffffffff7401000000000000000000000000000000000000000080880482169a7c01000000000000000000000000000000000000000000000000000000009889900481169a8486169a928504909316989093049092169594939290811691168c565b6040516101c69c9b9a99989796959493929190613fcf565b6101bc670de0b6b3a764000081565b610278610738366004613acc565b612326565b61024061074b366004613ae5565b6124fe565b60065461077c9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101c6565b600061084284848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060065488945090925082915067ffffffffffffffff740100000000000000000000000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff1661081a81610e41565b7f4153534552545f545255544800000000000000000000000000000000000000006000610e89565b90505b9392505050565b610854612631565b610881600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6000818152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f74206578697374000000000000000060448201526064015b60405180910390fd5b60028101547c0100000000000000000000000000000000000000000000000000000000900460ff16156109a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f417373657274696f6e20616c726561647920736574746c656400000000000000604482015260640161090c565b6002810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055600881015473ffffffffffffffffffffffffffffffffffffffff16610b865742600382015474010000000000000000000000000000000000000000900467ffffffffffffffff161115610a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420657870697265640000000000000000000000604482015260640161090c565b6003810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff81167c01000000000000000000000000000000000000000000000000000000001790915560028201546006830154610b159273ffffffffffffffffffffffffffffffffffffffff90811692169061269d565b610b20826001612776565b60028101546040805160008152600160208201523381830152905173ffffffffffffffffffffffffffffffffffffffff9092169184917ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a13919081900360600190a3610e0d565b60058101546002820154600091610bc19185919074010000000000000000000000000000000000000000900467ffffffffffffffff166128e3565b8254909150610100900460ff1615610c02576003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055610c58565b6003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16670de0b6b3a764000083147c0100000000000000000000000000000000000000000000000000000000021790555b6000670de0b6b3a76400008214610c8957600883015473ffffffffffffffffffffffffffffffffffffffff16610ca5565b600283015473ffffffffffffffffffffffffffffffffffffffff165b90506000670de0b6b3a76400008460060154600554610cc491906140da565b610cce9190614146565b905060008185600601546002610ce491906140da565b610cee9190614181565b9050610d1d610cfb612973565b600387015473ffffffffffffffffffffffffffffffffffffffff16908461269d565b6003850154610d439073ffffffffffffffffffffffffffffffffffffffff16848361269d565b8454610100900460ff16610d84576003850154610d849087907c0100000000000000000000000000000000000000000000000000000000900460ff16612776565b600385015460408051600181527c010000000000000000000000000000000000000000000000000000000090920460ff1615156020830152339082015273ffffffffffffffffffffffffffffffffffffffff84169087907ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a139060600160405180910390a3505050505b50610e3e600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040812060010154600554610e7f82670de0b6b3a76400006140da565b6108459190614146565b6000610e93612631565b610ec0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b42610edb8b8667ffffffffffffffff84168a8a8e8e8b612a4a565b915073ffffffffffffffffffffffffffffffffffffffff8a16610f5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f41737365727465722063616e7420626520300000000000000000000000000000604482015260640161090c565b60008281526004602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1615610fe9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20616c7265616479206578697374730000000000000000604482015260640161090c565b610ff284612a91565b611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e737570706f72746564206964656e74696669657200000000000000000000604482015260640161090c565b61106186612b75565b6110c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e737570706f727465642063757272656e6379000000000000000000000000604482015260640161090c565b6110d086610e41565b851015611139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f426f6e6420616d6f756e7420746f6f206c6f7700000000000000000000000000604482015260640161090c565b6040805161022081018252600061018082018181526101a083018290526101c08301829052336101e084015273ffffffffffffffffffffffffffffffffffffffff8c81166102008501529083528d8116602084015267ffffffffffffffff8516938301939093526060820152908716608082015260a081016111bb8984614194565b67ffffffffffffffff1681526020016000151581526020018481526020018581526020018681526020018a73ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152506004600084815260200190815260200160002060008201518160000160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548160ff02191690831515021790555060608201518160000160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505060208201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550606082015181600201601c6101000a81548160ff02191690831515021790555060808201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160030160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c082015181600301601c6101000a81548160ff02191690831515021790555060e08201518160040155610100820151816005015561012082015181600601556101408201518160070160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101608201518160080160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600061151283612d68565b80519091501561157e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420616c6c6f7765640000000000000000000000604482015260640161090c565b600083815260046020908152604091829020908301519183015160609093015181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff1662010000911515919091027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010093151593909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517905561164873ffffffffffffffffffffffffffffffffffffffff8716333088612e70565b838a73ffffffffffffffffffffffffffffffffffffffff16837fdb1513f0abeb57a364db56aa3eb52015cca5268f00fd67bc73aaf22bccab02b7868f8e8e338f8a6116939190614194565b8f8f6040516116a99897969594939291906141b5565b60405180910390a4506116e2600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b9998505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b6117806000612ece565b565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b670de0b6b3a764000081111561187b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4275726e656420626f6e642070657263656e74616765203e2031303000000000604482015260640161090c565b600081116118e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4275726e656420626f6e642070657263656e7461676520697320300000000000604482015260640161090c565b60058190556006805467ffffffffffffffff841674010000000000000000000000000000000000000000027fffffffff0000000000000000000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff8616171790556119797f4153534552545f5452555448000000000000000000000000000000000000000084611e24565b6040805173ffffffffffffffffffffffffffffffffffffffff8516815267ffffffffffffffff841660208201529081018290527fd0f09246d369018534c67fec6a6c3259c6f962ef82c5521c337ae0ccc104e4bd9060600160405180910390a1505050565b6000818152600460205260408120600201547c0100000000000000000000000000000000000000000000000000000000900460ff16611a2057611a208261084c565b611a2982612326565b92915050565b611a37612631565b611a64600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b73ffffffffffffffffffffffffffffffffffffffff8116611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465722063616e2774206265203000000000000000000000000000604482015260640161090c565b6000828152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16611b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f742065786973740000000000000000604482015260640161090c565b600881015473ffffffffffffffffffffffffffffffffffffffff1615611bf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f417373657274696f6e20616c7265616479206469737075746564000000000000604482015260640161090c565b42600382015474010000000000000000000000000000000000000000900467ffffffffffffffff1611611c81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f417373657274696f6e2069732065787069726564000000000000000000000000604482015260640161090c565b611c8a83612f4b565b611cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465206e6f7420616c6c6f77656400000000000000000000000000604482015260640161090c565b6008810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911790915560068201546003830154611d5092169033903090612e70565b60058101546002820154611d8791859174010000000000000000000000000000000000000000900467ffffffffffffffff1661303a565b611d90836130be565b8054610100900460ff1615611daa57611daa836000612776565b60405173ffffffffffffffffffffffffffffffffffffffff831690339085907f60133788b013c89f2a3756dbc47e3484997b87bd7e0af98a7d70232032c1ce2b90600090a450611e20600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4f7261636c65000000000000000000000000000000000000000000000000000060048201527f00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c373ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401602060405180830381865afa158015611ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef29190614225565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055611f3f6131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401611f7991815260200190565b602060405180830381865afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba9190614252565b600083815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ffd61327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690633a3ab67290602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190614252565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556120e9612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690635b97aadd90602401602060405180830381865afa158015612157573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217b919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90911660009081526002602052604090206001015550565b60608167ffffffffffffffff8111156121c4576121c4613b02565b6040519080825280602002602001820160405280156121f757816020015b60608152602001906001900390816121e25790505b50905060005b82811015612314576000803086868581811061221b5761221b6142af565b905060200281019061222d91906142de565b60405161223b92919061434a565b600060405180830381855af49150503d8060008114612276576040519150601f19603f3d011682016040523d82523d6000602084013e61227b565b606091505b5091509150816122e15760448151101561229457600080fd5b600481019050808060200190518101906122ae919061435a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b808484815181106122f4576122f46142af565b60200260200101819052505050808061230c906143d1565b9150506121fd565b5092915050565b6060611a2982613311565b6000818152600460208181526040808420815161022081018352815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169785019790975267ffffffffffffffff740100000000000000000000000000000000000000008089048216978601979097527c010000000000000000000000000000000000000000000000000000000097889004831615156060860152600386015480851660808701529687041660a085015295909404909316151560c08201529381015460e08501526005810154928401929092526006820154610120840152600782015481166101408401526008909101541661016082018190521580159061247b57508051602001515b156124895750600092915050565b80606001516124f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420736574746c65640000000000000000000000604482015260640161090c565b60c0015192915050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314612585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b73ffffffffffffffffffffffffffffffffffffffff8116612628576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161090c565b610e3e81612ece565b60005460ff16611780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161090c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526127719084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526133c9565b505050565b6000828152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115612838576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff83169063f1b156b290604401600060405180830381600087803b15801561281f57600080fd5b505af1158015612833573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff8116156128dd576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff82169063f1b156b290604401600060405180830381600087803b1580156128c457600080fd5b505af11580156128d8573d6000803e3d6000fd5b505050505b50505050565b60006128ee846134d5565b73ffffffffffffffffffffffffffffffffffffffff1663719c6d56848461291488613311565b6040518463ffffffff1660e01b815260040161293293929190614409565b602060405180830381865afa15801561294f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108429190614428565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f53746f726500000000000000000000000000000000000000000000000000000060048201526000907f00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c373ffffffffffffffffffffffffffffffffffffffff169063aafd5e40906024015b602060405180830381865afa158015612a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a459190614225565b905090565b6000888888888888888833604051602001612a6d99989796959493929190614441565b60405160208183030381529060405280519060200120905098975050505050505050565b60008181526003602052604081205460ff1615612ab057506001919050565b612ab86131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401612af291815260200190565b602060405180830381865afa158015612b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b339190614252565b60009283526003602052604090922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001692151592831790555060ff1690565b73ffffffffffffffffffffffffffffffffffffffff811660009081526002602052604081205460ff1615612bab57506001919050565b612bb361327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690633a3ab67290602401602060405180830381865afa158015612c21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c459190614252565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612c9f612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690635b97aadd90602401602060405180830381865afa158015612d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d31919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90921660009081526002602052604090206001810192909255505460ff1690565b60408051608081018252600080825260208083018290528284018290526060830182905284825260049052919091206001015473ffffffffffffffffffffffffffffffffffffffff1680612de1575050604080516080810182526000808252602082018190529181018290526060810191909152919050565b6040517fa6b011a70000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063a6b011a790602401608060405180830381865afa158015612e4c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084591906144b7565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526128dd9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016126ef565b6000805473ffffffffffffffffffffffffffffffffffffffff8381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008181526004602052604081205462010000900460ff16612f6f57506001919050565b60008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff1680612fa55750600192915050565b6040517f6b915d910000000000000000000000000000000000000000000000000000000081526004810184905233602482015273ffffffffffffffffffffffffffffffffffffffff821690636b915d9190604401602060405180830381865afa158015613016573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108459190614252565b613043836134d5565b73ffffffffffffffffffffffffffffffffffffffff1663216666a4838361306987613311565b6040518463ffffffff1660e01b815260040161308793929190614409565b600060405180830381600087803b1580156130a157600080fd5b505af11580156130b5573d6000803e3d6000fd5b50505050505050565b6000818152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115613178576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff83169063d448a4ec90602401600060405180830381600087803b15801561315f57600080fd5b505af1158015613173573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff811615612771576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063d448a4ec90602401613087565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4964656e74696669657257686974656c6973740000000000000000000000000060048201526000907f00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c373ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f436f6c6c61746572616c57686974656c6973740000000000000000000000000060048201526000907f00000000000000000000000040f941e48a552bf496b154af6bf55725f18d77c373ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6060611a29613365604051806020016040528060008152506040518060400160405280600b81526020017f617373657274696f6e496400000000000000000000000000000000000000000081525085613537565b604080518082018252600a81527f6f6f41737365727465720000000000000000000000000000000000000000000060208083019190915260008781526004909152919091206002015473ffffffffffffffffffffffffffffffffffffffff1661357d565b600061342b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166135989092919063ffffffff16565b80519091501561277157808060200190518101906134499190614252565b612771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161090c565b60008181526004602052604081205460ff16156135195760008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff16611a29565b505060015473ffffffffffffffffffffffffffffffffffffffff1690565b6060600061354585856135a7565b90508481613552856135e9565b60405160200161356493929190614534565b6040516020818303038152906040529150509392505050565b6060600061358b85856135a7565b905084816135528561362a565b606061084284846000856136a2565b8151606090156135d857816040516020016135c29190614577565b6040516020818303038152906040529050611a29565b816040516020016135c291906145e3565b60606135f8608083901c613822565b61360183613822565b6040805160208101939093528201526060015b6040516020818303038152906040529050919050565b606061364b6fffffffffffffffffffffffffffffffff602084901c16613822565b6136668360601b6bffffffffffffffffffffffff1916613822565b6040516020016136149291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b606082471015613734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161090c565b843b61379c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161090c565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516137c59190614624565b60006040518083038185875af1925050503d8060008114613802576040519150601f19603f3d011682016040523d82523d6000602084013e613807565b606091505b50915091506138178282866139c4565b979650505050505050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161394657613946614117565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b606083156139d3575081610845565b8251156139e35782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b73ffffffffffffffffffffffffffffffffffffffff81168114610e3e57600080fd5b8035613a4481613a17565b919050565b600080600060408486031215613a5e57600080fd5b833567ffffffffffffffff80821115613a7657600080fd5b818601915086601f830112613a8a57600080fd5b813581811115613a9957600080fd5b876020828501011115613aab57600080fd5b60209283019550935050840135613ac181613a17565b809150509250925092565b600060208284031215613ade57600080fd5b5035919050565b600060208284031215613af757600080fd5b813561084581613a17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b7857613b78613b02565b604052919050565b600067ffffffffffffffff821115613b9a57613b9a613b02565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b803567ffffffffffffffff81168114613a4457600080fd5b60008060008060008060008060006101208a8c031215613bfd57600080fd5b893567ffffffffffffffff811115613c1457600080fd5b8a01601f81018c13613c2557600080fd5b8035613c38613c3382613b80565b613b31565b8181528d6020838501011115613c4d57600080fd5b81602084016020830137600060208383010152809b50505050613c7260208b01613a39565b9750613c8060408b01613a39565b9650613c8e60608b01613a39565b9550613c9c60808b01613bc6565b9450613caa60a08b01613a39565b935060c08a0135925060e08a013591506101008a013590509295985092959850929598565b600080600060608486031215613ce457600080fd5b8335613cef81613a17565b9250613cfd60208501613bc6565b9150604084013590509250925092565b815180511515825260208082015115158184015260408083015115158185015260608084015173ffffffffffffffffffffffffffffffffffffffff9081168287015260809485015181168587015292860151831660a08601529085015167ffffffffffffffff1660c0850152840151151560e084015290830151908116610100808401919091526102008301919060a08501519150610120613dba8186018467ffffffffffffffff169052565b60c08601519250610140613dd18187018515159052565b60e08701516101608781019190915292870151610180870152908601516101a086015285015173ffffffffffffffffffffffffffffffffffffffff9081166101c0860152908501519081166101e08501529050612314565b60008060408385031215613e3c57600080fd5b823591506020830135613e4e81613a17565b809150509250929050565b60008060208385031215613e6c57600080fd5b823567ffffffffffffffff80821115613e8457600080fd5b818501915085601f830112613e9857600080fd5b813581811115613ea757600080fd5b8660208260051b8501011115613ebc57600080fd5b60209290920196919550909350505050565b60005b83811015613ee9578181015183820152602001613ed1565b50506000910152565b60008151808452613f0a816020860160208601613ece565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613faf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613f9d858351613ef2565b94509285019290850190600101613f63565b5092979650505050505050565b6020815260006108456020830184613ef2565b610200810161402b828f805115158252602081015115156020830152604081015115156040830152606081015173ffffffffffffffffffffffffffffffffffffffff808216606085015280608084015116608085015250505050565b73ffffffffffffffffffffffffffffffffffffffff9c8d1660a083015267ffffffffffffffff9b8c1660c083015299151560e0820152978b16610100890152959098166101208701529215156101408601526101608501919091526101808401526101a08301529284166101c0820152919092166101e090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614112576141126140ab565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261417c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115611a2957611a296140ab565b67ffffffffffffffff818116838216019080821115612314576123146140ab565b60006101008a83528060208401526141cf8184018b613ef2565b73ffffffffffffffffffffffffffffffffffffffff998a16604085015297891660608401525050938616608085015267ffffffffffffffff9290921660a084015290931660c082015260e0019190915292915050565b60006020828403121561423757600080fd5b815161084581613a17565b80518015158114613a4457600080fd5b60006020828403121561426457600080fd5b61084582614242565b60006020828403121561427f57600080fd5b6040516020810181811067ffffffffffffffff821117156142a2576142a2613b02565b6040529151825250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261431357600080fd5b83018035915067ffffffffffffffff82111561432e57600080fd5b60200191503681900382131561434357600080fd5b9250929050565b8183823760009101908152919050565b60006020828403121561436c57600080fd5b815167ffffffffffffffff81111561438357600080fd5b8201601f8101841361439457600080fd5b80516143a2613c3382613b80565b8181528560208385010111156143b757600080fd5b6143c8826020830160208601613ece565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614402576144026140ab565b5060010190565b8381528260208201526060604082015260006143c86060830184613ef2565b60006020828403121561443a57600080fd5b5051919050565b60006101208083526144558184018d613ef2565b602084019b909b525050604081019790975267ffffffffffffffff95909516606087015273ffffffffffffffffffffffffffffffffffffffff938416608087015291831660a0860152821660c085015260e08401521661010090910152919050565b6000608082840312156144c957600080fd5b6040516080810181811067ffffffffffffffff821117156144ec576144ec613b02565b6040526144f883614242565b815261450660208401614242565b602082015261451760408401614242565b604082015261452860608401614242565b60608201529392505050565b60008451614546818460208901613ece565b84519083019061455a818360208901613ece565b845191019061456d818360208801613ece565b0195945050505050565b7f2c000000000000000000000000000000000000000000000000000000000000008152600082516145af816001850160208701613ece565b7f3a000000000000000000000000000000000000000000000000000000000000006001939091019283015250600201919050565b600082516145f5818460208701613ece565b7f3a00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b60008251614636818460208701613ece565b919091019291505056fea2646970667358221220e938127cb66b422a58ecfce740a559128963768438cd88d5587246651f74c86964736f6c63430008100033

Verified Source Code Full Match

Compiler: v0.8.16+commit.07a7930e EVM: london Optimization: Yes (1000000 runs)
Address.sol 217 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
Ownable.sol 76 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
Lockable.sol 77 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract
 * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol
 * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol.
 */
contract Lockable {
    bool private _notEntered;

    constructor() {
        // Storing an initial 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.
        _notEntered = true;
    }

    /**
     * @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 state modification.
     */
    modifier nonReentrant() {
        _preEntranceCheck();
        _preEntranceSet();
        _;
        _postEntranceReset();
    }

    /**
     * @dev Designed to prevent a view-only method from being re-entered during a call to a `nonReentrant()` state-changing method.
     */
    modifier nonReentrantView() {
        _preEntranceCheck();
        _;
    }

    // Internal methods are used to avoid copying the require statement's bytecode to every `nonReentrant()` method.
    // On entry into a function, `_preEntranceCheck()` should always be called to check if the function is being
    // re-entered. Then, if the function modifies state, it should call `_postEntranceSet()`, perform its logic, and
    // then call `_postEntranceReset()`.
    // View-only methods can simply call `_preEntranceCheck()` to make sure that it is not being re-entered.
    function _preEntranceCheck() internal view {
        // On the first call to nonReentrant, _notEntered will be true
        require(_notEntered, "ReentrancyGuard: reentrant call");
    }

    function _preEntranceSet() internal {
        // Any calls to nonReentrant after this point will fail
        _notEntered = false;
    }

    function _postEntranceReset() internal {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _notEntered = true;
    }

    // These functions are intended to be used by child contracts to temporarily disable and re-enable the guard.
    // Intended use:
    // _startReentrantGuardDisabled();
    // ...
    // _endReentrantGuardDisabled();
    //
    // IMPORTANT: these should NEVER be used in a method that isn't inside a nonReentrant block. Otherwise, it's
    // possible to permanently lock your contract.
    function _startReentrantGuardDisabled() internal {
        _notEntered = true;
    }

    function _endReentrantGuardDisabled() internal {
        _notEntered = false;
    }
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
FixedPoint.sol 763 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/math/SignedSafeMath.sol";

/**
 * @title Library for fixed point arithmetic on uints
 */
library FixedPoint {
    using SafeMath for uint256;
    using SignedSafeMath for int256;

    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For unsigned values:
    //   This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77.
    uint256 private constant FP_SCALING_FACTOR = 10**18;

    // --------------------------------------- UNSIGNED -----------------------------------------------------------------------------
    struct Unsigned {
        uint256 rawValue;
    }

    /**
     * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a uint to convert into a FixedPoint.
     * @return the converted FixedPoint.
     */
    function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) {
        return Unsigned(a.mul(FP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue == fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if equal, or False.
     */
    function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue > fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue >= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue < fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a < b`, or False.
     */
    function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) {
        return a.rawValue <= fromUnscaledUint(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) {
        return fromUnscaledUint(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the minimum of `a` and `b`.
     */
    function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the maximum of `a` and `b`.
     */
    function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the sum of `a` and `b`.
     */
    function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return add(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts two `Unsigned`s, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the difference of `a` and `b`.
     */
    function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return sub(a, fromUnscaledUint(b));
    }

    /**
     * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow.
     * @param a a uint256.
     * @param b a FixedPoint.
     * @return the difference of `a` and `b`.
     */
    function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return sub(fromUnscaledUint(a), b);
    }

    /**
     * @notice Multiplies two `Unsigned`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as a uint256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because FP_SCALING_FACTOR != 0.
        return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.
     * @param b a uint256.
     * @return the product of `a` and `b`.
     */
    function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        uint256 mulRaw = a.rawValue.mul(b.rawValue);
        uint256 mulFloor = mulRaw / FP_SCALING_FACTOR;
        uint256 mod = mulRaw.mod(FP_SCALING_FACTOR);
        if (mod != 0) {
            return Unsigned(mulFloor.add(1));
        } else {
            return Unsigned(mulFloor);
        }
    }

    /**
     * @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.
     * @param b a FixedPoint.
     * @return the product of `a` and `b`.
     */
    function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        // Since b is an uint, there is no risk of truncation and we can just mul it normally
        return Unsigned(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as a uint256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        return Unsigned(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a uint256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) {
        return div(fromUnscaledUint(a), b);
    }

    /**
     * @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) {
        uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR);
        uint256 divFloor = aScaled.div(b.rawValue);
        uint256 mod = aScaled.mod(b.rawValue);
        if (mod != 0) {
            return Unsigned(divFloor.add(1));
        } else {
            return Unsigned(divFloor);
        }
    }

    /**
     * @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) {
        // Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))"
        // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned.
        // This creates the possibility of overflow if b is very large.
        return divCeil(a, fromUnscaledUint(b));
    }

    /**
     * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint numerator.
     * @param b a uint256 denominator.
     * @return output is `a` to the power of `b`.
     */
    function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) {
        output = fromUnscaledUint(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }

    // ------------------------------------------------- SIGNED -------------------------------------------------------------
    // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5".
    // For signed values:
    //   This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76.
    int256 private constant SFP_SCALING_FACTOR = 10**18;

    struct Signed {
        int256 rawValue;
    }

    function fromSigned(Signed memory a) internal pure returns (Unsigned memory) {
        require(a.rawValue >= 0, "Negative value provided");
        return Unsigned(uint256(a.rawValue));
    }

    function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) {
        require(a.rawValue <= uint256(type(int256).max), "Unsigned too large");
        return Signed(int256(a.rawValue));
    }

    /**
     * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`.
     * @param a int to convert into a FixedPoint.Signed.
     * @return the converted FixedPoint.Signed.
     */
    function fromUnscaledInt(int256 a) internal pure returns (Signed memory) {
        return Signed(a.mul(SFP_SCALING_FACTOR));
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a int256.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue == fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if equal, or False.
     */
    function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue == b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue > fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a > b`, or False.
     */
    function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue > b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue >= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is greater than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a >= b`, or False.
     */
    function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue >= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a < b`, or False.
     */
    function isLessThan(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue < fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a < b`, or False.
     */
    function isLessThan(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue < b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) {
        return a.rawValue <= b.rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) {
        return a.rawValue <= fromUnscaledInt(b).rawValue;
    }

    /**
     * @notice Whether `a` is less than or equal to `b`.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return True if `a <= b`, or False.
     */
    function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) {
        return fromUnscaledInt(a).rawValue <= b.rawValue;
    }

    /**
     * @notice The minimum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the minimum of `a` and `b`.
     */
    function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return a.rawValue < b.rawValue ? a : b;
    }

    /**
     * @notice The maximum of `a` and `b`.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the maximum of `a` and `b`.
     */
    function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return a.rawValue > b.rawValue ? a : b;
    }

    /**
     * @notice Adds two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.add(b.rawValue));
    }

    /**
     * @notice Adds an `Signed` to an unscaled int, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the sum of `a` and `b`.
     */
    function add(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return add(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts two `Signed`s, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.sub(b.rawValue));
    }

    /**
     * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the difference of `a` and `b`.
     */
    function sub(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return sub(a, fromUnscaledInt(b));
    }

    /**
     * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow.
     * @param a an int256.
     * @param b a FixedPoint.Signed.
     * @return the difference of `a` and `b`.
     */
    function sub(int256 a, Signed memory b) internal pure returns (Signed memory) {
        return sub(fromUnscaledInt(a), b);
    }

    /**
     * @notice Multiplies two `Signed`s, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        // There are two caveats with this computation:
        // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is
        // stored internally as an int256 ~10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which
        // would round to 3, but this computation produces the result 2.
        // No need to use SafeMath because SFP_SCALING_FACTOR != 0.
        return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR);
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow.
     * @dev This will "floor" the product.
     * @param a a FixedPoint.Signed.
     * @param b an int256.
     * @return the product of `a` and `b`.
     */
    function mul(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        int256 mulRaw = a.rawValue.mul(b.rawValue);
        int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR;
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = mulRaw % SFP_SCALING_FACTOR;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(mulTowardsZero.add(valueToAdd));
        } else {
            return Signed(mulTowardsZero);
        }
    }

    /**
     * @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow.
     * @param a a FixedPoint.Signed.
     * @param b a FixedPoint.Signed.
     * @return the product of `a` and `b`.
     */
    function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
        // Since b is an int, there is no risk of truncation and we can just mul it normally
        return Signed(a.rawValue.mul(b));
    }

    /**
     * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        // There are two caveats with this computation:
        // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows.
        // 10^41 is stored internally as an int256 10^59.
        // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which
        // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666.
        return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue));
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(Signed memory a, int256 b) internal pure returns (Signed memory) {
        return Signed(a.rawValue.div(b));
    }

    /**
     * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0.
     * @dev This will "floor" the quotient.
     * @param a an int256 numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function div(int256 a, Signed memory b) internal pure returns (Signed memory) {
        return div(fromUnscaledInt(a), b);
    }

    /**
     * @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b a FixedPoint denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) {
        int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR);
        int256 divTowardsZero = aScaled.div(b.rawValue);
        // Manual mod because SignedSafeMath doesn't support it.
        int256 mod = aScaled % b.rawValue;
        if (mod != 0) {
            bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0);
            int256 valueToAdd = isResultPositive ? int256(1) : int256(-1);
            return Signed(divTowardsZero.add(valueToAdd));
        } else {
            return Signed(divTowardsZero);
        }
    }

    /**
     * @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0.
     * @param a a FixedPoint numerator.
     * @param b an int256 denominator.
     * @return the quotient of `a` divided by `b`.
     */
    function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) {
        // Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))"
        // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed.
        // This creates the possibility of overflow if b is very large.
        return divAwayFromZero(a, fromUnscaledInt(b));
    }

    /**
     * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`.
     * @dev This will "floor" the result.
     * @param a a FixedPoint.Signed.
     * @param b a uint256 (negative exponents are not allowed).
     * @return output is `a` to the power of `b`.
     */
    function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) {
        output = fromUnscaledInt(1);
        for (uint256 i = 0; i < b; i = i.add(1)) {
            output = mul(output, a);
        }
    }
}
SafeMath.sol 227 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

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

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
MultiCaller.sol 28 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)
// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value
// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.

/// @title MultiCaller
/// @notice Enables calling multiple methods in a single call to the contract
contract MultiCaller {
    function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}
AncillaryData.sol 144 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Library for encoding and decoding ancillary data for DVM price requests.
 * @notice  We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via
 * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value
 * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity
 * smart contracts. More details on UMA's ancillary data guidelines below:
 * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit
 */
library AncillaryData {
    // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way.
    // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b.
    function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) {
        unchecked {
            uint256 x = uint256(bytesIn);

            // Nibble interleave
            x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
            x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff;
            x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff;
            x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff;
            x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff;
            x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;

            // Hex encode
            uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8;
            uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4;
            uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2;
            x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030;

            // Return the result.
            return bytes32(x);
        }
    }

    /**
     * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8.
     * @dev Will return bytes32 in all lower case hex characters and without the leading 0x.
     * This has minor changes from the toUtf8BytesAddress to control for the size of the input.
     * @param bytesIn bytes32 to encode.
     * @return utf8 encoded bytes32.
     */
    function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) {
        return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn));
    }

    /**
     * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8.
     * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447
     * @dev Will return address in all lower case characters and without the leading 0x.
     * @param x address to encode.
     * @return utf8 encoded address bytes.
     */
    function toUtf8BytesAddress(address x) internal pure returns (bytes memory) {
        return
            abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x))));
    }

    /**
     * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type.
     * @dev This method is based off of this code: https://stackoverflow.com/a/65707309.
     */
    function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) {
        if (x == 0) {
            return "0";
        }
        uint256 j = x;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (x != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(x - (x / 10) * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            x /= 10;
        }
        return bstr;
    }

    function appendKeyValueBytes32(
        bytes memory currentAncillaryData,
        bytes memory key,
        bytes32 value
    ) internal pure returns (bytes memory) {
        bytes memory prefix = constructPrefix(currentAncillaryData, key);
        return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value));
    }

    /**
     * @notice Adds "key:value" to `currentAncillaryData` where `value` is an address that first needs to be converted
     * to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return
     * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.
     * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.
     * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.
     * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`.
     * @return Newly appended ancillary data.
     */
    function appendKeyValueAddress(
        bytes memory currentAncillaryData,
        bytes memory key,
        address value
    ) internal pure returns (bytes memory) {
        bytes memory prefix = constructPrefix(currentAncillaryData, key);
        return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value));
    }

    /**
     * @notice Adds "key:value" to `currentAncillaryData` where `value` is a uint that first needs to be converted
     * to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return
     * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`.
     * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not.
     * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not.
     * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`.
     * @return Newly appended ancillary data.
     */
    function appendKeyValueUint(
        bytes memory currentAncillaryData,
        bytes memory key,
        uint256 value
    ) internal pure returns (bytes memory) {
        bytes memory prefix = constructPrefix(currentAncillaryData, key);
        return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value));
    }

    /**
     * @notice Helper method that returns the left hand side of a "key:value" pair plus the colon ":" and a leading
     * comma "," if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to
     * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary.
     */
    function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) {
        if (currentAncillaryData.length > 0) {
            return abi.encodePacked(",", key, ":");
        } else {
            return abi.encodePacked(key, ":");
        }
    }
}
AddressWhitelist.sol 88 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import "../interfaces/AddressWhitelistInterface.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Lockable.sol";

/**
 * @title A contract to track a whitelist of addresses.
 */
contract AddressWhitelist is AddressWhitelistInterface, Ownable, Lockable {
    enum Status { None, In, Out }
    mapping(address => Status) public whitelist;

    address[] public whitelistIndices;

    event AddedToWhitelist(address indexed addedAddress);
    event RemovedFromWhitelist(address indexed removedAddress);

    /**
     * @notice Adds an address to the whitelist.
     * @param newElement the new address to add.
     */
    function addToWhitelist(address newElement) external override nonReentrant() onlyOwner {
        // Ignore if address is already included
        if (whitelist[newElement] == Status.In) {
            return;
        }

        // Only append new addresses to the array, never a duplicate
        if (whitelist[newElement] == Status.None) {
            whitelistIndices.push(newElement);
        }

        whitelist[newElement] = Status.In;

        emit AddedToWhitelist(newElement);
    }

    /**
     * @notice Removes an address from the whitelist.
     * @param elementToRemove the existing address to remove.
     */
    function removeFromWhitelist(address elementToRemove) external override nonReentrant() onlyOwner {
        if (whitelist[elementToRemove] != Status.Out) {
            whitelist[elementToRemove] = Status.Out;
            emit RemovedFromWhitelist(elementToRemove);
        }
    }

    /**
     * @notice Checks whether an address is on the whitelist.
     * @param elementToCheck the address to check.
     * @return True if `elementToCheck` is on the whitelist, or False.
     */
    function isOnWhitelist(address elementToCheck) external view override nonReentrantView() returns (bool) {
        return whitelist[elementToCheck] == Status.In;
    }

    /**
     * @notice Gets all addresses that are currently included in the whitelist.
     * @dev Note: This method skips over, but still iterates through addresses. It is possible for this call to run out
     * of gas if a large number of addresses have been removed. To reduce the likelihood of this unlikely scenario, we
     * can modify the implementation so that when addresses are removed, the last addresses in the array is moved to
     * the empty index.
     * @return activeWhitelist the list of addresses on the whitelist.
     */
    function getWhitelist() external view override nonReentrantView() returns (address[] memory activeWhitelist) {
        // Determine size of whitelist first
        uint256 activeCount = 0;
        for (uint256 i = 0; i < whitelistIndices.length; i++) {
            if (whitelist[whitelistIndices[i]] == Status.In) {
                activeCount++;
            }
        }

        // Populate whitelist
        activeWhitelist = new address[](activeCount);
        activeCount = 0;
        for (uint256 i = 0; i < whitelistIndices.length; i++) {
            address addr = whitelistIndices[i];
            if (whitelist[addr] == Status.In) {
                activeWhitelist[activeCount] = addr;
                activeCount++;
            }
        }
    }
}
SignedSafeMath.sol 68 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SignedSafeMath {
    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int256 a, int256 b) internal pure returns (int256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int256 a, int256 b) internal pure returns (int256) {
        return a / b;
    }

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

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        return a + b;
    }
}
SafeERC20.sol 99 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.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));
        }
    }

    /**
     * @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");
        }
    }
}
AddressWhitelistInterface.sol 12 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

interface AddressWhitelistInterface {
    function addToWhitelist(address newElement) external;

    function removeFromWhitelist(address newElement) external;

    function isOnWhitelist(address newElement) external view returns (bool);

    function getWhitelist() external view returns (address[] memory);
}
Constants.sol 34 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Stores common interface names used throughout the DVM by registration in the Finder.
 */
library OracleInterfaces {
    bytes32 public constant Oracle = "Oracle";
    bytes32 public constant IdentifierWhitelist = "IdentifierWhitelist";
    bytes32 public constant Store = "Store";
    bytes32 public constant FinancialContractsAdmin = "FinancialContractsAdmin";
    bytes32 public constant Registry = "Registry";
    bytes32 public constant CollateralWhitelist = "CollateralWhitelist";
    bytes32 public constant OptimisticOracle = "OptimisticOracle";
    bytes32 public constant OptimisticOracleV2 = "OptimisticOracleV2";
    bytes32 public constant Bridge = "Bridge";
    bytes32 public constant GenericHandler = "GenericHandler";
    bytes32 public constant SkinnyOptimisticOracle = "SkinnyOptimisticOracle";
    bytes32 public constant ChildMessenger = "ChildMessenger";
    bytes32 public constant OracleHub = "OracleHub";
    bytes32 public constant OracleSpoke = "OracleSpoke";
    bytes32 public constant OptimisticOracleV3 = "OptimisticOracleV3";
}

/**
 * @title Commonly re-used values for contracts associated with the OptimisticOracle.
 */
library OptimisticOracleConstraints {
    // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value.
    // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible
    // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which
    // refuses to accept a price request made with ancillary data length over a certain size.
    uint256 public constant ancillaryBytesLimit = 8192;
}
StoreInterface.sol 46 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../common/implementation/FixedPoint.sol";

/**
 * @title Interface that allows financial contracts to pay oracle fees for their use of the system.
 */
interface StoreInterface {
    /**
     * @notice Pays Oracle fees in ETH to the store.
     * @dev To be used by contracts whose margin currency is ETH.
     */
    function payOracleFees() external payable;

    /**
     * @notice Pays oracle fees in the margin currency, erc20Address, to the store.
     * @dev To be used if the margin currency is an ERC20 token rather than ETH.
     * @param erc20Address address of the ERC20 token used to pay the fee.
     * @param amount number of tokens to transfer. An approval for at least this amount must exist.
     */
    function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external;

    /**
     * @notice Computes the regular oracle fees that a contract should pay for a period.
     * @param startTime defines the beginning time from which the fee is paid.
     * @param endTime end time until which the fee is paid.
     * @param pfc "profit from corruption", or the maximum amount of margin currency that a
     * token sponsor could extract from the contract through corrupting the price feed in their favor.
     * @return regularFee amount owed for the duration from start to end time for the given pfc.
     * @return latePenalty for paying the fee after the deadline.
     */
    function computeRegularFee(
        uint256 startTime,
        uint256 endTime,
        FixedPoint.Unsigned calldata pfc
    ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty);

    /**
     * @notice Computes the final oracle fees that a contract should pay at settlement.
     * @param currency token used to pay the final fee.
     * @return finalFee amount due.
     */
    function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory);
}
FinderInterface.sol 22 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Provides addresses of the live contracts implementing certain interfaces.
 * @dev Examples are the Oracle or Store interfaces.
 */
interface FinderInterface {
    /**
     * @notice Updates the address of the contract that implements `interfaceName`.
     * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.
     * @param implementationAddress address of the deployed contract that implements the interface.
     */
    function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;

    /**
     * @notice Gets the address of the contract that implements the given `interfaceName`.
     * @param interfaceName queried interface.
     * @return implementationAddress address of the deployed contract that implements the interface.
     */
    function getImplementationAddress(bytes32 interfaceName) external view returns (address);
}
OptimisticOracleV3.sol 502 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../interfaces/OptimisticOracleV3CallbackRecipientInterface.sol";
import "../interfaces/OptimisticOracleV3Interface.sol";
import "../interfaces/EscalationManagerInterface.sol";

import "../../data-verification-mechanism/implementation/Constants.sol";
import "../../data-verification-mechanism/interfaces/FinderInterface.sol";
import "../../data-verification-mechanism/interfaces/IdentifierWhitelistInterface.sol";
import "../../data-verification-mechanism/interfaces/OracleAncillaryInterface.sol";
import "../../data-verification-mechanism/interfaces/StoreInterface.sol";

import "../../common/implementation/AddressWhitelist.sol";
import "../../common/implementation/AncillaryData.sol";
import "../../common/implementation/Lockable.sol";
import "../../common/implementation/MultiCaller.sol";

/**
 * @title Optimistic Oracle V3.
 * @notice The OOv3 is used to assert truths about the world which are verified using an optimistic escalation game.
 * @dev Core idea: an asserter makes a statement about a truth, calling "assertTruth". If this statement is not
 * challenged, it is taken as the state of the world. If challenged, it is arbitrated using the UMA DVM, or if
 * configured, an escalation manager. Escalation managers enable integrations to define their own security properties and
 * tradeoffs, enabling the notion of "sovereign security".
 */

contract OptimisticOracleV3 is OptimisticOracleV3Interface, Lockable, Ownable, MultiCaller {
    using SafeERC20 for IERC20;

    FinderInterface public immutable finder; // Finder used to discover other UMA ecosystem contracts.

    // Cached UMA parameters.
    address public cachedOracle;
    mapping(address => WhitelistedCurrency) public cachedCurrencies;
    mapping(bytes32 => bool) public cachedIdentifiers;

    mapping(bytes32 => Assertion) public assertions; // All assertions made by the Optimistic Oracle V3.

    uint256 public burnedBondPercentage; // Percentage of the bond that is paid to the UMA store if the assertion is disputed.

    bytes32 public constant defaultIdentifier = "ASSERT_TRUTH";
    int256 public constant numericalTrue = 1e18; // Numerical representation of true.
    IERC20 public defaultCurrency;
    uint64 public defaultLiveness;

    /**
     * @notice Construct the OptimisticOracleV3 contract.
     * @param _finder keeps track of all contracts within the UMA system based on their interfaceName.
     * @param _defaultCurrency the default currency to bond asserters in assertTruthWithDefaults.
     * @param _defaultLiveness the default liveness for assertions in assertTruthWithDefaults.
     */
    constructor(
        FinderInterface _finder,
        IERC20 _defaultCurrency,
        uint64 _defaultLiveness
    ) {
        finder = _finder;
        setAdminProperties(_defaultCurrency, _defaultLiveness, 0.5e18);
    }

    /**
     * @notice Sets the default currency, liveness, and burned bond percentage.
     * @dev Only callable by the contract owner (UMA governor).
     * @param _defaultCurrency the default currency to bond asserters in assertTruthWithDefaults.
     * @param _defaultLiveness the default liveness for assertions in assertTruthWithDefaults.
     * @param _burnedBondPercentage the percentage of the bond that is sent as fee to UMA Store contract on disputes.
     */
    function setAdminProperties(
        IERC20 _defaultCurrency,
        uint64 _defaultLiveness,
        uint256 _burnedBondPercentage
    ) public onlyOwner {
        require(_burnedBondPercentage <= 1e18, "Burned bond percentage > 100");
        require(_burnedBondPercentage > 0, "Burned bond percentage is 0");
        burnedBondPercentage = _burnedBondPercentage;
        defaultCurrency = _defaultCurrency;
        defaultLiveness = _defaultLiveness;
        syncUmaParams(defaultIdentifier, address(_defaultCurrency));

        emit AdminPropertiesSet(_defaultCurrency, _defaultLiveness, _burnedBondPercentage);
    }

    /**
     * @notice Asserts a truth about the world, using the default currency and liveness. No callback recipient or
     * escalation manager is enabled. The caller is expected to provide a bond of finalFee/burnedBondPercentage
     * (with burnedBondPercentage set to 50%, the bond is 2x final fee) of the default currency.
     * @dev The caller must approve this contract to spend at least the result of getMinimumBond(defaultCurrency).
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter account that receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @return assertionId unique identifier for this assertion.
     */

    function assertTruthWithDefaults(bytes calldata claim, address asserter) external returns (bytes32) {
        // Note: re-entrancy guard is done in the inner call.
        return
            assertTruth(
                claim,
                asserter, // asserter
                address(0), // callbackRecipient
                address(0), // escalationManager
                defaultLiveness,
                defaultCurrency,
                getMinimumBond(address(defaultCurrency)),
                defaultIdentifier,
                bytes32(0)
            );
    }

    /**
     * @notice Asserts a truth about the world, using a fully custom configuration.
     * @dev The caller must approve this contract to spend at least bond amount of currency.
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter account that receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @param callbackRecipient if configured, this address will receive a function call assertionResolvedCallback and
     * assertionDisputedCallback at resolution or dispute respectively. Enables dynamic responses to these events. The
     * recipient _must_ implement these callbacks and not revert or the assertion resolution will be blocked.
     * @param escalationManager if configured, this address will control escalation properties of the assertion. This
     * means a) choosing to arbitrate via the UMA DVM, b) choosing to discard assertions on dispute, or choosing to
     * validate disputes. Combining these, the asserter can define their own security properties for the assertion.
     * escalationManager also _must_ implement the same callbacks as callbackRecipient.
     * @param liveness time to wait before the assertion can be resolved. Assertion can be disputed in this time.
     * @param currency bond currency pulled from the caller and held in escrow until the assertion is resolved.
     * @param bond amount of currency to pull from the caller and hold in escrow until the assertion is resolved. This
     * must be >= getMinimumBond(address(currency)).
     * @param identifier UMA DVM identifier to use for price requests in the event of a dispute. Must be pre-approved.
     * @param domainId optional domain that can be used to relate this assertion to others in the escalationManager and
     * can be used by the configured escalationManager to define custom behavior for groups of assertions. This is
     * typically used for "escalation games" by changing bonds or other assertion properties based on the other
     * assertions that have come before. If not needed this value should be 0 to save gas.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruth(
        bytes memory claim,
        address asserter,
        address callbackRecipient,
        address escalationManager,
        uint64 liveness,
        IERC20 currency,
        uint256 bond,
        bytes32 identifier,
        bytes32 domainId
    ) public nonReentrant returns (bytes32 assertionId) {
        uint64 time = uint64(getCurrentTime());
        assertionId = _getId(claim, bond, time, liveness, currency, callbackRecipient, escalationManager, identifier);

        require(asserter != address(0), "Asserter cant be 0");
        require(assertions[assertionId].asserter == address(0), "Assertion already exists");
        require(_validateAndCacheIdentifier(identifier), "Unsupported identifier");
        require(_validateAndCacheCurrency(address(currency)), "Unsupported currency");
        require(bond >= getMinimumBond(address(currency)), "Bond amount too low");

        assertions[assertionId] = Assertion({
            escalationManagerSettings: EscalationManagerSettings({
                arbitrateViaEscalationManager: false, // Default behavior: use the DVM as an oracle.
                discardOracle: false, // Default behavior: respect the Oracle result.
                validateDisputers: false, // Default behavior: disputer will not be validated.
                escalationManager: escalationManager,
                assertingCaller: msg.sender
            }),
            asserter: asserter,
            disputer: address(0),
            callbackRecipient: callbackRecipient,
            currency: currency,
            domainId: domainId,
            identifier: identifier,
            bond: bond,
            settled: false,
            settlementResolution: false,
            assertionTime: time,
            expirationTime: time + liveness
        });

        {
            EscalationManagerInterface.AssertionPolicy memory assertionPolicy = _getAssertionPolicy(assertionId);
            require(!assertionPolicy.blockAssertion, "Assertion not allowed"); // Check if the assertion is permitted.
            EscalationManagerSettings storage emSettings = assertions[assertionId].escalationManagerSettings;
            (emSettings.arbitrateViaEscalationManager, emSettings.discardOracle, emSettings.validateDisputers) = (
                // Choose which oracle to arbitrate disputes via. If set to true then the escalation manager will
                // arbitrate disputes. Else, the DVM arbitrates disputes. This lets integrations "unplug" the DVM.
                assertionPolicy.arbitrateViaEscalationManager,
                // Choose whether to discard the Oracle result. If true then "throw away" the assertion. To get an
                // assertion to be true it must be re-asserted and not disputed.
                assertionPolicy.discardOracle,
                // Configures if the escalation manager should validate the disputer on assertions. This enables you
                // to construct setups such as whitelisted disputers.
                assertionPolicy.validateDisputers
            );
        }

        currency.safeTransferFrom(msg.sender, address(this), bond); // Pull the bond from the caller.

        emit AssertionMade(
            assertionId,
            domainId,
            claim,
            asserter,
            callbackRecipient,
            escalationManager,
            msg.sender,
            time + liveness,
            currency,
            bond,
            identifier
        );
    }

    /**
     * @notice Disputes an assertion. Depending on how the assertion was configured, this may either escalate to the UMA
     * DVM or the configured escalation manager for arbitration.
     * @dev The caller must approve this contract to spend at least bond amount of currency for the associated assertion.
     * @param assertionId unique identifier for the assertion to dispute.
     * @param disputer receives bonds back at settlement.
     */
    function disputeAssertion(bytes32 assertionId, address disputer) external nonReentrant {
        require(disputer != address(0), "Disputer can't be 0");
        Assertion storage assertion = assertions[assertionId];
        require(assertion.asserter != address(0), "Assertion does not exist");
        require(assertion.disputer == address(0), "Assertion already disputed");
        require(assertion.expirationTime > getCurrentTime(), "Assertion is expired");
        require(_isDisputeAllowed(assertionId), "Dispute not allowed");

        assertion.disputer = disputer;

        assertion.currency.safeTransferFrom(msg.sender, address(this), assertion.bond);

        _oracleRequestPrice(assertionId, assertion.identifier, assertion.assertionTime);

        _callbackOnAssertionDispute(assertionId);

        // Send resolve callback if dispute resolution is discarded
        if (assertion.escalationManagerSettings.discardOracle) _callbackOnAssertionResolve(assertionId, false);

        emit AssertionDisputed(assertionId, msg.sender, disputer);
    }

    /**
     * @notice Resolves an assertion. If the assertion has not been disputed, the assertion is resolved as true and the
     * asserter receives the bond. If the assertion has been disputed, the assertion is resolved depending on the oracle
     * result. Based on the result, the asserter or disputer receives the bond. If the assertion was disputed then an
     * amount of the bond is sent to the UMA Store as an oracle fee based on the burnedBondPercentage. The remainder of
     * the bond is returned to the asserter or disputer.
     * @param assertionId unique identifier for the assertion to resolve.
     */
    function settleAssertion(bytes32 assertionId) public nonReentrant {
        Assertion storage assertion = assertions[assertionId];
        require(assertion.asserter != address(0), "Assertion does not exist"); // Revert if assertion does not exist.
        require(!assertion.settled, "Assertion already settled"); // Revert if assertion already settled.
        assertion.settled = true;
        if (assertion.disputer == address(0)) {
            // No dispute, settle with the asserter
            require(assertion.expirationTime <= getCurrentTime(), "Assertion not expired"); // Revert if not expired.
            assertion.settlementResolution = true;
            assertion.currency.safeTransfer(assertion.asserter, assertion.bond);
            _callbackOnAssertionResolve(assertionId, true);

            emit AssertionSettled(assertionId, assertion.asserter, false, true, msg.sender);
        } else {
            // Dispute, settle with the disputer. Reverts if price not resolved.
            int256 resolvedPrice = _oracleGetPrice(assertionId, assertion.identifier, assertion.assertionTime);

            // If set to discard settlement resolution then false. Else, use oracle value to find resolution.
            if (assertion.escalationManagerSettings.discardOracle) assertion.settlementResolution = false;
            else assertion.settlementResolution = resolvedPrice == numericalTrue;

            address bondRecipient = resolvedPrice == numericalTrue ? assertion.asserter : assertion.disputer;

            // Calculate oracle fee and the remaining amount of bonds to send to the correct party (asserter or disputer).
            uint256 oracleFee = (burnedBondPercentage * assertion.bond) / 1e18;
            uint256 bondRecipientAmount = assertion.bond * 2 - oracleFee;

            // Pay out the oracle fee and remaining bonds to the correct party. Note: the oracle fee is sent to the
            // Store contract, even if the escalation manager is used to arbitrate disputes.
            assertion.currency.safeTransfer(address(_getStore()), oracleFee);
            assertion.currency.safeTransfer(bondRecipient, bondRecipientAmount);

            if (!assertion.escalationManagerSettings.discardOracle)
                _callbackOnAssertionResolve(assertionId, assertion.settlementResolution);

            emit AssertionSettled(assertionId, bondRecipient, true, assertion.settlementResolution, msg.sender);
        }
    }

    /**
     * @notice Settles an assertion and returns the resolution.
     * @param assertionId unique identifier for the assertion to resolve and return the resolution for.
     * @return resolution of the assertion.
     */
    function settleAndGetAssertionResult(bytes32 assertionId) external returns (bool) {
        // Note: re-entrancy guard is done in the inner settleAssertion call.
        if (!assertions[assertionId].settled) settleAssertion(assertionId);
        return getAssertionResult(assertionId);
    }

    /**
     * @notice Fetches information about a specific identifier & currency from the UMA contracts and stores a local copy
     * of the information within this contract. This is used to save gas when making assertions as we can avoid an
     * external call to the UMA contracts to fetch this.
     * @param identifier identifier to fetch information for and store locally.
     * @param currency currency to fetch information for and store locally.
     */
    function syncUmaParams(bytes32 identifier, address currency) public {
        cachedOracle = finder.getImplementationAddress(OracleInterfaces.Oracle);
        cachedIdentifiers[identifier] = _getIdentifierWhitelist().isIdentifierSupported(identifier);
        cachedCurrencies[currency].isWhitelisted = _getCollateralWhitelist().isOnWhitelist(currency);
        cachedCurrencies[currency].finalFee = _getStore().computeFinalFee(currency).rawValue;
    }

    /**
     * @notice Fetches information about a specific assertion and returns it.
     * @param assertionId unique identifier for the assertion to fetch information for.
     * @return assertion information about the assertion.
     */
    function getAssertion(bytes32 assertionId) external view returns (Assertion memory) {
        return assertions[assertionId];
    }

    /**
     * @notice Fetches the resolution of a specific assertion and returns it. If the assertion has not been settled then
     * this will revert. If the assertion was disputed and configured to discard the oracle resolution return false.
     * @param assertionId unique identifier for the assertion to fetch the resolution for.
     * @return resolution of the assertion.
     */
    function getAssertionResult(bytes32 assertionId) public view returns (bool) {
        Assertion memory assertion = assertions[assertionId];
        // Return early if not using answer from resolved dispute.
        if (assertion.disputer != address(0) && assertion.escalationManagerSettings.discardOracle) return false;
        require(assertion.settled, "Assertion not settled"); // Revert if assertion not settled.
        return assertion.settlementResolution;
    }

    /**
     * @notice Returns the current block timestamp.
     * @dev Can be overridden to control contract time.
     * @return current block timestamp.
     */
    function getCurrentTime() public view virtual returns (uint256) {
        return block.timestamp;
    }

    /**
     * @notice Appends information onto an assertionId to construct ancillary data used for dispute resolution.
     * @param assertionId unique identifier for the assertion to construct ancillary data for.
     * @return ancillaryData stamped assertion information.
     */
    function stampAssertion(bytes32 assertionId) public view returns (bytes memory) {
        return _stampAssertion(assertionId);
    }

    /**
     * @notice Returns the minimum bond amount required to make an assertion. This is calculated as the final fee of the
     * currency divided by the burnedBondPercentage. If burn percentage is 50% then the min bond is 2x the final fee.
     * @param currency currency to calculate the minimum bond for.
     * @return minimum bond amount.
     */
    function getMinimumBond(address currency) public view returns (uint256) {
        uint256 finalFee = cachedCurrencies[currency].finalFee;
        return (finalFee * 1e18) / burnedBondPercentage;
    }

    // Returns the unique identifier for this assertion. This identifier is used to identify the assertion.
    function _getId(
        bytes memory claim,
        uint256 bond,
        uint256 time,
        uint64 liveness,
        IERC20 currency,
        address callbackRecipient,
        address escalationManager,
        bytes32 identifier
    ) internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    claim,
                    bond,
                    time,
                    liveness,
                    currency,
                    callbackRecipient,
                    escalationManager,
                    identifier,
                    msg.sender
                )
            );
    }

    // Returns ancillary data for the Oracle request containing assertionId and asserter.
    function _stampAssertion(bytes32 assertionId) internal view returns (bytes memory) {
        return
            AncillaryData.appendKeyValueAddress(
                AncillaryData.appendKeyValueBytes32("", "assertionId", assertionId),
                "ooAsserter",
                assertions[assertionId].asserter
            );
    }

    // Returns the Address Whitelist contract to validate the currency.
    function _getCollateralWhitelist() internal view returns (AddressWhitelist) {
        return AddressWhitelist(finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist));
    }

    // Returns the Identifier Whitelist contract to validate the identifier.
    function _getIdentifierWhitelist() internal view returns (IdentifierWhitelistInterface) {
        return IdentifierWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist));
    }

    // Returns the Store contract to fetch the final fee.
    function _getStore() internal view returns (StoreInterface) {
        return StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store));
    }

    // Returns the Oracle contract to use on dispute. This can be either UMA DVM or the escalation manager.
    function _getOracle(bytes32 assertionId) internal view returns (OracleAncillaryInterface) {
        if (assertions[assertionId].escalationManagerSettings.arbitrateViaEscalationManager)
            return OracleAncillaryInterface(_getEscalationManager(assertionId));
        return OracleAncillaryInterface(cachedOracle);
    }

    // Requests resolving dispute from the Oracle (UMA DVM or escalation manager).
    function _oracleRequestPrice(
        bytes32 assertionId,
        bytes32 identifier,
        uint256 time
    ) internal {
        _getOracle(assertionId).requestPrice(identifier, time, _stampAssertion(assertionId));
    }

    // Returns the resolved resolution from the Oracle (UMA DVM or escalation manager).
    function _oracleGetPrice(
        bytes32 assertionId,
        bytes32 identifier,
        uint256 time
    ) internal view returns (int256) {
        return _getOracle(assertionId).getPrice(identifier, time, _stampAssertion(assertionId));
    }

    // Returns the escalation manager address for the assertion.
    function _getEscalationManager(bytes32 assertionId) internal view returns (address) {
        return assertions[assertionId].escalationManagerSettings.escalationManager;
    }

    // Returns the assertion policy parameters from the escalation manager. If no escalation manager is set then return
    // default values.
    function _getAssertionPolicy(bytes32 assertionId)
        internal
        view
        returns (EscalationManagerInterface.AssertionPolicy memory)
    {
        address em = _getEscalationManager(assertionId);
        if (em == address(0)) return EscalationManagerInterface.AssertionPolicy(false, false, false, false);
        return EscalationManagerInterface(em).getAssertionPolicy(assertionId);
    }

    // Returns whether the dispute is allowed by the escalation manager. If no escalation manager is set or the
    // escalation manager is not configured to validate disputers then return true.
    function _isDisputeAllowed(bytes32 assertionId) internal view returns (bool) {
        if (!assertions[assertionId].escalationManagerSettings.validateDisputers) return true;
        address em = assertions[assertionId].escalationManagerSettings.escalationManager;
        if (em == address(0)) return true;
        return EscalationManagerInterface(em).isDisputeAllowed(assertionId, msg.sender);
    }

    // Validates if the identifier is whitelisted by first checking the cache. If not whitelisted in the cache then
    // checks it from the identifier whitelist contract and caches result.
    function _validateAndCacheIdentifier(bytes32 identifier) internal returns (bool) {
        if (cachedIdentifiers[identifier]) return true;
        cachedIdentifiers[identifier] = _getIdentifierWhitelist().isIdentifierSupported(identifier);
        return cachedIdentifiers[identifier];
    }

    // Validates if the currency is whitelisted by first checking the cache. If not whitelisted in the cache then
    // checks it from the collateral whitelist contract and caches whitelist status and final fee.
    function _validateAndCacheCurrency(address currency) internal returns (bool) {
        if (cachedCurrencies[currency].isWhitelisted) return true;
        cachedCurrencies[currency].isWhitelisted = _getCollateralWhitelist().isOnWhitelist(currency);
        cachedCurrencies[currency].finalFee = _getStore().computeFinalFee(currency).rawValue;
        return cachedCurrencies[currency].isWhitelisted;
    }

    // Sends assertion resolved callback to the callback recipient and escalation manager (if set).
    function _callbackOnAssertionResolve(bytes32 assertionId, bool assertedTruthfully) internal {
        address cr = assertions[assertionId].callbackRecipient;
        address em = _getEscalationManager(assertionId);
        if (cr != address(0))
            OptimisticOracleV3CallbackRecipientInterface(cr).assertionResolvedCallback(assertionId, assertedTruthfully);
        if (em != address(0)) EscalationManagerInterface(em).assertionResolvedCallback(assertionId, assertedTruthfully);
    }

    // Sends assertion disputed callback to the callback recipient and escalation manager (if set).
    function _callbackOnAssertionDispute(bytes32 assertionId) internal {
        address cr = assertions[assertionId].callbackRecipient;
        address em = _getEscalationManager(assertionId);
        if (cr != address(0)) OptimisticOracleV3CallbackRecipientInterface(cr).assertionDisputedCallback(assertionId);
        if (em != address(0)) EscalationManagerInterface(em).assertionDisputedCallback(assertionId);
    }
}
EscalationManagerInterface.sol 61 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "./OptimisticOracleV3CallbackRecipientInterface.sol";

/**
 * @title Escalation Manager Interface
 * @notice Interface for contracts that manage the escalation policy for assertions.
 */
interface EscalationManagerInterface is OptimisticOracleV3CallbackRecipientInterface {
    // Assertion policy parameters as returned by the escalation manager.
    struct AssertionPolicy {
        bool blockAssertion; // If true, the the assertion should be blocked.
        bool arbitrateViaEscalationManager; // If true, the escalation manager will arbitrate the assertion.
        bool discardOracle; // If true, the Optimistic Oracle V3 should discard the oracle price.
        bool validateDisputers; // If true, the escalation manager will validate the disputers.
    }

    /**
     * @notice Returns the assertion policy for the given assertion.
     * @param assertionId the assertion identifier to get the assertion policy for.
     * @return the assertion policy for the given assertion identifier.
     */
    function getAssertionPolicy(bytes32 assertionId) external view returns (AssertionPolicy memory);

    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is disputed. Used to validate
     * if the dispute should be allowed based on the escalation policy.
     * @param assertionId the assertionId to validate the dispute for.
     * @param disputeCaller the caller of the dispute function.
     * @return bool true if the dispute is allowed, false otherwise.
     */
    function isDisputeAllowed(bytes32 assertionId, address disputeCaller) external view returns (bool);

    /**
     * @notice Implements price getting logic. This method is called by Optimistic Oracle V3 settling an assertion that
     * is configured to use the escalation manager as the oracle. The interface is constructed to mimic the UMA DVM.
     * @param identifier price identifier being requested.
     * @param time timestamp of the price being requested.
     * @param ancillaryData ancillary data of the price being requested.
     * @return price from the escalation manager to inform the resolution of the dispute.
     */
    function getPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) external returns (int256);

    /**
     * @notice Implements price requesting logic for the escalation manager. This function is called by the Optimistic
     * Oracle V3 on dispute and is constructed to mimic that of the UMA DVM interface.
     * @param identifier the identifier to fetch the price for.
     * @param time the time to fetch the price for.
     * @param ancillaryData ancillary data of the price being requested.
     */
    function requestPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) external;
}
OptimisticOracleV3Interface.sol 169 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Optimistic Oracle V3 Interface that callers must use to assert truths about the world.
 */
interface OptimisticOracleV3Interface {
    // Struct grouping together the settings related to the escalation manager stored in the assertion.
    struct EscalationManagerSettings {
        bool arbitrateViaEscalationManager; // False if the DVM is used as an oracle (EscalationManager on True).
        bool discardOracle; // False if Oracle result is used for resolving assertion after dispute.
        bool validateDisputers; // True if the EM isDisputeAllowed should be checked on disputes.
        address assertingCaller; // Stores msg.sender when assertion was made.
        address escalationManager; // Address of the escalation manager (zero address if not configured).
    }

    // Struct for storing properties and lifecycle of an assertion.
    struct Assertion {
        EscalationManagerSettings escalationManagerSettings; // Settings related to the escalation manager.
        address asserter; // Address of the asserter.
        uint64 assertionTime; // Time of the assertion.
        bool settled; // True if the request is settled.
        IERC20 currency; // ERC20 token used to pay rewards and fees.
        uint64 expirationTime; // Unix timestamp marking threshold when the assertion can no longer be disputed.
        bool settlementResolution; // Resolution of the assertion (false till resolved).
        bytes32 domainId; // Optional domain that can be used to relate the assertion to others in the escalationManager.
        bytes32 identifier; // UMA DVM identifier to use for price requests in the event of a dispute.
        uint256 bond; // Amount of currency that the asserter has bonded.
        address callbackRecipient; // Address that receives the callback.
        address disputer; // Address of the disputer.
    }

    // Struct for storing cached currency whitelist.
    struct WhitelistedCurrency {
        bool isWhitelisted; // True if the currency is whitelisted.
        uint256 finalFee; // Final fee of the currency.
    }

    /**
     * @notice Returns the default identifier used by the Optimistic Oracle V3.
     * @return The default identifier.
     */
    function defaultIdentifier() external view returns (bytes32);

    /**
     * @notice Fetches information about a specific assertion and returns it.
     * @param assertionId unique identifier for the assertion to fetch information for.
     * @return assertion information about the assertion.
     */
    function getAssertion(bytes32 assertionId) external view returns (Assertion memory);

    /**
     * @notice Asserts a truth about the world, using the default currency and liveness. No callback recipient or
     * escalation manager is enabled. The caller is expected to provide a bond of finalFee/burnedBondPercentage
     * (with burnedBondPercentage set to 50%, the bond is 2x final fee) of the default currency.
     * @dev The caller must approve this contract to spend at least the result of getMinimumBond(defaultCurrency).
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruthWithDefaults(bytes memory claim, address asserter) external returns (bytes32);

    /**
     * @notice Asserts a truth about the world, using a fully custom configuration.
     * @dev The caller must approve this contract to spend at least bond amount of currency.
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @param callbackRecipient if configured, this address will receive a function call assertionResolvedCallback and
     * assertionDisputedCallback at resolution or dispute respectively. Enables dynamic responses to these events. The
     * recipient _must_ implement these callbacks and not revert or the assertion resolution will be blocked.
     * @param escalationManager if configured, this address will control escalation properties of the assertion. This
     * means a) choosing to arbitrate via the UMA DVM, b) choosing to discard assertions on dispute, or choosing to
     * validate disputes. Combining these, the asserter can define their own security properties for the assertion.
     * escalationManager also _must_ implement the same callbacks as callbackRecipient.
     * @param liveness time to wait before the assertion can be resolved. Assertion can be disputed in this time.
     * @param currency bond currency pulled from the caller and held in escrow until the assertion is resolved.
     * @param bond amount of currency to pull from the caller and hold in escrow until the assertion is resolved. This
     * must be >= getMinimumBond(address(currency)).
     * @param identifier UMA DVM identifier to use for price requests in the event of a dispute. Must be pre-approved.
     * @param domainId optional domain that can be used to relate this assertion to others in the escalationManager and
     * can be used by the configured escalationManager to define custom behavior for groups of assertions. This is
     * typically used for "escalation games" by changing bonds or other assertion properties based on the other
     * assertions that have come before. If not needed this value should be 0 to save gas.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruth(
        bytes memory claim,
        address asserter,
        address callbackRecipient,
        address escalationManager,
        uint64 liveness,
        IERC20 currency,
        uint256 bond,
        bytes32 identifier,
        bytes32 domainId
    ) external returns (bytes32);

    /**
     * @notice Fetches information about a specific identifier & currency from the UMA contracts and stores a local copy
     * of the information within this contract. This is used to save gas when making assertions as we can avoid an
     * external call to the UMA contracts to fetch this.
     * @param identifier identifier to fetch information for and store locally.
     * @param currency currency to fetch information for and store locally.
     */
    function syncUmaParams(bytes32 identifier, address currency) external;

    /**
     * @notice Resolves an assertion. If the assertion has not been disputed, the assertion is resolved as true and the
     * asserter receives the bond. If the assertion has been disputed, the assertion is resolved depending on the oracle
     * result. Based on the result, the asserter or disputer receives the bond. If the assertion was disputed then an
     * amount of the bond is sent to the UMA Store as an oracle fee based on the burnedBondPercentage. The remainder of
     * the bond is returned to the asserter or disputer.
     * @param assertionId unique identifier for the assertion to resolve.
     */
    function settleAssertion(bytes32 assertionId) external;

    /**
     * @notice Settles an assertion and returns the resolution.
     * @param assertionId unique identifier for the assertion to resolve and return the resolution for.
     * @return resolution of the assertion.
     */
    function settleAndGetAssertionResult(bytes32 assertionId) external returns (bool);

    /**
     * @notice Fetches the resolution of a specific assertion and returns it. If the assertion has not been settled then
     * this will revert. If the assertion was disputed and configured to discard the oracle resolution return false.
     * @param assertionId unique identifier for the assertion to fetch the resolution for.
     * @return resolution of the assertion.
     */
    function getAssertionResult(bytes32 assertionId) external view returns (bool);

    /**
     * @notice Returns the minimum bond amount required to make an assertion. This is calculated as the final fee of the
     * currency divided by the burnedBondPercentage. If burn percentage is 50% then the min bond is 2x the final fee.
     * @param currency currency to calculate the minimum bond for.
     * @return minimum bond amount.
     */
    function getMinimumBond(address currency) external view returns (uint256);

    event AssertionMade(
        bytes32 indexed assertionId,
        bytes32 domainId,
        bytes claim,
        address indexed asserter,
        address callbackRecipient,
        address escalationManager,
        address caller,
        uint64 expirationTime,
        IERC20 currency,
        uint256 bond,
        bytes32 indexed identifier
    );

    event AssertionDisputed(bytes32 indexed assertionId, address indexed caller, address indexed disputer);

    event AssertionSettled(
        bytes32 indexed assertionId,
        address indexed bondRecipient,
        bool disputed,
        bool settlementResolution,
        address settleCaller
    );

    event AdminPropertiesSet(IERC20 defaultCurrency, uint64 defaultLiveness, uint256 burnedBondPercentage);
}
OracleAncillaryInterface.sol 51 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Financial contract facing Oracle interface.
 * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
 */
abstract contract OracleAncillaryInterface {
    /**
     * @notice Enqueues a request (if a request isn't already present) for the given `identifier`, `time` pair.
     * @dev Time must be in the past and the identifier must be supported.
     * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
     * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller.
     * @param time unix timestamp for the price request.
     */

    function requestPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) public virtual;

    /**
     * @notice Whether the price for `identifier` and `time` is available.
     * @dev Time must be in the past and the identifier must be supported.
     * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
     * @param time unix timestamp for the price request.
     * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller.
     * @return bool if the DVM has resolved to a price for the given identifier and timestamp.
     */
    function hasPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) public view virtual returns (bool);

    /**
     * @notice Gets the price for `identifier` and `time` if it has already been requested and resolved.
     * @dev If the price is not available, the method reverts.
     * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested.
     * @param time unix timestamp for the price request.
     * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller.
     * @return int256 representing the resolved price for the given identifier and timestamp.
     */

    function getPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) public view virtual returns (int256);
}
IdentifierWhitelistInterface.sol 28 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Interface for whitelists of supported identifiers that the oracle can provide prices for.
 */
interface IdentifierWhitelistInterface {
    /**
     * @notice Adds the provided identifier as a supported identifier.
     * @dev Price requests using this identifier will succeed after this call.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     */
    function addSupportedIdentifier(bytes32 identifier) external;

    /**
     * @notice Removes the identifier from the whitelist.
     * @dev Price requests using this identifier will no longer succeed after this call.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     */
    function removeSupportedIdentifier(bytes32 identifier) external;

    /**
     * @notice Checks whether an identifier is on the whitelist.
     * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD.
     * @return bool if the identifier is supported (or not).
     */
    function isIdentifierSupported(bytes32 identifier) external view returns (bool);
}
OptimisticOracleV3CallbackRecipientInterface.sol 21 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

/**
 * @title Optimistic Oracle V3 Callback Recipient Interface
 * @notice Interface for contracts implementing callbacks to be received from the Optimistic Oracle V3.
 */
interface OptimisticOracleV3CallbackRecipientInterface {
    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is resolved.
     * @param assertionId The identifier of the assertion that was resolved.
     * @param assertedTruthfully Whether the assertion was resolved as truthful or not.
     */
    function assertionResolvedCallback(bytes32 assertionId, bool assertedTruthfully) external;

    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is disputed.
     * @param assertionId The identifier of the assertion that was disputed.
     */
    function assertionDisputedCallback(bytes32 assertionId) external;
}

Read Contract

assertions 0xd60715b5 → tuple, address, uint64, bool, address, uint64, bool, bytes32, bytes32, uint256, address, address
burnedBondPercentage 0x08e7c3e6 → uint256
cachedCurrencies 0x70762157 → bool, uint256
cachedIdentifiers 0x530dd392 → bool
cachedOracle 0xa7af2d0f → address
defaultCurrency 0x20402e1d → address
defaultIdentifier 0xd509b017 → bytes32
defaultLiveness 0xfe4e1983 → uint64
finder 0xb9a3c84c → address
getAssertion 0x88302884 → tuple
getAssertionResult 0xe39dfd7f → bool
getCurrentTime 0x29cb924d → uint256
getMinimumBond 0x4360af3d → uint256
numericalTrue 0xda03b36e → int256
owner 0x8da5cb5b → address
stampAssertion 0xafedba4f → bytes

Write Contract 10 functions

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

assertTruth 0x6457c979
bytes claim
address asserter
address callbackRecipient
address escalationManager
uint64 liveness
address currency
uint256 bond
bytes32 identifier
bytes32 domainId
returns: bytes32
assertTruthWithDefaults 0x36b13af4
bytes claim
address asserter
returns: bytes32
disputeAssertion 0xa6a22b43
bytes32 assertionId
address disputer
multicall 0xac9650d8
bytes[] data
returns: bytes[]
renounceOwnership 0x715018a6
No parameters
setAdminProperties 0x82762520
address _defaultCurrency
uint64 _defaultLiveness
uint256 _burnedBondPercentage
settleAndGetAssertionResult 0x8ea2f2ab
bytes32 assertionId
returns: bool
settleAssertion 0x4124beef
bytes32 assertionId
syncUmaParams 0xa8655785
bytes32 identifier
address currency
transferOwnership 0xf2fde38b
address newOwner

Recent Transactions

No transactions found for this address