Address Contract Partially Verified
Address
0x584902BCe4282003E420Cf5b7ae5063D6C1c182a
Balance
0 ETH
Nonce
1
Code Size
9901 bytes
Creator
0xf03E9981...90e5 at tx 0xe356b793...6d23e6
Indexed Transactions
0
Contract Bytecode
9901 bytes
0x608060405234801561001057600080fd5b50600436106103615760003560e01c8063781097d0116101c8578063c809d4ed11610104578063e0fba44b116100a2578063ebf43bca1161007c578063ebf43bca14610950578063f097486c1461096e578063f6ccaad41461098c578063f97697ff1461099657610361565b8063e0fba44b146108f5578063e5a66dfa14610913578063eb995c431461093157610361565b8063cbda2f1a116100de578063cbda2f1a1461087e578063cca992fa1461089d578063d7360946146108bb578063e0d2e780146108d757610361565b8063c809d4ed14610828578063c82f2b1214610844578063cb757b971461086257610361565b806399a64f2811610171578063b374839b1161014b578063b374839b146107ae578063b93cd816146107cc578063bd9a548b146107ec578063c433c80a1461080c57610361565b806399a64f28146107545780639c0d313f14610772578063a2cc77031461079057610361565b806390e67fe8116101a257806390e67fe8146106fa578063952dca4814610718578063993e3d541461073657610361565b8063781097d0146106a05780637c99a499146106be5780638c1e2f92146106dc57610361565b80633cb6f5fa116102a25780634f8b4ae71161024057806359f768b21161021a57806359f768b2146106145780636ff48472146106325780637068d2b014610650578063726de1a51461068257610361565b80634f8b4ae7146105d057806356ee4c08146105da57806359c909e1146105f657610361565b8063471d77891161027c578063471d7789146105565780634bc66f32146105745780634d3375e8146105925780634e6c27cb146105b257610361565b80633cb6f5fa146104fc578063417d25a91461051c578063450140951461053a57610361565b8063208880041161030f578063313ce567116102e9578063313ce5671461048657806337f85f66146104a45780633b17136a146104c25780633be38cf9146104e057610361565b8063208880041461042c578063269392051461044a57806326d895451461046857610361565b8063090f3f5011610340578063090f3f50146103d25780630b7f3ffe146103f0578063116d79761461040e57610361565b806232e91a1461036657806301ffc9a71461038457806306fdde03146103b4575b600080fd5b61036e6109b4565b60405161037b9190611baf565b60405180910390f35b61039e60048036038101906103999190611c27565b6109d8565b6040516103ab9190611c6f565b60405180910390f35b6103bc610a4f565b6040516103c99190611d1a565b60405180910390f35b6103da610a6f565b6040516103e79190611d7d565b60405180910390f35b6103f8610a95565b6040516104059190611db1565b60405180910390f35b610416610aa4565b6040516104239190611d7d565b60405180910390f35b610434610ac8565b6040516104419190611d7d565b60405180910390f35b610452610aec565b60405161045f9190611d7d565b60405180910390f35b610470610b10565b60405161047d9190611deb565b60405180910390f35b61048e610b26565b60405161049b9190611e22565b60405180910390f35b6104ac610b2f565b6040516104b99190611db1565b60405180910390f35b6104ca610b53565b6040516104d79190611e22565b60405180910390f35b6104fa60048036038101906104f59190611e69565b610b77565b005b610504610b8b565b60405161051393929190611e96565b60405180910390f35b610524610ba9565b6040516105319190611d7d565b60405180910390f35b610554600480360381019061054f9190611ef9565b610bcd565b005b61055e610be1565b60405161056b9190611db1565b60405180910390f35b61057c610be7565b6040516105899190611d7d565b60405180910390f35b61059a610c0d565b6040516105a993929190611e96565b60405180910390f35b6105ba610c2b565b6040516105c79190611db1565b60405180910390f35b6105d8610c3a565b005b6105f460048036038101906105ef9190611e69565b610c60565b005b6105fe610c74565b60405161060b9190611d7d565b60405180910390f35b61061c610c98565b6040516106299190611db1565b60405180910390f35b61063a610c9e565b6040516106479190611db1565b60405180910390f35b61066a60048036038101906106659190611f52565b610cad565b60405161067993929190611e96565b60405180910390f35b61068a610cd8565b6040516106979190611db1565b60405180910390f35b6106a8610cfc565b6040516106b59190611db1565b60405180910390f35b6106c6610d20565b6040516106d39190611db1565b60405180910390f35b6106e4610d26565b6040516106f19190611db1565b60405180910390f35b610702610d32565b60405161070f9190611d7d565b60405180910390f35b610720610d56565b60405161072d9190611db1565b60405180910390f35b61073e610d5c565b60405161074b9190611d7d565b60405180910390f35b61075c610d80565b6040516107699190611d7d565b60405180910390f35b61077a610da4565b6040516107879190611db1565b60405180910390f35b610798610db0565b6040516107a59190611d7d565b60405180910390f35b6107b6610dd4565b6040516107c39190611d7d565b60405180910390f35b6107d4610df8565b6040516107e393929190611e96565b60405180910390f35b6107f4610e16565b60405161080393929190611e96565b60405180910390f35b6108266004803603810190610821919061200b565b610e34565b005b610842600480360381019061083d9190611e69565b610e48565b005b61084c610e5c565b6040516108599190611baf565b60405180910390f35b61087c60048036038101906108779190612076565b610e80565b005b610886610f0a565b6040516108949291906120a3565b60405180910390f35b6108a5610f67565b6040516108b29190611db1565b60405180910390f35b6108d560048036038101906108d09190611e69565b610f8b565b005b6108df610f9f565b6040516108ec9190611d7d565b60405180910390f35b6108fd610fc3565b60405161090a919061212b565b60405180910390f35b61091b610fe7565b6040516109289190611db1565b60405180910390f35b61093961100b565b6040516109479291906120a3565b60405180910390f35b610958611068565b6040516109659190611e22565b60405180910390f35b61097661108c565b6040516109839190611db1565b60405180910390f35b6109946110b0565b005b61099e6110c2565b6040516109ab9190612171565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000081565b60006109e3826110ce565b80610a485750600080837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060009054906101000a900460ff165b9050919050565b60606040518060800160405280605e8152602001612643605e9139905090565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610a9f611138565b905090565b7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f81565b7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f81565b7f0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc81565b600360009054906101000a900463ffffffff1681565b60006012905090565b7f000000000000000000000000000000000000000000000000000000000000001281565b7f000000000000000000000000000000000000000000000000000000000000000881565b610b7f6111fd565b610b8881611286565b50565b6000806000610b986112cb565b809350819450829550505050909192565b7f00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f5681565b610bd56111fd565b610bde81611394565b50565b60045481565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000610c1a611454565b809350819450829550505050909192565b6000610c35611138565b905090565b610c426111fd565b610c4a6114b3565b610c546000611394565b610c5e600061153c565b565b610c686111fd565b610c71816115fc565b50565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60015481565b6000610ca8611641565b905090565b6000806000610cc08989898989896117f5565b80935081945082955050505096509650969350505050565b7f0000000000000000000000000000000000000000000000000000000005f5e10081565b7f000000000000000000000000000000000000000000000000000000000000001281565b60055481565b670de0b6b3a764000081565b7f0000000000000000000000005e8422345238f34275888049021821e8e08caa1f81565b60025481565b7f0000000000000000000000005e8422345238f34275888049021821e8e08caa1f81565b7f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841981565b670de0b6b3a764000081565b7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e81565b7f000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd81565b6000806000610e056118f6565b809350819450829550505050909192565b6000806000610e23611454565b809350819450829550505050909192565b610e3c6111fd565b610e45816119bf565b50565b610e506111fd565b610e5981611a2e565b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000610e8d611454565b9250925092508373ffffffffffffffffffffffffffffffffffffffff166345d9f582848484426040518563ffffffff1660e01b8152600401610ed294939291906121d4565b600060405180830381600087803b158015610eec57600080fd5b505af1158015610f00573d6000803e3d6000fd5b5050505050505050565b600080600080610f186118f6565b92505091508193507f0000000000000000000000000000000000000000000000000000000005f5e10081670de0b6b3a7640000610f559190612248565b610f5f91906122b9565b925050509091565b7f0000000000000000000000000000000000000000000000000000000005f5e10081565b610f936111fd565b610f9c81611a73565b50565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b7f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f81565b7f000000000000000000000000000000000000000000000000000000000000001281565b60008060006110186112cb565b905080925081945050507f0000000000000000000000000000000000000000000000000000000005f5e10081670de0b6b3a76400006110579190612248565b61106191906122b9565b9150509091565b7f000000000000000000000000000000000000000000000000000000000000000881565b7f000000000000000000000000000000000000000000000000000000000000001281565b6110b86114b3565b6110c0611ab8565b565b670de0b6b3a764000081565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6000807f0000000000000000000000009c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc73ffffffffffffffffffffffffffffffffffffffff166386fc88d36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ca91906122ff565b9050600060025482116111dd57816111e1565b6002545b905060015481106111f257806111f6565b6001545b9250505090565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611284576040517f1c0be90a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b7f5215771cad7bc88de36c71ac95764acc6eb44eeca03f4b9f90eb8a8c1131e3aa600454826040516112b992919061232c565b60405180910390a18060048190555050565b60008060008060007f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561133e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136291906123c3565b5093505092505060008213158061138557506005548142611383919061243e565b115b94508093508192505050909192565b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a60405160405180910390a350565b600080600080611462610c2b565b9050600061146e611641565b905060008061147b61100b565b9150915060008061148a610f0a565b9150915061149c8686868686866117f5565b809950819a50829b50505050505050505050909192565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461153a576040517ff5c49e6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b8073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc660405160405180910390a380600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b7fcfde23b8b5cb70458592a0920d25ba0c811d04a57f0737cc8a379cbbf0dbbbb46002548260405161162f92919061232c565b60405180910390a18060028190555050565b600080600167ffffffffffffffff81111561165f5761165e612472565b5b60405190808252806020026020018201604052801561168d5781602001602082028036833780820191505090505b5090507f00000000000000000000000036c060cc4b088c830a561e959a679a58205d3f56816000815181106116c5576116c46124a1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b210ce856631eeeb767efa666ec7c1c57738d43873ffffffffffffffffffffffffffffffffffffffff166307f7ca9f670de0b6b3a76400007f0000000000000000000000005e8422345238f34275888049021821e8e08caa1f7f000000000000000000000000853d955acef822db058eb8505911ed77f175b99e85600360009054906101000a900463ffffffff166040518663ffffffff1660e01b81526004016117ae95949392919061258e565b602060405180830381865afa1580156117cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ef91906122ff565b91505090565b6000806000611808898989898989611b05565b80935081945082955050505060007f000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38f73ffffffffffffffffffffffffffffffffffffffff166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa158015611881573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a591906122ff565b9050670de0b6b3a764000083826118bc9190612248565b6118c691906122b9565b9250670de0b6b3a764000082826118dd9190612248565b6118e791906122b9565b91505096509650969350505050565b60008060008060007f000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd73ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611969573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198d91906123c3565b509350509250506000821315806119b0575060045481426119ae919061243e565b115b94508093508192505050909192565b7fa5868b8f066a74ed982ad7843f1f76a16fc96b95c00596d6249b5fe5dee54413600360009054906101000a900463ffffffff1682604051611a02929190612619565b60405180910390a180600360006101000a81548163ffffffff021916908363ffffffff16021790555050565b7f2d76fda59e51b6069c5600ca7d7f2cb8449933f16ba284b7a22f410d487ac90460015482604051611a6192919061232c565b60405180910390a18060018190555050565b7f1b427db70b2e813aae1e9f4dc54fcd2ae904b1350f60b84a7bab7d379aa2b02e60055482604051611aa692919061232c565b60405180910390a18060058190555050565b6000600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611b033361153c565b565b60008060008086858a611b189190612248565b611b2291906122b9565b905060006002549050600060015490506000828411611b415783611b43565b825b90506000828210611b545781611b56565b825b90508b80611b615750895b9750808e10611b705780611b72565b8d5b96508d8111611b81578d611b83565b805b9550505050505096509650969350505050565b6000819050919050565b611ba981611b96565b82525050565b6000602082019050611bc46000830184611ba0565b92915050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611c0481611bcf565b8114611c0f57600080fd5b50565b600081359050611c2181611bfb565b92915050565b600060208284031215611c3d57611c3c611bca565b5b6000611c4b84828501611c12565b91505092915050565b60008115159050919050565b611c6981611c54565b82525050565b6000602082019050611c846000830184611c60565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611cc4578082015181840152602081019050611ca9565b60008484015250505050565b6000601f19601f8301169050919050565b6000611cec82611c8a565b611cf68185611c95565b9350611d06818560208601611ca6565b611d0f81611cd0565b840191505092915050565b60006020820190508181036000830152611d348184611ce1565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611d6782611d3c565b9050919050565b611d7781611d5c565b82525050565b6000602082019050611d926000830184611d6e565b92915050565b6000819050919050565b611dab81611d98565b82525050565b6000602082019050611dc66000830184611da2565b92915050565b600063ffffffff82169050919050565b611de581611dcc565b82525050565b6000602082019050611e006000830184611ddc565b92915050565b600060ff82169050919050565b611e1c81611e06565b82525050565b6000602082019050611e376000830184611e13565b92915050565b611e4681611d98565b8114611e5157600080fd5b50565b600081359050611e6381611e3d565b92915050565b600060208284031215611e7f57611e7e611bca565b5b6000611e8d84828501611e54565b91505092915050565b6000606082019050611eab6000830186611c60565b611eb86020830185611da2565b611ec56040830184611da2565b949350505050565b611ed681611d5c565b8114611ee157600080fd5b50565b600081359050611ef381611ecd565b92915050565b600060208284031215611f0f57611f0e611bca565b5b6000611f1d84828501611ee4565b91505092915050565b611f2f81611c54565b8114611f3a57600080fd5b50565b600081359050611f4c81611f26565b92915050565b60008060008060008060c08789031215611f6f57611f6e611bca565b5b6000611f7d89828a01611e54565b9650506020611f8e89828a01611e54565b9550506040611f9f89828a01611f3d565b9450506060611fb089828a01611e54565b9350506080611fc189828a01611f3d565b92505060a0611fd289828a01611e54565b9150509295509295509295565b611fe881611dcc565b8114611ff357600080fd5b50565b60008135905061200581611fdf565b92915050565b60006020828403121561202157612020611bca565b5b600061202f84828501611ff6565b91505092915050565b600061204382611d5c565b9050919050565b61205381612038565b811461205e57600080fd5b50565b6000813590506120708161204a565b92915050565b60006020828403121561208c5761208b611bca565b5b600061209a84828501612061565b91505092915050565b60006040820190506120b86000830185611c60565b6120c56020830184611da2565b9392505050565b6000819050919050565b60006120f16120ec6120e784611d3c565b6120cc565b611d3c565b9050919050565b6000612103826120d6565b9050919050565b6000612115826120f8565b9050919050565b6121258161210a565b82525050565b6000602082019050612140600083018461211c565b92915050565b60006fffffffffffffffffffffffffffffffff82169050919050565b61216b81612146565b82525050565b60006020820190506121866000830184612162565b92915050565b60006cffffffffffffffffffffffffff82169050919050565b6121ae8161218c565b82525050565b600064ffffffffff82169050919050565b6121ce816121b4565b82525050565b60006080820190506121e96000830187611c60565b6121f660208301866121a5565b61220360408301856121a5565b61221060608301846121c5565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061225382611d98565b915061225e83611d98565b925082820261226c81611d98565b9150828204841483151761228357612282612219565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006122c482611d98565b91506122cf83611d98565b9250826122df576122de61228a565b5b828204905092915050565b6000815190506122f981611e3d565b92915050565b60006020828403121561231557612314611bca565b5b6000612323848285016122ea565b91505092915050565b60006040820190506123416000830185611da2565b61234e6020830184611da2565b9392505050565b600069ffffffffffffffffffff82169050919050565b61237481612355565b811461237f57600080fd5b50565b6000815190506123918161236b565b92915050565b6123a081611b96565b81146123ab57600080fd5b50565b6000815190506123bd81612397565b92915050565b600080600080600060a086880312156123df576123de611bca565b5b60006123ed88828901612382565b95505060206123fe888289016123ae565b945050604061240f888289016122ea565b9350506060612420888289016122ea565b925050608061243188828901612382565b9150509295509295909350565b600061244982611d98565b915061245483611d98565b925082820390508181111561246c5761246b612219565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61250581611d5c565b82525050565b600061251783836124fc565b60208301905092915050565b6000602082019050919050565b600061253b826124d0565b61254581856124db565b9350612550836124ec565b8060005b83811015612581578151612568888261250b565b975061257383612523565b925050600181019050612554565b5085935050505092915050565b600060a0820190506125a36000830188612162565b6125b06020830187611d6e565b6125bd6040830186611d6e565b81810360608301526125cf8185612530565b90506125de6080830184611ddc565b9695505050505050565b60006126036125fe6125f984611dcc565b6120cc565b611d98565b9050919050565b612613816125e8565b82525050565b600060408201905061262e600083018561260a565b61263b602083018461260a565b939250505056fe73667278457468204475616c204f7261636c6520496e2057657468207769746820437572766520506f6f6c20454d4120616e6420556e6973776170207633205457415020616e64204672617820616e642045544820436861696e6c696e6ba164736f6c6343000813000a
Verified Source Code Partial Match
Compiler: v0.8.19+commit.7dd6d404
EVM: paris
Optimization: No
DualOracleBase.sol 93 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================== DualOracleBase ==========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Author
// Drake Evans: https://github.com/DrakeEvans
// ====================================================================
import "interfaces/IDualOracle.sol";
struct ConstructorParams {
address baseToken0;
uint8 baseToken0Decimals;
address quoteToken0;
uint8 quoteToken0Decimals;
address baseToken1;
uint8 baseToken1Decimals;
address quoteToken1;
uint8 quoteToken1Decimals;
}
/// @title DualOracleBase
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice Base Contract for Frax Dual Oracles
abstract contract DualOracleBase is IDualOracle {
/// @notice The precision of the oracle
uint256 public constant ORACLE_PRECISION = 1e18;
/// @notice The first quote token
address public immutable QUOTE_TOKEN_0;
/// @notice The first quote token decimals
uint256 public immutable QUOTE_TOKEN_0_DECIMALS;
/// @notice The second quote token
address public immutable QUOTE_TOKEN_1;
/// @notice The second quote token decimals
uint256 public immutable QUOTE_TOKEN_1_DECIMALS;
/// @notice The first base token
address public immutable BASE_TOKEN_0;
/// @notice The first base token decimals
uint256 public immutable BASE_TOKEN_0_DECIMALS;
/// @notice The second base token
address public immutable BASE_TOKEN_1;
/// @notice The second base token decimals
uint256 public immutable BASE_TOKEN_1_DECIMALS;
/// @notice The first normalization factor which accounts for different decimals across ERC20s
/// @dev Normalization = quoteTokenDecimals - baseTokenDecimals
int256 public immutable NORMALIZATION_0;
/// @notice The second normalization factor which accounts for different decimals across ERC20s
/// @dev Normalization = quoteTokenDecimals - baseTokenDecimals
int256 public immutable NORMALIZATION_1;
constructor(ConstructorParams memory _params) {
QUOTE_TOKEN_0 = _params.quoteToken0;
QUOTE_TOKEN_0_DECIMALS = _params.quoteToken0Decimals;
QUOTE_TOKEN_1 = _params.quoteToken1;
QUOTE_TOKEN_1_DECIMALS = _params.quoteToken1Decimals;
BASE_TOKEN_0 = _params.baseToken0;
BASE_TOKEN_0_DECIMALS = _params.baseToken0Decimals;
BASE_TOKEN_1 = _params.baseToken1;
BASE_TOKEN_1_DECIMALS = _params.baseToken1Decimals;
NORMALIZATION_0 = int256(QUOTE_TOKEN_0_DECIMALS) - int256(BASE_TOKEN_0_DECIMALS);
NORMALIZATION_1 = int256(QUOTE_TOKEN_1_DECIMALS) - int256(BASE_TOKEN_1_DECIMALS);
}
// ====================================================================
// View Helpers
// ====================================================================
function decimals() external pure returns (uint8) {
return 18;
}
}
ISfrxEth.sol 91 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;
// NOTE: This file generated from sfrxEth contract at https://etherscan.io/address/0xac3e018457b222d93114458476f3e3416abbe38f#code
interface ISfrxEth {
function DOMAIN_SEPARATOR() external view returns (bytes32);
function allowance(address, address) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function asset() external view returns (address);
function balanceOf(address) external view returns (uint256);
function convertToAssets(uint256 shares) external view returns (uint256);
function convertToShares(uint256 assets) external view returns (uint256);
function decimals() external view returns (uint8);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function depositWithSignature(
uint256 assets,
address receiver,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 shares);
function lastRewardAmount() external view returns (uint192);
function lastSync() external view returns (uint32);
function maxDeposit(address) external view returns (uint256);
function maxMint(address) external view returns (uint256);
function maxRedeem(address owner) external view returns (uint256);
function maxWithdraw(address owner) external view returns (uint256);
function mint(uint256 shares, address receiver) external returns (uint256 assets);
function name() external view returns (string memory);
function nonces(address) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function previewDeposit(uint256 assets) external view returns (uint256);
function previewMint(uint256 shares) external view returns (uint256);
function previewRedeem(uint256 shares) external view returns (uint256);
function previewWithdraw(uint256 assets) external view returns (uint256);
function pricePerShare() external view returns (uint256);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
function rewardsCycleEnd() external view returns (uint32);
function rewardsCycleLength() external view returns (uint32);
function symbol() external view returns (string memory);
function syncRewards() external;
function totalAssets() external view returns (uint256);
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
}
IDualOracle.sol 36 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IDualOracle is IERC165 {
function ORACLE_PRECISION() external view returns (uint256);
function BASE_TOKEN_0() external view returns (address);
function BASE_TOKEN_0_DECIMALS() external view returns (uint256);
function BASE_TOKEN_1() external view returns (address);
function BASE_TOKEN_1_DECIMALS() external view returns (uint256);
function decimals() external view returns (uint8);
function getPricesNormalized() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);
function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);
function name() external view returns (string memory);
function NORMALIZATION_0() external view returns (int256);
function NORMALIZATION_1() external view returns (int256);
function QUOTE_TOKEN_0() external view returns (address);
function QUOTE_TOKEN_0_DECIMALS() external view returns (uint256);
function QUOTE_TOKEN_1() external view returns (address);
function QUOTE_TOKEN_1_DECIMALS() external view returns (uint256);
}
FrxEthWethDualOracle.sol 323 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================= FrxEthWethDualOracle =======================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// ====================================================================
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { Timelock2Step } from "frax-std/access-control/v1/Timelock2Step.sol";
import { ITimelock2Step } from "frax-std/access-control/v1/interfaces/ITimelock2Step.sol";
import { DualOracleBase, ConstructorParams as DualOracleBaseParams } from "src/contracts/DualOracleBase.sol";
import { UniswapV3SingleTwapOracle, ConstructorParams as UniswapV3SingleTwapOracleParams } from "../abstracts/UniswapV3SingleTwapOracle.sol";
import { EthUsdChainlinkOracleWithMaxDelay, ConstructorParams as EthUsdChainlinkOracleWithMaxDelayParams } from "../abstracts/EthUsdChainlinkOracleWithMaxDelay.sol";
import { CurvePoolEmaPriceOracleWithMinMax, ConstructorParams as CurvePoolEmaPriceOracleWithMinMaxParams } from "../abstracts/CurvePoolEmaPriceOracleWithMinMax.sol";
import { FraxUsdChainlinkOracleWithMaxDelay, ConstructorParams as FraxUsdChainlinkOracleWithMaxDelayParams } from "../abstracts/FraxUsdChainlinkOracleWithMaxDelay.sol";
import { IDualOracle } from "interfaces/IDualOracle.sol";
import { IPriceSource } from "./interfaces/IPriceSource.sol";
import { IPriceSourceReceiver } from "./interfaces/IPriceSourceReceiver.sol";
/// @notice minimumCurvePoolEma Minimum price to return from Curve for frxEth i.e. 7e17 = .7 ether
/// @notice maximumCurvePoolEma Maximum price to return from Curve for frxEth i.e. 1e18 = 1 ether
struct ConstructorParams {
// = DualOracleBase
address baseToken0; // frxEth
uint8 baseToken0Decimals;
address quoteToken0; // weth
uint8 quoteToken0Decimals;
address baseToken1; // frxEth
uint8 baseToken1Decimals;
address quoteToken1; // weth
uint8 quoteToken1Decimals;
// = UniswapV3SingleTwapOracle
address frxEthErc20;
address fraxErc20;
address uniV3PairAddress;
uint32 twapDuration;
// = FraxUsdChainlinkOracleWithMaxDelay
address fraxUsdChainlinkFeedAddress;
uint256 fraxUsdMaximumOracleDelay;
// = EthUsdChainlinkOracleWithMaxDelay
address ethUsdChainlinkFeed;
uint256 maxEthUsdOracleDelay;
// = CurvePoolEmaPriceOracleWithMinMax
address curvePoolEmaPriceOracleAddress;
uint256 minimumCurvePoolEma;
uint256 maximumCurvePoolEma;
// = Timelock2Step
address timelockAddress;
}
/// @title FrxEthWethDualOracle
/// @notice This price source feeds prices to the FraxOracle system
/// @dev Returns prices of Frax assets in Ether
contract FrxEthWethDualOracle is
DualOracleBase,
CurvePoolEmaPriceOracleWithMinMax,
UniswapV3SingleTwapOracle,
FraxUsdChainlinkOracleWithMaxDelay,
EthUsdChainlinkOracleWithMaxDelay,
IPriceSource,
Timelock2Step
{
/// @notice The address of the Erc20 token contract
address public immutable FRXETH_ERC20;
constructor(
ConstructorParams memory _params
)
DualOracleBase(
DualOracleBaseParams({
baseToken0: _params.baseToken0,
baseToken0Decimals: _params.baseToken0Decimals,
quoteToken0: _params.quoteToken0,
quoteToken0Decimals: _params.quoteToken0Decimals,
baseToken1: _params.baseToken1,
baseToken1Decimals: _params.baseToken1Decimals,
quoteToken1: _params.quoteToken1,
quoteToken1Decimals: _params.quoteToken1Decimals
})
)
CurvePoolEmaPriceOracleWithMinMax(
CurvePoolEmaPriceOracleWithMinMaxParams({
curvePoolEmaPriceOracleAddress: _params.curvePoolEmaPriceOracleAddress,
minimumCurvePoolEma: _params.minimumCurvePoolEma,
maximumCurvePoolEma: _params.maximumCurvePoolEma
})
)
UniswapV3SingleTwapOracle(
UniswapV3SingleTwapOracleParams({
uniswapV3PairAddress: _params.uniV3PairAddress,
twapDuration: _params.twapDuration,
baseToken: _params.frxEthErc20,
quoteToken: _params.fraxErc20
})
)
EthUsdChainlinkOracleWithMaxDelay(
EthUsdChainlinkOracleWithMaxDelayParams({
ethUsdChainlinkFeedAddress: _params.ethUsdChainlinkFeed,
maxEthUsdOracleDelay: _params.maxEthUsdOracleDelay
})
)
FraxUsdChainlinkOracleWithMaxDelay(
FraxUsdChainlinkOracleWithMaxDelayParams({
fraxUsdChainlinkFeedAddress: _params.fraxUsdChainlinkFeedAddress,
fraxUsdMaximumOracleDelay: _params.fraxUsdMaximumOracleDelay
})
)
Timelock2Step()
{
_setTimelock({ _newTimelock: _params.timelockAddress });
_registerInterface({ interfaceId: type(IDualOracle).interfaceId });
_registerInterface({ interfaceId: type(ITimelock2Step).interfaceId });
_registerInterface({ interfaceId: type(IPriceSource).interfaceId });
FRXETH_ERC20 = _params.frxEthErc20;
}
// ====================================================================
// Metadata
// ====================================================================
/// @notice The ```name``` function returns the name of the contract
/// @return _name The name of the contract
function name() external pure virtual returns (string memory _name) {
_name = "frxEth Dual Oracle In Weth with Curve Pool EMA and Uniswap v3 TWAP and Frax and ETH Chainlink";
}
// ====================================================================
// Configuration Setters
// ====================================================================
/// @notice The ```setMinimumCurvePoolEma``` function sets the minimum price of frxEth in Ether units of the EMA
/// @dev Must match precision of the EMA
/// @param _minimumPrice The minimum price of frxEth in Ether units of the EMA
function setMinimumCurvePoolEma(uint256 _minimumPrice) external override {
_requireTimelock();
_setMinimumCurvePoolEma({ _minimumPrice: _minimumPrice });
}
/// @notice The ```setMaximumCurvePoolEma``` function sets the maximum price of frxEth in Ether units of the EMA
/// @dev Must match precision of the EMA
/// @param _maximumPrice The maximum price of frxEth in Ether units of the EMA
function setMaximumCurvePoolEma(uint256 _maximumPrice) external override {
_requireTimelock();
_setMaximumCurvePoolEma({ _maximumPrice: _maximumPrice });
}
/// @notice The ```setTwapDuration``` function sets the TWAP duration for the Uniswap V3 oracle
/// @dev Must be called by the timelock
/// @param _newTwapDuration The new TWAP duration
function setTwapDuration(uint32 _newTwapDuration) external override {
_requireTimelock();
_setTwapDuration({ _newTwapDuration: _newTwapDuration });
}
/// @notice The ```setMaximumOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
/// @dev Requires msg.sender to be the timelock address
/// @param _newMaxOracleDelay The new max oracle delay
function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external override {
_requireTimelock();
_setMaximumEthUsdOracleDelay({ _newMaxOracleDelay: _newMaxOracleDelay });
}
/// @notice The ```setMaximumFraxUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
/// @dev Must be called by the timelock
/// @param _newMaxOracleDelay The new max oracle delay
function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external override {
_requireTimelock();
_setMaximumFraxUsdOracleDelay({ _newMaxOracleDelay: _newMaxOracleDelay });
}
// ====================================================================
// Price Source Function
// ====================================================================
/// @notice The ```addRoundData``` adds new price data to a FraxOracle
/// @dev This contract must be whitelisted on the receiver address
/// @param _fraxOracle Address of a FraxOracle that has this contract set as its priceSource
function addRoundData(IPriceSourceReceiver _fraxOracle) external {
(bool _isBadData, uint256 _priceLow, uint256 _priceHigh) = _getPrices();
// Authorization is handled on fraxOracle side
_fraxOracle.addRoundData({
isBadData: _isBadData,
priceLow: uint104(_priceLow),
priceHigh: uint104(_priceHigh),
timestamp: uint40(block.timestamp)
});
}
// ====================================================================
// Price Functions
// ====================================================================
/// @notice The ```getCurveEmaEthPerFrxEth``` function gets the EMA price of frxEth in eth units
/// @dev normalized to match precision of oracle
/// @return _ethPerFrxEth
function getCurveEmaEthPerFrxEth() public view returns (uint256 _ethPerFrxEth) {
_ethPerFrxEth = _getCurvePoolToken1EmaPrice();
// Note: ORACLE_PRECISION == CURVE_POOL_EMA_PRICE_ORACLE_PRECISION
// _ethPerFrxEth = (ORACLE_PRECISION * _getCurvePoolToken1EmaPrice()) / CURVE_POOL_EMA_PRICE_ORACLE_PRECISION;
}
/// @notice The ```getChainlinkUsdPerFrax``` function gets the Chainlink price of frax in usd units
/// @dev normalized to match precision of oracle
/// @return _isBadData Whether the Chainlink data is stale
/// @return _usdPerFrax
function getChainlinkUsdPerFrax() public view returns (bool _isBadData, uint256 _usdPerFrax) {
(bool _isBadDataChainlink, , uint256 _usdPerFraxRaw) = _getFraxUsdChainlinkPrice();
// Set return values
_isBadData = _isBadDataChainlink;
_usdPerFrax = (ORACLE_PRECISION * _usdPerFraxRaw) / FRAX_USD_CHAINLINK_FEED_PRECISION;
}
/// @notice The ```getUsdPerEthChainlink``` function returns USD per ETH using the Chainlink oracle
/// @return _isBadData If the Chainlink oracle is stale
/// @return _usdPerEth The Eth Price is usd units
function getUsdPerEthChainlink() public view returns (bool _isBadData, uint256 _usdPerEth) {
uint256 _usdPerEthChainlinkRaw;
(_isBadData, , _usdPerEthChainlinkRaw) = _getEthUsdChainlinkPrice();
_usdPerEth = (ORACLE_PRECISION * _usdPerEthChainlinkRaw) / ETH_USD_CHAINLINK_FEED_PRECISION;
}
function _calculatePrices(
uint256 _ethPerFrxEthCurveEma,
uint256 _fraxPerFrxEthTwap,
bool _isBadDataEthUsdChainlink,
uint256 _usdPerEthChainlink,
bool _isBadDataFraxUsdChainlink,
uint256 _usdPerFraxChainlink
) internal view virtual returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
uint256 _ethPerFrxEthRawTwap = (_fraxPerFrxEthTwap * _usdPerFraxChainlink) / _usdPerEthChainlink;
uint256 _maximumCurvePoolEma = maximumCurvePoolEma;
uint256 _minimumCurvePoolEma = minimumCurvePoolEma;
// Bound uniswap twap + chainlink price to same price min/max constraints as the curvePoolEma
uint256 twapEthPerFrxEthHighBounded = _ethPerFrxEthRawTwap > _maximumCurvePoolEma
? _maximumCurvePoolEma
: _ethPerFrxEthRawTwap;
uint256 twapEthPerFrxEth = twapEthPerFrxEthHighBounded < _minimumCurvePoolEma
? _minimumCurvePoolEma
: twapEthPerFrxEthHighBounded;
_isBadData = _isBadDataEthUsdChainlink || _isBadDataFraxUsdChainlink;
_priceLow = _ethPerFrxEthCurveEma < twapEthPerFrxEth ? _ethPerFrxEthCurveEma : twapEthPerFrxEth;
_priceHigh = twapEthPerFrxEth > _ethPerFrxEthCurveEma ? twapEthPerFrxEth : _ethPerFrxEthCurveEma;
}
/// @notice The ```calculatePrices``` function calculates the normalized prices in a pure function
/// @return _isBadData True if any of the oracles return stale data
/// @return _priceLow The normalized low price
/// @return _priceHigh The normalized high price
function calculatePrices(
uint256 _ethPerFrxEthCurveEma,
uint256 _fraxPerFrxEthTwap,
bool _isBadDataEthUsdChainlink,
uint256 _usdPerEthChainlink,
bool _isBadDataFraxUsdChainlink,
uint256 _usdPerFraxChainlink
) external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
(_isBadData, _priceLow, _priceHigh) = _calculatePrices({
_ethPerFrxEthCurveEma: _ethPerFrxEthCurveEma,
_fraxPerFrxEthTwap: _fraxPerFrxEthTwap,
_isBadDataEthUsdChainlink: _isBadDataEthUsdChainlink,
_usdPerEthChainlink: _usdPerEthChainlink,
_isBadDataFraxUsdChainlink: _isBadDataFraxUsdChainlink,
_usdPerFraxChainlink: _usdPerFraxChainlink
});
}
function _getPrices() internal view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
// first price
uint256 _ethPerFrxEthCurveEma = getCurveEmaEthPerFrxEth();
// second price
uint256 _fraxPerFrxEthTwap = _getUniswapV3Twap();
(bool _isBadDataEthUsdChainlink, uint256 _usdPerEthChainlink) = getUsdPerEthChainlink();
(bool _isBadDataFraxUsdChainlink, uint256 _usdPerFraxChainlink) = getChainlinkUsdPerFrax();
(_isBadData, _priceLow, _priceHigh) = _calculatePrices({
_ethPerFrxEthCurveEma: _ethPerFrxEthCurveEma,
_fraxPerFrxEthTwap: _fraxPerFrxEthTwap,
_isBadDataEthUsdChainlink: _isBadDataEthUsdChainlink,
_usdPerEthChainlink: _usdPerEthChainlink,
_isBadDataFraxUsdChainlink: _isBadDataFraxUsdChainlink,
_usdPerFraxChainlink: _usdPerFraxChainlink
});
}
/// @notice The ```getPrices``` function is intended to return two prices from different oracles
/// @return _isBadData is true when data is stale or otherwise bad
/// @return _priceLow is the lower of the two prices
/// @return _priceHigh is the higher of the two prices
function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
(_isBadData, _priceLow, _priceHigh) = _getPrices();
}
/// @notice The ```getPricesNormalized``` function returns the normalized prices in human readable form
/// @dev decimals of underlying tokens match so we can just return _getPrices()
/// @return _isBadDataNormal If the oracle is stale
/// @return _priceLowNormal The normalized low price
/// @return _priceHighNormal The normalized high price
function getPricesNormalized()
external
view
override
returns (bool _isBadDataNormal, uint256 _priceLowNormal, uint256 _priceHighNormal)
{
(_isBadDataNormal, _priceLowNormal, _priceHighNormal) = _getPrices();
}
}
SfrxEthWethDualOracle.sol 67 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ======================= SfrxEthWethDualOracle =======================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// ====================================================================
import { FrxEthWethDualOracle, ConstructorParams as FrxEthWethDualOracleParams } from "./FrxEthWethDualOracle.sol";
import { ISfrxEth } from "interfaces/ISfrxEth.sol";
struct ConstructorParams {
FrxEthWethDualOracleParams frxEthWethDualOracleParams;
address sfrxEthErc4626;
}
contract SfrxEthWethDualOracle is FrxEthWethDualOracle {
/// @notice The address of the Erc20 token contract
ISfrxEth public immutable SFRXETH_ERC4626;
constructor(ConstructorParams memory _params) FrxEthWethDualOracle(_params.frxEthWethDualOracleParams) {
SFRXETH_ERC4626 = ISfrxEth(_params.sfrxEthErc4626);
}
// ====================================================================
// View Helpers
// ====================================================================
function name() external pure override returns (string memory _name) {
_name = "sfrxEth Dual Oracle In Weth with Curve Pool EMA and Uniswap v3 TWAP and Frax and ETH Chainlink";
}
// ====================================================================
// Price Functions
// ====================================================================
function _calculatePrices(
uint256 _ethPerFrxEthCurveEma,
uint256 _fraxPerFrxEthTwap,
bool _isBadDataEthUsdChainlink,
uint256 _usdPerEthChainlink,
bool _isBadDataFraxUsdChainlink,
uint256 _usdPerFraxChainlink
) internal view override returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {
(_isBadData, _priceLow, _priceHigh) = super._calculatePrices({
_ethPerFrxEthCurveEma: _ethPerFrxEthCurveEma,
_fraxPerFrxEthTwap: _fraxPerFrxEthTwap,
_isBadDataEthUsdChainlink: _isBadDataEthUsdChainlink,
_usdPerEthChainlink: _usdPerEthChainlink,
_isBadDataFraxUsdChainlink: _isBadDataFraxUsdChainlink,
_usdPerFraxChainlink: _usdPerFraxChainlink
});
uint256 _sfrxEthPricePerShare = SFRXETH_ERC4626.pricePerShare();
_priceLow = (_sfrxEthPricePerShare * _priceLow) / ORACLE_PRECISION;
_priceHigh = (_sfrxEthPricePerShare * _priceHigh) / ORACLE_PRECISION;
}
}
UniswapV3SingleTwapOracle.sol 92 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ==================== UniswapV3SingleTwapOracle =====================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
import { IStaticOracle } from "@mean-finance/uniswap-v3-oracle/solidity/interfaces/IStaticOracle.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IUniswapV3SingleTwapOracle } from "interfaces/oracles/abstracts/IUniswapV3SingleTwapOracle.sol";
struct ConstructorParams {
address uniswapV3PairAddress;
uint32 twapDuration;
address baseToken;
address quoteToken;
}
/// @title UniswapV3SingleTwapOracle
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice An oracle for UniV3 Twap prices
abstract contract UniswapV3SingleTwapOracle is ERC165Storage, IUniswapV3SingleTwapOracle {
/// @notice address of the Uniswap V3 pair
address public immutable UNI_V3_PAIR_ADDRESS;
/// @notice The precision of the twap
uint128 public constant TWAP_PRECISION = 1e18;
/// @notice The base token of the twap
address public immutable UNISWAP_V3_TWAP_BASE_TOKEN;
/// @notice The quote token of the twap
address public immutable UNISWAP_V3_TWAP_QUOTE_TOKEN;
/// @notice The duration of the twap
uint32 public twapDuration;
constructor(ConstructorParams memory _params) {
_registerInterface({ interfaceId: type(IUniswapV3SingleTwapOracle).interfaceId });
UNI_V3_PAIR_ADDRESS = _params.uniswapV3PairAddress;
twapDuration = _params.twapDuration;
UNISWAP_V3_TWAP_BASE_TOKEN = _params.baseToken;
UNISWAP_V3_TWAP_QUOTE_TOKEN = _params.quoteToken;
}
/// @notice The ```_setTwapDuration``` function sets duration of the twap
/// @param _newTwapDuration The new twap duration
function _setTwapDuration(uint32 _newTwapDuration) internal {
emit SetTwapDuration({ oldTwapDuration: twapDuration, newTwapDuration: _newTwapDuration });
twapDuration = _newTwapDuration;
}
function setTwapDuration(uint32 _newTwapDuration) external virtual;
/// @notice The ```_getUniswapV3Twap``` function is called to get the twap
/// @return _twap The twap price
function _getUniswapV3Twap() internal view returns (uint256 _twap) {
address[] memory _pools = new address[](1);
_pools[0] = UNI_V3_PAIR_ADDRESS;
_twap = IStaticOracle(0xB210CE856631EeEB767eFa666EC7C1C57738d438).quoteSpecificPoolsWithTimePeriod({
baseAmount: TWAP_PRECISION,
baseToken: UNISWAP_V3_TWAP_BASE_TOKEN,
quoteToken: UNISWAP_V3_TWAP_QUOTE_TOKEN,
pools: _pools,
period: twapDuration
});
}
/// @notice The ```getUniswapV3Twap``` function is called to get the twap
/// @return _twap The twap price
function getUniswapV3Twap() external view virtual returns (uint256 _twap) {
_twap = _getUniswapV3Twap();
}
}
IPriceSource.sol 8 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
import { IPriceSourceReceiver } from "./IPriceSourceReceiver.sol";
interface IPriceSource {
function addRoundData(IPriceSourceReceiver _fraxOracle) external;
}
IEmaPriceOracleStableSwap.sol 6 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.19;
interface IEmaPriceOracleStableSwap {
function price_oracle() external view returns (uint256);
}
CurvePoolEmaPriceOracleWithMinMax.sol 93 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ================ CurvePoolEmaPriceOracleWithMinMax =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { ICurvePoolEmaPriceOracleWithMinMax } from "interfaces/oracles/abstracts/ICurvePoolEmaPriceOracleWithMinMax.sol";
import { IEmaPriceOracleStableSwap } from "interfaces/IEmaPriceOracleStableSwap.sol";
struct ConstructorParams {
address curvePoolEmaPriceOracleAddress;
uint256 minimumCurvePoolEma;
uint256 maximumCurvePoolEma;
}
/// @title CurvePoolEmaPriceOracleWithMinMax
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice An oracle for getting EMA prices from Curve
abstract contract CurvePoolEmaPriceOracleWithMinMax is ERC165Storage, ICurvePoolEmaPriceOracleWithMinMax {
/// @notice Curve pool, source of EMA
address public immutable CURVE_POOL_EMA_PRICE_ORACLE;
/// @notice Precision of Curve pool price_oracle()
uint256 public constant CURVE_POOL_EMA_PRICE_ORACLE_PRECISION = 1e18;
/// @notice Maximum price of token1 in token0 units of the EMA
/// @dev Must match precision of EMA
uint256 public minimumCurvePoolEma;
/// @notice Maximum price of token1 in token0 units of the EMA
/// @dev Must match precision of EMA
uint256 public maximumCurvePoolEma;
constructor(ConstructorParams memory _params) {
_registerInterface({ interfaceId: type(ICurvePoolEmaPriceOracleWithMinMax).interfaceId });
CURVE_POOL_EMA_PRICE_ORACLE = _params.curvePoolEmaPriceOracleAddress;
minimumCurvePoolEma = _params.minimumCurvePoolEma;
maximumCurvePoolEma = _params.maximumCurvePoolEma;
}
/// @notice The ```setMaximumCurvePoolEma``` function sets the maximum price of the EMA
/// @dev Must match precision of the EMA
/// @param _maximumPrice The maximum price of the EMA
function _setMaximumCurvePoolEma(uint256 _maximumPrice) internal {
emit SetMaximumCurvePoolEma({ oldMaximum: maximumCurvePoolEma, newMaximum: _maximumPrice });
maximumCurvePoolEma = _maximumPrice;
}
function setMaximumCurvePoolEma(uint256 _maximumPrice) external virtual;
/// @notice The ```setEmaMinimum``` function sets the minimum price of the EMA
/// @dev Must match precision of the EMA
/// @param _minimumPrice The minimum price of the EMA
function _setMinimumCurvePoolEma(uint256 _minimumPrice) internal {
emit SetMinimumCurvePoolEma({ oldMinimum: minimumCurvePoolEma, newMinimum: _minimumPrice });
minimumCurvePoolEma = _minimumPrice;
}
function setMinimumCurvePoolEma(uint256 _minimumPrice) external virtual;
function _getCurvePoolToken1EmaPrice() internal view returns (uint256 _token1Price) {
uint256 _priceRaw = IEmaPriceOracleStableSwap(CURVE_POOL_EMA_PRICE_ORACLE).price_oracle();
uint256 _price = _priceRaw > maximumCurvePoolEma ? maximumCurvePoolEma : _priceRaw;
_token1Price = _price < minimumCurvePoolEma ? minimumCurvePoolEma : _price;
}
/// @notice The ```getCurvePoolToken1EmaPrice``` function gets the price of the second token in the Curve pool (token1)
/// @dev Returned in units of the first token (token0)
/// @return _emaPrice The price of the second token in the Curve pool
function getCurvePoolToken1EmaPrice() external view returns (uint256 _emaPrice) {
return _getCurvePoolToken1EmaPrice();
}
}
EthUsdChainlinkOracleWithMaxDelay.sol 102 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ================ EthUsdChainlinkOracleWithMaxDelay =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IEthUsdChainlinkOracleWithMaxDelay } from "interfaces/oracles/abstracts/IEthUsdChainlinkOracleWithMaxDelay.sol";
struct ConstructorParams {
address ethUsdChainlinkFeedAddress;
uint256 maxEthUsdOracleDelay;
}
/// @title EthUsdChainlinkOracleWithMaxDelay
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice An abstract oracle for getting eth/usd prices from Chainlink
abstract contract EthUsdChainlinkOracleWithMaxDelay is ERC165Storage, IEthUsdChainlinkOracleWithMaxDelay {
/// @notice Chainlink aggregator
address public immutable ETH_USD_CHAINLINK_FEED_ADDRESS;
/// @notice Decimals of ETH/USD chainlink feed
uint8 public immutable ETH_USD_CHAINLINK_FEED_DECIMALS;
/// @notice Precision of ETH/USD chainlink feed
uint256 public immutable ETH_USD_CHAINLINK_FEED_PRECISION;
/// @notice Maximum delay of Chainlink data, after which it is considered stale
uint256 public maximumEthUsdOracleDelay;
constructor(ConstructorParams memory _params) {
_registerInterface({ interfaceId: type(IEthUsdChainlinkOracleWithMaxDelay).interfaceId });
ETH_USD_CHAINLINK_FEED_ADDRESS = _params.ethUsdChainlinkFeedAddress;
ETH_USD_CHAINLINK_FEED_DECIMALS = AggregatorV3Interface(ETH_USD_CHAINLINK_FEED_ADDRESS).decimals();
ETH_USD_CHAINLINK_FEED_PRECISION = 10 ** uint256(ETH_USD_CHAINLINK_FEED_DECIMALS);
maximumEthUsdOracleDelay = _params.maxEthUsdOracleDelay;
}
/// @notice The ```_setMaximumEthUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
/// @param _newMaxOracleDelay The new max oracle delay
function _setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) internal {
emit SetMaximumEthUsdOracleDelay({
oldMaxOracleDelay: maximumEthUsdOracleDelay,
newMaxOracleDelay: _newMaxOracleDelay
});
maximumEthUsdOracleDelay = _newMaxOracleDelay;
}
function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external virtual;
/// @notice The ```_getEthUsdChainlinkPrice``` function is called to get the eth/usd price from Chainlink
/// @dev If data is stale or negative, set bad data to true and return
/// @return _isBadData If the data is stale
/// @return _updatedAt The timestamp of the last update
/// @return _usdPerEth The eth/usd price
function _getEthUsdChainlinkPrice()
internal
view
returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth)
{
(, int256 _answer, , uint256 _ethUsdChainlinkUpdatedAt, ) = AggregatorV3Interface(
ETH_USD_CHAINLINK_FEED_ADDRESS
).latestRoundData();
// If data is stale or negative, set bad data to true and return
_isBadData = _answer <= 0 || ((block.timestamp - _ethUsdChainlinkUpdatedAt) > maximumEthUsdOracleDelay);
_updatedAt = _ethUsdChainlinkUpdatedAt;
_usdPerEth = uint256(_answer);
}
/// @notice The ```getEthUsdChainlinkPrice``` function is called to get the eth/usd price from Chainlink
/// @return _isBadData If the data is stale
/// @return _updatedAt The timestamp of the last update
/// @return _usdPerEth The eth/usd price
function getEthUsdChainlinkPrice()
external
view
virtual
returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth)
{
(_isBadData, _updatedAt, _usdPerEth) = _getEthUsdChainlinkPrice();
}
}
IPriceSourceReceiver.sol 8 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
interface IPriceSourceReceiver {
function addRoundData(bool isBadData, uint104 priceLow, uint104 priceHigh, uint40 timestamp) external;
function getPrices() external view returns (bool isBadData, uint256 priceLow, uint256 priceHigh);
}
FraxUsdChainlinkOracleWithMaxDelay.sol 102 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ================ FraxUsdChainlinkOracleWithMaxDelay =================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import { ERC165Storage } from "@openzeppelin/contracts/utils/introspection/ERC165Storage.sol";
import { IFraxUsdChainlinkOracleWithMaxDelay } from "interfaces/oracles/abstracts/IFraxUsdChainlinkOracleWithMaxDelay.sol";
struct ConstructorParams {
address fraxUsdChainlinkFeedAddress;
uint256 fraxUsdMaximumOracleDelay;
}
/// @title FraxUsdChainlinkOracleWithMaxDelay
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @notice An abstract oracle for getting frax/usd prices from Chainlink
abstract contract FraxUsdChainlinkOracleWithMaxDelay is ERC165Storage, IFraxUsdChainlinkOracleWithMaxDelay {
/// @notice Chainlink aggregator
address public immutable FRAX_USD_CHAINLINK_FEED_ADDRESS;
/// @notice Decimals of FRAX/USD chainlink feed
uint8 public immutable FRAX_USD_CHAINLINK_FEED_DECIMALS;
/// @notice Precision of FRAX/USD chainlink feed
uint256 public immutable FRAX_USD_CHAINLINK_FEED_PRECISION;
/// @notice Maximum delay of Chainlink data, after which it is considered stale
uint256 public maximumFraxUsdOracleDelay;
constructor(ConstructorParams memory _params) {
_registerInterface({ interfaceId: type(IFraxUsdChainlinkOracleWithMaxDelay).interfaceId });
FRAX_USD_CHAINLINK_FEED_ADDRESS = _params.fraxUsdChainlinkFeedAddress;
FRAX_USD_CHAINLINK_FEED_DECIMALS = AggregatorV3Interface(FRAX_USD_CHAINLINK_FEED_ADDRESS).decimals();
FRAX_USD_CHAINLINK_FEED_PRECISION = 10 ** uint256(FRAX_USD_CHAINLINK_FEED_DECIMALS);
maximumFraxUsdOracleDelay = _params.fraxUsdMaximumOracleDelay;
}
/// @notice The ```_setMaximumFraxUsdOracleDelay``` function sets the max oracle delay to determine if Chainlink data is stale
/// @param _newMaxOracleDelay The new max oracle delay
function _setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) internal {
emit SetMaximumFraxUsdOracleDelay({
oldMaxOracleDelay: maximumFraxUsdOracleDelay,
newMaxOracleDelay: _newMaxOracleDelay
});
maximumFraxUsdOracleDelay = _newMaxOracleDelay;
}
function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external virtual;
/// @notice The ```_getFraxUsdChainlinkPrice``` function is called to get the frax/usd price from Chainlink
/// @dev If data is stale or negative, set bad data to true and return
/// @return _isBadData If the data is stale
/// @return _updatedAt The timestamp of the last update
/// @return _usdPerFrax The frax/usd price
function _getFraxUsdChainlinkPrice()
internal
view
returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax)
{
(, int256 _answer, , uint256 _fraxUsdChainlinkUpdatedAt, ) = AggregatorV3Interface(
FRAX_USD_CHAINLINK_FEED_ADDRESS
).latestRoundData();
// If data is stale or negative, set bad data to true and return
_isBadData = _answer <= 0 || ((block.timestamp - _fraxUsdChainlinkUpdatedAt) > maximumFraxUsdOracleDelay);
_updatedAt = _fraxUsdChainlinkUpdatedAt;
_usdPerFrax = uint256(_answer);
}
/// @notice The ```getFraxUsdChainlinkPrice``` function is called to get the frax/usd price from Chainlink
/// @return _isBadData If the data is stale
/// @return _updatedAt The timestamp of the last update
/// @return _usdPerFrax The frax/usd price
function getFraxUsdChainlinkPrice()
external
view
virtual
returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax)
{
(_isBadData, _updatedAt, _usdPerFrax) = _getFraxUsdChainlinkPrice();
}
}
ERC165.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
IUniswapV3Factory.sol 78 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title The interface for the Uniswap V3 Factory
/// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees
interface IUniswapV3Factory {
/// @notice Emitted when the owner of the factory is changed
/// @param oldOwner The owner before the owner was changed
/// @param newOwner The owner after the owner was changed
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
/// @notice Emitted when a pool is created
/// @param token0 The first token of the pool by address sort order
/// @param token1 The second token of the pool by address sort order
/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks
/// @param pool The address of the created pool
event PoolCreated(
address indexed token0,
address indexed token1,
uint24 indexed fee,
int24 tickSpacing,
address pool
);
/// @notice Emitted when a new fee amount is enabled for pool creation via the factory
/// @param fee The enabled fee, denominated in hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
/// @notice Returns the current owner of the factory
/// @dev Can be changed by the current owner via setOwner
/// @return The address of the factory owner
function owner() external view returns (address);
/// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled
/// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context
/// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee
/// @return The tick spacing
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
/// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
/// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
/// @param tokenA The contract address of either token0 or token1
/// @param tokenB The contract address of the other token
/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
/// @return pool The pool address
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address pool);
/// @notice Creates a pool for the given two tokens and fee
/// @param tokenA One of the two tokens in the desired pool
/// @param tokenB The other of the two tokens in the desired pool
/// @param fee The desired fee for the pool
/// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved
/// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments
/// are invalid.
/// @return pool The address of the newly created pool
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
/// @notice Updates the owner of the factory
/// @dev Must be called by the current owner
/// @param _owner The new owner of the factory
function setOwner(address _owner) external;
/// @notice Enables a fee amount with the given tickSpacing
/// @dev Fee amounts may never be removed once enabled
/// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)
/// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
}
IUniswapV3SingleTwapOracle.sol 22 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IUniswapV3SingleTwapOracle is IERC165 {
event SetTwapDuration(uint256 oldTwapDuration, uint256 newTwapDuration);
function TWAP_PRECISION() external view returns (uint128);
function UNISWAP_V3_TWAP_BASE_TOKEN() external view returns (address);
function UNISWAP_V3_TWAP_QUOTE_TOKEN() external view returns (address);
function UNI_V3_PAIR_ADDRESS() external view returns (address);
function getUniswapV3Twap() external view returns (uint256 _twap);
function twapDuration() external view returns (uint32);
function setTwapDuration(uint32 _newTwapDuration) external;
}
ERC165Storage.sol 42 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol)
pragma solidity ^0.8.0;
import "./ERC165.sol";
/**
* @dev Storage based implementation of the {IERC165} interface.
*
* Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface.
*/
abstract contract ERC165Storage is ERC165 {
/**
* @dev Mapping of interface ids to whether or not it's supported.
*/
mapping(bytes4 => bool) private _supportedInterfaces;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];
}
/**
* @dev Registers the contract as an implementer of the interface defined by
* `interfaceId`. Support of the actual ERC165 interface is automatic and
* registering its interface id is not required.
*
* See {IERC165-supportsInterface}.
*
* Requirements:
*
* - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
*/
function _registerInterface(bytes4 interfaceId) internal virtual {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}
Timelock2Step.sol 123 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================== Timelock2Step ===========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Primary Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
/// @title Timelock2Step
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @dev Inspired by the OpenZeppelin's Ownable2Step contract
/// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address
abstract contract Timelock2Step {
/// @notice The pending timelock address
address public pendingTimelockAddress;
/// @notice The current timelock address
address public timelockAddress;
constructor() {
timelockAddress = msg.sender;
}
/// @notice Emitted when timelock is transferred
error OnlyTimelock();
/// @notice Emitted when pending timelock is transferred
error OnlyPendingTimelock();
/// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
/// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
/// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address
/// @return Whether or not msg.sender is current timelock address
function _isSenderTimelock() internal view returns (bool) {
return msg.sender == timelockAddress;
}
/// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address
function _requireTimelock() internal view {
if (msg.sender != timelockAddress) revert OnlyTimelock();
}
/// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address
/// @return Whether or not msg.sender is pending timelock address
function _isSenderPendingTimelock() internal view returns (bool) {
return msg.sender == pendingTimelockAddress;
}
/// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
function _requirePendingTimelock() internal view {
if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();
}
/// @notice The ```_transferTimelock``` function initiates the timelock transfer
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the nominated (pending) timelock
function _transferTimelock(address _newTimelock) internal {
pendingTimelockAddress = _newTimelock;
emit TimelockTransferStarted(timelockAddress, _newTimelock);
}
/// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
/// @dev This function is to be implemented by a public function
function _acceptTransferTimelock() internal {
pendingTimelockAddress = address(0);
_setTimelock(msg.sender);
}
/// @notice The ```_setTimelock``` function sets the timelock address
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the new timelock
function _setTimelock(address _newTimelock) internal {
emit TimelockTransferred(timelockAddress, _newTimelock);
timelockAddress = _newTimelock;
}
/// @notice The ```transferTimelock``` function initiates the timelock transfer
/// @dev Must be called by the current timelock
/// @param _newTimelock The address of the nominated (pending) timelock
function transferTimelock(address _newTimelock) external virtual {
_requireTimelock();
_transferTimelock(_newTimelock);
}
/// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
/// @dev Must be called by the pending timelock
function acceptTransferTimelock() external virtual {
_requirePendingTimelock();
_acceptTransferTimelock();
}
/// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
/// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
function renounceTimelock() external virtual {
_requireTimelock();
_requirePendingTimelock();
_transferTimelock(address(0));
_setTimelock(address(0));
}
}
AggregatorV3Interface.sol 32 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
ICurvePoolEmaPriceOracleWithMinMax.sol 23 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface ICurvePoolEmaPriceOracleWithMinMax is IERC165 {
event SetMaximumCurvePoolEma(uint256 oldMaximum, uint256 newMaximum);
event SetMinimumCurvePoolEma(uint256 oldMinimum, uint256 newMinimum);
function CURVE_POOL_EMA_PRICE_ORACLE() external view returns (address);
function CURVE_POOL_EMA_PRICE_ORACLE_PRECISION() external view returns (uint256);
function getCurvePoolToken1EmaPrice() external view returns (uint256 _emaPrice);
function maximumCurvePoolEma() external view returns (uint256);
function minimumCurvePoolEma() external view returns (uint256);
function setMaximumCurvePoolEma(uint256 _maximumPrice) external;
function setMinimumCurvePoolEma(uint256 _minimumPrice) external;
}
IEthUsdChainlinkOracleWithMaxDelay.sol 20 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IEthUsdChainlinkOracleWithMaxDelay is IERC165 {
event SetMaximumEthUsdOracleDelay(uint256 oldMaxOracleDelay, uint256 newMaxOracleDelay);
function ETH_USD_CHAINLINK_FEED_ADDRESS() external view returns (address);
function ETH_USD_CHAINLINK_FEED_DECIMALS() external view returns (uint8);
function ETH_USD_CHAINLINK_FEED_PRECISION() external view returns (uint256);
function maximumEthUsdOracleDelay() external view returns (uint256);
function getEthUsdChainlinkPrice() external view returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerEth);
function setMaximumEthUsdOracleDelay(uint256 _newMaxOracleDelay) external;
}
IStaticOracle.sol 150 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.6 <0.9.0;
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol';
/// @title Uniswap V3 Static Oracle
/// @notice Oracle contract for calculating price quoting against Uniswap V3
interface IStaticOracle {
/// @notice Returns the address of the Uniswap V3 factory
/// @dev This value is assigned during deployment and cannot be changed
/// @return The address of the Uniswap V3 factory
function UNISWAP_V3_FACTORY() external view returns (IUniswapV3Factory);
/// @notice Returns how many observations are needed per minute in Uniswap V3 oracles, on the deployed chain
/// @dev This value is assigned during deployment and cannot be changed
/// @return Number of observation that are needed per minute
function CARDINALITY_PER_MINUTE() external view returns (uint8);
/// @notice Returns all supported fee tiers
/// @return The supported fee tiers
function supportedFeeTiers() external view returns (uint24[] memory);
/// @notice Returns whether a specific pair can be supported by the oracle
/// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order
/// @return Whether the given pair can be supported by the oracle
function isPairSupported(address tokenA, address tokenB) external view returns (bool);
/// @notice Returns all existing pools for the given pair
/// @dev The pair can be provided in tokenA/tokenB or tokenB/tokenA order
/// @return All existing pools for the given pair
function getAllPoolsForPair(address tokenA, address tokenB) external view returns (address[] memory);
/// @notice Returns a quote, based on the given tokens and amount, by querying all of the pair's pools
/// @dev If some pools are not configured correctly for the given period, then they will be ignored
/// @dev Will revert if there are no pools available/configured for the pair and period combination
/// @param baseAmount Amount of token to be converted
/// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
/// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
/// @param period Number of seconds from which to calculate the TWAP
/// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
/// @return queriedPools The pools that were queried to calculate the quote
function quoteAllAvailablePoolsWithTimePeriod(
uint128 baseAmount,
address baseToken,
address quoteToken,
uint32 period
) external view returns (uint256 quoteAmount, address[] memory queriedPools);
/// @notice Returns a quote, based on the given tokens and amount, by querying only the specified fee tiers
/// @dev Will revert if the pair does not have a pool for one of the given fee tiers, or if one of the pools
/// is not prepared/configured correctly for the given period
/// @param baseAmount Amount of token to be converted
/// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
/// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
/// @param feeTiers The fee tiers to consider when calculating the quote
/// @param period Number of seconds from which to calculate the TWAP
/// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
/// @return queriedPools The pools that were queried to calculate the quote
function quoteSpecificFeeTiersWithTimePeriod(
uint128 baseAmount,
address baseToken,
address quoteToken,
uint24[] calldata feeTiers,
uint32 period
) external view returns (uint256 quoteAmount, address[] memory queriedPools);
/// @notice Returns a quote, based on the given tokens and amount, by querying only the specified pools
/// @dev Will revert if one of the pools is not prepared/configured correctly for the given period
/// @param baseAmount Amount of token to be converted
/// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
/// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
/// @param pools The pools to consider when calculating the quote
/// @param period Number of seconds from which to calculate the TWAP
/// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
function quoteSpecificPoolsWithTimePeriod(
uint128 baseAmount,
address baseToken,
address quoteToken,
address[] calldata pools,
uint32 period
) external view returns (uint256 quoteAmount);
/// @notice Will initialize all existing pools for the given pair, so that they can be queried with the given period in the future
/// @dev Will revert if there are no pools available for the pair and period combination
/// @param tokenA One of the pair's tokens
/// @param tokenB The other of the pair's tokens
/// @param period The period that will be guaranteed when quoting
/// @return preparedPools The pools that were prepared
function prepareAllAvailablePoolsWithTimePeriod(
address tokenA,
address tokenB,
uint32 period
) external returns (address[] memory preparedPools);
/// @notice Will initialize the pair's pools with the specified fee tiers, so that they can be queried with the given period in the future
/// @dev Will revert if the pair does not have a pool for a given fee tier
/// @param tokenA One of the pair's tokens
/// @param tokenB The other of the pair's tokens
/// @param feeTiers The fee tiers to consider when searching for the pair's pools
/// @param period The period that will be guaranteed when quoting
/// @return preparedPools The pools that were prepared
function prepareSpecificFeeTiersWithTimePeriod(
address tokenA,
address tokenB,
uint24[] calldata feeTiers,
uint32 period
) external returns (address[] memory preparedPools);
/// @notice Will initialize all given pools, so that they can be queried with the given period in the future
/// @param pools The pools to initialize
/// @param period The period that will be guaranteed when quoting
function prepareSpecificPoolsWithTimePeriod(address[] calldata pools, uint32 period) external;
/// @notice Will increase observations for all existing pools for the given pair, so they start accruing information for twap calculations
/// @dev Will revert if there are no pools available for the pair and period combination
/// @param tokenA One of the pair's tokens
/// @param tokenB The other of the pair's tokens
/// @param cardinality The cardinality that will be guaranteed when quoting
/// @return preparedPools The pools that were prepared
function prepareAllAvailablePoolsWithCardinality(
address tokenA,
address tokenB,
uint16 cardinality
) external returns (address[] memory preparedPools);
/// @notice Will increase the pair's pools with the specified fee tiers observations, so they start accruing information for twap calculations
/// @dev Will revert if the pair does not have a pool for a given fee tier
/// @param tokenA One of the pair's tokens
/// @param tokenB The other of the pair's tokens
/// @param feeTiers The fee tiers to consider when searching for the pair's pools
/// @param cardinality The cardinality that will be guaranteed when quoting
/// @return preparedPools The pools that were prepared
function prepareSpecificFeeTiersWithCardinality(
address tokenA,
address tokenB,
uint24[] calldata feeTiers,
uint16 cardinality
) external returns (address[] memory preparedPools);
/// @notice Will increase all given pools observations, so they start accruing information for twap calculations
/// @param pools The pools to initialize
/// @param cardinality The cardinality that will be guaranteed when quoting
function prepareSpecificPoolsWithCardinality(address[] calldata pools, uint16 cardinality) external;
/// @notice Adds support for a new fee tier
/// @dev Will revert if the given tier is invalid, or already supported
/// @param feeTier The new fee tier to add
function addNewFeeTier(uint24 feeTier) external;
}
IFraxUsdChainlinkOracleWithMaxDelay.sol 23 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IFraxUsdChainlinkOracleWithMaxDelay is IERC165 {
event SetMaximumFraxUsdOracleDelay(uint256 oldMaxOracleDelay, uint256 newMaxOracleDelay);
function FRAX_USD_CHAINLINK_FEED_ADDRESS() external view returns (address);
function FRAX_USD_CHAINLINK_FEED_DECIMALS() external view returns (uint8);
function FRAX_USD_CHAINLINK_FEED_PRECISION() external view returns (uint256);
function maximumFraxUsdOracleDelay() external view returns (uint256);
function getFraxUsdChainlinkPrice()
external
view
returns (bool _isBadData, uint256 _updatedAt, uint256 _usdPerFrax);
function setMaximumFraxUsdOracleDelay(uint256 _newMaxOracleDelay) external;
}
ITimelock2Step.sol 17 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
interface ITimelock2Step {
event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
function acceptTransferTimelock() external;
function pendingTimelockAddress() external view returns (address);
function renounceTimelock() external;
function timelockAddress() external view returns (address);
function transferTimelock(address _newTimelock) external;
}
Read Contract
BASE_TOKEN_0 0x116d7976 → address
BASE_TOKEN_0_DECIMALS 0xf097486c → uint256
BASE_TOKEN_1 0x20888004 → address
BASE_TOKEN_1_DECIMALS 0x37f85f66 → uint256
CURVE_POOL_EMA_PRICE_ORACLE 0x26939205 → address
CURVE_POOL_EMA_PRICE_ORACLE_PRECISION 0x8c1e2f92 → uint256
ETH_USD_CHAINLINK_FEED_ADDRESS 0x99a64f28 → address
ETH_USD_CHAINLINK_FEED_DECIMALS 0x3b17136a → uint8
ETH_USD_CHAINLINK_FEED_PRECISION 0x726de1a5 → uint256
FRAX_USD_CHAINLINK_FEED_ADDRESS 0xb374839b → address
FRAX_USD_CHAINLINK_FEED_DECIMALS 0xebf43bca → uint8
FRAX_USD_CHAINLINK_FEED_PRECISION 0xcca992fa → uint256
FRXETH_ERC20 0x90e67fe8 → address
NORMALIZATION_0 0xc82f2b12 → int256
NORMALIZATION_1 0x0032e91a → int256
ORACLE_PRECISION 0x9c0d313f → uint256
QUOTE_TOKEN_0 0xe0d2e780 → address
QUOTE_TOKEN_0_DECIMALS 0xe5a66dfa → uint256
QUOTE_TOKEN_1 0x59c909e1 → address
QUOTE_TOKEN_1_DECIMALS 0x781097d0 → uint256
SFRXETH_ERC4626 0xe0fba44b → address
TWAP_PRECISION 0xf97697ff → uint128
UNISWAP_V3_TWAP_BASE_TOKEN 0x993e3d54 → address
UNISWAP_V3_TWAP_QUOTE_TOKEN 0xa2cc7703 → address
UNI_V3_PAIR_ADDRESS 0x417d25a9 → address
calculatePrices 0x7068d2b0 → bool, uint256, uint256
decimals 0x313ce567 → uint8
getChainlinkUsdPerFrax 0xcbda2f1a → bool, uint256
getCurveEmaEthPerFrxEth 0x4e6c27cb → uint256
getCurvePoolToken1EmaPrice 0x0b7f3ffe → uint256
getEthUsdChainlinkPrice 0x3cb6f5fa → bool, uint256, uint256
getFraxUsdChainlinkPrice 0xb93cd816 → bool, uint256, uint256
getPrices 0xbd9a548b → bool, uint256, uint256
getPricesNormalized 0x4d3375e8 → bool, uint256, uint256
getUniswapV3Twap 0x6ff48472 → uint256
getUsdPerEthChainlink 0xeb995c43 → bool, uint256
maximumCurvePoolEma 0x952dca48 → uint256
maximumEthUsdOracleDelay 0x7c99a499 → uint256
maximumFraxUsdOracleDelay 0x471d7789 → uint256
minimumCurvePoolEma 0x59f768b2 → uint256
name 0x06fdde03 → string
pendingTimelockAddress 0x090f3f50 → address
supportsInterface 0x01ffc9a7 → bool
timelockAddress 0x4bc66f32 → address
twapDuration 0x26d89545 → uint32
Write Contract 9 functions
These functions modify contract state and require a wallet transaction to execute.
acceptTransferTimelock 0xf6ccaad4
No parameters
addRoundData 0xcb757b97
address _fraxOracle
renounceTimelock 0x4f8b4ae7
No parameters
setMaximumCurvePoolEma 0x56ee4c08
uint256 _maximumPrice
setMaximumEthUsdOracleDelay 0xd7360946
uint256 _newMaxOracleDelay
setMaximumFraxUsdOracleDelay 0x3be38cf9
uint256 _newMaxOracleDelay
setMinimumCurvePoolEma 0xc809d4ed
uint256 _minimumPrice
setTwapDuration 0xc433c80a
uint32 _newTwapDuration
transferTimelock 0x45014095
address _newTimelock
Recent Transactions
No transactions found for this address