Address Contract Verified
Address
0x84d4eaeb10f9E57b67622f667C6c13E22fA4b2B6
Balance
0 ETH
Nonce
1
Code Size
13033 bytes
Creator
0x6C15B25E...7649 at tx 0x8d844fb2...246f17
Indexed Transactions
0
Contract Bytecode
13033 bytes
0x608060405234801561001057600080fd5b506004361061030a5760003560e01c806375b238fc1161019c578063b3d03582116100ee578063dd3a9a1011610097578063f063aa3311610071578063f063aa3314610690578063f475877514610699578063f7ced0e7146106a257600080fd5b8063dd3a9a1014610668578063dddbc04914610670578063eb5f23a61461068357600080fd5b8063d547741f116100c8578063d547741f14610640578063d966a59414610653578063daf6bce41461066057600080fd5b8063b3d035821461060f578063cc6dfe791461062e578063d2f343c71461063757600080fd5b806391d1485411610150578063a217fddf1161012a578063a217fddf146105eb578063a4eb718c146105f3578063a66143821461060657600080fd5b806391d148541461058e5780639bdcaf59146105c55780639c66e162146105d857600080fd5b80638205bf6a116101815780638205bf6a146105745780638456cb591461057d5780638dbe7b9d1461058557600080fd5b806375b238fc1461053a57806379e666221461056157600080fd5b806336568abe1161026057806354e4d19a11610209578063693de592116101e3578063693de592146104ea5780636e04ff0d146104f2578063721be4221461051357600080fd5b806354e4d19a146104b95780635953de96146104c25780635c975abb146104df57600080fd5b8063424562131161023a578063424562131461046c5780634585e33b1461047f57806347e633801461049257600080fd5b806336568abe146104485780633ee7a7011461045b5780633f4ba83a1461046457600080fd5b80631d9ff6e4116102c25780632f2ff15d1161029c5780632f2ff15d146103ff578063313ce56714610412578063364bc15a1461042157600080fd5b80631d9ff6e4146103a3578063248a9ca3146103ac5780632c2f03e0146103cf57600080fd5b80630ca76175116102f35780630ca761751461036457806314f69ebe146103795780631aa46f591461038c57600080fd5b806301ffc9a71461030f57806309c1ba2e14610337575b600080fd5b61032261031d3660046129d4565b6106b5565b60405190151581526020015b60405180910390f35b60095461034b9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161032e565b610377610372366004612adb565b61074e565b005b610377610387366004612b8f565b6107eb565b61039560035481565b60405190815260200161032e565b61039560075481565b6103956103ba366004612c2d565b60009081526020819052604090206001015490565b6013546103e79061010090046001600160a01b031681565b6040516001600160a01b03909116815260200161032e565b61037761040d366004612c62565b61098e565b6040516012815260200161032e565b6103957ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab81565b610377610456366004612c62565b6109b9565b61039560125481565b610377610a0a565b61037761047a366004612c8e565b610a3f565b61037761048d366004612cda565b610c20565b6103957f73e573f9566d61418a34d5de3ff49360f9c51fec37f7486551670290f6285dab81565b61039561384081565b6104ca610d5b565b6040805192835260208301919091520161032e565b60025460ff16610322565b6104ca610d72565b610505610500366004612cda565b610d89565b60405161032e929190612d6c565b6103957f9d1945eeb09f3a9323e5f22a567caed248092672554a0b04901240709fb1347681565b6103957fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61037761056f366004612d9d565b610ec8565b61039560055481565b610377610f3c565b61039560085481565b61032261059c366004612c62565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103776105d3366004612dba565b610f6e565b6103776105e6366004612de6565b6110ab565b610395600081565b610377610601366004612e01565b61117f565b610395600c5481565b610619620186a081565b60405163ffffffff909116815260200161032e565b610395600f5481565b610395600e5481565b61037761064e366004612c62565b61124e565b6011546103229060ff1681565b610395611273565b61039561132b565b61037761067e366004612c2d565b6113be565b6013546103229060ff1681565b61039560105481565b610395600d5481565b6103776106b0366004612d9d565b61145f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061074857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b336001600160a01b037f00000000000000000000000065dcc24f8ff9e51f10dcc7ed1e4e2a61e6e14bd616146107b0576040517fc6829f8300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107bb8383836114ca565b60405183907f85e1543bf2f84fe80c6badbce3648c8539ad1df4d2b3d822938ca0538be727e690600090a2505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756108158161194e565b8667ffffffffffffffff1660000361084057604051630ebd8d1960e11b815260040160405180910390fd5b8561085e576040516391f7443960e01b815260040160405180910390fd5b600084900361088057604051631161b0b360e01b815260040160405180910390fd5b60008290036108bb576040517f08974bc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009805467ffffffffffffffff191667ffffffffffffffff89161790556008869055600a6108ea858783612ea8565b50600b6108f8838583612ea8565b506000858560405161090b929190612f68565b6040518091039020905060008484604051610927929190612f68565b6040805191829003822067ffffffffffffffff8c168352602083018b905290820184905260608201819052915033907fd0460bc9a3d662ffa248c53ead902bfc09de1660e8bf7e202467ba7d9c525b849060800160405180910390a2505050505050505050565b6000828152602081905260409020600101546109a98161194e565b6109b38383611958565b50505050565b6001600160a01b03811633146109fb576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a058282611a02565b505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610a348161194e565b610a3c611a85565b50565b610a47611ad7565b7f9d1945eeb09f3a9323e5f22a567caed248092672554a0b04901240709fb13476610a718161194e565b610a79611b16565b83600003610abb576040517fc0c148d4000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b600060105442610acb9190612f8e565b90506000601054118015610ae0575061384081105b15610b22576040517f29108fcd000000000000000000000000000000000000000000000000000000008152600481018290526138406024820152604401610ab2565b60045460009015610b785760006004548711610b4b5786600454610b469190612f8e565b610b58565b600454610b589088612f8e565b600454909150610b6a82612710612fa1565b610b749190612fce565b9150505b6004805460065560058054600755908790554290819055601055610b9b86611b59565b427f2d7f7ae13710a5fc7ea85533ac930ce3bb3317b7282af073f3645dd3e6a412f48783888833604051610bd3959493929190612fe2565b60405180910390a2427f224bbf4ba043354bee6487d05aa90892db4426afe8e3aa79007d0eae1b985ebc87604051610c0d91815260200190565b60405180910390a250506109b360018055565b610c28611ad7565b7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab610c528161194e565b6040517f6e04ff0d00000000000000000000000000000000000000000000000000000000815260206004820152600060248201819052903090636e04ff0d90604401600060405180830381865afa158015610cb1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cd99190810190613032565b50905080610d13576040517fa37ddd2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42600f8190556040519081527f883e407cc0ae0d12f7a01c2fdc3bd21afa3181401fc985b413f52316341eabe89060200160405180910390a1610d54611c5d565b5050505050565b600080610d66611ad7565b50506006546007549091565b600080610d7d611ad7565b50506004546005549091565b60115460009060609060ff161580610da3575060025460ff165b15610dc05750506040805160208101909152600080825290610ec1565b426000610dd062015180836130bf565b90506000610de0610e1083612fce565b90506000603c610df2610e10856130bf565b610dfc9190612fce565b90506000600d54603c610e0f9190612fa1565b600c54610e1e90610e10612fa1565b610e2891906130d3565b90506000610e37603c866130bf565b610e4284603c612fa1565b610e4e86610e10612fa1565b610e5891906130d3565b610e6291906130d3565b90506000828210158015610e815750600e54610e7e90846130d3565b82105b9050600062011940600f5489610e979190612f8e565b119050818015610ea45750805b995060405180602001604052806000815250985050505050505050505b9250929050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610ef28161194e565b6011805460ff191683151590811790915560405190815233907f84ea38e2d33114764b52620adfd1efa8dbc74614c1e2cdb6b16c16ffb798a2c59060200160405180910390a25050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610f668161194e565b610a3c611f18565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610f988161194e565b60188410610fd2576040517f6bae8b6500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603c831061100c576040517f053c1f4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012c82108061101e57506138408210155b15611055576040517fb11cd48100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c849055600d839055600e82905560408051858152602081018590529081018390527f7ba3a5f107a3591b604d817104b45edf844cd83ed1b93401dc66c4ac37a5bad09060600160405180910390a150505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756110d58161194e565b6001600160a01b038216611115576040517fa05ff47e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601380547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038516908102919091179091556040517fee26f3ffb0fd9f2274be5e2c82a9e710e999b2da7d338b2d662d2540b14cf1bb90600090a25050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756111a98161194e565b620186a063ffffffff831610156111d857604051630298914960e41b8152620186a06004820152602401610ab2565b6009805463ffffffff848116680100000000000000008181026bffffffff000000000000000019851617909455604080519490930490911680845260208401919091529133917fa33fca53ddda42966636288d60b6f6c9167d025c6e8e960f01cdd4a036932a76910160405180910390a2505050565b6000828152602081905260409020600101546112698161194e565b6109b38383611a02565b600061127d611ad7565b3360009081527f7d7ffb7a348e1c6a02869081a26547b49160dd3df72d1d75a570eb9b698292ec602052604090205460ff16806112e857503360009081527f738678fe42df6a4211eb7628ac9b056229141839eb4f4ef4cc249f1d36e8c921602052604090205460ff165b61131e576040517f9cf11bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611326611c5d565b905090565b6000611335611ad7565b6006546000036113455750600090565b60006006546004541015611368576004546006546113639190612f8e565b611378565b6006546004546113789190612f8e565b90506000600654826305f5e10061138f9190612fa1565b6113999190612fce565b905060065460045410156113b5576113b0816130e6565b6113b7565b805b9250505090565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756113e88161194e565b81600003611422576040517f5880a9f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60128290556040518281527f3f9ef5ed5d378ef819698e4b3c710d362f981f90087b428b7a1ee1e716d689d5906020015b60405180910390a15050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756114898161194e565b6013805460ff19168315159081179091556040519081527f4b3846e59e75439d5fd0202dae15523da9daacc4b91b1e0e2c7c9c6d5972aa4e90602001611453565b6114d2611b16565b8260035414611510576040517fd068bf5b00000000000000000000000000000000000000000000000000000000815260048101849052602401610ab2565b80511561155457827f427bedf194be24d8a151ec8cb762b5c8eae088b4f0c01e72a307cf5a51ade5d882604051611547919061311e565b60405180910390a2611945565b81516000036115bd57827f427bedf194be24d8a151ec8cb762b5c8eae088b4f0c01e72a307cf5a51ade5d86040516115479060208082526013908201527f456d70747920726573706f6e7365206461746100000000000000000000000000604082015260600190565b60208251101561164d57827f427bedf194be24d8a151ec8cb762b5c8eae088b4f0c01e72a307cf5a51ade5d8604051611547906020808252602d908201527f4d616c666f726d656420726573706f6e73652064617461202d20696e7375666660408201527f696369656e74206c656e67746800000000000000000000000000000000000000606082015260800190565b815160201415801561166157508151604014155b156116ec57827f427bedf194be24d8a151ec8cb762b5c8eae088b4f0c01e72a307cf5a51ade5d86040516115479060208082526023908201527f496e76616c696420726573706f6e7365206c656e67746820666f722075696e7460408201527f3235360000000000000000000000000000000000000000000000000000000000606082015260800190565b6000828060200190518101906117029190613131565b9050806000036117a057837f427bedf194be24d8a151ec8cb762b5c8eae088b4f0c01e72a307cf5a51ade5d86040516117929060208082526021908201527f43616e6e6f74207570646174652077697468207a65726f204e41562076616c7560408201527f6500000000000000000000000000000000000000000000000000000000000000606082015260800190565b60405180910390a250611945565b60135460ff1680156117b457506000600454115b156118b15760006004548211156117d9576004546117d29083612f8e565b90506117ea565b816004546117e79190612f8e565b90505b6004546000906117fc83612710612fa1565b6118069190612fce565b90506012548111156118ae57600454604080518581526020810192909252810182905286907f87f1134414af80af3c021db7f09983bd44be06e21b368b608181833a9e6289999060600160405180910390a2600454604080518581526020810192909252810182905286907f6f51259805c57907419075f90a8ed881dacf57fb4f4bc42c9d88585d4fffe28a9060600160405180910390a26118a6611f18565b505050611945565b50505b6004805460065560058054600755908290554290556118cf81611b59565b837f80bd2b323e3a6af589795c93e573d2de859bdd53d085cdf5b68eb5edc750b6c28260405161190191815260200190565b60405180910390a2427f224bbf4ba043354bee6487d05aa90892db4426afe8e3aa79007d0eae1b985ebc8260405161193b91815260200190565b60405180910390a2505b610a0560018055565b610a3c8133611f55565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166119fa576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556119b23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610748565b506000610748565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156119fa576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610748565b611a8d611fc5565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60025460ff1615611b14576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600260015403611b52576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600155565b60135461010090046001600160a01b031615610a3c576013546040517f16b60249000000000000000000000000000000000000000000000000000000008152600481018390526101009091046001600160a01b0316906316b6024990602401600060405180830381600087803b158015611bd257600080fd5b505af1925050508015611be3575060015b610a3c573d808015611c11576040519150601f19603f3d011682016040523d82523d6000602084013e611c16565b606091505b50601354604080518481526101009092046001600160a01b031660208301527fcc893a8b2c65b4d2b98d7ce00c3caf92cde0bf58c518a6cf746f792c1cf534c69101611453565b6000600a8054611c6c90612e27565b9050600003611c8e57604051631161b0b360e01b815260040160405180910390fd5b60095467ffffffffffffffff16600003611cbb57604051630ebd8d1960e11b815260040160405180910390fd5b600854611cdb576040516391f7443960e01b815260040160405180910390fd5b600954620186a06801000000000000000090910463ffffffff161015611d1957604051630298914960e41b8152620186a06004820152602401610ab2565b611d5a6040805160e0810190915280600081526020016000815260200160008152602001606081526020016060815260200160608152602001606081525090565b611df7600a8054611d6a90612e27565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9690612e27565b8015611de35780601f10611db857610100808354040283529160200191611de3565b820191906000526020600020905b815481529060010190602001808311611dc657829003601f168201915b50505050508261200190919063ffffffff16565b6000600b8054611e0690612e27565b90501115611eab57611eab600b8054611e1e90612e27565b80601f0160208091040260200160405190810160405280929190818152602001828054611e4a90612e27565b8015611e975780601f10611e6c57610100808354040283529160200191611e97565b820191906000526020600020905b815481529060010190602001808311611e7a57829003601f168201915b50505050508261200e90919063ffffffff16565b611ee1611eb782612058565b60095460085467ffffffffffffffff82169168010000000000000000900463ffffffff16906123c7565b600381905560405190925082907fe4a590f2aeb7a78489900321756fa3943a8ad762dcffc1daea08af7885afe91590600090a25090565b611f20611ad7565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611aba3390565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611fc1576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610ab2565b5050565b60025460ff16611b14576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fc18260008084612499565b8051600003612049576040517fe889636f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016020830152608090910152565b60606000612067610100612530565b90506120b16040518060400160405280600c81526020017f636f64654c6f636174696f6e00000000000000000000000000000000000000008152508261255190919063ffffffff16565b82516120cf9060028111156120c8576120c861314a565b829061256a565b60408051808201909152600881527f6c616e6775616765000000000000000000000000000000000000000000000000602082015261210e908290612551565b60408301516121259080156120c8576120c861314a565b60408051808201909152600681527f736f7572636500000000000000000000000000000000000000000000000000006020820152612164908290612551565b6060830151612174908290612551565b60a083015151156122195760408051808201909152600481527f617267730000000000000000000000000000000000000000000000000000000060208201526121be908290612551565b6121c7816125a3565b60005b8360a001515181101561220f576122078460a0015182815181106121f0576121f0613160565b60200260200101518361255190919063ffffffff16565b6001016121ca565b50612219816125c7565b6080830151511561231a5760008360200151600281111561223c5761223c61314a565b03612273576040517fa80d31f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201909152600f81527f736563726574734c6f636174696f6e000000000000000000000000000000000060208201526122b2908290612551565b6122cb836020015160028111156120c8576120c861314a565b60408051808201909152600781527f7365637265747300000000000000000000000000000000000000000000000000602082015261230a908290612551565b608083015161231a9082906125e5565b60c083015151156123bf5760408051808201909152600981527f62797465734172677300000000000000000000000000000000000000000000006020820152612364908290612551565b61236d816125a3565b60005b8360c00151518110156123b5576123ad8460c00151828151811061239657612396613160565b6020026020010151836125e590919063ffffffff16565b600101612370565b506123bf816125c7565b515192915050565b6000807f00000000000000000000000065dcc24f8ff9e51f10dcc7ed1e4e2a61e6e14bd66001600160a01b031663461d27628688600188886040518663ffffffff1660e01b815260040161241f959493929190613176565b6020604051808303816000875af115801561243e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124629190613131565b60405190915081907f1131472297a800fee664d1d89cfa8f7676ff07189ecc53f80bbb5f4969099db890600090a295945050505050565b80516000036124d4576040517f22ce3edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838360028111156124e7576124e761314a565b908160028111156124fa576124fa61314a565b905250604084018280156125105761251061314a565b908180156125205761252061314a565b9052506060909301929092525050565b61253861299f565b805161254490836125f2565b5060006020820152919050565b61255e8260038351612669565b8151610a05908261278a565b81516125779060c26127b2565b50611fc1828260405160200161258f91815260200190565b6040516020818303038152906040526125e5565b6125ae81600461281b565b6001816020018181516125c191906130d3565b90525050565b6125d281600761281b565b6001816020018181516125c19190612f8e565b61255e8260028351612669565b6040805180820190915260608152600060208201526126126020836130bf565b1561263a576126226020836130bf565b61262d906020612f8e565b61263790836130d3565b91505b60208084018390526040518085526000815290818401018181101561265e57600080fd5b604052509192915050565b60178167ffffffffffffffff16116126905782516109b39060e0600585901b1683176127b2565b60ff8167ffffffffffffffff16116126d25782516126b9906018611fe0600586901b16176127b2565b5082516109b39067ffffffffffffffff83166001612832565b61ffff8167ffffffffffffffff16116127155782516126fc906019611fe0600586901b16176127b2565b5082516109b39067ffffffffffffffff83166002612832565b63ffffffff8167ffffffffffffffff161161275a57825161274190601a611fe0600586901b16176127b2565b5082516109b39067ffffffffffffffff83166004612832565b825161277190601b611fe0600586901b16176127b2565b5082516109b39067ffffffffffffffff83166008612832565b6040805180820190915260608152600060208201526127ab838384516128b7565b9392505050565b60408051808201909152606081526000602082015282515160006127d78260016130d3565b9050846020015182106127f8576127f8856127f3836002612fa1565b612988565b8451602083820101858153508051821115612811578181525b5093949350505050565b8151610a0590601f611fe0600585901b16176127b2565b604080518082019091526060815260006020820152835151600061285682856130d3565b9050856020015181111561287357612873866127f3836002612fa1565b60006001612883866101006132a7565b61288d9190612f8e565b905086518281018783198251161781525080518311156128ab578281525b50959695505050505050565b60408051808201909152606081526000602082015282518211156128da57600080fd5b83515160006128e984836130d3565b9050856020015181111561290657612906866127f3836002612fa1565b855180518382016020019160009180851115612920578482525b505050602086015b60208610612960578051825261293f6020836130d3565b915061294c6020826130d3565b9050612959602087612f8e565b9550612928565b51815160001960208890036101000a0190811690199190911617905250849150509392505050565b815161299483836125f2565b506109b3838261278a565b60405180604001604052806129c7604051806040016040528060608152602001600081525090565b8152602001600081525090565b6000602082840312156129e657600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146127ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612a5557612a55612a16565b604052919050565b600067ffffffffffffffff821115612a7757612a77612a16565b50601f01601f191660200190565b600082601f830112612a9657600080fd5b8135612aa9612aa482612a5d565b612a2c565b818152846020838601011115612abe57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215612af057600080fd5b83359250602084013567ffffffffffffffff811115612b0e57600080fd5b612b1a86828701612a85565b925050604084013567ffffffffffffffff811115612b3757600080fd5b612b4386828701612a85565b9150509250925092565b60008083601f840112612b5f57600080fd5b50813567ffffffffffffffff811115612b7757600080fd5b602083019150836020828501011115610ec157600080fd5b60008060008060008060808789031215612ba857600080fd5b863567ffffffffffffffff81168114612bc057600080fd5b955060208701359450604087013567ffffffffffffffff811115612be357600080fd5b612bef89828a01612b4d565b909550935050606087013567ffffffffffffffff811115612c0f57600080fd5b612c1b89828a01612b4d565b979a9699509497509295939492505050565b600060208284031215612c3f57600080fd5b5035919050565b80356001600160a01b0381168114612c5d57600080fd5b919050565b60008060408385031215612c7557600080fd5b82359150612c8560208401612c46565b90509250929050565b600080600060408486031215612ca357600080fd5b83359250602084013567ffffffffffffffff811115612cc157600080fd5b612ccd86828701612b4d565b9497909650939450505050565b60008060208385031215612ced57600080fd5b823567ffffffffffffffff811115612d0457600080fd5b612d1085828601612b4d565b90969095509350505050565b60005b83811015612d37578181015183820152602001612d1f565b50506000910152565b60008151808452612d58816020860160208601612d1c565b601f01601f19169290920160200192915050565b8215158152604060208201526000612d876040830184612d40565b949350505050565b8015158114610a3c57600080fd5b600060208284031215612daf57600080fd5b81356127ab81612d8f565b600080600060608486031215612dcf57600080fd5b505081359360208301359350604090920135919050565b600060208284031215612df857600080fd5b6127ab82612c46565b600060208284031215612e1357600080fd5b813563ffffffff811681146127ab57600080fd5b600181811c90821680612e3b57607f821691505b602082108103612e5b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610a0557806000526020600020601f840160051c81016020851015612e885750805b601f840160051c820191505b81811015610d545760008155600101612e94565b67ffffffffffffffff831115612ec057612ec0612a16565b612ed483612ece8354612e27565b83612e61565b6000601f841160018114612f085760008515612ef05750838201355b600019600387901b1c1916600186901b178355610d54565b600083815260209020601f19861690835b82811015612f395786850135825560209485019460019092019101612f19565b5086821015612f565760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561074857610748612f78565b808202811582820484141761074857610748612f78565b634e487b7160e01b600052601260045260246000fd5b600082612fdd57612fdd612fb8565b500490565b85815284602082015260806040820152826080820152828460a0830137600060a08483010152600060a0601f19601f86011683010190506001600160a01b03831660608301529695505050505050565b6000806040838503121561304557600080fd5b825161305081612d8f565b602084015190925067ffffffffffffffff81111561306d57600080fd5b8301601f8101851361307e57600080fd5b805161308c612aa482612a5d565b8181528660208385010111156130a157600080fd5b6130b2826020830160208601612d1c565b8093505050509250929050565b6000826130ce576130ce612fb8565b500690565b8082018082111561074857610748612f78565b60007f8000000000000000000000000000000000000000000000000000000000000000820361311757613117612f78565b5060000390565b6020815260006127ab6020830184612d40565b60006020828403121561314357600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b67ffffffffffffffff8616815260a06020820152600061319960a0830187612d40565b61ffff9590951660408301525063ffffffff92909216606083015260809091015292915050565b6001815b60018411156131fb578085048111156131df576131df612f78565b60018416156131ed57908102905b60019390931c9280026131c4565b935093915050565b60008261321257506001610748565b8161321f57506000610748565b8160018114613235576002811461323f5761325b565b6001915050610748565b60ff84111561325057613250612f78565b50506001821b610748565b5060208310610133831016604e8410600b841016171561327e575081810a610748565b61328b60001984846131c0565b806000190482111561329f5761329f612f78565b029392505050565b60006127ab838361320356fea2646970667358221220829a2b129afa6fe6867c15d490662ae6316a3df107a01c2139fdfb9ad0fd384764736f6c634300081d0033
Verified Source Code Full Match
Compiler: v0.8.29+commit.ab55807c
EVM: paris
Optimization: Yes (1000 runs)
AutomationCompatibleInterface.sol 42 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// solhint-disable-next-line interface-starts-with-i
interface AutomationCompatibleInterface {
/**
* @notice method that is simulated by the keepers to see if any work actually
* needs to be performed. This method does does not actually need to be
* executable, and since it is only ever simulated it can consume lots of gas.
* @dev To ensure that it is never called, you may want to add the
* cannotExecute modifier from KeeperBase to your implementation of this
* method.
* @param checkData specified in the upkeep registration so it is always the
* same for a registered upkeep. This can easily be broken down into specific
* arguments using `abi.decode`, so multiple upkeeps can be registered on the
* same contract and easily differentiated by the contract.
* @return upkeepNeeded boolean to indicate whether the keeper should call
* performUpkeep or not.
* @return performData bytes that the keeper should call performUpkeep with, if
* upkeep is needed. If you would like to encode data to decode later, try
* `abi.encode`.
*/
function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
/**
* @notice method that is actually executed by the keepers, via the registry.
* The data returned by the checkUpkeep simulation will be passed into
* this method to actually be executed.
* @dev The input to this method should not be trusted, and the caller of the
* method should not even be restricted to any single registry. Anyone should
* be able call it, and the input should be validated, there is no guarantee
* that the data passed in is the performData returned from checkUpkeep. This
* could happen due to malicious keepers, racing keepers, or simply a state
* change while the performUpkeep transaction is waiting for confirmation.
* Always validate the data passed in.
* @param performData is the data which was passed back from the checkData
* simulation. If it is encoded, it can easily be decoded into other types by
* calling `abi.decode`. This data should not be trusted, and should be
* validated against the contract's current state.
*/
function performUpkeep(bytes calldata performData) external;
}
FunctionsClient.sol 62 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol";
import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol";
import {FunctionsRequest} from "./libraries/FunctionsRequest.sol";
/// @title The Chainlink Functions client contract
/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests
abstract contract FunctionsClient is IFunctionsClient {
using FunctionsRequest for FunctionsRequest.Request;
IFunctionsRouter internal immutable i_router;
event RequestSent(bytes32 indexed id);
event RequestFulfilled(bytes32 indexed id);
error OnlyRouterCanFulfill();
constructor(address router) {
i_router = IFunctionsRouter(router);
}
/// @notice Sends a Chainlink Functions request
/// @param data The CBOR encoded bytes data for a Functions request
/// @param subscriptionId The subscription ID that will be charged to service the request
/// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback
/// @return requestId The generated request ID for this request
function _sendRequest(
bytes memory data,
uint64 subscriptionId,
uint32 callbackGasLimit,
bytes32 donId
) internal returns (bytes32) {
bytes32 requestId = i_router.sendRequest(
subscriptionId,
data,
FunctionsRequest.REQUEST_DATA_VERSION,
callbackGasLimit,
donId
);
emit RequestSent(requestId);
return requestId;
}
/// @notice User defined function to handle a response from the DON
/// @param requestId The request ID, returned by sendRequest()
/// @param response Aggregated response from the execution of the user's source code
/// @param err Aggregated error from the execution of the user code or from the execution pipeline
/// @dev Either response or error parameter will be set, but never both
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual;
/// @inheritdoc IFunctionsClient
function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override {
if (msg.sender != address(i_router)) {
revert OnlyRouterCanFulfill();
}
fulfillRequest(requestId, response, err);
emit RequestFulfilled(requestId);
}
}
IFunctionsClient.sol 13 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @title Chainlink Functions client interface.
interface IFunctionsClient {
/// @notice Chainlink Functions response handler called by the Functions Router
/// during fullilment from the designated transmitter node in an OCR round.
/// @param requestId The requestId returned by FunctionsClient.sendRequest().
/// @param response Aggregated response from the request's source code.
/// @param err Aggregated error either from the request's source code or from the execution pipeline.
/// @dev Either response or error parameter will be set, but never both.
function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external;
}
IFunctionsRouter.sol 109 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {FunctionsResponse} from "../libraries/FunctionsResponse.sol";
/// @title Chainlink Functions Router interface.
interface IFunctionsRouter {
/// @notice The identifier of the route to retrieve the address of the access control contract
/// The access control contract controls which accounts can manage subscriptions
/// @return id - bytes32 id that can be passed to the "getContractById" of the Router
function getAllowListId() external view returns (bytes32);
/// @notice Set the identifier of the route to retrieve the address of the access control contract
/// The access control contract controls which accounts can manage subscriptions
function setAllowListId(bytes32 allowListId) external;
/// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network
/// @return adminFee
function getAdminFee() external view returns (uint72 adminFee);
/// @notice Sends a request using the provided subscriptionId
/// @param subscriptionId - A unique subscription ID allocated by billing system,
/// a client can make requests from different contracts referencing the same subscription
/// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
/// @param dataVersion - Gas limit for the fulfillment callback
/// @param callbackGasLimit - Gas limit for the fulfillment callback
/// @param donId - An identifier used to determine which route to send the request along
/// @return requestId - A unique request identifier
function sendRequest(
uint64 subscriptionId,
bytes calldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) external returns (bytes32);
/// @notice Sends a request to the proposed contracts
/// @param subscriptionId - A unique subscription ID allocated by billing system,
/// a client can make requests from different contracts referencing the same subscription
/// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
/// @param dataVersion - Gas limit for the fulfillment callback
/// @param callbackGasLimit - Gas limit for the fulfillment callback
/// @param donId - An identifier used to determine which route to send the request along
/// @return requestId - A unique request identifier
function sendRequestToProposed(
uint64 subscriptionId,
bytes calldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) external returns (bytes32);
/// @notice Fulfill the request by:
/// - calling back the data that the Oracle returned to the client contract
/// - pay the DON for processing the request
/// @dev Only callable by the Coordinator contract that is saved in the commitment
/// @param response response data from DON consensus
/// @param err error from DON consensus
/// @param juelsPerGas - current rate of juels/gas
/// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment
/// @param transmitter - The Node that transmitted the OCR report
/// @param commitment - The parameters of the request that must be held consistent between request and response time
/// @return fulfillResult -
/// @return callbackGasCostJuels -
function fulfill(
bytes memory response,
bytes memory err,
uint96 juelsPerGas,
uint96 costWithoutFulfillment,
address transmitter,
FunctionsResponse.Commitment memory commitment
) external returns (FunctionsResponse.FulfillResult, uint96);
/// @notice Validate requested gas limit is below the subscription max.
/// @param subscriptionId subscription ID
/// @param callbackGasLimit desired callback gas limit
function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view;
/// @notice Get the current contract given an ID
/// @param id A bytes32 identifier for the route
/// @return contract The current contract address
function getContractById(bytes32 id) external view returns (address);
/// @notice Get the proposed next contract given an ID
/// @param id A bytes32 identifier for the route
/// @return contract The current or proposed contract address
function getProposedContractById(bytes32 id) external view returns (address);
/// @notice Return the latest proprosal set
/// @return ids The identifiers of the contracts to update
/// @return to The addresses of the contracts that will be updated to
function getProposedContractSet() external view returns (bytes32[] memory, address[] memory);
/// @notice Proposes one or more updates to the contract routes
/// @dev Only callable by owner
function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external;
/// @notice Updates the current contract routes to the proposed contracts
/// @dev Only callable by owner
function updateContracts() external;
/// @dev Puts the system into an emergency stopped state.
/// @dev Only callable by owner
function pause() external;
/// @dev Takes the system out of an emergency stopped state.
/// @dev Only callable by owner
function unpause() external;
}
FunctionsRequest.sol 155 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {CBOR} from "../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol";
/// @title Library for encoding the input data of a Functions request into CBOR
library FunctionsRequest {
using CBOR for CBOR.CBORBuffer;
uint16 public constant REQUEST_DATA_VERSION = 1;
uint256 internal constant DEFAULT_BUFFER_SIZE = 256;
enum Location {
Inline, // Provided within the Request
Remote, // Hosted through remote location that can be accessed through a provided URL
DONHosted // Hosted on the DON's storage
}
enum CodeLanguage {
JavaScript
// In future version we may add other languages
}
struct Request {
Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON
Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported
CodeLanguage language; // ════════════╸ The coding language that the source code is written in
string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted
bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets())
string[] args; // ════════════════════╸ String arguments that will be passed into the source code
bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code
}
error EmptySource();
error EmptySecrets();
error EmptyArgs();
error NoInlineSecrets();
/// @notice Encodes a Request to CBOR encoded bytes
/// @param self The request to encode
/// @return CBOR encoded bytes
function encodeCBOR(Request memory self) internal pure returns (bytes memory) {
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("codeLocation");
buffer.writeUInt256(uint256(self.codeLocation));
buffer.writeString("language");
buffer.writeUInt256(uint256(self.language));
buffer.writeString("source");
buffer.writeString(self.source);
if (self.args.length > 0) {
buffer.writeString("args");
buffer.startArray();
for (uint256 i = 0; i < self.args.length; ++i) {
buffer.writeString(self.args[i]);
}
buffer.endSequence();
}
if (self.encryptedSecretsReference.length > 0) {
if (self.secretsLocation == Location.Inline) {
revert NoInlineSecrets();
}
buffer.writeString("secretsLocation");
buffer.writeUInt256(uint256(self.secretsLocation));
buffer.writeString("secrets");
buffer.writeBytes(self.encryptedSecretsReference);
}
if (self.bytesArgs.length > 0) {
buffer.writeString("bytesArgs");
buffer.startArray();
for (uint256 i = 0; i < self.bytesArgs.length; ++i) {
buffer.writeBytes(self.bytesArgs[i]);
}
buffer.endSequence();
}
return buffer.buf.buf;
}
/// @notice Initializes a Chainlink Functions Request
/// @dev Sets the codeLocation and code on the request
/// @param self The uninitialized request
/// @param codeLocation The user provided source code location
/// @param language The programming language of the user code
/// @param source The user provided source code or a url
function initializeRequest(
Request memory self,
Location codeLocation,
CodeLanguage language,
string memory source
) internal pure {
if (bytes(source).length == 0) revert EmptySource();
self.codeLocation = codeLocation;
self.language = language;
self.source = source;
}
/// @notice Initializes a Chainlink Functions Request
/// @dev Simplified version of initializeRequest for PoC
/// @param self The uninitialized request
/// @param javaScriptSource The user provided JS code (must not be empty)
function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure {
initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource);
}
/// @notice Adds Remote user encrypted secrets to a Request
/// @param self The initialized request
/// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets
function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure {
if (encryptedSecretsReference.length == 0) revert EmptySecrets();
self.secretsLocation = Location.Remote;
self.encryptedSecretsReference = encryptedSecretsReference;
}
/// @notice Adds DON-hosted secrets reference to a Request
/// @param self The initialized request
/// @param slotID Slot ID of the user's secrets hosted on DON
/// @param version User data version (for the slotID)
function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure {
CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);
buffer.writeString("slotID");
buffer.writeUInt64(slotID);
buffer.writeString("version");
buffer.writeUInt64(version);
self.secretsLocation = Location.DONHosted;
self.encryptedSecretsReference = buffer.buf.buf;
}
/// @notice Sets args for the user run function
/// @param self The initialized request
/// @param args The array of string args (must not be empty)
function setArgs(Request memory self, string[] memory args) internal pure {
if (args.length == 0) revert EmptyArgs();
self.args = args;
}
/// @notice Sets bytes args for the user run function
/// @param self The initialized request
/// @param args The array of bytes args (must not be empty)
function setBytesArgs(Request memory self, bytes[] memory args) internal pure {
if (args.length == 0) revert EmptyArgs();
self.bytesArgs = args;
}
}
FunctionsResponse.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @title Library of types that are used for fulfillment of a Functions request
library FunctionsResponse {
// Used to send request information from the Router to the Coordinator
struct RequestMeta {
bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request
bytes32 flags; // ═══════════════╸ Per-subscription flags
address requestingContract; // ══╗ The client contract that is sending the request
uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests.
uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request
uint64 initiatedRequests; // ║ The number of requests that have been started
uint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be given
uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data
uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out
address subscriptionOwner; // ═══╝ The owner of the billing subscription
}
enum FulfillResult {
FULFILLED, // 0
USER_CALLBACK_ERROR, // 1
INVALID_REQUEST_ID, // 2
COST_EXCEEDS_COMMITMENT, // 3
INSUFFICIENT_GAS_PROVIDED, // 4
SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5
INVALID_COMMITMENT // 6
}
struct Commitment {
bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request
address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request
uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request
address client; // ════════════════════╗ The client contract that sent the request
uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request
uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given
uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
uint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request
uint40 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback.
uint40 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback.
uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out
}
}
Buffer.sol 260 lines
// SPDX-License-Identifier: BSD-2-Clause
pragma solidity ^0.8.4;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for appending to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
let fpm := add(32, add(ptr, capacity))
if lt(fpm, ptr) {
revert(0, 0)
}
mstore(0x40, fpm)
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/
function fromBytes(bytes memory b) internal pure returns(buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/
function truncate(buffer memory buf) internal pure returns (buffer memory) {
assembly {
let bufptr := mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) {
require(len <= data.length);
uint off = buf.buf.length;
uint newCapacity = off + len;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(newCapacity, buflen) {
mstore(bufptr, newCapacity)
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
unchecked {
uint mask = (256 ** (32 - len)) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return append(buf, data, data.length);
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint offPlusOne = off + 1;
if (off >= buf.capacity) {
resize(buf, offPlusOne * 2);
}
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + off
let dest := add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended it
if gt(offPlusOne, mload(bufptr)) {
mstore(bufptr, offPlusOne)
}
}
return buf;
}
/**
* @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
unchecked {
uint mask = (256 ** len) - 1;
// Right-align data
data = data >> (8 * (32 - len));
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
}
return buf;
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/
function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
return append(buf, bytes32(data), 20);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
return append(buf, data, 32);
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer.
*/
function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
uint mask = (256 ** len) - 1;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
return buf;
}
}
CBOR.sol 222 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../../@ensdomains/buffer/v0.1.0/Buffer.sol";
/**
* @dev A library for populating CBOR encoded payload in Solidity.
*
* https://datatracker.ietf.org/doc/html/rfc7049
*
* The library offers various write* and start* methods to encode values of different types.
* The resulted buffer can be obtained with data() method.
* Encoding of primitive types is staightforward, whereas encoding of sequences can result
* in an invalid CBOR if start/write/end flow is violated.
* For the purpose of gas saving, the library does not verify start/write/end flow internally,
* except for nested start/end pairs.
*/
library CBOR {
using Buffer for Buffer.buffer;
struct CBORBuffer {
Buffer.buffer buf;
uint256 depth;
}
uint8 private constant MAJOR_TYPE_INT = 0;
uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
uint8 private constant MAJOR_TYPE_BYTES = 2;
uint8 private constant MAJOR_TYPE_STRING = 3;
uint8 private constant MAJOR_TYPE_ARRAY = 4;
uint8 private constant MAJOR_TYPE_MAP = 5;
uint8 private constant MAJOR_TYPE_TAG = 6;
uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;
uint8 private constant TAG_TYPE_BIGNUM = 2;
uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;
uint8 private constant CBOR_FALSE = 20;
uint8 private constant CBOR_TRUE = 21;
uint8 private constant CBOR_NULL = 22;
uint8 private constant CBOR_UNDEFINED = 23;
function create(uint256 capacity) internal pure returns(CBORBuffer memory cbor) {
Buffer.init(cbor.buf, capacity);
cbor.depth = 0;
return cbor;
}
function data(CBORBuffer memory buf) internal pure returns(bytes memory) {
require(buf.depth == 0, "Invalid CBOR");
return buf.buf.buf;
}
function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure {
buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));
writeBytes(buf, abi.encode(value));
}
function writeInt256(CBORBuffer memory buf, int256 value) internal pure {
if (value < 0) {
buf.buf.appendUint8(
uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)
);
writeBytes(buf, abi.encode(uint256(-1 - value)));
} else {
writeUInt256(buf, uint256(value));
}
}
function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_INT, value);
}
function writeInt64(CBORBuffer memory buf, int64 value) internal pure {
if(value >= 0) {
writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));
} else{
writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value));
}
}
function writeBytes(CBORBuffer memory buf, bytes memory value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));
buf.buf.append(value);
}
function writeString(CBORBuffer memory buf, string memory value) internal pure {
writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));
buf.buf.append(bytes(value));
}
function writeBool(CBORBuffer memory buf, bool value) internal pure {
writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE);
}
function writeNull(CBORBuffer memory buf) internal pure {
writeContentFree(buf, CBOR_NULL);
}
function writeUndefined(CBORBuffer memory buf) internal pure {
writeContentFree(buf, CBOR_UNDEFINED);
}
function startArray(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
buf.depth += 1;
}
function startFixedArray(CBORBuffer memory buf, uint64 length) internal pure {
writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length);
}
function startMap(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
buf.depth += 1;
}
function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure {
writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length);
}
function endSequence(CBORBuffer memory buf) internal pure {
writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
buf.depth -= 1;
}
function writeKVString(CBORBuffer memory buf, string memory key, string memory value) internal pure {
writeString(buf, key);
writeString(buf, value);
}
function writeKVBytes(CBORBuffer memory buf, string memory key, bytes memory value) internal pure {
writeString(buf, key);
writeBytes(buf, value);
}
function writeKVUInt256(CBORBuffer memory buf, string memory key, uint256 value) internal pure {
writeString(buf, key);
writeUInt256(buf, value);
}
function writeKVInt256(CBORBuffer memory buf, string memory key, int256 value) internal pure {
writeString(buf, key);
writeInt256(buf, value);
}
function writeKVUInt64(CBORBuffer memory buf, string memory key, uint64 value) internal pure {
writeString(buf, key);
writeUInt64(buf, value);
}
function writeKVInt64(CBORBuffer memory buf, string memory key, int64 value) internal pure {
writeString(buf, key);
writeInt64(buf, value);
}
function writeKVBool(CBORBuffer memory buf, string memory key, bool value) internal pure {
writeString(buf, key);
writeBool(buf, value);
}
function writeKVNull(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
writeNull(buf);
}
function writeKVUndefined(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
writeUndefined(buf);
}
function writeKVMap(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
startMap(buf);
}
function writeKVArray(CBORBuffer memory buf, string memory key) internal pure {
writeString(buf, key);
startArray(buf);
}
function writeFixedNumeric(
CBORBuffer memory buf,
uint8 major,
uint64 value
) private pure {
if (value <= 23) {
buf.buf.appendUint8(uint8((major << 5) | value));
} else if (value <= 0xFF) {
buf.buf.appendUint8(uint8((major << 5) | 24));
buf.buf.appendInt(value, 1);
} else if (value <= 0xFFFF) {
buf.buf.appendUint8(uint8((major << 5) | 25));
buf.buf.appendInt(value, 2);
} else if (value <= 0xFFFFFFFF) {
buf.buf.appendUint8(uint8((major << 5) | 26));
buf.buf.appendInt(value, 4);
} else {
buf.buf.appendUint8(uint8((major << 5) | 27));
buf.buf.appendInt(value, 8);
}
}
function writeIndefiniteLengthType(CBORBuffer memory buf, uint8 major)
private
pure
{
buf.buf.appendUint8(uint8((major << 5) | 31));
}
function writeDefiniteLengthType(CBORBuffer memory buf, uint8 major, uint64 length)
private
pure
{
writeFixedNumeric(buf, major, length);
}
function writeContentFree(CBORBuffer memory buf, uint8 value) private pure {
buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value));
}
}
AccessControl.sol 209 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
IAccessControl.sol 98 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
ERC165.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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);
}
Pausable.sol 119 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
INAVConsumer.sol 341 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {INAVReceiver} from "./INAVReceiver.sol";
// Authentication and Access Control Errors
error UnauthorizedNAVUpdateRequest();
// Configuration Errors
error InvalidSubscriptionId();
error InvalidDonId();
error InvalidSourceCode();
error InvalidGasLimit(uint32 minimum);
error InvalidEncryptedSecretsReference();
// Validation Errors
error DeviationCannotBeZero();
error InvalidNAVValue(uint256 navValue);
// Automation Errors
error UpkeepConditionsNotMet();
// Time Parameter Errors
error InvalidTargetHour();
error InvalidTargetMinute();
error InvalidTimeWindow();
// Force Update Errors
error ForceUpdateTooFrequent(uint256 timeSinceLastUpdate, uint256 minimumRequired);
// Receiver Errors
error InvalidReceiverAddress();
// Constructor Errors
error ZeroAddress(string parameter);
// Unexpected Request ID Error
error UnexpectedRequestID(bytes32 requestId);
/**
* @title NAV Consumer Interface
* @notice Interface for the NAV Consumer contract with Chainlink Functions and Automation
* @dev This interface declares all external functions, events, and errors for the NAV Consumer contract
* - Provides automated Net Asset Value (NAV) updates via Chainlink Functions and Automation
* - Supports manual and emergency NAV update mechanisms
* - Includes deviation checks to prevent erroneous NAV updates
* - Integrates with NAV receivers to propagate NAV updates to dependent contracts
* - Uses role-based access control for secure operation
*/
interface INAVConsumer {
// Events
/**
* @notice Emitted when the NAV value is updated (applies to all types of updates)
* @param timestamp The block timestamp when the NAV was updated
* @param navValue The new NAV value
*/
event NAVUpdated(uint256 indexed timestamp, uint256 navValue);
/**
* @notice Emitted when a NAV request is sent to Chainlink Functions
* @param requestId The unique ID for the Chainlink Functions request
*/
event NAVRequestSent(bytes32 indexed requestId);
/**
* @notice Emitted when a NAV request is successfully fulfilled by Chainlink Functions
* @param requestId The unique ID for the Chainlink Functions request
* @param navValue The NAV value received from the oracle
*/
event NAVFulfilled(bytes32 indexed requestId, uint256 navValue);
/**
* @notice Emitted when a NAV request fails
* @param requestId The unique ID for the Chainlink Functions request
* @param error The error message explaining the failure
*/
event NAVRequestFailed(bytes32 indexed requestId, string error);
/**
* @notice Emitted when an automated update is triggered via Chainlink Automation
* @param timestamp The block timestamp when the automated update was triggered
*/
event AutomatedUpdateTriggered(uint256 timestamp);
/**
* @notice Emitted when a NAV update is rejected due to excessive deviation
* @param requestId The unique ID for the Chainlink Functions request
* @param newNav The new NAV value that was rejected
* @param previousNav The previous NAV value used for comparison
* @param deviationBps The calculated deviation in basis points
*/
event ExcessiveNAVDeviation(bytes32 indexed requestId, uint256 newNav, uint256 previousNav, uint256 deviationBps);
/**
* @notice Emitted when the maximum allowed deviation is updated
* @param newMaxDeviationBps The new maximum deviation threshold in basis points
*/
event MaxDeviationUpdated(uint256 newMaxDeviationBps);
/**
* @notice Emitted when the deviation check is enabled or disabled
* @param enabled The new state of the deviation check
*/
event DeviationCheckToggled(bool enabled);
/**
* @notice Emitted when a NAV value is force updated by an emergency updater
* @param timestamp The block timestamp when the force update occurred
* @param navValue The new NAV value set via force update
* @param deviationBps The calculated deviation in basis points
* @param reason The reason provided for the force update
* @param caller The address that performed the force update
*/
event NAVForceUpdated(uint256 indexed timestamp, uint256 navValue, uint256 deviationBps, string reason, address caller);
/**
* @notice Emitted when a new NAV receiver is set
* @param receiver The address of the new NAV receiver
*/
event NAVReceiverUpdated(address indexed receiver);
/**
* @notice Emitted when an update to a NAV receiver fails
* @param navValue The NAV value that failed to be set
* @param receiver The address of the NAV receiver that failed
*/
event NAVReceiverUpdateFailed(uint256 navValue, address receiver);
/**
* @notice Emitted when automation time parameters are updated
* @param targetHour The new target hour for daily updates
* @param targetMinute The new target minute for daily updates
* @param timeWindow The new time window in seconds
*/
event AutomationParametersUpdated(uint256 targetHour, uint256 targetMinute, uint256 timeWindow);
/**
* @notice Emitted when the contract is paused due to excessive deviation
* @param requestId The unique ID for the Chainlink Functions request
* @param newNav The new NAV value that caused the deviation
* @param previousNav The previous NAV value used for comparison
* @param deviationBps The calculated deviation in basis points
*/
event PausedDueToDeviation(bytes32 indexed requestId, uint256 newNav, uint256 previousNav, uint256 deviationBps);
/**
* @notice Emitted when automation is enabled or disabled
* @param enabled The new state of automation (true=enabled, false=disabled)
* @param caller The address that changed the setting
*/
event AutomationEnabledChanged(bool enabled, address indexed caller);
/**
* @notice Emitted when the callback gas limit is updated
* @param oldLimit The previous gas limit value
* @param newLimit The new gas limit value
* @param caller The address that changed the setting
*/
event CallbackGasLimitUpdated(uint32 oldLimit, uint32 newLimit, address indexed caller);
/**
* @notice Emitted when Chainlink Functions configuration is updated
* @param subscriptionId The new Chainlink Functions subscription ID
* @param donId The new Decentralized Oracle Network ID
* @param sourceCodeHash Hash of the source code for identification
* @param secretsReferenceHash Hash of the encrypted secrets reference for identification
* @param caller The address that changed the configuration
*/
event ConfigurationUpdated(uint64 subscriptionId, bytes32 donId, bytes32 sourceCodeHash, bytes32 secretsReferenceHash, address indexed caller);
// External functions
/**
* @notice Enable or disable the automation feature
* @param enabled True to enable, false to disable
* @dev Only callable by admin role
*/
function setAutomationEnabled(bool enabled) external;
/**
* @notice Configure the Chainlink Functions parameters
* @param _subscriptionId The Chainlink Functions subscription ID for billing
* @param _donId The Decentralized Oracle Network ID
* @param _source The JavaScript source code to be executed by Chainlink Functions
* @param _encryptedSecretsReference Reference to encrypted secrets for the source code
* @dev Only callable by admin role
*/
function configure(
uint64 _subscriptionId,
bytes32 _donId,
string calldata _source,
bytes calldata _encryptedSecretsReference
) external;
/**
* @notice Set the gas limit for the Chainlink Functions callback
* @param _callbackGasLimit Gas limit for the fulfillRequest callback function
* @dev Only callable by admin role
*/
function setCallbackGasLimit(uint32 _callbackGasLimit) external;
/**
* @notice Request a NAV update from Chainlink Functions
* @return requestId The unique ID for this request
* @dev Only callable by admin or updater roles
*/
function requestNAV() external returns (bytes32 requestId);
/**
* @notice Entry point for Chainlink Automation to trigger NAV updates
* @param performData Arbitrary data passed from checkUpkeep to performUpkeep
* @dev Only callable by the Chainlink Automation registry
*/
function performUpkeep(bytes calldata performData) external;
/**
* @notice Set the maximum allowed deviation for NAV updates in basis points
* @param _maxDeviationBps The maximum allowed deviation (e.g., 1000 = 10%)
* @dev Only callable by admin role, cannot be set to zero
*/
function setMaxDeviation(uint256 _maxDeviationBps) external;
/**
* @notice Enable or disable the deviation check feature
* @param _enabled True to enable, false to disable deviation checks
* @dev Only callable by admin role
*/
function setDeviationCheckEnabled(bool _enabled) external;
/**
* @notice Force update the NAV value, bypassing the Chainlink Functions request
* @param _navValue The NAV value to set
* @param _reason Description explaining why this force update is necessary
* @dev Only callable by emergency updater role, subject to time restrictions
*/
function forceNAVUpdate(uint256 _navValue, string calldata _reason) external;
/**
* @notice Set the address of the NAV receiver contract
* @param _navReceiver The address of the contract implementing INAVReceiver
* @dev Only callable by admin role, cannot be zero address
*/
function setNAVReceiver(address _navReceiver) external;
/**
* @notice Get the current NAV value and its timestamp
* @return nav The latest NAV value with 18 decimal places
* @return timestamp The timestamp when this NAV value was last updated
*/
function getCurrentNAV() external view returns (uint256 nav, uint256 timestamp);
/**
* @notice Get the previous NAV value and its timestamp
* @return nav The previous NAV value with 18 decimal places
* @return timestamp The timestamp when the previous NAV value was updated
*/
function getPreviousNAV() external view returns (uint256 nav, uint256 timestamp);
/**
* @notice Calculate the percentage change between latest and previous NAV
* @return percentageChange The percentage change with 8 decimal places (e.g., 100000000 = 1%)
* @dev Returns 0 if there is no previous NAV
*/
function getPercentageChange() external view returns (int256 percentageChange);
// Read-only state variables
/**
* @notice Get the latest Chainlink Functions request ID
* @return The bytes32 request ID of the most recent request
*/
function latestRequestId() external view returns (bytes32);
/**
* @notice Get the timestamp of the latest NAV update
* @return The block timestamp when the latest NAV was updated
*/
function latestTimestamp() external view returns (uint256);
/**
* @notice Get the timestamp of the previous NAV update
* @return The block timestamp when the previous NAV was updated
*/
function previousTimestamp() external view returns (uint256);
/**
* @notice Get the Chainlink Functions DON ID used for requests
* @return The bytes32 DON ID
*/
function donId() external view returns (bytes32);
/**
* @notice Get the Chainlink Functions subscription ID used for billing
* @return The subscription ID
*/
function subscriptionId() external view returns (uint64);
/**
* @notice Get the timestamp of the last automated update via Chainlink Automation
* @return The block timestamp of the last automated update
*/
function lastAutomatedUpdateTimestamp() external view returns (uint256);
/**
* @notice Get the timestamp of the last force update
* @return The block timestamp of the last force update
*/
function lastForceUpdateTimestamp() external view returns (uint256);
/**
* @notice Check if automation is currently enabled
* @return True if automation is enabled, false otherwise
*/
function automationEnabled() external view returns (bool);
/**
* @notice Get the maximum allowed deviation in basis points
* @return The maximum deviation threshold in basis points (e.g., 1000 = 10%)
*/
function maxDeviationBps() external view returns (uint256);
/**
* @notice Check if deviation check is currently enabled
* @return True if deviation check is enabled, false otherwise
*/
function deviationCheckEnabled() external view returns (bool);
/**
* @notice Get the current NAV receiver contract
* @return The address of the contract implementing INAVReceiver
*/
function navReceiver() external view returns (INAVReceiver);
/**
* @notice Get the number of decimal places used in NAV values
* @return The number of decimal places (18)
* @dev NAV values are fixed-point numbers with 18 decimal places
*/
function decimals() external pure returns (uint8);
}
INAVReceiver.sol 18 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
/**
* @title NAV Receiver Interface
* @notice Interface for contracts that receive and process NAV updates from NAVConsumer
* @dev Any contract that needs to receive and act on NAV updates should implement this interface
*/
interface INAVReceiver {
/**
* @notice Updates the share price based on the provided NAV value
* @param nav The NAV value with 18 decimal places
* @dev This function is called by the NAVConsumer contract when the NAV is updated
* Implementations should handle potential failure gracefully as the NAVConsumer
* will not revert if this function fails
*/
function setSharePrice(uint256 nav) external;
}
NAVConsumer.sol 617 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol";
import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol";
import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/automation/interfaces/AutomationCompatibleInterface.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {INAVConsumer,
UnauthorizedNAVUpdateRequest,
DeviationCannotBeZero,
UpkeepConditionsNotMet,
InvalidTargetHour,
InvalidTargetMinute,
InvalidTimeWindow,
InvalidNAVValue,
ForceUpdateTooFrequent,
InvalidSubscriptionId,
InvalidDonId,
InvalidSourceCode,
InvalidEncryptedSecretsReference,
InvalidGasLimit,
InvalidReceiverAddress,
ZeroAddress,
UnexpectedRequestID
} from "./interfaces/INAVConsumer.sol";
import {INAVReceiver} from "./interfaces/INAVReceiver.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
/**
* @title Re Protocol NAV Consumer Contract with Automation
* @notice This contract receives, stores NAV data and automatically triggers daily updates
* @dev Implements both Chainlink Functions consumer and Chainlink Automation for scheduled updates
*
* Contract Security:
* - Uses AccessControl for role-based permissions:
* - ADMIN_ROLE: Can configure all parameters and settings
* - UPDATER_ROLE: Can trigger NAV updates
* - EMERGENCY_UPDATER_ROLE: Can force update NAV values directly
* - KEEPER_ROLE: Can perform upkeep
* - Uses ReentrancyGuard to prevent reentrancy attacks during NAV updates and external calls
* - Includes deviation checks to prevent erroneous NAV updates
* - Handles failure gracefully when updating NAV receivers
*
* Automation Flow:
* 1. checkUpkeep validates if an update should run based on time window and elapsed time
* 2. performUpkeep makes the actual Chainlink Functions request when conditions are met
* 3. fulfillRequest processes the response and updates NAV values
*
* Security Considerations:
* - NAV receiver could be malicious (try/catch pattern is used)
* - Oracle responses are validated for format and reasonableness
* - Force updates have time limitations and require special role
* - All parameters have validation and sanitization
* - Zero addresses are explicitly prevented
*/
contract NAVConsumer is INAVConsumer, FunctionsClient, AutomationCompatibleInterface, AccessControl, ReentrancyGuard, Pausable {
/// @notice Role that can configure all parameters and settings
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
/// @notice Role that can trigger NAV updates
bytes32 public constant UPDATER_ROLE = keccak256("UPDATER_ROLE");
/// @notice Role that can force update NAV values directly
bytes32 public constant EMERGENCY_UPDATER_ROLE = keccak256("EMERGENCY_UPDATER_ROLE");
/// @notice Role that can perform upkeep
bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE");
/// @notice Minimum time required between force updates (4 hours)
/// @dev Prevents abuse of force update mechanism and ensures time for proper review between emergency updates
uint256 public constant MIN_FORCE_UPDATE_INTERVAL = 4 hours;
using FunctionsRequest for FunctionsRequest.Request;
/// @notice State variables for NAV data
/// @dev Stores the latest Chainlink Functions request ID
bytes32 public latestRequestId;
/// @dev Current NAV value with 18 decimal places
uint256 internal latestNAV;
/// @dev Timestamp when the current NAV was updated
uint256 public latestTimestamp;
/// @dev Previous NAV value before the current update
uint256 internal previousNAV;
/// @dev Timestamp when the previous NAV was updated
uint256 public previousTimestamp;
/// @notice Chainlink Functions configuration
/// @dev DON ID for the Chainlink Functions network
bytes32 public donId;
/// @dev Subscription ID for billing Chainlink Functions requests
uint64 public subscriptionId;
/// @dev Gas limit for the fulfillRequest callback function
uint32 internal callbackGasLimit;
/// @dev JavaScript source code executed by Chainlink Functions
string internal source;
/// @dev Reference to encrypted secrets used by the source code
bytes internal encryptedSecretsReference;
/// @notice Chainlink Automation configuration
/// @dev Target hour (0-23) in UTC for daily updates - default 23:00
uint256 public targetHour = 23;
/// @dev Target minute (0-59) in UTC for daily updates - default 45 minutes
uint256 public targetMinute = 45;
/// @dev Time window in seconds during which updates are allowed - default 15 minutes (900 seconds)
/// @notice This defines how long after the target time an update can be performed
uint256 public timeWindow = 900;
/// @dev Timestamp of the last successful automated update via Chainlink Automation
/// @notice Used to enforce minimum time between automated updates (20 hours)
uint256 public lastAutomatedUpdateTimestamp;
/// @dev Timestamp of the last forced update via emergency mechanism
/// @notice Used to enforce minimum time between force updates (4 hours)
uint256 public lastForceUpdateTimestamp;
/// @dev Flag to enable or disable the automation feature
/// @notice When disabled, checkUpkeep will always return false
bool public automationEnabled = true;
/// @notice NAV deviation check configuration
/// @dev Maximum allowed deviation in basis points - default 10% (1000 basis points)
/// @notice Used to reject NAV updates with suspiciously large changes
uint256 public maxDeviationBps = 1000;
/// @dev Flag to enable or disable the deviation check feature
/// @notice When disabled, any NAV value will be accepted regardless of deviation
bool public deviationCheckEnabled = true;
/// @notice The contract that receives NAV updates
/// @dev Must implement INAVReceiver interface, can be set to zero address if not needed
INAVReceiver public navReceiver;
/**
* @notice Constructor initializes the contract with the Chainlink Functions router address and role assignments
* @param router The address of the Chainlink Functions router
* @param admin The address to assign as admin
* @param updater The address to assign as updater
* @param emergencyUpdater The address to assign as emergency updater
*/
constructor(
address router,
address admin,
address updater,
address emergencyUpdater
) FunctionsClient(router) {
if (router == address(0)) revert ZeroAddress("router");
if (admin == address(0)) revert ZeroAddress("admin");
if (updater == address(0)) revert ZeroAddress("updater");
if (emergencyUpdater == address(0)) revert ZeroAddress("emergencyUpdater");
callbackGasLimit = 300000; // Initial value well above minimum
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(ADMIN_ROLE, admin);
_grantRole(UPDATER_ROLE, updater);
_grantRole(EMERGENCY_UPDATER_ROLE, emergencyUpdater);
_grantRole(KEEPER_ROLE, admin); // Grant KEEPER_ROLE to admin initially
}
/**
* @notice Enable or disable the automation feature
* @param enabled True to enable, false to disable
* @dev Only callable by admin role
*/
function setAutomationEnabled(bool enabled) external virtual override onlyRole(ADMIN_ROLE) {
automationEnabled = enabled;
emit AutomationEnabledChanged(enabled, msg.sender);
}
/**
* @notice Configure the Chainlink Functions parameters
* @param _subscriptionId The Chainlink Functions subscription ID for billing
* @param _donId The Decentralized Oracle Network ID
* @param _source The JavaScript source code to be executed by Chainlink Functions
* @param _encryptedSecretsReference Reference to encrypted secrets for the source code
* @dev Only callable by admin role
*/
function configure(
uint64 _subscriptionId,
bytes32 _donId,
string calldata _source,
bytes calldata _encryptedSecretsReference
) external override onlyRole(ADMIN_ROLE) {
if (_subscriptionId == 0) revert InvalidSubscriptionId();
if (_donId == bytes32(0)) revert InvalidDonId();
if (bytes(_source).length == 0) revert InvalidSourceCode();
if (_encryptedSecretsReference.length == 0) revert InvalidEncryptedSecretsReference();
subscriptionId = _subscriptionId;
donId = _donId;
source = _source;
encryptedSecretsReference = _encryptedSecretsReference;
// Calculate hashes of source and secrets reference
bytes32 sourceCodeHash = keccak256(bytes(_source));
bytes32 secretsReferenceHash = keccak256(_encryptedSecretsReference);
emit ConfigurationUpdated(_subscriptionId, _donId, sourceCodeHash, secretsReferenceHash, msg.sender);
}
/// @notice Minimum gas needed for fulfillRequest based on testing
uint32 public constant MIN_CALLBACK_GAS_LIMIT = 100000;
/**
* @notice Set the gas limit for the Chainlink Functions callback
* @param _callbackGasLimit Gas limit for the fulfillRequest callback function
* @dev Only callable by admin role
*/
function setCallbackGasLimit(uint32 _callbackGasLimit) external override onlyRole(ADMIN_ROLE) {
if (_callbackGasLimit < MIN_CALLBACK_GAS_LIMIT) revert InvalidGasLimit(MIN_CALLBACK_GAS_LIMIT);
uint32 oldLimit = callbackGasLimit;
callbackGasLimit = _callbackGasLimit;
emit CallbackGasLimitUpdated(oldLimit, _callbackGasLimit, msg.sender);
}
/**
* @notice Request a NAV update from Chainlink Functions
* @return requestId The unique ID for this request
* @dev Only callable by admin or updater roles
*/
function requestNAV() public virtual override whenNotPaused returns (bytes32 requestId) {
// Ensure only authorized callers can trigger NAV updates
if (!(hasRole(ADMIN_ROLE, msg.sender) || hasRole(UPDATER_ROLE, msg.sender))) {
revert UnauthorizedNAVUpdateRequest();
}
// Call the internal implementation that contains the actual request logic
return _performRequestNAV();
}
/**
* @notice Internal implementation of the NAV request logic
* @dev Separated to allow performUpkeep to bypass the authorization check
* @dev Validates all configuration parameters before making the request
* @dev Emits NAVRequestSent event with request ID
* @return requestId The ID of the Chainlink Functions request
*/
function _performRequestNAV() internal virtual returns (bytes32 requestId) {
// Validate configuration components individually for detailed errors
if (bytes(source).length == 0) revert InvalidSourceCode();
if (subscriptionId == 0) revert InvalidSubscriptionId();
if (donId == bytes32(0)) revert InvalidDonId();
if (callbackGasLimit < MIN_CALLBACK_GAS_LIMIT) revert InvalidGasLimit(MIN_CALLBACK_GAS_LIMIT);
// Create and initialize the Chainlink Functions request
FunctionsRequest.Request memory req;
req.initializeRequestForInlineJavaScript(source);
// Add encrypted secrets reference if provided
if (encryptedSecretsReference.length > 0) {
req.addSecretsReference(encryptedSecretsReference);
}
// Send the request to Chainlink Functions
requestId = _sendRequest(
req.encodeCBOR(),
subscriptionId,
callbackGasLimit,
donId
);
// Store the request ID and emit event
latestRequestId = requestId;
emit NAVRequestSent(requestId);
return requestId;
}
/**
* @notice Set the address of the NAV receiver contract
* @param _navReceiver The address of the contract implementing INAVReceiver
* @dev Only callable by admin role, cannot be zero address
*/
function setNAVReceiver(address _navReceiver) external onlyRole(ADMIN_ROLE) {
if (_navReceiver == address(0)) revert InvalidReceiverAddress();
navReceiver = INAVReceiver(_navReceiver);
emit NAVReceiverUpdated(_navReceiver);
}
/**
* @notice Internal function to update NAV receiver with latest NAV value
* @param navValue The NAV value to set in the receiver contract
* @dev Uses try/catch pattern to handle potential failures in the receiver contract
* @dev Will not revert if the receiver fails - NAV updates succeed regardless of receiver state
* @dev Emits NAVReceiverUpdateFailed event if the receiver call fails
* @dev Does nothing if navReceiver is not set (zero address)
*/
function _updateNAVReceiver(uint256 navValue) internal {
// Call the NAV receiver to update the share price if it's set
if (address(navReceiver) != address(0)) {
try navReceiver.setSharePrice(navValue) {
// Successfully updated the share price - nothing more to do
} catch (bytes memory /* reason */) {
// Receiver call failed, but we don't want to revert the entire NAV update
emit NAVReceiverUpdateFailed(navValue, address(navReceiver));
}
}
}
/**
* @notice Callback function for Chainlink Functions to deliver the response
* @param requestId The ID of the request being fulfilled
* @param response The response data from Chainlink Functions (NAV value)
* @param err Error message if the request failed
* @dev Contains extensive validation of response format and data
* @dev Protected against reentrancy with ReentrancyGuard
* @dev Performs deviation check to prevent erroneous NAV updates
* @dev Updates NAV data storage and propagates to NAV receiver if successful
* @dev Emits appropriate events based on result (success, failure, deviation)
*/
function fulfillRequest(
bytes32 requestId,
bytes memory response,
bytes memory err
) internal override nonReentrant {
// Verify that the response is for the expected request
if (latestRequestId != requestId) {
revert UnexpectedRequestID(requestId);
}
// First, check for errors from the Chainlink Functions service
if (err.length > 0) {
emit NAVRequestFailed(requestId, string(err));
return;
}
// Check if response data exists
if (response.length == 0) {
emit NAVRequestFailed(requestId, "Empty response data");
return;
}
// Check if response has minimum length for a uint256
if (response.length < 32) {
emit NAVRequestFailed(requestId, "Malformed response data - insufficient length");
return;
}
// Validate response format for a uint256
if (response.length != 32 && response.length != 64) {
emit NAVRequestFailed(requestId, "Invalid response length for uint256");
return;
}
// Decode the response - we've already validated format above
uint256 navValue = abi.decode(response, (uint256));
// Reject zero NAV values
if (navValue == 0) {
emit NAVRequestFailed(requestId, "Cannot update with zero NAV value");
return;
}
// Check for excessive deviation if enabled and we have an initial value
if (deviationCheckEnabled && latestNAV > 0) {
// Calculate absolute difference safely
uint256 changeAbs;
if (navValue > latestNAV) {
changeAbs = navValue - latestNAV;
} else {
changeAbs = latestNAV - navValue;
}
// Calculate deviation in basis points
uint256 deviationBps = (changeAbs * 10000) / latestNAV;
// If deviation exceeds limit, reject the update and emit event with detailed error
if (deviationBps > maxDeviationBps) {
emit ExcessiveNAVDeviation(requestId, navValue, latestNAV, deviationBps);
emit PausedDueToDeviation(requestId, navValue, latestNAV, deviationBps);
_pause();
return; // Reject update but don't revert
}
}
// Update the NAV data
previousNAV = latestNAV;
previousTimestamp = latestTimestamp;
latestNAV = navValue;
latestTimestamp = block.timestamp;
// Update the NAV receiver
_updateNAVReceiver(navValue);
emit NAVFulfilled(requestId, navValue);
emit NAVUpdated(block.timestamp, navValue);
}
/**
* @notice Determine if upkeep is needed based on time (for Chainlink Automation)
* @return upkeepNeeded Boolean indicating if upkeep is needed
* @return performData The data to be used in performUpkeep (empty in this case)
* @dev Checks if automation is enabled
* @dev Calculates current UTC time components (hour, minute, seconds)
* @dev Determines if current time is within the configured target window
* @dev Checks if enough time has passed since last update (20+ hours)
* @dev Returns true only when all conditions are met
*/
function checkUpkeep(bytes calldata /* checkData */)
external
view
override
returns (bool upkeepNeeded, bytes memory performData)
{
// Skip check if automation is disabled
if (!automationEnabled || paused()) {
return (false, "");
}
// Get current UTC time components
uint256 timestamp = block.timestamp;
uint256 secondsInDay = timestamp % 86400; // Seconds since midnight UTC
uint256 currentHour = secondsInDay / 3600;
uint256 currentMinute = (secondsInDay % 3600) / 60;
// Calculate target time in seconds since midnight UTC
uint256 targetTimeSeconds = (targetHour * 3600) + (targetMinute * 60);
// Calculate current time in seconds since midnight UTC
uint256 currentTimeSeconds = (currentHour * 3600) + (currentMinute * 60) + (secondsInDay % 60);
// Check if we're in the target time window (23:45-23:50 UTC)
bool inTimeWindow = currentTimeSeconds >= targetTimeSeconds &&
currentTimeSeconds < (targetTimeSeconds + timeWindow);
// Check if it's been more than 20 hours since the last update
bool enoughTimePassed = (timestamp - lastAutomatedUpdateTimestamp) > 20 hours;
// Upkeep is needed if we're in the target time window AND it's been enough time since the last update
upkeepNeeded = inTimeWindow && enoughTimePassed;
// We don't need to pass any data to performUpkeep
performData = "";
return (upkeepNeeded, performData);
}
/**
* @notice Perform the upkeep by requesting a NAV update
* @dev Verifies upkeep conditions via checkUpkeep before proceeding
* @dev Reverts with UpkeepConditionsNotMet if conditions aren't satisfied
* @dev Calls _performRequestNAV to initiate Chainlink Functions request
* @dev Updates lastAutomatedUpdateTimestamp and emits AutomatedUpdateTriggered event
*/
function performUpkeep(bytes calldata /* performData */) external override(INAVConsumer, AutomationCompatibleInterface) whenNotPaused onlyRole(KEEPER_ROLE) {
// Check if upkeep conditions are satisfied
(bool upkeepNeeded, ) = this.checkUpkeep("");
if (!upkeepNeeded) {
revert UpkeepConditionsNotMet();
}
// Update the last automated update timestamp BEFORE external interactions
lastAutomatedUpdateTimestamp = block.timestamp;
// Emit event
emit AutomatedUpdateTriggered(block.timestamp);
// Perform NAV update (external interaction)
_performRequestNAV();
}
/**
* @notice Set the maximum allowed deviation for NAV updates in basis points
* @param _maxDeviationBps The maximum allowed deviation (e.g., 1000 = 10%)
* @dev Only callable by admin role, cannot be set to zero
*/
function setMaxDeviation(uint256 _maxDeviationBps) external override onlyRole(ADMIN_ROLE) {
if (_maxDeviationBps == 0) {
revert DeviationCannotBeZero();
}
maxDeviationBps = _maxDeviationBps;
emit MaxDeviationUpdated(_maxDeviationBps);
}
/**
* @notice Enable or disable the deviation check feature
* @param _enabled True to enable, false to disable deviation checks
* @dev Only callable by admin role
*/
function setDeviationCheckEnabled(bool _enabled) external override onlyRole(ADMIN_ROLE) {
deviationCheckEnabled = _enabled;
emit DeviationCheckToggled(_enabled);
}
/**
* @notice Force update the NAV value, bypassing the Chainlink Functions request
* @param _navValue The NAV value to set
* @param _reason Description explaining why this force update is necessary
* @dev Only callable by emergency updater role, subject to time restrictions
*/
function forceNAVUpdate(
uint256 _navValue,
string calldata _reason
) external override whenNotPaused onlyRole(EMERGENCY_UPDATER_ROLE) nonReentrant {
// Basic validation to prevent clearly erroneous values
if (_navValue == 0) revert InvalidNAVValue(0);
// Enforce minimum time between forced updates
uint256 timeSinceLastForceUpdate = block.timestamp - lastForceUpdateTimestamp;
if (lastForceUpdateTimestamp > 0 && timeSinceLastForceUpdate < MIN_FORCE_UPDATE_INTERVAL) {
revert ForceUpdateTooFrequent(timeSinceLastForceUpdate, MIN_FORCE_UPDATE_INTERVAL);
}
// Calculate deviation for transparency, even though we're bypassing checks
uint256 deviationBps = 0;
if (latestNAV > 0) {
uint256 changeAbs = _navValue > latestNAV
? _navValue - latestNAV
: latestNAV - _navValue;
deviationBps = (changeAbs * 10000) / latestNAV;
}
// Update the NAV data
previousNAV = latestNAV;
previousTimestamp = latestTimestamp;
latestNAV = _navValue;
latestTimestamp = block.timestamp;
lastForceUpdateTimestamp = block.timestamp;
// Update the NAV receiver
_updateNAVReceiver(_navValue);
// Emit events with enhanced information
emit NAVForceUpdated(block.timestamp, _navValue, deviationBps, _reason, msg.sender);
emit NAVUpdated(block.timestamp, _navValue);
}
/**
* @notice Get the current NAV value and its timestamp
* @return nav The latest NAV value with 18 decimal places
* @return timestamp The timestamp when this NAV value was last updated
*/
function getCurrentNAV() external view override whenNotPaused returns (uint256 nav, uint256 timestamp) {
return (latestNAV, latestTimestamp);
}
/**
* @notice Get the previous NAV value and its timestamp
* @return nav The previous NAV value with 18 decimal places
* @return timestamp The timestamp when the previous NAV value was updated
*/
function getPreviousNAV() external view override whenNotPaused returns (uint256 nav, uint256 timestamp) {
return (previousNAV, previousTimestamp);
}
/**
* @notice Calculate the percentage change between latest and previous NAV
* @return percentageChange The percentage change with 8 decimal places (e.g., 100000000 = 1%)
* @dev Returns 0 if there is no previous NAV
*/
function getPercentageChange() external view override whenNotPaused returns (int256 percentageChange) {
if (previousNAV == 0) return 0;
// Calculate absolute difference
uint256 changeAbs = latestNAV >= previousNAV
? latestNAV - previousNAV
: previousNAV - latestNAV;
// Calculate percentage change using uint256 math
uint256 percentageChangeAbs = (changeAbs * 100000000) / previousNAV;
// Apply sign to result (safe cast since percentage value is much smaller)
percentageChange = latestNAV >= previousNAV
? int256(percentageChangeAbs)
: -int256(percentageChangeAbs);
return percentageChange;
}
/**
* @notice Get the number of decimal places used in NAV values
* @return The number of decimal places (18)
* @dev NAV values are fixed-point numbers with 18 decimal places
* @dev Follows ERC20 convention for better integration with other protocols
*/
function decimals() external pure override returns (uint8) {
return 18;
}
/**
* @notice Update automation scheduling parameters
* @param _targetHour New target hour (0-23) for the daily update
* @param _targetMinute New target minute (0-59) for the daily update
* @param _timeWindow New time window in seconds
* @dev Only callable by admin role, includes validation of parameters
*/
function setAutomationTimeParameters(uint256 _targetHour, uint256 _targetMinute, uint256 _timeWindow) external onlyRole(ADMIN_ROLE) {
if (_targetHour >= 24) revert InvalidTargetHour();
if (_targetMinute >= 60) revert InvalidTargetMinute();
// Time window must be between 5 minutes and 4 hours
if (_timeWindow < 300 || _timeWindow >= 14400) revert InvalidTimeWindow();
targetHour = _targetHour;
targetMinute = _targetMinute;
timeWindow = _timeWindow;
emit AutomationParametersUpdated(_targetHour, _targetMinute, _timeWindow);
}
/**
* @notice Pause the contract
* @dev Only callable by admin role
*/
function pause() external onlyRole(ADMIN_ROLE) {
_pause();
}
/**
* @notice Unpause the contract
* @dev Only callable by admin role
*/
function unpause() external onlyRole(ADMIN_ROLE) {
_unpause();
}
}
ChainedNAVReceiver.sol 107 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {INAVReceiver} from "../interfaces/INAVReceiver.sol";
/**
* @title Chained NAV Receiver
* @notice A contract that implements INAVReceiver and forwards updates to another receiver
* @dev Used for testing multi-receiver scenarios
*/
contract ChainedNAVReceiver is INAVReceiver {
// The current share price
uint256 public sharePrice;
// The next receiver in the chain
INAVReceiver public nextReceiver;
// Track update propagation
uint256 public updateCount;
uint256 public lastUpdatedValue;
bool public propagateUpdates = true;
bool public shouldFail = false;
// Event for tracking updates
event SharePriceUpdated(uint256 oldPrice, uint256 newPrice);
event UpdatePropagated(address nextReceiver, uint256 value);
/**
* @notice Constructor to initialize with an optional next receiver
* @param _nextReceiver The next receiver in the chain
*/
constructor(address _nextReceiver) {
if (_nextReceiver != address(0)) {
nextReceiver = INAVReceiver(_nextReceiver);
}
}
/**
* @notice Set the next receiver in the chain
* @param _nextReceiver The address of the next receiver
*/
function setNextReceiver(address _nextReceiver) external {
nextReceiver = INAVReceiver(_nextReceiver);
}
/**
* @notice Control whether to propagate updates to the next receiver
* @param _propagate Whether to propagate updates
*/
function setPropagateUpdates(bool _propagate) external {
propagateUpdates = _propagate;
}
/**
* @notice Toggle failure mode (for testing error handling)
* @param _shouldFail Whether this receiver should fail when updated
*/
function setShouldFail(bool _shouldFail) external {
shouldFail = _shouldFail;
}
/**
* @notice Implementation of setSharePrice from INAVReceiver
* @param nav The new NAV value
*/
function setSharePrice(uint256 nav) external override {
if (shouldFail) {
revert("ChainedNAVReceiver: Intentional failure");
}
// Store the old price for the event
uint256 oldPrice = sharePrice;
// Update the share price
sharePrice = nav;
lastUpdatedValue = nav;
updateCount++;
// Emit event
emit SharePriceUpdated(oldPrice, nav);
// Propagate to the next receiver if configured
if (address(nextReceiver) != address(0) && propagateUpdates) {
try nextReceiver.setSharePrice(nav) {
emit UpdatePropagated(address(nextReceiver), nav);
} catch {
// Silently catch errors from next receiver
// This ensures errors don't bubble up to the NAVConsumer
}
}
}
/**
* @notice Get the current share price
* @return The current share price
*/
function getSharePrice() external view returns (uint256) {
return sharePrice;
}
/**
* @notice Reset the update counter (for testing)
*/
function resetUpdateCount() external {
updateCount = 0;
}
}
FailingMockNAVReceiver.sol 25 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {INAVReceiver} from "../interfaces/INAVReceiver.sol";
/**
* @title Failing NAV Receiver Mock
* @notice This mock receiver always reverts when setSharePrice is called
* @dev Used for testing error handling in the NAV Consumer
*/
contract FailingMockNAVReceiver is INAVReceiver {
// Custom error for explaining failures
error AlwaysFailingReceiver();
// This will never be updated since all calls revert
uint256 public sharePrice;
/**
* @notice Implementation of setSharePrice that always reverts
* @dev Unused parameter intentionally unnamed to avoid compiler warnings
*/
function setSharePrice(uint256) external pure override {
revert AlwaysFailingReceiver();
}
}
MaliciousNAVReceiver.sol 133 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {INAVReceiver} from "../interfaces/INAVReceiver.sol";
import {INAVConsumer} from "../interfaces/INAVConsumer.sol";
/**
* @title Malicious NAV Receiver
* @notice This contract attempts to perform reentrancy attacks on the NAV Consumer
* @dev Used only for testing reentrancy protections
*/
contract MaliciousNAVReceiver is INAVReceiver {
// The NAV consumer contract that will be targeted
address public navConsumer;
// The target function for reentrancy
string public reentrancyTarget;
// Share price state
uint256 public sharePrice;
// Custom attack parameters
uint256 public attackNav = 9999999; // Default attack NAV value
address public attackReceiver; // Address to try to set as a new receiver
address public nextReceiver; // Next receiver in a chain attack
// Tracking variables
bool public reentrancyAttempted;
uint256 public callCounter;
/**
* @notice Constructor
*/
constructor() {
// Default initialization - navConsumer will be set later
}
/**
* @notice Set the NAV consumer contract address
* @param _navConsumer The address of the NAV consumer contract
*/
function setNAVConsumer(address _navConsumer) external {
navConsumer = _navConsumer;
}
/**
* @notice Set the target function for reentrancy
* @param _target The function to target ('forceNAVUpdate', 'requestNAV', or 'setNAVReceiver')
*/
function setReentrancyTarget(string calldata _target) external {
reentrancyTarget = _target;
}
/**
* @notice Set the NAV value to use in attacks
* @param _attackNav The NAV value to try to set during reentrancy
*/
function setAttackNav(uint256 _attackNav) external {
attackNav = _attackNav;
}
/**
* @notice Set the receiver address to use in setNAVReceiver attacks
* @param _attackReceiver The address to try to set as a new receiver
*/
function setAttackReceiver(address _attackReceiver) external {
attackReceiver = _attackReceiver;
}
/**
* @notice Set the next receiver for chained attacks
* @param _nextReceiver The address of the next malicious receiver
*/
function setNextReceiver(address _nextReceiver) external {
nextReceiver = _nextReceiver;
}
/**
* @notice Implementation of setSharePrice that attempts reentrancy
* @param _sharePrice The new share price
*/
function setSharePrice(uint256 _sharePrice) external override {
// Store the share price
sharePrice = _sharePrice;
// Increment call counter for test verification
callCounter++;
// Mark that we attempted reentrancy
reentrancyAttempted = true;
// Attempt the appropriate attack based on target string
if (keccak256(abi.encodePacked(reentrancyTarget)) == keccak256(abi.encodePacked("forceNAVUpdate"))) {
// Try to reenter forceNAVUpdate with the new signature
try INAVConsumer(navConsumer).forceNAVUpdate(attackNav, "Malicious update") {
// If successful, this would be unexpected in a secure contract
} catch {
// Expected to fail due to reentrancy guard
}
} else if (keccak256(abi.encodePacked(reentrancyTarget)) == keccak256(abi.encodePacked("requestNAV"))) {
// Try to reenter requestNAV
try INAVConsumer(navConsumer).requestNAV() {
// If successful, this would be unexpected in a secure contract
} catch {
// Expected to fail due to reentrancy guard or role check
}
} else if (keccak256(abi.encodePacked(reentrancyTarget)) == keccak256(abi.encodePacked("setNAVReceiver"))) {
// Try to reenter setNAVReceiver
try INAVConsumer(navConsumer).setNAVReceiver(attackReceiver) {
// If successful, this would be unexpected in a secure contract
} catch {
// Expected to fail due to reentrancy guard or role check
}
}
// If we have a next receiver, try to change to it (multi-step attack)
if (nextReceiver != address(0)) {
try INAVConsumer(navConsumer).setNAVReceiver(nextReceiver) {
// If successful, this would be unexpected in a secure contract
} catch {
// Expected to fail due to reentrancy guard or role check
}
}
}
/**
* @notice Get the current share price
* @return The current share price
*/
function getSharePrice() external view returns (uint256) {
return sharePrice;
}
}
MockFunctionsRouter.sol 114 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {IFunctionsClient} from "@chainlink/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsClient.sol";
/**
* @title Mock Functions Router
* @notice Mock implementation of Chainlink Functions Router for testing
*/
contract MockFunctionsRouter {
event RequestProcessed(bytes32 indexed requestId, address consumer);
event ResponseDelivered(bytes32 indexed requestId, address consumer, bytes response, bytes error);
/**
* @notice Process a request directly (for testing)
* @param consumer The consumer contract address
* @param requestId The request ID to process
* @param response The response data to send
* @param err Any error message
*/
function sendResponse(
address consumer,
bytes32 requestId,
bytes memory response,
bytes memory err
) external {
// Call the consumer's handleOracleFulfillment function (matches IFunctionsClient interface)
IFunctionsClient(consumer).handleOracleFulfillment(requestId, response, err);
emit ResponseDelivered(requestId, consumer, response, err);
}
/**
* @notice Alternative name for sendResponse (for compatibility with different test styles)
*/
function fulfillRequest(
address consumer,
bytes32 requestId,
bytes memory response,
bytes memory err
) external {
// Call the consumer's handleOracleFulfillment function (matches IFunctionsClient interface)
IFunctionsClient(consumer).handleOracleFulfillment(requestId, response, err);
emit ResponseDelivered(requestId, consumer, response, err);
}
/**
* @notice Mock implementation of sendRequest from IFunctionsRouter
* @dev This function returns a deterministic requestId for testing
*/
function sendRequest(
uint64 subscriptionId,
bytes calldata data,
uint16 dataVersion,
uint32 callbackGasLimit,
bytes32 donId
) external returns (bytes32) {
// Create a deterministic requestId based on inputs for testing predictability
bytes32 requestId = keccak256(
abi.encode(
msg.sender,
subscriptionId,
data,
dataVersion,
callbackGasLimit,
donId,
block.timestamp
)
);
// Store the request info
latestRequestId = requestId;
requestCount++;
emit RequestProcessed(requestId, msg.sender);
return requestId;
}
// For testing - track request info
bytes32 public latestRequestId;
uint256 public requestCount;
/**
* @notice Get the latest request ID
*/
function getLatestRequestId() external view returns (bytes32) {
return latestRequestId;
}
/**
* @notice Get the count of requests
*/
function getRequestCount() external view returns (uint256) {
return requestCount;
}
/**
* @notice Simplified version of sendResponse - renamed to avoid overloading issues
* @param requestId The request ID to process
* @param response The response data to send
* @param err Any error message
*/
function sendSimpleResponse(
bytes32 requestId,
bytes memory response,
bytes memory err
) external {
// Call the consumer's handleOracleFulfillment function (matches IFunctionsClient interface)
IFunctionsClient(msg.sender).handleOracleFulfillment(requestId, response, err);
emit ResponseDelivered(requestId, msg.sender, response, err);
}
}
MockNAVReceiver.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {INAVReceiver} from "../interfaces/INAVReceiver.sol";
contract MockNAVReceiver is INAVReceiver {
uint256 public sharePrice;
bool public shouldRevert;
event SharePriceUpdated(uint256 value);
function setSharePrice(uint256 nav) external override {
require(!shouldRevert, "MockNAVReceiver: reverting as configured");
sharePrice = nav;
emit SharePriceUpdated(nav);
}
function setShouldRevert(bool _shouldRevert) external {
shouldRevert = _shouldRevert;
}
}
Read Contract
ADMIN_ROLE 0x75b238fc → bytes32
DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
EMERGENCY_UPDATER_ROLE 0x721be422 → bytes32
KEEPER_ROLE 0x364bc15a → bytes32
MIN_CALLBACK_GAS_LIMIT 0xb3d03582 → uint32
MIN_FORCE_UPDATE_INTERVAL 0x54e4d19a → uint256
UPDATER_ROLE 0x47e63380 → bytes32
automationEnabled 0xd966a594 → bool
checkUpkeep 0x6e04ff0d → bool, bytes
decimals 0x313ce567 → uint8
deviationCheckEnabled 0xeb5f23a6 → bool
donId 0x8dbe7b9d → bytes32
getCurrentNAV 0x693de592 → uint256, uint256
getPercentageChange 0xdd3a9a10 → int256
getPreviousNAV 0x5953de96 → uint256, uint256
getRoleAdmin 0x248a9ca3 → bytes32
hasRole 0x91d14854 → bool
lastAutomatedUpdateTimestamp 0xcc6dfe79 → uint256
lastForceUpdateTimestamp 0xf063aa33 → uint256
latestRequestId 0x1aa46f59 → bytes32
latestTimestamp 0x8205bf6a → uint256
maxDeviationBps 0x3ee7a701 → uint256
navReceiver 0x2c2f03e0 → address
paused 0x5c975abb → bool
previousTimestamp 0x1d9ff6e4 → uint256
subscriptionId 0x09c1ba2e → uint64
supportsInterface 0x01ffc9a7 → bool
targetHour 0xa6614382 → uint256
targetMinute 0xf4758775 → uint256
timeWindow 0xd2f343c7 → uint256
Write Contract 16 functions
These functions modify contract state and require a wallet transaction to execute.
configure 0x14f69ebe
uint64 _subscriptionId
bytes32 _donId
string _source
bytes _encryptedSecretsReference
forceNAVUpdate 0x42456213
uint256 _navValue
string _reason
grantRole 0x2f2ff15d
bytes32 role
address account
handleOracleFulfillment 0x0ca76175
bytes32 requestId
bytes response
bytes err
pause 0x8456cb59
No parameters
performUpkeep 0x4585e33b
bytes
renounceRole 0x36568abe
bytes32 role
address callerConfirmation
requestNAV 0xdaf6bce4
No parameters
returns: bytes32
revokeRole 0xd547741f
bytes32 role
address account
setAutomationEnabled 0x79e66622
bool enabled
setAutomationTimeParameters 0x9bdcaf59
uint256 _targetHour
uint256 _targetMinute
uint256 _timeWindow
setCallbackGasLimit 0xa4eb718c
uint32 _callbackGasLimit
setDeviationCheckEnabled 0xf7ced0e7
bool _enabled
setMaxDeviation 0xdddbc049
uint256 _maxDeviationBps
setNAVReceiver 0x9c66e162
address _navReceiver
unpause 0x3f4ba83a
No parameters
Recent Transactions
No transactions found for this address