Address Contract Verified
Address
0xfb55F43fB9F48F63f9269DB7Dde3BbBe1ebDC0dE
Balance
0 ETH
Nonce
1
Code Size
18038 bytes
Creator
0x9A8f92a8...b04D at tx 0x2683282d...2729d2
Indexed Transactions
0
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
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address