Address Contract Verified
Address
0xD1c436Eb62e1d23e66842701B09E3d65aA8522E8
Balance
0 ETH
Nonce
1
Code Size
23327 bytes
Creator
Create2 Deployer at tx 0x9fcb21f3...00be1e
Indexed Transactions
0
Contract Bytecode
23327 bytes
0x608060405234801561001057600080fd5b50600436106102325760003560e01c80636567b40611610130578063b1e6d2a1116100b8578063f0118e181161007c578063f0118e18146105f7578063f12b64a51461060a578063f434c9141461061d578063fb61b4e314610644578063ffa082441461065757600080fd5b8063b1e6d2a114610575578063c02c63ad14610588578063c1ec61ee1461059b578063c7fb92de146105bd578063d4a1b4b1146105d057600080fd5b80638a36dffd116100ff5780638a36dffd1461050957806399d25a341461051c578063a2d532e61461052f578063a312889b14610542578063b1a50e331461056257600080fd5b80636567b40614610489578063702a3977146104a95780637da0a877146104bc57806388bc2ef3146104e257600080fd5b8063303f5dfa116101be578063419296261161018257806341929626146103fd5780634da781a914610410578063572b6c051461042357806358178191146104635780635c7465e51461047657600080fd5b8063303f5dfa146103915780633141db70146103a457806339284f35146103b757806339975571146103ca578063405b84fa146103ea57600080fd5b80631f47ce69116102055780631f47ce69146102e657806325a61d5c1461030d578063293c49991461032e5780632fa90203146103555780632fdb77e91461036a57600080fd5b806301ffc9a714610237578063090db2f11461025f5780631d831d5c146102805780631eabcd34146102bf575b600080fd5b61024a6102453660046139ca565b61067e565b60405190151581526020015b60405180910390f35b61027261026d3660046139f4565b61073c565b604051908152602001610256565b6102a77f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf3681565b6040516001600160a01b039091168152602001610256565b6102a77f000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d781565b6102a77f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c81565b61032061031b366004613a0d565b610747565b604051610256929190613c19565b6102a77f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad81565b610368610363366004613c4e565b6107fc565b005b6102a77f000000000000000000000000a7e0cbcfb2c6df7db07cc4ca05df681f1307cedd81565b61036861039f366004613c9f565b610963565b6102726103b2366004613d6a565b610a07565b6102726103c5366004613de3565b610b56565b6102726103d83660046139f4565b60006020819052908152604090205481565b6103686103f8366004613e86565b610eb4565b61032061040b3660046139f4565b610f99565b61027261041e3660046139f4565b610fc4565b61024a610431366004613eb6565b7f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f8876001600160a01b0390811691161490565b6102a7610471366004613ed3565b611066565b610272610484366004613f54565b611265565b61049c61049736600461402c565b61140b565b6040516102569190614058565b6103686104b73660046140bb565b61157b565b7f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f8876102a7565b6102a77f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa4181565b610368610517366004614106565b611672565b61024a61052a3660046139f4565b611759565b61036861053d366004614158565b611777565b6105556105503660046139f4565b611854565b6040516102569190614200565b61024a6105703660046139f4565b6118ee565b610368610583366004614213565b611907565b6103206105963660046139f4565b6119b1565b6105ae6105a93660046139f4565b6119ca565b6040516102569392919061425b565b6102726105cb3660046142be565b611a7e565b6102a77f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c8982681565b610368610605366004614339565b611d94565b610368610618366004613e86565b611f25565b6102a77f000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb1481565b610368610652366004614365565b61209a565b6102a77f000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb881565b60006001600160e01b03198216635709f28160e01b14806106af57506001600160e01b03198216632fdb77e960e01b145b806106ca57506001600160e01b031982166334ce2c7b60e21b145b806106e557506001600160e01b03198216632877540760e01b145b8061070057506001600160e01b03198216635825057160e11b145b8061071b57506001600160e01b03198216633d0d324560e21b145b8061073657506001600160e01b031982166301ffc9a760e01b145b92915050565b6000610736826121b4565b61074f6138bd565b610757613909565b604051630969875760e21b815260048101859052602481018490527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906325a61d5c9060440161012060405180830381865afa1580156107c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e89190614635565b91506107f3826123e7565b90509250929050565b6040516331a9108f60e11b815260048101859052610891907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610865573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108899190614652565b856012612621565b600061089c85612739565b610100810151909150604c1c6001908116146108cb576040516383d788ab60e01b815260040160405180910390fd5b60405163c6081d7160e01b81526004810186905260248101859052604481018490526001600160a01b0383811660648301527f000000000000000000000000e712d14b04f1a1fe464be930e3ea72b9b0a141d7169063c6081d71906084015b600060405180830381600087803b15801561094457600080fd5b505af1158015610958573d6000803e3d6000fd5b505050505050505050565b61096f8484600b612621565b60405163181faefd60e11b81526001600160a01b038581166004830152602482018590526044820184905282811660648301527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063303f5dfa906084015b600060405180830381600087803b1580156109e957600080fd5b505af11580156109fd573d6000803e3d6000fd5b5050505050505050565b6000838103610a2957604051632b72d06560e01b815260040160405180910390fd5b6040516331a9108f60e11b815260048101879052610afa907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab69190614652565b8760026001600160a01b037f000000000000000000000000a7e0cbcfb2c6df7db07cc4ca05df681f1307cedd16610aeb6127cc565b6001600160a01b0316146127db565b610b058686866127eb565b90507f24d02d612b06648bfa2000859f3de7e6f336139eaf5877c24b0d21320625286281878585610b346127cc565b604051610b45959493929190614698565b60405180910390a195945050505050565b6000858103610b7857604051632b72d06560e01b815260040160405180910390fd5b6000610b826127cc565b6040516331a9108f60e11b8152600481018b9052909150610c52906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa158015610bee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c129190614652565b8a600260ff167f000000000000000000000000a7e0cbcfb2c6df7db07cc4ca05df681f1307cedd6001600160a01b0316856001600160a01b0316146127db565b6040516331a9108f60e11b8152600481018a9052610d1f907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015610cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cdf9190614652565b8a600e60ff167f000000000000000000000000a7e0cbcfb2c6df7db07cc4ca05df681f1307cedd6001600160a01b0316856001600160a01b0316146127db565b6040516319fade8560e11b8152600481018a90526000907f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906333f5bd0a90602401602060405180830381865afa158015610d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dab91906146d2565b1115610dca576040516319d957db60e01b815260040160405180910390fd5b6040516338a73f9960e11b8152600481018a90523060248201527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b03169063714e7f3290604401600060405180830381600087803b158015610e3257600080fd5b505af1158015610e46573d6000803e3d6000fd5b50505050610e55898787612b05565b610e608989896127eb565b91507f23164adda696b19106c2eef50ba44461997682bf5aeb9fdb383117fa9952cc75828a8686610e8f6127cc565b604051610ea0959493929190614698565b60405180910390a150979650505050505050565b336001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411614610f3357604051639653dbed60e01b81523360048201526001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411660248201526044015b60405180910390fd5b604080516001600160a01b038316815233602082015283917f01f954abace731a88ab86e71186040cc2be49fe517ea06bc0d24f25b82b83456910160405180910390a260008281526020819052604090205415610f9557610f93826121b4565b505b5050565b610fa16138bd565b610fa9613909565b610fb283612739565b9150610fbd826123e7565b9050915091565b6000818152602081905260408082205490516375b0d9cd60e01b8152600481018490527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf366001600160a01b0316906375b0d9cd90602401602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c91906146d2565b6107369190614701565b6040516331a9108f60e11b8152600481018790526000906110fe906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190614652565b886007612621565b60008261110c57600061115a565b6111146127cc565b8360405160200161114392919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b604051602081830303815290604052805190602001205b90506111646127cc565b6001600160a01b0316887fa05dbc6b81da28529b01c0a1d1166c44ccd67676f06d2441002870ec5bc4a15885846111996127cc565b6040805193845260208401929092526001600160a01b03169082015260600160405180910390a3604051635817819160e01b81526001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf361690635817819190611216908b908b908b908b908b908990600401614714565b6020604051808303816000875af1158015611235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112599190614652565b98975050505050505050565b60405163180e2b1160e31b81526001600160a01b038a811660048301526000917f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad9091169063c0715888906024016020604051808303816000875af11580156112d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f691906146d2565b90508715611319576000818152600160205260409020611317898b836147df565b505b6040516338a73f9960e11b8152600481018290523060248201527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b03169063714e7f3290604401600060405180830381600087803b15801561138157600080fd5b505af1158015611395573d6000803e3d6000fd5b505050506113a4818686612b05565b60006113b18289896127eb565b90507f8dac501f24f52bda9ebdfa6a1789878c1d1e23823c771f7d52b5ba41261b0f4581838c8c88886113e26127cc565b6040516113f5979695949392919061489f565b60405180910390a1509998505050505050505050565b6040516301fd03bb60e71b81526004810184905260248101839052604481018290526060906000906001600160a01b037f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c89826169063fe81dd8090606401600060405180830381865afa158015611484573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114ac9190810190614912565b8051909150806001600160401b038111156114c9576114c96143e0565b60405190808252806020026020018201604052801561150257816020015b6114ef6139a5565b8152602001906001900390816114e75790505b50925060005b81811015611571576000838281518110611524576115246149b7565b602002602001015190506040518060400160405280828152602001611548836123e7565b81525085838151811061155d5761155d6149b7565b602090810291909101015250600101611508565b5050509392505050565b6040516331a9108f60e11b815260048101849052611610907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa1580156115e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116089190614652565b846006612621565b60008381526001602052604090206116298284836147df565b50827f0f3d240fe5efaeda774d27bf0425f932ddd2098297b26de8070d6c8bef534b1683836116566127cc565b604051611665939291906149cd565b60405180910390a2505050565b6040516331a9108f60e11b815260048101859052611707907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa1580156116db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ff9190614652565b856011612621565b604051638a36dffd60e01b81526001600160a01b037f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c1690638a36dffd906109cf908790879087908790600401614a24565b600061176c61176783612739565b6123e7565b610120015192915050565b6117948585600a61178f8261178a6127cc565b612c7c565b6127db565b826000036117b5576040516346545c9960e11b815260040160405180910390fd5b83856001600160a01b03167fdf04e13ee4fcd48a81ab2fd114757093740a3efa9b6475d86e05878b4c59d0798585856117ec6127cc565b6040516117fc9493929190614ba8565b60405180910390a360405163124d91e560e01b81526001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063124d91e59061092a90889088908890600401614bdb565b6001602052600090815260409020805461186d90614755565b80601f016020809104026020016040519081016040528092919081815260200182805461189990614755565b80156118e65780601f106118bb576101008083540402835291602001916118e6565b820191906000526020600020905b8154815290600101906020018083116118c957829003601f168201915b505050505081565b60006118fc61176783612739565b610100015192915050565b6119138484600c612621565b600061191e84612739565b61010081015190915060451c60019081160361194d57604051636af4c57760e01b815260040160405180910390fd5b60405163b1e6d2a160e01b81526001600160a01b038681166004830152602482018690528481166044830152606482018490527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063b1e6d2a19060840161092a565b6119b96138bd565b6119c1613909565b610fb283612d19565b6119d26138bd565b6119da613909565b60405163855a54ed60e01b8152600481018490526000907f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b03169063855a54ed9060240161014060405180830381865afa158015611a43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a679190614bfc565b9093509050611a75836123e7565b91509193909250565b600085600003611aa15760405163064fae8d60e41b815260040160405180910390fd5b600080611aad89612739565b6040516331a9108f60e11b8152600481018b9052909150611b8f906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa158015611b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3d9190614652565b8a6009611b4c8261178a6127cc565b80611b77575061010085015160521c6001600160a01b0316611b6c6127cc565b6001600160a01b0316145b8061178f575061178f8d86611b8a6127cc565b612d6e565b602081015165ffffffffffff1615801590611bb6575061010081015160461c600190811614155b8015611bcb5750611bc98961178a6127cc565b155b8015611bf8575061010081015160521c6001600160a01b0316611bec6127cc565b6001600160a01b031614155b8015611c0e5750611c0c8982611b8a6127cc565b155b15611c2c57604051632475c19d60e21b815260040160405180910390fd5b83611c38576000611c42565b61010081015160041c5b61ffff1691506127108214611d0157611c6988611c6184612710614c2f565b612710612e85565b60405163aab68bdb60e01b81529093506001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063aab68bdb90611cbc908a908d908890600401614bdb565b6020604051808303816000875af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff9190614652565b505b88876001600160a01b03167fe6fee9c572244c0c2238c3112ac12d411750a7ee00eeebd32521c3e5a666c14b8a868a8a88611d3a6127cc565b604051611d4c96959493929190614c42565b60405180910390a38115611d8857611d648389614c2f565b60008a81526020819052604081208054909190611d82908490614701565b90915550505b50509695505050505050565b6000611d9e6127cc565b90507f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b0316816001600160a01b031614611e2557604051639653dbed60e01b81526001600160a01b0380831660048301527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41166024820152604401610f2a565b6040516301ffc9a760e01b81526334ce2c7b60e21b60048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa158015611e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e949190614c85565b15610f935760405163a312889b60e01b8152600481018390526001600160a01b0384169063a312889b90602401600060405180830381865afa158015611ede573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f069190810190614ca2565b600083815260016020526040902090611f1f9082614d35565b50505050565b6040516331a9108f60e11b815260048101839052611fba907f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad6001600160a01b031690636352211e90602401602060405180830381865afa158015611f8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb29190614652565b836008612621565b6000611fc583612739565b9050806020015165ffffffffffff16600003611fe757611fe483612d19565b90505b61010081015160471c60019081161461201357604051631b6846ab60e01b815260040160405180910390fd5b60405163f12b64a560e01b8152600481018490526001600160a01b0383811660248301527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063f12b64a590604401600060405180830381600087803b15801561207d57600080fd5b505af1158015612091573d6000803e3d6000fd5b50505050505050565b3330146120a657600080fd5b6120ba6001600160a01b0386168886612f59565b60405163fef4325760e01b81526001600160a01b0388169063fef43257906120f39089908990899089906000908a908a90600401614df4565b6020604051808303816000875af1158015612112573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213691906146d2565b50604051636eb1769f60e11b81523060048201526001600160a01b03888116602483015286169063dd62ed3e90604401602060405180830381865afa158015612183573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a791906146d2565b1561209157612091614e4f565b600081815260208190526040812054908190036121e4576040516364d7bdaf60e01b815260040160405180910390fd5b60006121ef83612739565b6040516331a9108f60e11b8152600481018590529091506000906001600160a01b037f0000000000000000000000000b538a02610d7d3cc91ce2870f423e0a34d646ad1690636352211e90602401602060405180830381865afa15801561225a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227e9190614652565b6000858152602081905260408082208290555163aab68bdb60e01b8152919250906001600160a01b037f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063aab68bdb906122e290309089908990600401614bdb565b6020604051808303816000875af1158015612301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123259190614652565b90506000841561234e5761234986856020015165ffffffffffff1660018886613017565b612351565b60005b905080156123655761236586828585613523565b85846000015165ffffffffffff16856020015165ffffffffffff167f32411cac611c47cfe73afc187645c9cf3aec828d5f91780138d8421378fc0edb8689866123ac6127cc565b604080516001600160a01b0395861681526020810194909452830191909152909116606082015260800160405180910390a450505050919050565b6123ef613909565b60405180610260016040528061240a84610100015160041c90565b61ffff16815260200161242284610100015160141c90565b61ffff16815260200161243a84610100015160241c90565b63ffffffff16815260200161245c846101000151600160449190911c81161490565b1515815260200161247a846101000151600160459190911c81161490565b15158152602001612498846101000151600160469190911c81161490565b151581526020016124b6846101000151600160479190911c81161490565b151581526020016124d4846101000151600160489190911c81161490565b151581526020016124f2846101000151600160499190911c81161490565b151581526020016125108461010001516001604a9190911c81161490565b1515815260200161252e8461010001516001604b9190911c81161490565b1515815260200161254c8461010001516001604c9190911c81161490565b1515815260200161256a8461010001516001604d9190911c81161490565b151581526020016125888461010001516001604e9190911c81161490565b151581526020016125a68461010001516001604f9190911c81161490565b151581526020016125c4846101000151600160509190911c81161490565b151581526020016125e2846101000151600160519190911c81161490565b151581526020016125f884610100015160521c90565b6001600160a01b0316815260200161261584610100015160f21c90565b61ffff16905292915050565b600061262b6127cc565b9050836001600160a01b0316816001600160a01b0316141580156126fa5750604051631a45b42760e11b81526001600160a01b0382811660048301528581166024830152604482018590526064820184905260016084830181905260a48301527f000000000000000000000000f5ca295dc286a176e35ebb7833031fd95550eb14169063348b684e9060c401602060405180830381865afa1580156126d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f89190614c85565b155b15611f1f57604051631326f75560e11b81526001600160a01b038086166004830152821660248201526044810184905260648101839052608401610f2a565b6127416138bd565b6040516321d1336160e11b8152600481018390527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b0316906343a266c2906024015b61012060405180830381865afa1580156127a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107369190614635565b60006127d66135ad565b905090565b80611f1f57611f1f848484612621565b6000805b82811015612afd57600084848381811061280b5761280b6149b7565b905060200281019061281d9190614e65565b61282690615352565b905061271061ffff168160a001516000015161ffff1611156128705760a08101515160405163a162453f60e01b815261ffff90911660048201526127106024820152604401610f2a565b61271061ffff168160a001516020015161ffff1611156128bb5760a0810151602001516040516318e037d360e11b815261ffff90911660048201526127106024820152604401610f2a565b60007f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b03166370174dcc88846020015185604001518660600151876080015161290e8960a00151613622565b895160405160e089901b6001600160e01b0319168152600481019790975263ffffffff95861660248801526001600160701b0390941660448701529390911660648501526001600160a01b0316608484015260a483019190915265ffffffffffff1660c482015260e401610120604051808303816000875af1158015612998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129bc9190614635565b602081015160c0840151604051638a36dffd60e01b81529293506001600160a01b037f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c1692638a36dffd92612a15928c92600401615487565b600060405180830381600087803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050602082015160e08401516040516323c620f360e21b81526001600160a01b037f000000000000000000000000f1e1df5bba779e977a27ccc273847ab1346fceb8169350638f1883cc92612a9d928c926004016155a0565b600060405180830381600087803b158015612ab757600080fd5b505af1158015612acb573d6000803e3d6000fd5b50612add925060019150879050614c2f565b8303612af357806020015165ffffffffffff1693505b50506001016127ef565b509392505050565b6000816001600160401b03811115612b1f57612b1f6143e0565b604051908082528060200260200182016040528015612b48578160200160208202803683370190505b50905060005b82811015612c27576000848483818110612b6a57612b6a6149b7565b9050602002810190612b7c919061564e565b612b8590615664565b805160208201516040516304a6e43960e31b81529293506001600160a01b039091169163253721c891612bbd918a9190600401615761565b600060405180830381600087803b158015612bd757600080fd5b505af1158015612beb573d6000803e3d6000fd5b505050508060000151838381518110612c0657612c066149b7565b6001600160a01b039092166020928302919091019091015250600101612b4e565b508115611f1f5760405163104373fb60e31b81526001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41169063821b9fd8906109cf90879085906004016157d9565b604051636e49181f60e01b8152600481018390526001600160a01b0382811660248301526000917f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa4190911690636e49181f90604401602060405180830381865afa158015612cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d129190614c85565b9392505050565b612d216138bd565b604051631735e2c560e11b8152600481018390527f000000000000000000000000da86eedb67c6c9fb3e58fe83efa28674d7c898266001600160a01b031690632e6bc58a9060240161278a565b600080612d8084610100015160521c90565b90506001600160a01b03811615801590612e0457506040516301ffc9a760e01b815263eeb73e8960e01b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e049190614c85565b8015612e7c57506040516399f6d77f60e01b81526001600160a01b038216906399f6d77f90612e3b90889088908890600401615832565b602060405180830381865afa158015612e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e7c9190614c85565b95945050505050565b6000808060001985870985870292508281108382030391505080600003612ebf57838281612eb557612eb5615861565b0492505050612d12565b838110612ef057604051630c740aef60e31b8152600481018790526024810186905260448101859052606401610f2a565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052612faa84826137cc565b611f1f576040516001600160a01b0384811660248301526000604483015261300d91869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505061381b565b611f1f848261381b565b6040516369e11cc560e01b815260048101869052602481018590526044810184905282906000907f0000000000000000000000009e834f2ae0970f8746e25fba6d42fd90bb96630c6001600160a01b0316906369e11cc590606401600060405180830381865afa15801561308f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526130b79190810190615877565b805190915060005b818110156135175760008382815181106130db576130db6149b7565b60200260200101519050600061310688836000015163ffffffff16633b9aca0063ffffffff16612e85565b905080156134c85760a08201516001600160a01b0316156131ce576131318b828460a001518a613523565b8160a001516001600160a01b031663c5a093886040518060c001604052808a6001600160a01b03168152602001848152602001601281526020018e81526020018c8152602001858152506040518263ffffffff1660e01b8152600401613197919061597c565b600060405180830381600087803b1580156131b157600080fd5b505af11580156131c5573d6000803e3d6000fd5b505050506134bb565b60408201516000906001600160a01b03166131f0576131eb6127cc565b6131f6565b82604001515b905082602001516001600160401b03166000146134135760006001600160a01b038916156132c2576020840151604051630862026560e41b81526001600160401b0390911660048201526001600160a01b038a811660248301527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411690638620265090604401602060405180830381865afa158015613299573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132bd9190614652565b6132c5565b60005b90506001600160a01b03891615806132e457506001600160a01b038116155b156132fa576132f58d84848c613523565b61340d565b60008d60405160200161330f91815260200190565b60408051601f1981840301815290829052602087015163fb61b4e360e01b8352909250309163fb61b4e391613351918691908f908a908a9089906004016159d0565b600060405180830381600087803b15801561336b57600080fd5b505af192505050801561337c575060015b61340b573d8080156133aa576040519150601f19603f3d011682016040523d82523d6000602084013e6133af565b606091505b508e7fdba24f3504238ca84f6411d16a14bb7ae54061b0a80892bf93eb5a8912ed73558787846133dd6127cc565b6040516133ed9493929190615a1a565b60405180910390a26134096001600160a01b038c16858761388c565b505b505b506134b9565b61deac196001600160a01b038216016134ad577f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf366001600160a01b031663124d91e5308e856040518463ffffffff1660e01b815260040161347693929190614bdb565b600060405180830381600087803b15801561349057600080fd5b505af11580156134a4573d6000803e3d6000fd5b505050506134b9565b6134b98c83838b613523565b505b6134c58187614c2f565b95505b888a8c7fbfcad5a78fa104a30927810dfb51a41d1119d43ce12be27620ab589e1273cebe85856134f66127cc565b60405161350593929190615a5c565b60405180910390a450506001016130bf565b50505095945050505050565b6001600160a01b0381161561354b576135466001600160a01b038216838561388c565b611f1f565b60405163b1e6d2a160e01b8152306004820152602481018590526001600160a01b038381166044830152606482018590527f000000000000000000000000a59e9f424901fb9dbd8913a9a32a081f9425bf36169063b1e6d2a1906084016109cf565b6000366014336001600160a01b037f0000000000000000000000008a5ba591ed2bed5691a378c65611ed492500f887161480156135ea5750808210155b1561361a576000366135fc8385614c2f565b613607928290615a8a565b61361091615ab4565b60601c9250505090565b339250505090565b6000600190506004826000015161ffff16901b811790506014826020015161ffff16901b811790506024826040015163ffffffff16901b811790508160600151156136735768100000000000000000175b8160800151156136895768200000000000000000175b8160a001511561369f5768400000000000000000175b8160c00151156136b55768800000000000000000175b8160e00151156136cc576901000000000000000000175b816101000151156136e4576902000000000000000000175b816101200151156136fc576904000000000000000000175b81610140015115613714576908000000000000000000175b8161016001511561372c576910000000000000000000175b81610180015115613744576920000000000000000000175b816101a001511561375c576940000000000000000000175b816101c0015115613774576980000000000000000000175b816101e001511561378657600160501b175b8161020001511561379857600160511b175b6102208201516102409092015160529290921b600160521b600160f21b03161760f29190911b6001600160f21b0319161790565b6000806000806020600086516020880160008a5af192503d91506000519050828015613811575081156138025780600114613811565b6000866001600160a01b03163b115b9695505050505050565b600080602060008451602086016000885af18061383e576040513d6000823e3d81fd5b50506000513d91508115613856578060011415613863565b6001600160a01b0384163b155b15611f1f57604051635274afe760e01b81526001600160a01b0385166004820152602401610f2a565b6040516001600160a01b03838116602483015260448201839052610f9391859182169063a9059cbb90606401612fdb565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b6040805161026081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101829052610220810182905261024081019190915290565b60405180604001604052806139b86138bd565b81526020016139c5613909565b905290565b6000602082840312156139dc57600080fd5b81356001600160e01b031981168114612d1257600080fd5b600060208284031215613a0657600080fd5b5035919050565b60008060408385031215613a2057600080fd5b50508035926020909101359150565b65ffffffffffff808251168352806020830151166020840152806040830151166040840152506060810151613a6e606084018265ffffffffffff169052565b506080810151613a86608084018263ffffffff169052565b5060a0810151613aa160a08401826001600160701b03169052565b5060c0810151613ab960c084018263ffffffff169052565b5060e0810151613ad460e08401826001600160a01b03169052565b5061010090810151910152565b805161ffff1682526020810151613afe602084018261ffff169052565b506040810151613b16604084018263ffffffff169052565b506060810151613b2a606084018215159052565b506080810151613b3e608084018215159052565b5060a0810151613b5260a084018215159052565b5060c0810151613b6660c084018215159052565b5060e0810151613b7a60e084018215159052565b5061010081810151151590830152610120808201511515908301526101408082015115159083015261016080820151151590830152610180808201511515908301526101a0808201511515908301526101c0808201511515908301526101e08082015115159083015261020080820151151590830152610220808201516001600160a01b0316908301526102408082015161ffff811682850152611f1f565b6103808101613c288285613a2f565b612d12610120830184613ae1565b6001600160a01b0381168114613c4b57600080fd5b50565b60008060008060808587031215613c6457600080fd5b8435935060208501359250604085013591506060850135613c8481613c36565b939692955090935050565b8035613c9a81613c36565b919050565b60008060008060808587031215613cb557600080fd5b8435613cc081613c36565b935060208501359250604085013591506060850135613c8481613c36565b60008083601f840112613cf057600080fd5b5081356001600160401b03811115613d0757600080fd5b6020830191508360208260051b8501011115613d2257600080fd5b9250929050565b60008083601f840112613d3b57600080fd5b5081356001600160401b03811115613d5257600080fd5b602083019150836020828501011115613d2257600080fd5b600080600080600060608688031215613d8257600080fd5b8535945060208601356001600160401b0380821115613da057600080fd5b613dac89838a01613cde565b90965094506040880135915080821115613dc557600080fd5b50613dd288828901613d29565b969995985093965092949392505050565b60008060008060008060006080888a031215613dfe57600080fd5b8735965060208801356001600160401b0380821115613e1c57600080fd5b613e288b838c01613cde565b909850965060408a0135915080821115613e4157600080fd5b613e4d8b838c01613cde565b909650945060608a0135915080821115613e6657600080fd5b50613e738a828b01613d29565b989b979a50959850939692959293505050565b60008060408385031215613e9957600080fd5b823591506020830135613eab81613c36565b809150509250929050565b600060208284031215613ec857600080fd5b8135612d1281613c36565b60008060008060008060808789031215613eec57600080fd5b8635955060208701356001600160401b0380821115613f0a57600080fd5b613f168a838b01613d29565b90975095506040890135915080821115613f2f57600080fd5b50613f3c89828a01613d29565b979a9699509497949695606090950135949350505050565b600080600080600080600080600060a08a8c031215613f7257600080fd5b8935613f7d81613c36565b985060208a01356001600160401b0380821115613f9957600080fd5b613fa58d838e01613d29565b909a50985060408c0135915080821115613fbe57600080fd5b613fca8d838e01613cde565b909850965060608c0135915080821115613fe357600080fd5b613fef8d838e01613cde565b909650945060808c013591508082111561400857600080fd5b506140158c828d01613d29565b915080935050809150509295985092959850929598565b60008060006060848603121561404157600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b818110156140af578351614089848251613a2f565b85015161409a610120850182613ae1565b50928401926103809290920191600101614074565b50909695505050505050565b6000806000604084860312156140d057600080fd5b8335925060208401356001600160401b038111156140ed57600080fd5b6140f986828701613d29565b9497909650939450505050565b6000806000806060858703121561411c57600080fd5b843593506020850135925060408501356001600160401b0381111561414057600080fd5b61414c87828801613cde565b95989497509550505050565b60008060008060006080868803121561417057600080fd5b853561417b81613c36565b9450602086013593506040860135925060608601356001600160401b038111156141a457600080fd5b613dd288828901613d29565b60005b838110156141cb5781810151838201526020016141b3565b50506000910152565b600081518084526141ec8160208601602086016141b0565b601f01601f19169290920160200192915050565b602081526000612d1260208301846141d4565b6000806000806080858703121561422957600080fd5b843561423481613c36565b935060208501359250604085013561424b81613c36565b9396929550929360600135925050565b6103a0810161426a8286613a2f565b614278610120830185613ae1565b6006831061429657634e487b7160e01b600052602160045260246000fd5b82610380830152949350505050565b8015158114613c4b57600080fd5b8035613c9a816142a5565b60008060008060008060a087890312156142d757600080fd5b863595506020870135945060408701356142f081613c36565b935060608701356001600160401b0381111561430b57600080fd5b61431789828a01613d29565b909450925050608087013561432b816142a5565b809150509295509295509295565b6000806040838503121561434c57600080fd5b823561435781613c36565b946020939093013593505050565b600080600080600080600060c0888a03121561438057600080fd5b873561438b81613c36565b96506020880135955060408801356143a281613c36565b94506060880135935060808801356143b981613c36565b925060a08801356001600160401b038111156143d457600080fd5b613e738a828b01613d29565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715614419576144196143e0565b60405290565b60405161026081016001600160401b0381118282101715614419576144196143e0565b604080519081016001600160401b0381118282101715614419576144196143e0565b60405160c081016001600160401b0381118282101715614419576144196143e0565b604051608081016001600160401b0381118282101715614419576144196143e0565b60405161010081016001600160401b0381118282101715614419576144196143e0565b604051606081016001600160401b0381118282101715614419576144196143e0565b604051601f8201601f191681016001600160401b0381118282101715614515576145156143e0565b604052919050565b65ffffffffffff81168114613c4b57600080fd5b8051613c9a8161451d565b63ffffffff81168114613c4b57600080fd5b8051613c9a8161453c565b6001600160701b0381168114613c4b57600080fd5b8051613c9a81614559565b8051613c9a81613c36565b6000610120828403121561459757600080fd5b61459f6143f6565b90506145aa82614531565b81526145b860208301614531565b60208201526145c960408301614531565b60408201526145da60608301614531565b60608201526145eb6080830161454e565b60808201526145fc60a0830161456e565b60a082015261460d60c0830161454e565b60c082015261461e60e08301614579565b60e082015261010080830151818301525092915050565b6000610120828403121561464857600080fd5b612d128383614584565b60006020828403121561466457600080fd5b8151612d1281613c36565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8581528460208201526080604082015260006146b860808301858761466f565b905060018060a01b03831660608301529695505050505050565b6000602082840312156146e457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610736576107366146eb565b86815260806020820152600061472e60808301878961466f565b828103604084015261474181868861466f565b915050826060830152979650505050505050565b600181811c9082168061476957607f821691505b60208210810361478957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610f93576000816000526020600020601f850160051c810160208610156147b85750805b601f850160051c820191505b818110156147d7578281556001016147c4565b505050505050565b6001600160401b038311156147f6576147f66143e0565b61480a836148048354614755565b8361478f565b6000601f84116001811461483e57600085156148265750838201355b600019600387901b1c1916600186901b178355614898565b600083815260209020601f19861690835b8281101561486f578685013582556020948501946001909201910161484f565b508682101561488c5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b87815286602082015260a0604082015260006148bf60a08301878961466f565b82810360608401526148d281868861466f565b91505060018060a01b038316608083015298975050505050505050565b60006001600160401b03821115614908576149086143e0565b5060051b60200190565b6000602080838503121561492557600080fd5b82516001600160401b0381111561493b57600080fd5b8301601f8101851361494c57600080fd5b805161495f61495a826148ef565b6144ed565b80828252602082019150610120602081850286010193508884111561498357600080fd5b6020850194505b838510156149ab5761499c8986614584565b8352938401939185019161498a565b50979650505050505050565b634e487b7160e01b600052603260045260246000fd5b6040815260006149e160408301858761466f565b905060018060a01b0383166020830152949350505050565b8035613c9a8161453c565b6001600160401b0381168114613c4b57600080fd5b8035613c9a8161451d565b6000606080830187845260208781860152604060606040870152828784526080935060808701905060808860051b8801018960005b8a811015614b9657898303607f190184528135368d9003603e19018112614a7f57600080fd5b8c01803584528386018782013536839003601e19018112614a9f57600080fd5b9091018781019190356001600160401b0380821115614abd57600080fd5b60c08083023603851315614ad057600080fd5b878b018a9052928290526000928c88015b83851015614b7f578535614af48161453c565b63ffffffff168152858c0135614b0981614a04565b8316818d0152858b0135614b1c81613c36565b6001600160a01b0316818c0152858e0135614b36816142a5565b1515818f0152614b47868e01614a19565b65ffffffffffff168d82015260a0614b60878201613c8f565b6001600160a01b03169082015294810194600194909401938101614ae1565b988b01989750505093880193505050600101614a59565b50909c9b505050505050505050505050565b848152606060208201526000614bc260608301858761466f565b905060018060a01b038316604083015295945050505050565b6001600160a01b039390931683526020830191909152604082015260600190565b6000806101408385031215614c1057600080fd5b614c1a8484614584565b915061012083015160068110613eab57600080fd5b81810381811115610736576107366146eb565b86815285602082015260a060408201526000614c6260a08301868861466f565b6060830194909452506001600160a01b0391909116608090910152949350505050565b600060208284031215614c9757600080fd5b8151612d12816142a5565b600060208284031215614cb457600080fd5b81516001600160401b0380821115614ccb57600080fd5b818401915084601f830112614cdf57600080fd5b815181811115614cf157614cf16143e0565b614d04601f8201601f19166020016144ed565b9150808252856020828501011115614d1b57600080fd5b614d2c8160208401602086016141b0565b50949350505050565b81516001600160401b03811115614d4e57614d4e6143e0565b614d6281614d5c8454614755565b8461478f565b602080601f831160018114614d975760008415614d7f5750858301515b600019600386901b1c1916600185901b1785556147d7565b600085815260208120601f198616915b82811015614dc657888601518255948401946001909101908401614da7565b5085821015614de45787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b878152600060018060a01b03808916602084015287604084015280871660608401525084608083015260e060a0830152600060e08301526101008060c0840152614e41818401858761466f565b9a9950505050505050505050565b634e487b7160e01b600052600160045260246000fd5b6000823561033e19833603018112614e7c57600080fd5b9190910192915050565b8035613c9a81614559565b803561ffff81168114613c9a57600080fd5b60006102608284031215614eb657600080fd5b614ebe61441f565b9050614ec982614e91565b8152614ed760208301614e91565b6020820152614ee8604083016149f9565b6040820152614ef9606083016142b3565b6060820152614f0a608083016142b3565b6080820152614f1b60a083016142b3565b60a0820152614f2c60c083016142b3565b60c0820152614f3d60e083016142b3565b60e0820152610100614f508184016142b3565b90820152610120614f628382016142b3565b90820152610140614f748382016142b3565b90820152610160614f868382016142b3565b90820152610180614f988382016142b3565b908201526101a0614faa8382016142b3565b908201526101c0614fbc8382016142b3565b908201526101e0614fce8382016142b3565b90820152610200614fe08382016142b3565b90820152610220614ff2838201613c8f565b90820152610240615004838201614e91565b9082015292915050565b600082601f83011261501f57600080fd5b8135602061502f61495a836148ef565b82815260059290921b8401810191818101908684111561504e57600080fd5b8286015b848110156151a25780356001600160401b038082111561507157600080fd5b908801906040828b03601f190181131561508a57600080fd5b615092614442565b87840135815281840135838111156150a957600080fd5b8085019450508b603f8501126150be57600080fd5b8784013592506150d061495a846148ef565b83815260c09093028401820192888101908d8511156150ee57600080fd5b948301945b8486101561518d5760c0868f03121561510b57600080fd5b615113614464565b863561511e8161453c565b8152868b013561512d81614a04565b818c01528685013561513e81613c36565b818601526060870135615150816142a5565b606082015260808701356151638161451d565b608082015260a087013561517681613c36565b60a0820152825260c09590950194908901906150f3565b828a0152508652505050918301918301615052565b509695505050505050565b600082601f8301126151be57600080fd5b813560206151ce61495a836148ef565b82815260069290921b840181019181810190868411156151ed57600080fd5b8286015b848110156151a2576040818903121561520a5760008081fd5b615212614442565b81356001600160e01b038116811461522a5760008081fd5b8152818501356152398161453c565b818601528352918301916040016151f1565b600082601f83011261525c57600080fd5b8135602061526c61495a836148ef565b82815260059290921b8401810191818101908684111561528b57600080fd5b8286015b848110156151a25780356001600160401b03808211156152af5760008081fd5b908801906080828b03601f19018113156152c95760008081fd5b6152d1614486565b878401356152de81613c36565b81526040848101356152ef81613c36565b828a0152606085810135858111156153075760008081fd5b6153158f8c838a01016151ad565b848401525092850135928484111561532f57600091508182fd5b61533d8e8b868901016151ad565b9083015250865250505091830191830161528f565b6000610340823603121561536557600080fd5b61536d6144a8565b61537683614a19565b8152615384602084016149f9565b602082015261539560408401614e86565b60408201526153a6606084016149f9565b60608201526153b760808401613c8f565b60808201526153c93660a08501614ea3565b60a08201526103008301356001600160401b03808211156153e957600080fd5b6153f53683870161500e565b60c084015261032085013591508082111561540f57600080fd5b5061541c3682860161524b565b60e08301525092915050565b805163ffffffff1682526020808201516001600160401b0316908301526040808201516001600160a01b039081169184019190915260608083015115159084015260808083015165ffffffffffff169084015260a09182015116910152565b60006060808301868452602065ffffffffffff87168186015260406060604087015282875180855260808801915060808160051b89010194508389016000805b83811015615538578a8803607f190185528251805189528701518789018790528051878a018190529088019083908b8b01905b808310156155235761550d828551615428565b60c0820191508a840193506001830192506154fa565b509950505093860193918601916001016154c7565b50959c9b505050505050505050505050565b60008151808452602080850194506020840160005b8381101561559557815180516001600160e01b0316885283015163ffffffff16838801526040909601959082019060010161555f565b509495945050505050565b60006060808301868452602065ffffffffffff8716818601526040606060408701528287518085526080945060808801915060808160051b890101848a0160005b83811015614b96578a8303607f19018552815180516001600160a01b039081168552888201511688850152868101518785018a90526156228a86018261554a565b918b0151858303868d015291905061563a818361554a565b9689019694505050908601906001016155e1565b60008235603e19833603018112614e7c57600080fd5b6000604080833603121561567757600080fd5b61567f614442565b833561568a81613c36565b81526020848101356001600160401b038111156156a657600080fd5b850136601f8201126156b757600080fd5b80356156c561495a826148ef565b818152606091820283018401918482019190368411156156e457600080fd5b938501935b8385101561574e578085360312156157015760008081fd5b6157096144cb565b853561571481613c36565b81528587013560ff8116811461572a5760008081fd5b818801528589013561573b8161453c565b818a0152835293840193918501916156e9565b5093850193909352509195945050505050565b60006040808301858452602060406020860152818651808452606093506060870191506020880160005b828110156157ca57815180516001600160a01b031685528581015160ff168686015287015163ffffffff1687850152928501929084019060010161578b565b50919998505050505050505050565b60006040820184835260206040602085015281855180845260608601915060208701935060005b818110156158255784516001600160a01b031683529383019391830191600101615800565b5090979650505050505050565b83815261016081016158476020830185613a2f565b6001600160a01b0392909216610140919091015292915050565b634e487b7160e01b600052601260045260246000fd5b6000602080838503121561588a57600080fd5b82516001600160401b038111156158a057600080fd5b8301601f810185136158b157600080fd5b80516158bf61495a826148ef565b81815260c091820283018401918482019190888411156158de57600080fd5b938501935b838510156149ab5780858a0312156158fb5760008081fd5b615903614464565b855161590e8161453c565b81528587015161591d81614a04565b8188015260408681015161593081613c36565b90820152606086810151615943816142a5565b908201526080868101516159568161451d565b9082015260a08681015161596981613c36565b90820152835293840193918501916158e3565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0828101516101608301916159c990840182615428565b5092915050565b6001600160a01b0387811682526001600160401b03871660208301528581166040830152606082018590528316608082015260c060a08201819052600090611259908301846141d4565b6000610120615a298388615428565b8560c08401528060e0840152615a41818401866141d4565b91505060018060a01b03831661010083015295945050505050565b6101008101615a6b8286615428565b60c08201939093526001600160a01b039190911660e090910152919050565b60008085851115615a9a57600080fd5b83861115615aa757600080fd5b5050820193919092039150565b6bffffffffffffffffffffffff198135818116916014851015615ae15780818660140360031b1b83161692505b50509291505056fea26469706673582212201450db7c9b990c7ad6904bfbb50bc205e6bb5da70424322ee77ad92c3c006e8164736f6c63430008170033
Verified Source Code Full Match
Compiler: v0.8.23+commit.f704f362
EVM: paris
Optimization: Yes (200 runs)
JBPermissionIds.sol 55 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Permission IDs for `JBPermissions`, used throughout the Bananapus ecosystem. See
/// [`JBPermissions`](https://github.com/Bananapus/nana-core/blob/main/src/JBPermissions.sol)
/// @dev `JBPermissions` allows one address to grant another address permission to call functions in Juicebox contracts
/// on their behalf. Each ID in `JBPermissionIds` grants access to a specific set of these functions.
library JBPermissionIds {
uint8 internal constant ROOT = 1; // All permissions across every contract. Very dangerous. BE CAREFUL!
/* Used by `nana-core`: https://github.com/Bananapus/nana-core */
uint8 internal constant QUEUE_RULESETS = 2; // Permission to call `JBController.queueRulesetsOf` and
// `JBController.launchRulesetsFor`.
uint8 internal constant CASH_OUT_TOKENS = 3; // Permission to call `JBMultiTerminal.cashOutTokensOf`.
uint8 internal constant SEND_PAYOUTS = 4; // Permission to call `JBMultiTerminal.sendPayoutsOf`.
uint8 internal constant MIGRATE_TERMINAL = 5; // Permission to call `JBMultiTerminal.migrateBalanceOf`.
uint8 internal constant SET_PROJECT_URI = 6; // Permission to call `JBController.setUriOf`.
uint8 internal constant DEPLOY_ERC20 = 7; // Permission to call `JBController.deployERC20For`.
uint8 internal constant SET_TOKEN = 8; // Permission to call `JBController.setTokenFor`.
uint8 internal constant MINT_TOKENS = 9; // Permission to call `JBController.mintTokensOf`.
uint8 internal constant BURN_TOKENS = 10; // Permission to call `JBController.burnTokensOf`.
uint8 internal constant CLAIM_TOKENS = 11; // Permission to call `JBController.claimTokensFor`.
uint8 internal constant TRANSFER_CREDITS = 12; // Permission to call `JBController.transferCreditsFrom`.
uint8 internal constant SET_CONTROLLER = 13; // Permission to call `JBDirectory.setControllerOf`.
uint8 internal constant SET_TERMINALS = 14; // Permission to call `JBDirectory.setTerminalsOf`.
// Be careful - `SET_TERMINALS` can be used to remove the primary terminal.
uint8 internal constant SET_PRIMARY_TERMINAL = 15; // Permission to call `JBDirectory.setPrimaryTerminalOf`.
uint8 internal constant USE_ALLOWANCE = 16; // Permission to call `JBMultiTerminal.useAllowanceOf`.
uint8 internal constant SET_SPLIT_GROUPS = 17; // Permission to call `JBController.setSplitGroupsOf`.
uint8 internal constant ADD_PRICE_FEED = 18; // Permission to call `JBPrices.addPriceFeedFor`.
uint8 internal constant ADD_ACCOUNTING_CONTEXTS = 19; // Permission to call
// `JBMultiTerminal.addAccountingContextsFor`.
/* Used by `nana-721-hook`: https://github.com/Bananapus/nana-721-hook */
uint8 internal constant ADJUST_721_TIERS = 20; // Permission to call `JB721TiersHook.adjustTiers`.
uint8 internal constant SET_721_METADATA = 21; // Permission to call `JB721TiersHook.setMetadata`.
uint8 internal constant MINT_721 = 22; // Permission to call `JB721TiersHook.mintFor`.
uint8 internal constant SET_721_DISCOUNT_PERCENT = 23; // Permission to call `JB721TiersHook.setDiscountPercentOf`.
/* Used by `nana-buyback-hook`: https://github.com/Bananapus/nana-buyback-hook */
uint8 internal constant SET_BUYBACK_TWAP = 24; // Permission to call `JBBuybackHook.setTwapWindowOf` and
// `JBBuybackHook.setTwapSlippageToleranceOf`.
uint8 internal constant SET_BUYBACK_POOL = 25; // Permission to call `JBBuybackHook.setPoolFor`.
/* Used by `nana-swap-terminal`: https://github.com/Bananapus/nana-swap-terminal */
uint8 internal constant ADD_SWAP_TERMINAL_POOL = 26; // Permission to call `JBSwapTerminal.addDefaultPool`.
uint8 internal constant ADD_SWAP_TERMINAL_TWAP_PARAMS = 27; // Permission to call
// `JBSwapTerminal.addTwapParamsFor`.
/* Used by `nana-suckers`: https://github.com/Bananapus/nana-suckers */
uint8 internal constant MAP_SUCKER_TOKEN = 28; // Permission to call `BPSucker.mapToken`.
uint8 internal constant DEPLOY_SUCKERS = 29; // Permission to call `BPSuckerRegistry.deploySuckersFor`.
uint8 internal constant SUCKER_SAFETY = 30; // Permission to call `BPSucker.enableEmergencyHatchFor` and
// `BPSucker.setDeprecation`.
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
ERC2771Context.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Context variant with ERC-2771 support.
*
* WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll
* be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC-2771
* specification adding the address size in bytes (20) to the calldata size. An example of an unexpected
* behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive`
* function only accessible if `msg.data.length == 0`.
*
* WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption.
* Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender}
* recovery.
*/
abstract contract ERC2771Context is Context {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable _trustedForwarder;
/**
* @dev Initializes the contract with a trusted forwarder, which will be able to
* invoke functions on this contract on behalf of other accounts.
*
* NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}.
*/
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address trustedForwarder_) {
_trustedForwarder = trustedForwarder_;
}
/**
* @dev Returns the address of the trusted forwarder.
*/
function trustedForwarder() public view virtual returns (address) {
return _trustedForwarder;
}
/**
* @dev Indicates whether any particular address is the trusted forwarder.
*/
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return forwarder == trustedForwarder();
}
/**
* @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever
* a call is not performed by the trusted forwarder or the calldata length is less than
* 20 bytes (an address length).
*/
function _msgSender() internal view virtual override returns (address) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
} else {
return super._msgSender();
}
}
/**
* @dev Override for `msg.data`. Defaults to the original `msg.data` whenever
* a call is not performed by the trusted forwarder or the calldata length is less than
* 20 bytes (an address length).
*/
function _msgData() internal view virtual override returns (bytes calldata) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return msg.data[:calldataLength - contextSuffixLength];
} else {
return super._msgData();
}
}
/**
* @dev ERC-2771 specifies the context as being a single address (20 bytes).
*/
function _contextSuffixLength() internal view virtual override returns (uint256) {
return 20;
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
SafeERC20.sol 198 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
IERC721.sol 135 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
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;
}
}
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);
}
Common.sol 675 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19;
// Common.sol
//
// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not
// always operate with SD59x18 and UD60x18 numbers.
/*//////////////////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);
/// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);
/// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();
/// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/
/// @dev The maximum value a uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;
/// @dev The maximum value a uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;
/// @dev The maximum value a uint64 number can have.
uint64 constant MAX_UINT64 = type(uint64).max;
/// @dev The unit number, which the decimal precision of the fixed-point types.
uint256 constant UNIT = 1e18;
/// @dev The unit number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;
/// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
/// bit in the binary representation of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;
/*//////////////////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function exp2(uint256 x) pure returns (uint256 result) {
unchecked {
// Start from 0.5 in the 192.64-bit fixed-point format.
result = 0x800000000000000000000000000000000000000000000000;
// The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
//
// 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
// 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
// a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
// we know that `x & 0xFF` is also 1.
if (x & 0xFF00000000000000 > 0) {
if (x & 0x8000000000000000 > 0) {
result = (result * 0x16A09E667F3BCC909) >> 64;
}
if (x & 0x4000000000000000 > 0) {
result = (result * 0x1306FE0A31B7152DF) >> 64;
}
if (x & 0x2000000000000000 > 0) {
result = (result * 0x1172B83C7D517ADCE) >> 64;
}
if (x & 0x1000000000000000 > 0) {
result = (result * 0x10B5586CF9890F62A) >> 64;
}
if (x & 0x800000000000000 > 0) {
result = (result * 0x1059B0D31585743AE) >> 64;
}
if (x & 0x400000000000000 > 0) {
result = (result * 0x102C9A3E778060EE7) >> 64;
}
if (x & 0x200000000000000 > 0) {
result = (result * 0x10163DA9FB33356D8) >> 64;
}
if (x & 0x100000000000000 > 0) {
result = (result * 0x100B1AFA5ABCBED61) >> 64;
}
}
if (x & 0xFF000000000000 > 0) {
if (x & 0x80000000000000 > 0) {
result = (result * 0x10058C86DA1C09EA2) >> 64;
}
if (x & 0x40000000000000 > 0) {
result = (result * 0x1002C605E2E8CEC50) >> 64;
}
if (x & 0x20000000000000 > 0) {
result = (result * 0x100162F3904051FA1) >> 64;
}
if (x & 0x10000000000000 > 0) {
result = (result * 0x1000B175EFFDC76BA) >> 64;
}
if (x & 0x8000000000000 > 0) {
result = (result * 0x100058BA01FB9F96D) >> 64;
}
if (x & 0x4000000000000 > 0) {
result = (result * 0x10002C5CC37DA9492) >> 64;
}
if (x & 0x2000000000000 > 0) {
result = (result * 0x1000162E525EE0547) >> 64;
}
if (x & 0x1000000000000 > 0) {
result = (result * 0x10000B17255775C04) >> 64;
}
}
if (x & 0xFF0000000000 > 0) {
if (x & 0x800000000000 > 0) {
result = (result * 0x1000058B91B5BC9AE) >> 64;
}
if (x & 0x400000000000 > 0) {
result = (result * 0x100002C5C89D5EC6D) >> 64;
}
if (x & 0x200000000000 > 0) {
result = (result * 0x10000162E43F4F831) >> 64;
}
if (x & 0x100000000000 > 0) {
result = (result * 0x100000B1721BCFC9A) >> 64;
}
if (x & 0x80000000000 > 0) {
result = (result * 0x10000058B90CF1E6E) >> 64;
}
if (x & 0x40000000000 > 0) {
result = (result * 0x1000002C5C863B73F) >> 64;
}
if (x & 0x20000000000 > 0) {
result = (result * 0x100000162E430E5A2) >> 64;
}
if (x & 0x10000000000 > 0) {
result = (result * 0x1000000B172183551) >> 64;
}
}
if (x & 0xFF00000000 > 0) {
if (x & 0x8000000000 > 0) {
result = (result * 0x100000058B90C0B49) >> 64;
}
if (x & 0x4000000000 > 0) {
result = (result * 0x10000002C5C8601CC) >> 64;
}
if (x & 0x2000000000 > 0) {
result = (result * 0x1000000162E42FFF0) >> 64;
}
if (x & 0x1000000000 > 0) {
result = (result * 0x10000000B17217FBB) >> 64;
}
if (x & 0x800000000 > 0) {
result = (result * 0x1000000058B90BFCE) >> 64;
}
if (x & 0x400000000 > 0) {
result = (result * 0x100000002C5C85FE3) >> 64;
}
if (x & 0x200000000 > 0) {
result = (result * 0x10000000162E42FF1) >> 64;
}
if (x & 0x100000000 > 0) {
result = (result * 0x100000000B17217F8) >> 64;
}
}
if (x & 0xFF000000 > 0) {
if (x & 0x80000000 > 0) {
result = (result * 0x10000000058B90BFC) >> 64;
}
if (x & 0x40000000 > 0) {
result = (result * 0x1000000002C5C85FE) >> 64;
}
if (x & 0x20000000 > 0) {
result = (result * 0x100000000162E42FF) >> 64;
}
if (x & 0x10000000 > 0) {
result = (result * 0x1000000000B17217F) >> 64;
}
if (x & 0x8000000 > 0) {
result = (result * 0x100000000058B90C0) >> 64;
}
if (x & 0x4000000 > 0) {
result = (result * 0x10000000002C5C860) >> 64;
}
if (x & 0x2000000 > 0) {
result = (result * 0x1000000000162E430) >> 64;
}
if (x & 0x1000000 > 0) {
result = (result * 0x10000000000B17218) >> 64;
}
}
if (x & 0xFF0000 > 0) {
if (x & 0x800000 > 0) {
result = (result * 0x1000000000058B90C) >> 64;
}
if (x & 0x400000 > 0) {
result = (result * 0x100000000002C5C86) >> 64;
}
if (x & 0x200000 > 0) {
result = (result * 0x10000000000162E43) >> 64;
}
if (x & 0x100000 > 0) {
result = (result * 0x100000000000B1721) >> 64;
}
if (x & 0x80000 > 0) {
result = (result * 0x10000000000058B91) >> 64;
}
if (x & 0x40000 > 0) {
result = (result * 0x1000000000002C5C8) >> 64;
}
if (x & 0x20000 > 0) {
result = (result * 0x100000000000162E4) >> 64;
}
if (x & 0x10000 > 0) {
result = (result * 0x1000000000000B172) >> 64;
}
}
if (x & 0xFF00 > 0) {
if (x & 0x8000 > 0) {
result = (result * 0x100000000000058B9) >> 64;
}
if (x & 0x4000 > 0) {
result = (result * 0x10000000000002C5D) >> 64;
}
if (x & 0x2000 > 0) {
result = (result * 0x1000000000000162E) >> 64;
}
if (x & 0x1000 > 0) {
result = (result * 0x10000000000000B17) >> 64;
}
if (x & 0x800 > 0) {
result = (result * 0x1000000000000058C) >> 64;
}
if (x & 0x400 > 0) {
result = (result * 0x100000000000002C6) >> 64;
}
if (x & 0x200 > 0) {
result = (result * 0x10000000000000163) >> 64;
}
if (x & 0x100 > 0) {
result = (result * 0x100000000000000B1) >> 64;
}
}
if (x & 0xFF > 0) {
if (x & 0x80 > 0) {
result = (result * 0x10000000000000059) >> 64;
}
if (x & 0x40 > 0) {
result = (result * 0x1000000000000002C) >> 64;
}
if (x & 0x20 > 0) {
result = (result * 0x10000000000000016) >> 64;
}
if (x & 0x10 > 0) {
result = (result * 0x1000000000000000B) >> 64;
}
if (x & 0x8 > 0) {
result = (result * 0x10000000000000006) >> 64;
}
if (x & 0x4 > 0) {
result = (result * 0x10000000000000003) >> 64;
}
if (x & 0x2 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
if (x & 0x1 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
}
// In the code snippet below, two operations are executed simultaneously:
//
// 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
// accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
// 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
//
// The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
// integer part, $2^n$.
result *= UNIT;
result >>= (191 - (x >> 64));
}
}
/// @notice Finds the zero-based index of the first 1 in the binary representation of x.
///
/// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
///
/// Each step in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
/// x >>= 128;
/// result += 128;
/// }
/// ```
///
/// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// The Yul instructions used below are:
///
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as a uint256.
/// @custom:smtchecker abstract-function-nondet
function msb(uint256 x) pure returns (uint256 result) {
// 2^128
assembly ("memory-safe") {
let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^64
assembly ("memory-safe") {
let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^32
assembly ("memory-safe") {
let factor := shl(5, gt(x, 0xFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^16
assembly ("memory-safe") {
let factor := shl(4, gt(x, 0xFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^8
assembly ("memory-safe") {
let factor := shl(3, gt(x, 0xFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^4
assembly ("memory-safe") {
let factor := shl(2, gt(x, 0xF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^2
assembly ("memory-safe") {
let factor := shl(1, gt(x, 0x3))
x := shr(factor, x)
result := or(result, factor)
}
// 2^1
// No need to shift x any more.
assembly ("memory-safe") {
let factor := gt(x, 0x1)
result := or(result, factor)
}
}
/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - The denominator must not be zero.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as a uint256.
/// @param y The multiplier as a uint256.
/// @param denominator The divisor as a uint256.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
unchecked {
return prod0 / denominator;
}
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (prod1 >= denominator) {
revert PRBMath_MulDiv_Overflow(x, y, denominator);
}
////////////////////////////////////////////////////////////////////////////
// 512 by 256 division
////////////////////////////////////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using the mulmod Yul instruction.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512-bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
unchecked {
// Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
// because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
// For more detail, see https://cs.stackexchange.com/q/138556/92363.
uint256 lpotdod = denominator & (~denominator + 1);
uint256 flippedLpotdod;
assembly ("memory-safe") {
// Factor powers of two out of denominator.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
// `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
// However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * flippedLpotdod;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
}
}
/// @notice Calculates x*y÷1e18 with 512-bit precision.
///
/// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
///
/// Notes:
/// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
/// - The result is rounded toward zero.
/// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
///
/// $$
/// \begin{cases}
/// x * y = MAX\_UINT256 * UNIT \\
/// (x * y) \% UNIT \geq \frac{UNIT}{2}
/// \end{cases}
/// $$
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - The result must fit in uint256.
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
/// @custom:smtchecker abstract-function-nondet
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
unchecked {
return prod0 / UNIT;
}
}
if (prod1 >= UNIT) {
revert PRBMath_MulDiv18_Overflow(x, y);
}
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(x, y, UNIT)
result :=
mul(
or(
div(sub(prod0, remainder), UNIT_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
),
UNIT_INVERSE
)
}
}
/// @notice Calculates x*y÷denominator with 512-bit precision.
///
/// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
///
/// Notes:
/// - The result is rounded toward zero.
///
/// Requirements:
/// - Refer to the requirements in {mulDiv}.
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit in int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
/// @custom:smtchecker abstract-function-nondet
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
revert PRBMath_MulDivSigned_InputTooSmall();
}
// Get hold of the absolute values of x, y and the denominator.
uint256 xAbs;
uint256 yAbs;
uint256 dAbs;
unchecked {
xAbs = x < 0 ? uint256(-x) : uint256(x);
yAbs = y < 0 ? uint256(-y) : uint256(y);
dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);
}
// Compute the absolute value of x*y÷denominator. The result must fit in int256.
uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
if (resultAbs > uint256(type(int256).max)) {
revert PRBMath_MulDivSigned_Overflow(x, y);
}
// Get the signs of x, y and the denominator.
uint256 sx;
uint256 sy;
uint256 sd;
assembly ("memory-safe") {
// "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
// XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
// If there are, the result should be negative. Otherwise, it should be positive.
unchecked {
result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
}
}
/// @notice Calculates the square root of x using the Babylonian method.
///
/// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Notes:
/// - If x is not a perfect square, the result is rounded down.
/// - Credits to OpenZeppelin for the explanations in comments below.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as a uint256.
/// @custom:smtchecker abstract-function-nondet
function sqrt(uint256 x) pure returns (uint256 result) {
if (x == 0) {
return 0;
}
// For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
//
// We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
//
// $$
// msb(x) <= x <= 2*msb(x)$
// $$
//
// We write $msb(x)$ as $2^k$, and we get:
//
// $$
// k = log_2(x)
// $$
//
// Thus, we can write the initial inequality as:
//
// $$
// 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
// sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
// 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
// $$
//
// Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 2 ** 128) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 2 ** 64) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 2 ** 32) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 2 ** 16) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 2 ** 8) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 2 ** 4) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 2 ** 2) {
result <<= 1;
}
// At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
// most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision
// doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of
// precision into the expected uint128 result.
unchecked {
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
// If x is not a perfect square, round the result toward zero.
uint256 roundedResult = x / result;
if (result >= roundedResult) {
result = roundedResult;
}
}
}
JBController4_1.sol 1193 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {JBPermissionIds} from "@bananapus/permission-ids/src/JBPermissionIds.sol";
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {mulDiv} from "@prb/math/src/Common.sol";
import {JBPermissioned} from "./abstract/JBPermissioned.sol";
import {JBApprovalStatus} from "./enums/JBApprovalStatus.sol";
import {IJBController} from "./interfaces/IJBController.sol";
import {IJBController4_1} from "./interfaces/IJBController4_1.sol";
import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
import {IJBDirectoryAccessControl} from "./interfaces/IJBDirectoryAccessControl.sol";
import {IJBFundAccessLimits} from "./interfaces/IJBFundAccessLimits.sol";
import {IJBMigratable} from "./interfaces/IJBMigratable.sol";
import {IJBPermissioned} from "./interfaces/IJBPermissioned.sol";
import {IJBPermissions} from "./interfaces/IJBPermissions.sol";
import {IJBPriceFeed} from "./interfaces/IJBPriceFeed.sol";
import {IJBPrices} from "./interfaces/IJBPrices.sol";
import {IJBProjects} from "./interfaces/IJBProjects.sol";
import {IJBProjectUriRegistry} from "./interfaces/IJBProjectUriRegistry.sol";
import {IJBRulesetDataHook4_1} from "./interfaces/IJBRulesetDataHook4_1.sol";
import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
import {IJBSplitHook} from "./interfaces/IJBSplitHook.sol";
import {IJBSplits} from "./interfaces/IJBSplits.sol";
import {IJBTerminal} from "./interfaces/IJBTerminal.sol";
import {IJBToken} from "./interfaces/IJBToken.sol";
import {IJBTokens} from "./interfaces/IJBTokens.sol";
import {JBConstants} from "./libraries/JBConstants.sol";
import {JBRulesetMetadataResolver} from "./libraries/JBRulesetMetadataResolver.sol";
import {JBSplitGroupIds} from "./libraries/JBSplitGroupIds.sol";
import {JBRuleset} from "./structs/JBRuleset.sol";
import {JBRulesetConfig} from "./structs/JBRulesetConfig.sol";
import {JBRulesetMetadata} from "./structs/JBRulesetMetadata.sol";
import {JBRulesetWithMetadata} from "./structs/JBRulesetWithMetadata.sol";
import {JBSplit} from "./structs/JBSplit.sol";
import {JBSplitGroup} from "./structs/JBSplitGroup.sol";
import {JBSplitHookContext} from "./structs/JBSplitHookContext.sol";
import {JBTerminalConfig} from "./structs/JBTerminalConfig.sol";
/// @notice `JBController` coordinates rulesets and project tokens, and is the entry point for most operations related
/// to rulesets and project tokens.
contract JBController4_1 is JBPermissioned, ERC2771Context, IJBController4_1, IJBMigratable {
// A library that parses packed ruleset metadata into a friendlier format.
using JBRulesetMetadataResolver for JBRuleset;
// A library that adds default safety checks to ERC20 functionality.
using SafeERC20 for IERC20;
//*********************************************************************//
// --------------------------- custom errors ------------------------- //
//*********************************************************************//
error JBController_AddingPriceFeedNotAllowed();
error JBController_CreditTransfersPaused();
error JBController_InvalidCashOutTaxRate(uint256 rate, uint256 limit);
error JBController_InvalidReservedPercent(uint256 percent, uint256 limit);
error JBController_MintNotAllowedAndNotTerminalOrHook();
error JBController_NoReservedTokens();
error JBController_OnlyDirectory(address sender, IJBDirectory directory);
error JBController_RulesetsAlreadyLaunched();
error JBController_RulesetsArrayEmpty();
error JBController_RulesetSetTokenNotAllowed();
error JBController_ZeroTokensToBurn();
error JBController_ZeroTokensToMint();
//*********************************************************************//
// --------------- public immutable stored properties ---------------- //
//*********************************************************************//
/// @notice The directory of terminals and controllers for projects.
IJBDirectory public immutable override DIRECTORY;
/// @notice A contract that stores fund access limits for each project.
IJBFundAccessLimits public immutable override FUND_ACCESS_LIMITS;
/// @notice A contract that stores prices for each project.
IJBPrices public immutable override PRICES;
/// @notice Mints ERC-721s that represent project ownership and transfers.
IJBProjects public immutable override PROJECTS;
/// @notice The contract storing and managing project rulesets.
IJBRulesets public immutable override RULESETS;
/// @notice The contract that stores splits for each project.
IJBSplits public immutable override SPLITS;
/// @notice The contract that manages token minting and burning.
IJBTokens public immutable override TOKENS;
/// @notice The address of the contract that manages omnichain ruleset ops.
address public immutable OMNICHAIN_RULESET_OPERATOR;
//*********************************************************************//
// --------------------- public stored properties -------------------- //
//*********************************************************************//
/// @notice A project's unrealized reserved token balance (i.e. reserved tokens which haven't been sent out to the
/// reserved token split group yet).
/// @custom:param projectId The ID of the project to get the pending reserved token balance of.
mapping(uint256 projectId => uint256) public override pendingReservedTokenBalanceOf;
/// @notice The metadata URI for each project. This is typically an IPFS hash, optionally with an `ipfs://` prefix.
/// @custom:param projectId The ID of the project to get the metadata URI of.
mapping(uint256 projectId => string) public override uriOf;
//*********************************************************************//
// ---------------------------- constructor -------------------------- //
//*********************************************************************//
/// @param directory A contract storing directories of terminals and controllers for each project.
/// @param fundAccessLimits A contract that stores fund access limits for each project.
/// @param permissions A contract storing permissions.
/// @param prices A contract that stores prices for each project.
/// @param projects A contract which mints ERC-721s that represent project ownership and transfers.
/// @param rulesets A contract storing and managing project rulesets.
/// @param splits A contract that stores splits for each project.
/// @param tokens A contract that manages token minting and burning.
/// @param omnichainRulesetOperator The address of the contract that manages omnichain ruleset ops.
/// @param trustedForwarder The trusted forwarder for the ERC2771Context.
constructor(
IJBDirectory directory,
IJBFundAccessLimits fundAccessLimits,
IJBPermissions permissions,
IJBPrices prices,
IJBProjects projects,
IJBRulesets rulesets,
IJBSplits splits,
IJBTokens tokens,
address omnichainRulesetOperator,
address trustedForwarder
)
JBPermissioned(permissions)
ERC2771Context(trustedForwarder)
{
DIRECTORY = directory;
FUND_ACCESS_LIMITS = fundAccessLimits;
PRICES = prices;
PROJECTS = projects;
RULESETS = rulesets;
SPLITS = splits;
TOKENS = tokens;
OMNICHAIN_RULESET_OPERATOR = omnichainRulesetOperator;
}
//*********************************************************************//
// ------------------------- external views -------------------------- //
//*********************************************************************//
/// @notice Get an array of a project's rulesets (with metadata) up to a maximum array size, sorted from latest to
/// earliest.
/// @param projectId The ID of the project to get the rulesets of.
/// @param startingId The ID of the ruleset to begin with. This will be the latest ruleset in the result. If the
/// `startingId` is 0, passed, the project's latest ruleset will be used.
/// @param size The maximum number of rulesets to return.
/// @return rulesets The array of rulesets with their metadata.
function allRulesetsOf(
uint256 projectId,
uint256 startingId,
uint256 size
)
external
view
override
returns (JBRulesetWithMetadata[] memory rulesets)
{
// Get the rulesets (without metadata).
JBRuleset[] memory baseRulesets = RULESETS.allOf(projectId, startingId, size);
// Keep a reference to the number of rulesets.
uint256 numberOfRulesets = baseRulesets.length;
// Initialize the array being returned.
rulesets = new JBRulesetWithMetadata[](numberOfRulesets);
// Populate the array with rulesets AND their metadata.
for (uint256 i; i < numberOfRulesets; i++) {
// Set the ruleset being iterated on.
JBRuleset memory baseRuleset = baseRulesets[i];
// Set the returned value.
rulesets[i] = JBRulesetWithMetadata({ruleset: baseRuleset, metadata: baseRuleset.expandMetadata()});
}
}
/// @notice A project's currently active ruleset and its metadata.
/// @param projectId The ID of the project to get the current ruleset of.
/// @return ruleset The current ruleset's struct.
/// @return metadata The current ruleset's metadata.
function currentRulesetOf(uint256 projectId)
external
view
override
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
{
ruleset = _currentRulesetOf(projectId);
metadata = ruleset.expandMetadata();
}
/// @notice Get the `JBRuleset` and `JBRulesetMetadata` corresponding to the specified `rulesetId`.
/// @param projectId The ID of the project the ruleset belongs to.
/// @return ruleset The ruleset's struct.
/// @return metadata The ruleset's metadata.
function getRulesetOf(
uint256 projectId,
uint256 rulesetId
)
external
view
override
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
{
ruleset = RULESETS.getRulesetOf(projectId, rulesetId);
metadata = ruleset.expandMetadata();
}
/// @notice Gets the latest ruleset queued for a project, its approval status, and its metadata.
/// @dev The 'latest queued ruleset' is the ruleset initialized furthest in the future (at the end of the ruleset
/// queue).
/// @param projectId The ID of the project to get the latest ruleset of.
/// @return ruleset The struct for the project's latest queued ruleset.
/// @return metadata The ruleset's metadata.
/// @return approvalStatus The ruleset's approval status.
function latestQueuedRulesetOf(uint256 projectId)
external
view
override
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata, JBApprovalStatus approvalStatus)
{
(ruleset, approvalStatus) = RULESETS.latestQueuedOf(projectId);
metadata = ruleset.expandMetadata();
}
/// @notice Check whether the project's terminals can currently be set.
/// @param projectId The ID of the project to check.
/// @return A `bool` which is true if the project allows terminals to be set.
function setTerminalsAllowed(uint256 projectId) external view returns (bool) {
return _currentRulesetOf(projectId).expandMetadata().allowSetTerminals;
}
/// @notice Check whether the project's controller can currently be set.
/// @param projectId The ID of the project to check.
/// @return A `bool` which is true if the project allows controllers to be set.
function setControllerAllowed(uint256 projectId) external view returns (bool) {
return _currentRulesetOf(projectId).expandMetadata().allowSetController;
}
/// @notice Gets the a project token's total supply, including pending reserved tokens.
/// @param projectId The ID of the project to get the total token supply of.
/// @return The total supply of the project's token, including pending reserved tokens.
function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view override returns (uint256) {
// Add the reserved tokens to the total supply.
return TOKENS.totalSupplyOf(projectId) + pendingReservedTokenBalanceOf[projectId];
}
/// @notice A project's next ruleset along with its metadata.
/// @dev If an upcoming ruleset isn't found, returns an empty ruleset with all properties set to 0.
/// @param projectId The ID of the project to get the next ruleset of.
/// @return ruleset The upcoming ruleset's struct.
/// @return metadata The upcoming ruleset's metadata.
function upcomingRulesetOf(uint256 projectId)
external
view
override
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata)
{
ruleset = _upcomingRulesetOf(projectId);
metadata = ruleset.expandMetadata();
}
//*********************************************************************//
// -------------------------- public views --------------------------- //
//*********************************************************************//
/// @notice Indicates whether this contract adheres to the specified interface.
/// @dev See {IERC165-supportsInterface}.
/// @param interfaceId The ID of the interface to check for adherence to.
/// @return A flag indicating if the provided interface ID is supported.
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == type(IJBController).interfaceId || interfaceId == type(IJBController4_1).interfaceId
|| interfaceId == type(IJBProjectUriRegistry).interfaceId
|| interfaceId == type(IJBDirectoryAccessControl).interfaceId || interfaceId == type(IJBMigratable).interfaceId
|| interfaceId == type(IJBPermissioned).interfaceId || interfaceId == type(IERC165).interfaceId;
}
//*********************************************************************//
// -------------------------- internal views ------------------------- //
//*********************************************************************//
/// @dev `ERC-2771` specifies the context as being a single address (20 bytes).
function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256) {
return super._contextSuffixLength();
}
/// @notice The project's current ruleset.
/// @param projectId The ID of the project to check.
/// @return The project's current ruleset.
function _currentRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
return RULESETS.currentOf(projectId);
}
/// @notice Indicates whether the provided address is a terminal for the project.
/// @param projectId The ID of the project to check.
/// @param terminal The address to check.
/// @return A flag indicating if the provided address is a terminal for the project.
function _isTerminalOf(uint256 projectId, address terminal) internal view returns (bool) {
return DIRECTORY.isTerminalOf(projectId, IJBTerminal(terminal));
}
/// @notice Indicates whether the provided address has mint permission for the project byway of the data hook.
/// @param projectId The ID of the project to check.
/// @param ruleset The ruleset to check.
/// @param addr The address to check.
/// @return A flag indicating if the provided address has mint permission for the project.
function _hasDataHookMintPermissionFor(
uint256 projectId,
JBRuleset memory ruleset,
address addr
)
internal
view
returns (bool)
{
address dataHook = ruleset.dataHook();
return dataHook != address(0) && IERC165(dataHook).supportsInterface(type(IJBRulesetDataHook4_1).interfaceId)
&& IJBRulesetDataHook4_1(dataHook).hasMintPermissionFor({projectId: projectId, ruleset: ruleset, addr: addr});
}
/// @notice The calldata. Preferred to use over `msg.data`.
/// @return calldata The `msg.data` of this call.
function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
return ERC2771Context._msgData();
}
/// @notice The message's sender. Preferred to use over `msg.sender`.
/// @return sender The address which sent this call.
function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
return ERC2771Context._msgSender();
}
/// @notice The project's upcoming ruleset.
/// @param projectId The ID of the project to check.
/// @return The project's upcoming ruleset.
function _upcomingRulesetOf(uint256 projectId) internal view returns (JBRuleset memory) {
return RULESETS.upcomingOf(projectId);
}
//*********************************************************************//
// --------------------- external transactions ----------------------- //
//*********************************************************************//
/// @notice Add a price feed for a project.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `ADD_PRICE_FEED`.
/// @param projectId The ID of the project to add the feed for.
/// @param pricingCurrency The currency the feed's output price is in terms of.
/// @param unitCurrency The currency being priced by the feed.
/// @param feed The address of the price feed to add.
function addPriceFeed(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency,
IJBPriceFeed feed
)
external
override
{
// Enforce permissions.
_requirePermissionFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.ADD_PRICE_FEED
});
JBRuleset memory ruleset = _currentRulesetOf(projectId);
// Make sure the project's ruleset allows adding price feeds.
if (!ruleset.allowAddPriceFeed()) revert JBController_AddingPriceFeedNotAllowed();
PRICES.addPriceFeedFor({
projectId: projectId,
pricingCurrency: pricingCurrency,
unitCurrency: unitCurrency,
feed: feed
});
}
/// @notice Burns a project's tokens or credits from the specific holder's balance.
/// @dev Can only be called by the holder, an address with the holder's permission to `BURN_TOKENS`, or a project's
/// terminal.
/// @param holder The address whose tokens are being burned.
/// @param projectId The ID of the project whose tokens are being burned.
/// @param tokenCount The number of tokens to burn.
/// @param memo A memo to pass along to the emitted event.
function burnTokensOf(
address holder,
uint256 projectId,
uint256 tokenCount,
string calldata memo
)
external
override
{
// Enforce permissions.
_requirePermissionAllowingOverrideFrom({
account: holder,
projectId: projectId,
permissionId: JBPermissionIds.BURN_TOKENS,
alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender())
});
// There must be tokens to burn.
if (tokenCount == 0) revert JBController_ZeroTokensToBurn();
emit BurnTokens({holder: holder, projectId: projectId, tokenCount: tokenCount, memo: memo, caller: _msgSender()});
// Burn the tokens.
TOKENS.burnFrom({holder: holder, projectId: projectId, count: tokenCount});
}
/// @notice Redeem credits to claim tokens into a `beneficiary`'s account.
/// @dev Can only be called by the credit holder or an address with the holder's permission to `CLAIM_TOKENS`.
/// @param holder The address to redeem credits from.
/// @param projectId The ID of the project whose tokens are being claimed.
/// @param tokenCount The number of tokens to claim.
/// @param beneficiary The account the claimed tokens will go to.
function claimTokensFor(
address holder,
uint256 projectId,
uint256 tokenCount,
address beneficiary
)
external
override
{
// Enforce permissions.
_requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.CLAIM_TOKENS});
TOKENS.claimTokensFor({holder: holder, projectId: projectId, count: tokenCount, beneficiary: beneficiary});
}
/// @notice Deploys an ERC-20 token for a project. It will be used when claiming tokens (with credits).
/// @dev Deploys the project's ERC-20 contract.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `DEPLOY_ERC20`.
/// @param projectId The ID of the project to deploy the ERC-20 for.
/// @param name The ERC-20's name.
/// @param symbol The ERC-20's symbol.
/// @param salt The salt used for ERC-1167 clone deployment. Pass a non-zero salt for deterministic deployment based
/// on `msg.sender` and the `TOKEN` implementation address.
/// @return token The address of the token that was deployed.
function deployERC20For(
uint256 projectId,
string calldata name,
string calldata symbol,
bytes32 salt
)
external
override
returns (IJBToken token)
{
// Enforce permissions.
_requirePermissionFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.DEPLOY_ERC20
});
// If a salt is provided, use it.
bytes32 saltHash = salt != bytes32(0) ? keccak256(abi.encodePacked(_msgSender(), salt)) : bytes32(0);
// Emit the event.
emit DeployERC20({
projectId: projectId,
deployer: _msgSender(),
salt: salt,
saltHash: saltHash,
caller: _msgSender()
});
// Deploy the ERC-20 token with the hashed salt.
return TOKENS.deployERC20For({projectId: projectId, name: name, symbol: symbol, salt: saltHash});
}
/// @notice When a project receives reserved tokens, if it has a terminal for the token, this is used to pay the
/// terminal.
/// @dev Can only be called by this controller.
/// @param terminal The terminal to pay.
/// @param projectId The ID of the project being paid.
/// @param token The token being paid with.
/// @param splitTokenCount The number of tokens being paid.
/// @param beneficiary The payment's beneficiary.
/// @param metadata The pay metadata sent to the terminal.
function executePayReservedTokenToTerminal(
IJBTerminal terminal,
uint256 projectId,
IJBToken token,
uint256 splitTokenCount,
address beneficiary,
bytes calldata metadata
)
external
{
// Can only be called by this contract.
require(msg.sender == address(this));
// Approve the tokens being paid.
IERC20(address(token)).forceApprove(address(terminal), splitTokenCount);
// slither-disable-next-line unused-return
terminal.pay({
projectId: projectId,
token: address(token),
amount: splitTokenCount,
beneficiary: beneficiary,
minReturnedTokens: 0,
memo: "",
metadata: metadata
});
// Make sure that the terminal received the tokens.
assert(IERC20(address(token)).allowance(address(this), address(terminal)) == 0);
}
/// @notice Creates a project.
/// @dev This will mint the project's ERC-721 to the `owner`'s address, queue the specified rulesets, and set up the
/// specified splits and terminals. Each operation within this transaction can be done in sequence separately.
/// @dev Anyone can deploy a project to any `owner`'s address.
/// @param owner The project's owner. The project ERC-721 will be minted to this address.
/// @param projectUri The project's metadata URI. This is typically an IPFS hash, optionally with the `ipfs://`
/// prefix. This can be updated by the project's owner.
/// @param rulesetConfigurations The rulesets to queue.
/// @param terminalConfigurations The terminals to set up for the project.
/// @param memo A memo to pass along to the emitted event.
/// @return projectId The project's ID.
function launchProjectFor(
address owner,
string calldata projectUri,
JBRulesetConfig[] calldata rulesetConfigurations,
JBTerminalConfig[] calldata terminalConfigurations,
string calldata memo
)
external
override
returns (uint256 projectId)
{
// Mint the project ERC-721 into the owner's wallet.
// slither-disable-next-line reentrancy-benign
projectId = PROJECTS.createFor(owner);
// If provided, set the project's metadata URI.
if (bytes(projectUri).length > 0) {
uriOf[projectId] = projectUri;
}
// Set this contract as the project's controller in the directory.
DIRECTORY.setControllerOf(projectId, IERC165(this));
// Configure the terminals.
_configureTerminals(projectId, terminalConfigurations);
// Queue the rulesets.
// slither-disable-next-line reentrancy-events
uint256 rulesetId = _queueRulesets(projectId, rulesetConfigurations);
emit LaunchProject({
rulesetId: rulesetId,
projectId: projectId,
projectUri: projectUri,
memo: memo,
caller: _msgSender()
});
}
/// @notice Queue a project's initial rulesets and set up terminals for it. Projects which already have rulesets
/// should use `queueRulesetsOf(...)`.
/// @dev Each operation within this transaction can be done in sequence separately.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
/// @param projectId The ID of the project to launch rulesets for.
/// @param rulesetConfigurations The rulesets to queue.
/// @param terminalConfigurations The terminals to set up.
/// @param memo A memo to pass along to the emitted event.
/// @return rulesetId The ID of the last successfully queued ruleset.
function launchRulesetsFor(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations,
JBTerminalConfig[] calldata terminalConfigurations,
string calldata memo
)
external
override
returns (uint256 rulesetId)
{
// Make sure there are rulesets being queued.
if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();
// Keep a reference to the sender.
address sender = _msgSender();
// Enforce permissions.
_requirePermissionAllowingOverrideFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.QUEUE_RULESETS,
alsoGrantAccessIf: sender == OMNICHAIN_RULESET_OPERATOR
});
// Enforce permissions.
_requirePermissionAllowingOverrideFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.SET_TERMINALS,
alsoGrantAccessIf: sender == OMNICHAIN_RULESET_OPERATOR
});
// If the project has already had rulesets, use `queueRulesetsOf(...)` instead.
if (RULESETS.latestRulesetIdOf(projectId) > 0) {
revert JBController_RulesetsAlreadyLaunched();
}
// Set this contract as the project's controller in the directory.
DIRECTORY.setControllerOf(projectId, IERC165(this));
// Configure the terminals.
_configureTerminals(projectId, terminalConfigurations);
// Queue the first ruleset.
// slither-disable-next-line reentrancy-events
rulesetId = _queueRulesets(projectId, rulesetConfigurations);
emit LaunchRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
}
/// @notice Migrate a project from this controller to another one.
/// @dev Can only be called by the directory.
/// @param projectId The ID of the project to migrate.
/// @param to The controller to migrate the project to.
function migrate(uint256 projectId, IERC165 to) external override {
// Make sure this is being called by the directory.
if (msg.sender != address(DIRECTORY)) revert JBController_OnlyDirectory(msg.sender, DIRECTORY);
emit Migrate({projectId: projectId, to: to, caller: msg.sender});
// Mint any pending reserved tokens before migrating.
if (pendingReservedTokenBalanceOf[projectId] != 0) {
_sendReservedTokensToSplitsOf(projectId);
}
}
/// @notice Add new project tokens or credits to the specified beneficiary's balance. Optionally, reserve a portion
/// according to the ruleset's reserved percent.
/// @dev Can only be called by the project's owner, an address with the owner's permission to `MINT_TOKENS`, one of
/// the project's terminals, or the project's data hook.
/// @dev If the ruleset's metadata has `allowOwnerMinting` set to `false`, this function can only be called by the
/// project's terminals or data hook.
/// @param projectId The ID of the project whose tokens are being minted.
/// @param tokenCount The number of tokens to mint, including any reserved tokens.
/// @param beneficiary The address which will receive the (non-reserved) tokens.
/// @param memo A memo to pass along to the emitted event.
/// @param useReservedPercent Whether to apply the ruleset's reserved percent.
/// @return beneficiaryTokenCount The number of tokens minted for the `beneficiary`.
function mintTokensOf(
uint256 projectId,
uint256 tokenCount,
address beneficiary,
string calldata memo,
bool useReservedPercent
)
external
override
returns (uint256 beneficiaryTokenCount)
{
// There should be tokens to mint.
if (tokenCount == 0) revert JBController_ZeroTokensToMint();
// Keep a reference to the reserved percent.
uint256 reservedPercent;
// Get a reference to the project's ruleset.
JBRuleset memory ruleset = _currentRulesetOf(projectId);
// Minting is restricted to: the project's owner, addresses with permission to `MINT_TOKENS`, the project's
// terminals, and the project's data hook.
_requirePermissionAllowingOverrideFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.MINT_TOKENS,
alsoGrantAccessIf: _isTerminalOf(projectId, _msgSender()) || _msgSender() == ruleset.dataHook()
|| _hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
});
// If the message sender is not the project's terminal or data hook, the ruleset must have `allowOwnerMinting`
// set to `true`.
if (
ruleset.id != 0 && !ruleset.allowOwnerMinting() && !_isTerminalOf(projectId, _msgSender())
&& _msgSender() != address(ruleset.dataHook())
&& !_hasDataHookMintPermissionFor(projectId, ruleset, _msgSender())
) revert JBController_MintNotAllowedAndNotTerminalOrHook();
// Determine the reserved percent to use.
reservedPercent = useReservedPercent ? ruleset.reservedPercent() : 0;
if (reservedPercent != JBConstants.MAX_RESERVED_PERCENT) {
// Calculate the number of (non-reserved) tokens that will be minted to the beneficiary.
beneficiaryTokenCount =
mulDiv(tokenCount, JBConstants.MAX_RESERVED_PERCENT - reservedPercent, JBConstants.MAX_RESERVED_PERCENT);
// Mint the tokens.
// slither-disable-next-line reentrancy-benign,reentrancy-events,unused-return
TOKENS.mintFor({holder: beneficiary, projectId: projectId, count: beneficiaryTokenCount});
}
emit MintTokens({
beneficiary: beneficiary,
projectId: projectId,
tokenCount: tokenCount,
beneficiaryTokenCount: beneficiaryTokenCount,
memo: memo,
reservedPercent: reservedPercent,
caller: _msgSender()
});
// Add any reserved tokens to the pending reserved token balance.
if (reservedPercent > 0) {
pendingReservedTokenBalanceOf[projectId] += tokenCount - beneficiaryTokenCount;
}
}
/// @notice Add one or more rulesets to the end of a project's ruleset queue. Rulesets take effect after the
/// previous ruleset in the queue ends, and only if they are approved by the previous ruleset's approval hook.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
/// @param projectId The ID of the project to queue rulesets for.
/// @param rulesetConfigurations The rulesets to queue.
/// @param memo A memo to pass along to the emitted event.
/// @return rulesetId The ID of the last ruleset which was successfully queued.
function queueRulesetsOf(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations,
string calldata memo
)
external
override
returns (uint256 rulesetId)
{
// Make sure there are rulesets being queued.
if (rulesetConfigurations.length == 0) revert JBController_RulesetsArrayEmpty();
// Enforce permissions.
_requirePermissionAllowingOverrideFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.QUEUE_RULESETS,
alsoGrantAccessIf: _msgSender() == OMNICHAIN_RULESET_OPERATOR
});
// Queue the rulesets.
// slither-disable-next-line reentrancy-events
rulesetId = _queueRulesets(projectId, rulesetConfigurations);
emit QueueRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
}
/// @notice Prepares this controller to receive a project being migrated from another controller.
/// @dev This controller should not be the project's controller yet.
/// @param from The controller being migrated from.
/// @param projectId The ID of the project that will migrate to this controller.
function beforeReceiveMigrationFrom(IERC165 from, uint256 projectId) external override {
// Keep a reference to the sender.
address sender = _msgSender();
// Make sure the sender is the expected source controller.
if (sender != address(DIRECTORY)) revert JBController_OnlyDirectory(sender, DIRECTORY);
// If the sending controller is an `IJBProjectUriRegistry`, copy the project's metadata URI.
if (from.supportsInterface(type(IJBProjectUriRegistry).interfaceId)) {
uriOf[projectId] = IJBProjectUriRegistry(address(from)).uriOf(projectId);
}
}
/// @notice Sends a project's pending reserved tokens to its reserved token splits.
/// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
/// the project's owner.
/// @param projectId The ID of the project to send reserved tokens for.
/// @return The amount of reserved tokens minted and sent.
function sendReservedTokensToSplitsOf(uint256 projectId) external override returns (uint256) {
return _sendReservedTokensToSplitsOf(projectId);
}
/// @notice Sets a project's split groups. The new split groups must include any current splits which are locked.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_SPLIT_GROUPS`.
/// @param projectId The ID of the project to set the split groups of.
/// @param rulesetId The ID of the ruleset the split groups should be active in. Use a `rulesetId` of 0 to set the
/// default split groups, which are used when a ruleset has no splits set. If there are no default splits and no
/// splits are set, all splits are sent to the project's owner.
/// @param splitGroups An array of split groups to set.
function setSplitGroupsOf(
uint256 projectId,
uint256 rulesetId,
JBSplitGroup[] calldata splitGroups
)
external
override
{
// Enforce permissions.
_requirePermissionFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.SET_SPLIT_GROUPS
});
// Set the split groups.
SPLITS.setSplitGroupsOf({projectId: projectId, rulesetId: rulesetId, splitGroups: splitGroups});
}
/// @notice Set a project's token. If the project's token is already set, this will revert.
/// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_TOKEN`.
/// @param projectId The ID of the project to set the token of.
/// @param token The new token's address.
function setTokenFor(uint256 projectId, IJBToken token) external override {
// Enforce permissions.
_requirePermissionFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.SET_TOKEN
});
// Get a reference to the current ruleset.
JBRuleset memory ruleset = _currentRulesetOf(projectId);
// If there's no current ruleset, get a reference to the upcoming one.
if (ruleset.id == 0) ruleset = _upcomingRulesetOf(projectId);
// If owner minting is disabled for the ruleset, the owner cannot change the token.
if (!ruleset.allowSetCustomToken()) revert JBController_RulesetSetTokenNotAllowed();
TOKENS.setTokenFor({projectId: projectId, token: token});
}
/// @notice Set a project's metadata URI.
/// @dev This is typically an IPFS hash, optionally with an `ipfs://` prefix.
/// @dev Can only be called by the project's owner or an address with the owner's permission to
/// `SET_PROJECT_URI`.
/// @param projectId The ID of the project to set the metadata URI of.
/// @param uri The metadata URI to set.
function setUriOf(uint256 projectId, string calldata uri) external override {
// Enforce permissions.
_requirePermissionFrom({
account: PROJECTS.ownerOf(projectId),
projectId: projectId,
permissionId: JBPermissionIds.SET_PROJECT_URI
});
// Set the project's metadata URI.
uriOf[projectId] = uri;
emit SetUri({projectId: projectId, uri: uri, caller: _msgSender()});
}
/// @notice Allows a credit holder to transfer credits to another address.
/// @dev Can only be called by the credit holder or an address with the holder's permission to `TRANSFER_CREDITS`.
/// @param holder The address to transfer credits from.
/// @param projectId The ID of the project whose credits are being transferred.
/// @param recipient The address to transfer credits to.
/// @param creditCount The number of credits to transfer.
function transferCreditsFrom(
address holder,
uint256 projectId,
address recipient,
uint256 creditCount
)
external
override
{
// Enforce permissions.
_requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.TRANSFER_CREDITS});
// Get a reference to the project's ruleset.
JBRuleset memory ruleset = _currentRulesetOf(projectId);
// Credit transfers must not be paused.
if (ruleset.pauseCreditTransfers()) revert JBController_CreditTransfersPaused();
TOKENS.transferCreditsFrom({holder: holder, projectId: projectId, recipient: recipient, count: creditCount});
}
//*********************************************************************//
// ------------------------ internal functions ----------------------- //
//*********************************************************************//
/// @notice Set up a project's terminals.
/// @param projectId The ID of the project to set up terminals for.
/// @param terminalConfigs The terminals to set up.
function _configureTerminals(uint256 projectId, JBTerminalConfig[] calldata terminalConfigs) internal {
// Initialize an array of terminals to populate.
IJBTerminal[] memory terminals = new IJBTerminal[](terminalConfigs.length);
for (uint256 i; i < terminalConfigs.length; i++) {
// Set the terminal configuration being iterated on.
JBTerminalConfig memory terminalConfig = terminalConfigs[i];
// Add the accounting contexts for the specified tokens.
terminalConfig.terminal.addAccountingContextsFor({
projectId: projectId,
accountingContexts: terminalConfig.accountingContextsToAccept
});
// Add the terminal.
terminals[i] = terminalConfig.terminal;
}
// Set the terminals in the directory.
if (terminalConfigs.length > 0) {
DIRECTORY.setTerminalsOf({projectId: projectId, terminals: terminals});
}
}
/// @notice Queues one or more rulesets and stores information pertinent to the configuration.
/// @param projectId The ID of the project to queue rulesets for.
/// @param rulesetConfigurations The rulesets being queued.
/// @return rulesetId The ID of the last ruleset that was successfully queued.
function _queueRulesets(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations
)
internal
returns (uint256 rulesetId)
{
for (uint256 i; i < rulesetConfigurations.length; i++) {
// Get a reference to the ruleset config being iterated on.
JBRulesetConfig memory rulesetConfig = rulesetConfigurations[i];
// Make sure its reserved percent is valid.
if (rulesetConfig.metadata.reservedPercent > JBConstants.MAX_RESERVED_PERCENT) {
revert JBController_InvalidReservedPercent(
rulesetConfig.metadata.reservedPercent, JBConstants.MAX_RESERVED_PERCENT
);
}
// Make sure its cash out tax rate is valid.
if (rulesetConfig.metadata.cashOutTaxRate > JBConstants.MAX_CASH_OUT_TAX_RATE) {
revert JBController_InvalidCashOutTaxRate(
rulesetConfig.metadata.cashOutTaxRate, JBConstants.MAX_CASH_OUT_TAX_RATE
);
}
// Queue its ruleset.
JBRuleset memory ruleset = RULESETS.queueFor({
projectId: projectId,
duration: rulesetConfig.duration,
weight: rulesetConfig.weight,
weightCutPercent: rulesetConfig.weightCutPercent,
approvalHook: rulesetConfig.approvalHook,
metadata: JBRulesetMetadataResolver.packRulesetMetadata(rulesetConfig.metadata),
mustStartAtOrAfter: rulesetConfig.mustStartAtOrAfter
});
// Set its split groups.
SPLITS.setSplitGroupsOf({
projectId: projectId,
rulesetId: ruleset.id,
splitGroups: rulesetConfig.splitGroups
});
// Set its fund access limits.
FUND_ACCESS_LIMITS.setFundAccessLimitsFor({
projectId: projectId,
rulesetId: ruleset.id,
fundAccessLimitGroups: rulesetConfig.fundAccessLimitGroups
});
// If this is the last configuration being queued, return the ruleset's ID.
if (i == rulesetConfigurations.length - 1) {
rulesetId = ruleset.id;
}
}
}
/// @notice Sends pending reserved tokens to the project's reserved token splits.
/// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
/// the project's owner.
/// @param projectId The ID of the project to send reserved tokens for.
/// @return tokenCount The amount of reserved tokens minted and sent.
function _sendReservedTokensToSplitsOf(uint256 projectId) internal returns (uint256 tokenCount) {
// Get a reference to the number of tokens that need to be minted.
tokenCount = pendingReservedTokenBalanceOf[projectId];
// Revert if there are no pending reserved tokens
if (tokenCount == 0) revert JBController_NoReservedTokens();
// Get the ruleset to read the reserved percent from.
JBRuleset memory ruleset = _currentRulesetOf(projectId);
// Get a reference to the project's owner.
address owner = PROJECTS.ownerOf(projectId);
// Reset the pending reserved token balance.
pendingReservedTokenBalanceOf[projectId] = 0;
// Mint the tokens to this contract.
IJBToken token = TOKENS.mintFor({holder: address(this), projectId: projectId, count: tokenCount});
// Send reserved tokens to splits and get a reference to the amount left after the splits have all been paid.
uint256 leftoverTokenCount = tokenCount == 0
? 0
: _sendReservedTokensToSplitGroupOf({
projectId: projectId,
rulesetId: ruleset.id,
groupId: JBSplitGroupIds.RESERVED_TOKENS,
tokenCount: tokenCount,
token: token
});
// Mint any leftover tokens to the project owner.
if (leftoverTokenCount > 0) {
_sendTokens({projectId: projectId, tokenCount: leftoverTokenCount, recipient: owner, token: token});
}
emit SendReservedTokensToSplits({
rulesetId: ruleset.id,
rulesetCycleNumber: ruleset.cycleNumber,
projectId: projectId,
owner: owner,
tokenCount: tokenCount,
leftoverAmount: leftoverTokenCount,
caller: _msgSender()
});
}
/// @notice Send project tokens to a split group.
/// @dev This is used to send reserved tokens to the reserved token split group.
/// @param projectId The ID of the project the splits belong to.
/// @param rulesetId The ID of the split group's ruleset.
/// @param groupId The ID of the split group.
/// @param tokenCount The number of tokens to send.
/// @param token The token to send.
/// @return leftoverTokenCount If the split percents don't add up to 100%, the leftover amount is returned.
function _sendReservedTokensToSplitGroupOf(
uint256 projectId,
uint256 rulesetId,
uint256 groupId,
uint256 tokenCount,
IJBToken token
)
internal
returns (uint256 leftoverTokenCount)
{
// Set the leftover amount to the initial amount.
leftoverTokenCount = tokenCount;
// Get a reference to the split group.
JBSplit[] memory splits = SPLITS.splitsOf({projectId: projectId, rulesetId: rulesetId, groupId: groupId});
// Keep a reference to the number of splits being iterated on.
uint256 numberOfSplits = splits.length;
// Send the tokens to the splits.
for (uint256 i; i < numberOfSplits; i++) {
// Get a reference to the split being iterated on.
JBSplit memory split = splits[i];
// Calculate the amount to send to the split.
uint256 splitTokenCount = mulDiv(tokenCount, split.percent, JBConstants.SPLITS_TOTAL_PERCENT);
// Mints tokens for the split if needed.
if (splitTokenCount > 0) {
// 1. If the split has a `hook`, call the hook's `processSplitWith` function.
// 2. Otherwise, if the split has a `projectId`, try to pay the project using the split's `beneficiary`,
// or the `_msgSender()` if the split has no beneficiary.
// 3. Otherwise, if the split has a beneficiary, send the tokens to the split's beneficiary.
// 4. Otherwise, send the tokens to the `_msgSender()`.
// If the split has a hook, call its `processSplitWith` function.
if (split.hook != IJBSplitHook(address(0))) {
// Send the tokens to the split hook.
// slither-disable-next-line reentrancy-events
_sendTokens({
projectId: projectId,
tokenCount: splitTokenCount,
recipient: address(split.hook),
token: token
});
// slither-disable-next-line reentrancy-events
...
// [truncated — 55338 bytes total]
JBPermissioned.sol 77 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IJBPermissioned} from "./../interfaces/IJBPermissioned.sol";
import {IJBPermissions} from "./../interfaces/IJBPermissions.sol";
/// @notice Modifiers to allow access to transactions based on which permissions the message's sender has.
abstract contract JBPermissioned is Context, IJBPermissioned {
//*********************************************************************//
// --------------------------- custom errors -------------------------- //
//*********************************************************************//
error JBPermissioned_Unauthorized(address account, address sender, uint256 projectId, uint256 permissionId);
//*********************************************************************//
// ---------------- public immutable stored properties --------------- //
//*********************************************************************//
/// @notice A contract storing permissions.
IJBPermissions public immutable override PERMISSIONS;
//*********************************************************************//
// -------------------------- constructor ---------------------------- //
//*********************************************************************//
/// @param permissions A contract storing permissions.
constructor(IJBPermissions permissions) {
PERMISSIONS = permissions;
}
//*********************************************************************//
// -------------------------- internal views ------------------------- //
//*********************************************************************//
/// @notice Require the message sender to be the account or have the relevant permission.
/// @param account The account to allow.
/// @param projectId The project ID to check the permission under.
/// @param permissionId The required permission ID. The operator must have this permission within the specified
/// project ID.
function _requirePermissionFrom(address account, uint256 projectId, uint256 permissionId) internal view {
address sender = _msgSender();
if (
sender != account
&& !PERMISSIONS.hasPermission({
operator: sender,
account: account,
projectId: projectId,
permissionId: permissionId,
includeRoot: true,
includeWildcardProjectId: true
})
) revert JBPermissioned_Unauthorized(account, sender, projectId, permissionId);
}
/// @notice If the 'alsoGrantAccessIf' condition is truthy, proceed. Otherwise, require the message sender to be the
/// account or
/// have the relevant permission.
/// @param account The account to allow.
/// @param projectId The project ID to check the permission under.
/// @param permissionId The required permission ID. The operator must have this permission within the specified
/// project ID.
/// @param alsoGrantAccessIf An override condition which will allow access regardless of permissions.
function _requirePermissionAllowingOverrideFrom(
address account,
uint256 projectId,
uint256 permissionId,
bool alsoGrantAccessIf
)
internal
view
{
if (alsoGrantAccessIf) return;
_requirePermissionFrom(account, projectId, permissionId);
}
}
JBApprovalStatus.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice A ruleset's approval status in a ruleset approval hook.
enum JBApprovalStatus {
Empty,
Upcoming,
Active,
ApprovalExpected,
Approved,
Failed
}
IJBCashOutHook.sol 16 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {JBAfterCashOutRecordedContext} from "./../structs/JBAfterCashOutRecordedContext.sol";
/// @notice Hook called after a terminal's `cashOutTokensOf(...)` logic completes (if passed by the ruleset's data
/// hook).
interface IJBCashOutHook is IERC165 {
/// @notice This function is called by the terminal's `cashOutTokensOf(...)` function after the cash out has been
/// recorded in the terminal store.
/// @dev Critical business logic should be protected by appropriate access control.
/// @param context The context passed in by the terminal, as a `JBAfterCashOutRecordedContext` struct.
function afterCashOutRecordedWith(JBAfterCashOutRecordedContext calldata context) external payable;
}
IJBController.sol 158 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IJBDirectory} from "./IJBDirectory.sol";
import {IJBDirectoryAccessControl} from "./IJBDirectoryAccessControl.sol";
import {IJBFundAccessLimits} from "./IJBFundAccessLimits.sol";
import {IJBPriceFeed} from "./IJBPriceFeed.sol";
import {IJBPrices} from "./IJBPrices.sol";
import {IJBProjects} from "./IJBProjects.sol";
import {IJBProjectUriRegistry} from "./IJBProjectUriRegistry.sol";
import {IJBRulesets} from "./IJBRulesets.sol";
import {IJBSplits} from "./IJBSplits.sol";
import {IJBTerminal} from "./IJBTerminal.sol";
import {IJBToken} from "./IJBToken.sol";
import {IJBTokens} from "./IJBTokens.sol";
import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBRulesetConfig} from "./../structs/JBRulesetConfig.sol";
import {JBRulesetMetadata} from "./../structs/JBRulesetMetadata.sol";
import {JBRulesetWithMetadata} from "./../structs/JBRulesetWithMetadata.sol";
import {JBSplit} from "./../structs/JBSplit.sol";
import {JBSplitGroup} from "./../structs/JBSplitGroup.sol";
import {JBTerminalConfig} from "./../structs/JBTerminalConfig.sol";
interface IJBController is IERC165, IJBProjectUriRegistry, IJBDirectoryAccessControl {
event BurnTokens(
address indexed holder, uint256 indexed projectId, uint256 tokenCount, string memo, address caller
);
event LaunchProject(uint256 rulesetId, uint256 projectId, string projectUri, string memo, address caller);
event LaunchRulesets(uint256 rulesetId, uint256 projectId, string memo, address caller);
event MintTokens(
address indexed beneficiary,
uint256 indexed projectId,
uint256 tokenCount,
uint256 beneficiaryTokenCount,
string memo,
uint256 reservedPercent,
address caller
);
event PrepMigration(uint256 indexed projectId, address from, address caller);
event QueueRulesets(uint256 rulesetId, uint256 projectId, string memo, address caller);
event ReservedDistributionReverted(
uint256 indexed projectId, JBSplit split, uint256 tokenCount, bytes reason, address caller
);
event SendReservedTokensToSplit(
uint256 indexed projectId,
uint256 indexed rulesetId,
uint256 indexed groupId,
JBSplit split,
uint256 tokenCount,
address caller
);
event SendReservedTokensToSplits(
uint256 indexed rulesetId,
uint256 indexed rulesetCycleNumber,
uint256 indexed projectId,
address owner,
uint256 tokenCount,
uint256 leftoverAmount,
address caller
);
event SetUri(uint256 indexed projectId, string uri, address caller);
function DIRECTORY() external view returns (IJBDirectory);
function FUND_ACCESS_LIMITS() external view returns (IJBFundAccessLimits);
function PRICES() external view returns (IJBPrices);
function PROJECTS() external view returns (IJBProjects);
function RULESETS() external view returns (IJBRulesets);
function SPLITS() external view returns (IJBSplits);
function TOKENS() external view returns (IJBTokens);
function allRulesetsOf(
uint256 projectId,
uint256 startingId,
uint256 size
)
external
view
returns (JBRulesetWithMetadata[] memory rulesets);
function currentRulesetOf(uint256 projectId)
external
view
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);
function getRulesetOf(
uint256 projectId,
uint256 rulesetId
)
external
view
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);
function latestQueuedRulesetOf(uint256 projectId)
external
view
returns (JBRuleset memory, JBRulesetMetadata memory metadata, JBApprovalStatus);
function pendingReservedTokenBalanceOf(uint256 projectId) external view returns (uint256);
function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view returns (uint256);
function upcomingRulesetOf(uint256 projectId)
external
view
returns (JBRuleset memory ruleset, JBRulesetMetadata memory metadata);
function addPriceFeed(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency,
IJBPriceFeed feed
)
external;
function burnTokensOf(address holder, uint256 projectId, uint256 tokenCount, string calldata memo) external;
function claimTokensFor(address holder, uint256 projectId, uint256 tokenCount, address beneficiary) external;
function deployERC20For(
uint256 projectId,
string calldata name,
string calldata symbol,
bytes32 salt
)
external
returns (IJBToken token);
function launchProjectFor(
address owner,
string calldata projectUri,
JBRulesetConfig[] calldata rulesetConfigurations,
JBTerminalConfig[] memory terminalConfigurations,
string calldata memo
)
external
returns (uint256 projectId);
function launchRulesetsFor(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations,
JBTerminalConfig[] memory terminalConfigurations,
string calldata memo
)
external
returns (uint256 rulesetId);
function mintTokensOf(
uint256 projectId,
uint256 tokenCount,
address beneficiary,
string calldata memo,
bool useReservedPercent
)
external
returns (uint256 beneficiaryTokenCount);
function queueRulesetsOf(
uint256 projectId,
JBRulesetConfig[] calldata rulesetConfigurations,
string calldata memo
)
external
returns (uint256 rulesetId);
function sendReservedTokensToSplitsOf(uint256 projectId) external returns (uint256);
function setSplitGroupsOf(uint256 projectId, uint256 rulesetId, JBSplitGroup[] calldata splitGroups) external;
function setTokenFor(uint256 projectId, IJBToken token) external;
function transferCreditsFrom(address holder, uint256 projectId, address recipient, uint256 creditCount) external;
}
IJBController4_1.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBController} from "./IJBController.sol";
interface IJBController4_1 is IJBController {
event DeployERC20(
uint256 indexed projectId, address indexed deployer, bytes32 salt, bytes32 saltHash, address caller
);
function OMNICHAIN_RULESET_OPERATOR() external view returns (address);
}
IJBDirectory.sol 30 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IJBProjects} from "./IJBProjects.sol";
import {IJBTerminal} from "./IJBTerminal.sol";
interface IJBDirectory {
event AddTerminal(uint256 indexed projectId, IJBTerminal indexed terminal, address caller);
event SetController(uint256 indexed projectId, IERC165 indexed controller, address caller);
event SetIsAllowedToSetFirstController(address indexed addr, bool indexed isAllowed, address caller);
event SetPrimaryTerminal(
uint256 indexed projectId, address indexed token, IJBTerminal indexed terminal, address caller
);
event SetTerminals(uint256 indexed projectId, IJBTerminal[] terminals, address caller);
function PROJECTS() external view returns (IJBProjects);
function controllerOf(uint256 projectId) external view returns (IERC165);
function isAllowedToSetFirstController(address account) external view returns (bool);
function isTerminalOf(uint256 projectId, IJBTerminal terminal) external view returns (bool);
function primaryTerminalOf(uint256 projectId, address token) external view returns (IJBTerminal);
function terminalsOf(uint256 projectId) external view returns (IJBTerminal[] memory);
function setControllerOf(uint256 projectId, IERC165 controller) external;
function setIsAllowedToSetFirstController(address account, bool flag) external;
function setPrimaryTerminalOf(uint256 projectId, address token, IJBTerminal terminal) external;
function setTerminalsOf(uint256 projectId, IJBTerminal[] calldata terminals) external;
}
IJBDirectoryAccessControl.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IJBDirectoryAccessControl {
function setControllerAllowed(uint256 projectId) external view returns (bool);
function setTerminalsAllowed(uint256 projectId) external view returns (bool);
}
IJBFundAccessLimits.sol 60 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBCurrencyAmount} from "./../structs/JBCurrencyAmount.sol";
import {JBFundAccessLimitGroup} from "./../structs/JBFundAccessLimitGroup.sol";
interface IJBFundAccessLimits {
event SetFundAccessLimits(
uint256 indexed rulesetId,
uint256 indexed projectId,
JBFundAccessLimitGroup fundAccessLimitGroup,
address caller
);
function payoutLimitOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token,
uint256 currency
)
external
view
returns (uint256 payoutLimit);
function payoutLimitsOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token
)
external
view
returns (JBCurrencyAmount[] memory payoutLimits);
function surplusAllowanceOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token,
uint256 currency
)
external
view
returns (uint256 surplusAllowance);
function surplusAllowancesOf(
uint256 projectId,
uint256 rulesetId,
address terminal,
address token
)
external
view
returns (JBCurrencyAmount[] memory surplusAllowances);
function setFundAccessLimitsFor(
uint256 projectId,
uint256 rulesetId,
JBFundAccessLimitGroup[] memory fundAccessLimitGroups
)
external;
}
IJBMigratable.sol 11 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IJBMigratable is IERC165 {
event Migrate(uint256 indexed projectId, IERC165 to, address caller);
function migrate(uint256 projectId, IERC165 to) external;
function beforeReceiveMigrationFrom(IERC165 from, uint256 projectId) external;
}
IJBPayHook.sol 15 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {JBAfterPayRecordedContext} from "./../structs/JBAfterPayRecordedContext.sol";
/// @notice Hook called after a terminal's `pay(...)` logic completes (if passed by the ruleset's data hook).
interface IJBPayHook is IERC165 {
/// @notice This function is called by the terminal's `pay(...)` function after the payment has been recorded in the
/// terminal store.
/// @dev Critical business logic should be protected by appropriate access control.
/// @param context The context passed in by the terminal, as a `JBAfterPayRecordedContext` struct.
function afterPayRecordedWith(JBAfterPayRecordedContext calldata context) external payable;
}
IJBPermissioned.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBPermissions} from "./IJBPermissions.sol";
interface IJBPermissioned {
function PERMISSIONS() external view returns (IJBPermissions);
}
IJBPermissions.sol 45 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBPermissionsData} from "./../structs/JBPermissionsData.sol";
interface IJBPermissions {
event OperatorPermissionsSet(
address indexed operator,
address indexed account,
uint256 indexed projectId,
uint8[] permissionIds,
uint256 packed,
address caller
);
function WILDCARD_PROJECT_ID() external view returns (uint256);
function permissionsOf(address operator, address account, uint256 projectId) external view returns (uint256);
function hasPermission(
address operator,
address account,
uint256 projectId,
uint256 permissionId,
bool includeRoot,
bool includeWildcardProjectId
)
external
view
returns (bool);
function hasPermissions(
address operator,
address account,
uint256 projectId,
uint256[] calldata permissionIds,
bool includeRoot,
bool includeWildcardProjectId
)
external
view
returns (bool);
function setPermissionsFor(address account, JBPermissionsData calldata permissionsData) external;
}
IJBPriceFeed.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IJBPriceFeed {
function currentUnitPrice(uint256 targetDecimals) external view returns (uint256);
}
IJBPrices.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBPriceFeed} from "./IJBPriceFeed.sol";
import {IJBProjects} from "./IJBProjects.sol";
interface IJBPrices {
event AddPriceFeed(
uint256 indexed projectId,
uint256 indexed pricingCurrency,
uint256 indexed unitCurrency,
IJBPriceFeed feed,
address caller
);
function DEFAULT_PROJECT_ID() external view returns (uint256);
function PROJECTS() external view returns (IJBProjects);
function priceFeedFor(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency
)
external
view
returns (IJBPriceFeed);
function pricePerUnitOf(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency,
uint256 decimals
)
external
view
returns (uint256);
function addPriceFeedFor(
uint256 projectId,
uint256 pricingCurrency,
uint256 unitCurrency,
IJBPriceFeed feed
)
external;
}
IJBProjectUriRegistry.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IJBProjectUriRegistry {
function uriOf(uint256 projectId) external view returns (string memory);
function setUriOf(uint256 projectId, string calldata uri) external;
}
IJBProjects.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IJBTokenUriResolver} from "./IJBTokenUriResolver.sol";
interface IJBProjects is IERC721 {
event Create(uint256 indexed projectId, address indexed owner, address caller);
event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);
function count() external view returns (uint256);
function tokenUriResolver() external view returns (IJBTokenUriResolver);
function createFor(address owner) external returns (uint256 projectId);
function setTokenUriResolver(IJBTokenUriResolver resolver) external;
}
IJBRulesetApprovalHook.sol 23 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";
/// @notice `IJBRulesetApprovalHook`s are used to determine whether the next ruleset in the ruleset queue is approved or
/// rejected.
/// @dev Project rulesets are stored in a queue. Rulesets take effect after the previous ruleset in the queue ends, and
/// only if they are approved by the previous ruleset's approval hook.
interface IJBRulesetApprovalHook is IERC165 {
function DURATION() external view returns (uint256);
function approvalStatusOf(
uint256 projectId,
uint256 rulesetId,
uint256 start
)
external
view
returns (JBApprovalStatus);
}
IJBRulesetDataHook4_1.sol 63 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBBeforePayRecordedContext} from "./../structs/JBBeforePayRecordedContext.sol";
import {JBBeforeCashOutRecordedContext} from "./../structs/JBBeforeCashOutRecordedContext.sol";
import {JBCashOutHookSpecification} from "./../structs/JBCashOutHookSpecification.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
/// @notice Data hooks can extend a terminal's core pay/cashout functionality by overriding the weight or memo. They can
/// also specify pay/cashout hooks for the terminal to fulfill, or allow addresses to mint a project's tokens on-demand.
/// @dev If a project's ruleset has `useDataHookForPay` or `useDataHookForCashOut` enabled, its `dataHook` is called by
/// the terminal upon payments/cashouts (respectively).
interface IJBRulesetDataHook4_1 is IERC165 {
/// @notice A flag indicating whether an address has permission to mint a project's tokens on-demand.
/// @dev A project's data hook can allow any address to mint its tokens.
/// @param projectId The ID of the project whose token can be minted.
/// @param ruleset The ruleset to check the token minting permission of.
/// @param addr The address to check the token minting permission of.
/// @return flag A flag indicating whether the address has permission to mint the project's tokens on-demand.
function hasMintPermissionFor(
uint256 projectId,
JBRuleset memory ruleset,
address addr
)
external
view
returns (bool flag);
/// @notice The data calculated before a payment is recorded in the terminal store. This data is provided to the
/// terminal's `pay(...)` transaction.
/// @param context The context passed to this data hook by the `pay(...)` function as a `JBBeforePayRecordedContext`
/// struct.
/// @return weight The new `weight` to use, overriding the ruleset's `weight`.
/// @return hookSpecifications The amount and data to send to pay hooks instead of adding to the terminal's balance.
function beforePayRecordedWith(JBBeforePayRecordedContext calldata context)
external
view
returns (uint256 weight, JBPayHookSpecification[] memory hookSpecifications);
/// @notice The data calculated before a cash out is recorded in the terminal store. This data is provided to the
/// terminal's `cashOutTokensOf(...)` transaction.
/// @param context The context passed to this data hook by the `cashOutTokensOf(...)` function as a
/// `JBBeforeCashOutRecordedContext` struct.
/// @return cashOutTaxRate The rate determining the amount that should be reclaimable for a given surplus and token
/// supply.
/// @return cashOutCount The amount of tokens that should be considered cashed out.
/// @return totalSupply The total amount of tokens that are considered to be existing.
/// @return hookSpecifications The amount and data to send to cash out hooks instead of returning to the
/// beneficiary.
function beforeCashOutRecordedWith(JBBeforeCashOutRecordedContext calldata context)
external
view
returns (
uint256 cashOutTaxRate,
uint256 cashOutCount,
uint256 totalSupply,
JBCashOutHookSpecification[] memory hookSpecifications
);
}
IJBRulesets.sol 85 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBApprovalStatus} from "./../enums/JBApprovalStatus.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {IJBRulesetApprovalHook} from "./IJBRulesetApprovalHook.sol";
interface IJBRulesets {
event RulesetInitialized(
uint256 indexed rulesetId, uint256 indexed projectId, uint256 indexed basedOnId, address caller
);
event RulesetQueued(
uint256 indexed rulesetId,
uint256 indexed projectId,
uint256 duration,
uint256 weight,
uint256 weightCutPercent,
IJBRulesetApprovalHook approvalHook,
uint256 metadata,
uint256 mustStartAtOrAfter,
address caller
);
event WeightCacheUpdated(uint256 projectId, uint112 weight, uint256 weightCutMultiple, address caller);
function latestRulesetIdOf(uint256 projectId) external view returns (uint256);
function currentApprovalStatusForLatestRulesetOf(uint256 projectId) external view returns (JBApprovalStatus);
function currentOf(uint256 projectId) external view returns (JBRuleset memory ruleset);
function deriveCycleNumberFrom(
uint256 baseRulesetCycleNumber,
uint256 baseRulesetStart,
uint256 baseRulesetDuration,
uint256 start
)
external
returns (uint256);
function deriveStartFrom(
uint256 baseRulesetStart,
uint256 baseRulesetDuration,
uint256 mustStartAtOrAfter
)
external
view
returns (uint256 start);
function deriveWeightFrom(
uint256 projectId,
uint256 baseRulesetStart,
uint256 baseRulesetDuration,
uint256 baseRulesetWeight,
uint256 baseRulesetWeightCutPercent,
uint256 baseRulesetCacheId,
uint256 start
)
external
view
returns (uint256 weight);
function getRulesetOf(uint256 projectId, uint256 rulesetId) external view returns (JBRuleset memory);
function latestQueuedOf(uint256 projectId)
external
view
returns (JBRuleset memory ruleset, JBApprovalStatus approvalStatus);
function allOf(
uint256 projectId,
uint256 startingId,
uint256 size
)
external
view
returns (JBRuleset[] memory rulesets);
function upcomingOf(uint256 projectId) external view returns (JBRuleset memory ruleset);
function queueFor(
uint256 projectId,
uint256 duration,
uint256 weight,
uint256 weightCutPercent,
IJBRulesetApprovalHook approvalHook,
uint256 metadata,
uint256 mustStartAtOrAfter
)
external
returns (JBRuleset memory ruleset);
function updateRulesetWeightCache(uint256 projectId) external;
}
IJBSplitHook.sol 18 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {JBSplitHookContext} from "../structs/JBSplitHookContext.sol";
/// @title Split hook
/// @notice Allows processing a single split with custom logic.
/// @dev The split hook's address should be set as the `hook` in the relevant split.
interface IJBSplitHook is IERC165 {
/// @notice If a split has a split hook, payment terminals and controllers call this function while processing the
/// split.
/// @dev Critical business logic should be protected by appropriate access control. The tokens and/or native tokens
/// are optimistically transferred to the split hook when this function is called.
/// @param context The context passed by the terminal/controller to the split hook as a `JBSplitHookContext` struct:
function processSplitWith(JBSplitHookContext calldata context) external payable;
}
IJBSplits.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBSplit} from "./../structs/JBSplit.sol";
import {JBSplitGroup} from "./../structs/JBSplitGroup.sol";
interface IJBSplits {
event SetSplit(
uint256 indexed projectId, uint256 indexed rulesetId, uint256 indexed groupId, JBSplit split, address caller
);
function FALLBACK_RULESET_ID() external view returns (uint256);
function splitsOf(uint256 projectId, uint256 rulesetId, uint256 groupId) external view returns (JBSplit[] memory);
function setSplitGroupsOf(uint256 projectId, uint256 rulesetId, JBSplitGroup[] memory splitGroups) external;
}
IJBTerminal.sol 78 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IJBPayHook} from "./IJBPayHook.sol";
import {JBAccountingContext} from "../structs/JBAccountingContext.sol";
import {JBAfterPayRecordedContext} from "../structs/JBAfterPayRecordedContext.sol";
/// @notice A terminal that accepts payments and can be migrated.
interface IJBTerminal is IERC165 {
event AddToBalance(
uint256 indexed projectId, uint256 amount, uint256 returnedFees, string memo, bytes metadata, address caller
);
event HookAfterRecordPay(
IJBPayHook indexed hook, JBAfterPayRecordedContext context, uint256 specificationAmount, address caller
);
event MigrateTerminal(
uint256 indexed projectId, address indexed token, IJBTerminal indexed to, uint256 amount, address caller
);
event Pay(
uint256 indexed rulesetId,
uint256 indexed rulesetCycleNumber,
uint256 indexed projectId,
address payer,
address beneficiary,
uint256 amount,
uint256 newlyIssuedTokenCount,
string memo,
bytes metadata,
address caller
);
event SetAccountingContext(uint256 indexed projectId, JBAccountingContext context, address caller);
function accountingContextForTokenOf(
uint256 projectId,
address token
)
external
view
returns (JBAccountingContext memory);
function accountingContextsOf(uint256 projectId) external view returns (JBAccountingContext[] memory);
function currentSurplusOf(
uint256 projectId,
JBAccountingContext[] memory accountingContexts,
uint256 decimals,
uint256 currency
)
external
view
returns (uint256);
function addAccountingContextsFor(uint256 projectId, JBAccountingContext[] calldata accountingContexts) external;
function addToBalanceOf(
uint256 projectId,
address token,
uint256 amount,
bool shouldReturnHeldFees,
string calldata memo,
bytes calldata metadata
)
external
payable;
function migrateBalanceOf(uint256 projectId, address token, IJBTerminal to) external returns (uint256 balance);
function pay(
uint256 projectId,
address token,
uint256 amount,
address beneficiary,
uint256 minReturnedTokens,
string calldata memo,
bytes calldata metadata
)
external
payable
returns (uint256 beneficiaryTokenCount);
}
IJBToken.sol 13 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IJBToken {
function balanceOf(address account) external view returns (uint256);
function canBeAddedTo(uint256 projectId) external view returns (bool);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function initialize(string memory name, string memory symbol, address owner) external;
function burn(address account, uint256 amount) external;
function mint(address account, uint256 amount) external;
}
IJBTokenUriResolver.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IJBTokenUriResolver {
function getUri(uint256 projectId) external view returns (string memory tokenUri);
}
IJBTokens.sol 55 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBToken} from "./IJBToken.sol";
interface IJBTokens {
event DeployERC20(
uint256 indexed projectId, IJBToken indexed token, string name, string symbol, bytes32 salt, address caller
);
event Burn(
address indexed holder,
uint256 indexed projectId,
uint256 count,
uint256 creditBalance,
uint256 tokenBalance,
address caller
);
event ClaimTokens(
address indexed holder,
uint256 indexed projectId,
uint256 creditBalance,
uint256 count,
address beneficiary,
address caller
);
event Mint(
address indexed holder, uint256 indexed projectId, uint256 count, bool tokensWereClaimed, address caller
);
event SetToken(uint256 indexed projectId, IJBToken indexed token, address caller);
event TransferCredits(
address indexed holder, uint256 indexed projectId, address indexed recipient, uint256 count, address caller
);
function creditBalanceOf(address holder, uint256 projectId) external view returns (uint256);
function projectIdOf(IJBToken token) external view returns (uint256);
function tokenOf(uint256 projectId) external view returns (IJBToken);
function totalCreditSupplyOf(uint256 projectId) external view returns (uint256);
function totalBalanceOf(address holder, uint256 projectId) external view returns (uint256 result);
function totalSupplyOf(uint256 projectId) external view returns (uint256);
function burnFrom(address holder, uint256 projectId, uint256 count) external;
function claimTokensFor(address holder, uint256 projectId, uint256 count, address beneficiary) external;
function deployERC20For(
uint256 projectId,
string calldata name,
string calldata symbol,
bytes32 salt
)
external
returns (IJBToken token);
function mintFor(address holder, uint256 projectId, uint256 count) external returns (IJBToken token);
function setTokenFor(uint256 projectId, IJBToken token) external;
function transferCreditsFrom(address holder, uint256 projectId, address recipient, uint256 count) external;
}
JBConstants.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Global constants used across Juicebox contracts.
library JBConstants {
/// @notice Each chain's native token address in Juicebox is represented by
/// 0x000000000000000000000000000000000000EEEe.
address public constant NATIVE_TOKEN = address(0x000000000000000000000000000000000000EEEe);
uint16 public constant MAX_RESERVED_PERCENT = 10_000;
uint16 public constant MAX_CASH_OUT_TAX_RATE = 10_000;
uint32 public constant MAX_WEIGHT_CUT_PERCENT = 1_000_000_000;
uint32 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;
uint16 public constant MAX_FEE = 1000;
}
JBRulesetMetadataResolver.sol 160 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBRulesetMetadata} from "./../structs/JBRulesetMetadata.sol";
library JBRulesetMetadataResolver {
function reservedPercent(JBRuleset memory ruleset) internal pure returns (uint16) {
return uint16(ruleset.metadata >> 4);
}
function cashOutTaxRate(JBRuleset memory ruleset) internal pure returns (uint16) {
// Cash out tax rate is a number 0-10000.
return uint16(ruleset.metadata >> 20);
}
function baseCurrency(JBRuleset memory ruleset) internal pure returns (uint32) {
// Currency is a number 0-4294967296.
return uint32(ruleset.metadata >> 36);
}
function pausePay(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 68) & 1) == 1;
}
function pauseCreditTransfers(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 69) & 1) == 1;
}
function allowOwnerMinting(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 70) & 1) == 1;
}
function allowSetCustomToken(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 71) & 1) == 1;
}
function allowTerminalMigration(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 72) & 1) == 1;
}
function allowSetTerminals(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 73) & 1) == 1;
}
function allowSetController(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 74) & 1) == 1;
}
function allowAddAccountingContext(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 75) & 1) == 1;
}
function allowAddPriceFeed(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 76) & 1) == 1;
}
function ownerMustSendPayouts(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 77) & 1) == 1;
}
function holdFees(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 78) & 1) == 1;
}
function useTotalSurplusForCashOuts(JBRuleset memory ruleset) internal pure returns (bool) {
return ((ruleset.metadata >> 79) & 1) == 1;
}
function useDataHookForPay(JBRuleset memory ruleset) internal pure returns (bool) {
return (ruleset.metadata >> 80) & 1 == 1;
}
function useDataHookForCashOut(JBRuleset memory ruleset) internal pure returns (bool) {
return (ruleset.metadata >> 81) & 1 == 1;
}
function dataHook(JBRuleset memory ruleset) internal pure returns (address) {
return address(uint160(ruleset.metadata >> 82));
}
function metadata(JBRuleset memory ruleset) internal pure returns (uint16) {
return uint16(ruleset.metadata >> 242);
}
/// @notice Pack the funding cycle metadata.
/// @param rulesetMetadata The ruleset metadata to validate and pack.
/// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version.
function packRulesetMetadata(JBRulesetMetadata memory rulesetMetadata) internal pure returns (uint256 packed) {
// version 1 in the bits 0-3 (4 bits).
packed = 1;
// reserved percent in bits 4-19 (16 bits).
packed |= uint256(rulesetMetadata.reservedPercent) << 4;
// cash out tax rate in bits 20-35 (16 bits).
// cash out tax rate is a number 0-10000.
packed |= uint256(rulesetMetadata.cashOutTaxRate) << 20;
// base currency in bits 36-67 (32 bits).
// base currency is a number 0-16777215.
packed |= uint256(rulesetMetadata.baseCurrency) << 36;
// pause pay in bit 68.
if (rulesetMetadata.pausePay) packed |= 1 << 68;
// pause credit transfers in bit 69.
if (rulesetMetadata.pauseCreditTransfers) packed |= 1 << 69;
// allow discretionary minting in bit 70.
if (rulesetMetadata.allowOwnerMinting) packed |= 1 << 70;
// allow a custom token to be set in bit 71.
if (rulesetMetadata.allowSetCustomToken) packed |= 1 << 71;
// allow terminal migration in bit 72.
if (rulesetMetadata.allowTerminalMigration) packed |= 1 << 72;
// allow set terminals in bit 73.
if (rulesetMetadata.allowSetTerminals) packed |= 1 << 73;
// allow set controller in bit 74.
if (rulesetMetadata.allowSetController) packed |= 1 << 74;
// allow add accounting context in bit 75.
if (rulesetMetadata.allowAddAccountingContext) packed |= 1 << 75;
// allow add price feed in bit 76.
if (rulesetMetadata.allowAddPriceFeed) packed |= 1 << 76;
// allow controller migration in bit 77.
if (rulesetMetadata.ownerMustSendPayouts) packed |= 1 << 77;
// hold fees in bit 78.
if (rulesetMetadata.holdFees) packed |= 1 << 78;
// useTotalSurplusForCashOuts in bit 79.
if (rulesetMetadata.useTotalSurplusForCashOuts) packed |= 1 << 79;
// use pay data source in bit 80.
if (rulesetMetadata.useDataHookForPay) packed |= 1 << 80;
// use cash out data source in bit 81.
if (rulesetMetadata.useDataHookForCashOut) packed |= 1 << 81;
// data source address in bits 82-241.
packed |= uint256(uint160(address(rulesetMetadata.dataHook))) << 82;
// metadata in bits 242-255 (14 bits).
packed |= (uint256(rulesetMetadata.metadata) & 0x3FFF) << 242;
}
/// @notice Expand the funding cycle metadata.
/// @param ruleset The funding cycle having its metadata expanded.
/// @return rulesetMetadata The ruleset's metadata object.
function expandMetadata(JBRuleset memory ruleset) internal pure returns (JBRulesetMetadata memory) {
return JBRulesetMetadata(
reservedPercent(ruleset),
cashOutTaxRate(ruleset),
baseCurrency(ruleset),
pausePay(ruleset),
pauseCreditTransfers(ruleset),
allowOwnerMinting(ruleset),
allowSetCustomToken(ruleset),
allowTerminalMigration(ruleset),
allowSetTerminals(ruleset),
allowSetController(ruleset),
allowAddAccountingContext(ruleset),
allowAddPriceFeed(ruleset),
ownerMustSendPayouts(ruleset),
holdFees(ruleset),
useTotalSurplusForCashOuts(ruleset),
useDataHookForPay(ruleset),
useDataHookForCashOut(ruleset),
dataHook(ruleset),
metadata(ruleset)
);
}
}
JBSplitGroupIds.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Group IDs that categorize splits.
library JBSplitGroupIds {
uint256 public constant RESERVED_TOKENS = 1;
}
JBAccountingContext.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @custom:member token The address of the token that accounting is being done with.
/// @custom:member decimals The number of decimals expected in that token's fixed point accounting.
/// @custom:member currency The currency that the token is priced in terms of. By convention, this is
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
struct JBAccountingContext {
address token;
uint8 decimals;
uint32 currency;
}
JBAfterCashOutRecordedContext.sol 30 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBTokenAmount} from "./JBTokenAmount.sol";
/// @custom:member holder The holder of the tokens being cashed out.
/// @custom:member projectId The ID of the project being cashed out from.
/// @custom:member rulesetId The ID of the ruleset the cash out is being made during.
/// @custom:member cashOutCount The number of project tokens being cashed out.
/// @custom:member cashOutTaxRate The current ruleset's cash out tax rate.
/// @custom:member reclaimedAmount The token amount being reclaimed from the project's terminal balance. Includes the
/// token being
/// reclaimed, the value, the number of decimals included, and the currency of the amount.
/// @custom:member forwardedAmount The token amount being forwarded to the cash out hook. Includes the token
/// being forwarded, the value, the number of decimals included, and the currency of the amount.
/// @custom:member beneficiary The address the reclaimed amount will be sent to.
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the cash out hook.
/// @custom:member cashOutMetadata Extra data specified by the account cashing out, which is sent to the cash out hook.
struct JBAfterCashOutRecordedContext {
address holder;
uint256 projectId;
uint256 rulesetId;
uint256 cashOutCount;
JBTokenAmount reclaimedAmount;
JBTokenAmount forwardedAmount;
uint256 cashOutTaxRate;
address payable beneficiary;
bytes hookMetadata;
bytes cashOutMetadata;
}
JBAfterPayRecordedContext.sol 29 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBTokenAmount} from "./JBTokenAmount.sol";
/// @custom:member payer The address the payment originated from.
/// @custom:member projectId The ID of the project being paid.
/// @custom:member rulesetId The ID of the ruleset the payment is being made during.
/// @custom:member amount The payment's token amount. Includes the token being paid, the value, the number of decimals
/// included, and the currency of the amount.
/// @custom:member forwardedAmount The token amount being forwarded to the pay hook. Includes the token
/// being paid, the value, the number of decimals included, and the currency of the amount.
/// @custom:member weight The current ruleset's weight (used to determine how many tokens should be minted).
/// @custom:member newlyIssuedTokenCount The number of project tokens minted for the beneficiary.
/// @custom:member beneficiary The address which receives any tokens this payment yields.
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the pay hook.
/// @custom:member payerMetadata Extra data specified by the payer, which is sent to the pay hook.
struct JBAfterPayRecordedContext {
address payer;
uint256 projectId;
uint256 rulesetId;
JBTokenAmount amount;
JBTokenAmount forwardedAmount;
uint256 weight;
uint256 newlyIssuedTokenCount;
address beneficiary;
bytes hookMetadata;
bytes payerMetadata;
}
JBBeforeCashOutRecordedContext.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBTokenAmount} from "./JBTokenAmount.sol";
/// @notice Context sent from the terminal to the ruleset's data hook upon cash out.
/// @custom:member terminal The terminal that is facilitating the cash out.
/// @custom:member holder The holder of the tokens being cashed out.
/// @custom:member projectId The ID of the project whose tokens are being cashed out.
/// @custom:member rulesetId The ID of the ruleset the cash out is being made during.
/// @custom:member cashOutCount The number of tokens being cashed out, as a fixed point number with 18 decimals.
/// @custom:member totalSupply The total token supply being used for the calculation, as a fixed point number with 18
/// decimals.
/// @custom:member surplus The surplus amount used for the calculation, as a fixed point number with 18 decimals.
/// Includes the token of the surplus, the surplus value, the number of decimals
/// included, and the currency of the surplus.
/// @custom:member useTotalSurplus If surplus across all of a project's terminals is being used when making cash outs.
/// @custom:member cashOutTaxRate The cash out tax rate of the ruleset the cash out is being made during.
/// @custom:member metadata Extra data provided by the casher.
struct JBBeforeCashOutRecordedContext {
address terminal;
address holder;
uint256 projectId;
uint256 rulesetId;
uint256 cashOutCount;
uint256 totalSupply;
JBTokenAmount surplus;
bool useTotalSurplus;
uint256 cashOutTaxRate;
bytes metadata;
}
JBBeforePayRecordedContext.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBTokenAmount} from "./JBTokenAmount.sol";
/// @notice Context sent from the terminal to the ruleset's data hook upon payment.
/// @custom:member terminal The terminal that is facilitating the payment.
/// @custom:member payer The address that the payment originated from.
/// @custom:member amount The payment's token amount, including the token being paid, the value, the number of decimals
/// included, and the currency of the amount.
/// @custom:member projectId The ID of the project being paid.
/// @custom:member rulesetId The ID of the ruleset the payment is being made during.
/// @custom:member beneficiary The specified address that should be the beneficiary of anything that this payment
/// yields.
/// @custom:member weight The weight of the ruleset during which the payment is being made.
/// @custom:member reservedPercent The reserved percent of the ruleset the payment is being made during.
/// @custom:member metadata Extra data specified by the payer.
struct JBBeforePayRecordedContext {
address terminal;
address payer;
JBTokenAmount amount;
uint256 projectId;
uint256 rulesetId;
address beneficiary;
uint256 weight;
uint256 reservedPercent;
bytes metadata;
}
JBCashOutHookSpecification.sol 15 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBCashOutHook} from "../interfaces/IJBCashOutHook.sol";
/// @notice A cash out hook specification sent from the ruleset's data hook back to the terminal. This specification is
/// fulfilled by the terminal.
/// @custom:member hook The cash out hook to use when fulfilling this specification.
/// @custom:member amount The amount to send to the hook.
/// @custom:member metadata Metadata to pass to the hook.
struct JBCashOutHookSpecification {
IJBCashOutHook hook;
uint256 amount;
bytes metadata;
}
JBCurrencyAmount.sol 10 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @custom:member amount The amount of the currency.
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
struct JBCurrencyAmount {
uint224 amount;
uint32 currency;
}
JBFundAccessLimitGroup.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBCurrencyAmount} from "./JBCurrencyAmount.sol";
/// @dev Payout limit example: if the `amount` is 5, the `currency` is 1 (USD), and the terminal's token is ETH, then
/// the project can pay out 5 USD worth of ETH during a ruleset.
/// @dev Surplus allowance example: if the `amount` is 5, the `currency` is 1 (USD), and the terminal's token is ETH,
/// then the project can pay out 5 USD worth of ETH from its surplus during a ruleset. A project's surplus is its
/// balance minus its current combined payout limit.
/// @dev If a project has multiple payout limits or surplus allowances, they are all available. They can all be used
/// during a single ruleset.
/// @dev The payout limits' and surplus allowances' fixed point amounts have the same number of decimals as the
/// terminal.
/// @custom:member terminal The terminal that the payout limits and surplus allowances apply to.
/// @custom:member token The token that the payout limits and surplus allowances apply to within the `terminal`.
/// @custom:member payoutLimits An array of payout limits. The payout limits cumulatively dictate the maximum value of
/// `token`s a project can pay out from its balance in a terminal during a ruleset. Each payout limit can have a unique
/// currency and amount.
/// @custom:member surplusAllowances An array of surplus allowances. The surplus allowances cumulatively dictates the
/// maximum value of `token`s a project can pay out from its surplus (balance less payouts) in a terminal during a
/// ruleset. Each surplus allowance can have a unique currency and amount.
struct JBFundAccessLimitGroup {
address terminal;
address token;
JBCurrencyAmount[] payoutLimits;
JBCurrencyAmount[] surplusAllowances;
}
JBPayHookSpecification.sol 15 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBPayHook} from "../interfaces/IJBPayHook.sol";
/// @notice A pay hook specification sent from the ruleset's data hook back to the terminal. This specification is
/// fulfilled by the terminal.
/// @custom:member hook The pay hook to use when fulfilling this specification.
/// @custom:member amount The amount to send to the hook.
/// @custom:member metadata Metadata to pass the hook.
struct JBPayHookSpecification {
IJBPayHook hook;
uint256 amount;
bytes metadata;
}
JBPermissionsData.sol 13 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @custom:member operator The address that permissions are being given to.
/// @custom:member projectId The ID of the project the operator is being given permissions for. Operators only have
/// permissions under this project's scope. An ID of 0 is a wildcard, which gives an operator permissions across all
/// projects.
/// @custom:member permissionIds The IDs of the permissions being given. See the `JBPermissionIds` library.
struct JBPermissionsData {
address operator;
uint64 projectId;
uint8[] permissionIds;
}
JBRuleset.sol 42 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBRulesetApprovalHook} from "./../interfaces/IJBRulesetApprovalHook.sol";
/// @dev `JBRuleset` timestamps are unix timestamps (seconds since 00:00 January 1st, 1970 UTC).
/// @custom:member cycleNumber The ruleset's cycle number. Each ruleset's `cycleNumber` is the previous ruleset's
/// `cycleNumber` plus one. Each project's first ruleset has a `cycleNumber` of 1.
/// @custom:member id The ruleset's ID, which is a timestamp of when this ruleset's rules were initialized. The
/// `rulesetId` stays the same for rulesets that automatically cycle over from a manually queued ruleset.
/// @custom:member basedOnId The `rulesetId` of the ruleset which was active when this ruleset was created.
/// @custom:member start The timestamp from which this ruleset is considered active.
/// @custom:member duration The number of seconds the ruleset lasts for. After this duration, a new ruleset will start.
/// The project owner can queue new rulesets at any time, which will take effect once the current ruleset's duration is
/// over. If the `duration` is 0, newly queued rulesets will take effect immediately. If a ruleset ends and there are no
/// new rulesets queued, the current ruleset cycles over to another one with the same properties but a new `start`
/// timestamp and a `weight` reduced by the ruleset's `weightCutPercent`.
/// @custom:member weight A fixed point number with 18 decimals which is typically used by payment terminals to
/// determine how many tokens should be minted when a payment is received. This can be used by other contracts for
/// arbitrary calculations.
/// @custom:member weightCutPercent The percentage by which to reduce the `weight` each time a new ruleset starts.
/// `weight`
/// is
/// a percentage out of `JBConstants.MAX_WEIGHT_CUT_PERCENT`. If it's 0, the next ruleset will have the same `weight` by
/// default. If it's 90%, the next ruleset's `weight` will be 10% smaller. If a ruleset explicitly sets a new `weight`,
/// the `weightCutPercent` doesn't apply.
/// @custom:member approvalHook An address of a contract that says whether a queued ruleset should be approved or
/// rejected. If a
/// ruleset is rejected, it won't go into effect. An approval hook can be used to create rules which dictate how a
/// project owner can change their ruleset over time.
/// @custom:member metadata Extra data associated with a ruleset which can be used by other contracts.
struct JBRuleset {
uint48 cycleNumber;
uint48 id;
uint48 basedOnId;
uint48 start;
uint32 duration;
uint112 weight;
uint32 weightCutPercent;
IJBRulesetApprovalHook approvalHook;
uint256 metadata;
}
JBRulesetConfig.sol 43 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBRulesetApprovalHook} from "../interfaces/IJBRulesetApprovalHook.sol";
import {JBFundAccessLimitGroup} from "./JBFundAccessLimitGroup.sol";
import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";
import {JBSplitGroup} from "./JBSplitGroup.sol";
/// @custom:member mustStartAtOrAfter The earliest time the ruleset can start.
/// @custom:member duration The number of seconds the ruleset lasts for, after which a new ruleset will start. A
/// duration of 0 means that the ruleset will stay active until the project owner explicitly issues a reconfiguration,
/// at which point a new ruleset will immediately start with the updated properties. If the duration is greater than 0,
/// a project owner cannot make changes to a ruleset's parameters while it is active – any proposed changes will apply
/// to the subsequent ruleset. If no changes are proposed, a ruleset rolls over to another one with the same properties
/// but new `start` timestamp and a cut `weight`.
/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations
/// on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is
/// received.
/// @custom:member weightCutPercent A percent by how much the `weight` of the subsequent ruleset should be reduced, if
/// the
/// project owner hasn't queued the subsequent ruleset with an explicit `weight`. If it's 0, each ruleset will have
/// equal weight. If the number is 90%, the next ruleset will have a 10% smaller weight. This weight is out of
/// `JBConstants.MAX_WEIGHT_CUT_PERCENT`.
/// @custom:member approvalHook An address of a contract that says whether a proposed ruleset should be accepted or
/// rejected. It
/// can be used to create rules around how a project owner can change ruleset parameters over time.
/// @custom:member metadata Metadata specifying the controller-specific parameters that a ruleset can have. These
/// properties cannot change until the next ruleset starts.
/// @custom:member splitGroups An array of splits to use for any number of groups while the ruleset is active.
/// @custom:member fundAccessLimitGroups An array of structs which dictate the amount of funds a project can access from
/// its balance in each payment terminal while the ruleset is active. Amounts are fixed point numbers using the same
/// number of decimals as the corresponding terminal. The `_payoutLimit` and `_surplusAllowance` parameters must fit in
/// a `uint232`.
struct JBRulesetConfig {
uint48 mustStartAtOrAfter;
uint32 duration;
uint112 weight;
uint32 weightCutPercent;
IJBRulesetApprovalHook approvalHook;
JBRulesetMetadata metadata;
JBSplitGroup[] splitGroups;
JBFundAccessLimitGroup[] fundAccessLimitGroups;
}
JBRulesetMetadata.sol 56 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @custom:member reservedPercent The reserved percent of the ruleset. This number is a percentage calculated out of
/// `JBConstants.MAX_RESERVED_PERCENT`.
/// @custom:member cashOutTaxRate The cash out tax rate of the ruleset. This number is a percentage calculated out of
/// `JBConstants.MAX_CASH_OUT_TAX_RATE`.
/// @custom:member baseCurrency The currency on which to base the ruleset's weight. By convention, this is
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the ruleset.
/// @custom:member pauseCreditTransfers A flag indicating if the project token transfer functionality should be paused
/// during the funding cycle.
/// @custom:member allowOwnerMinting A flag indicating if the project owner or an operator with the `MINT_TOKENS`
/// permission from the owner should be allowed to mint project tokens on demand during this ruleset.
/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this
/// ruleset.
/// @custom:member allowSetTerminals A flag indicating if a project's terminals can be added or removed.
/// @custom:member allowSetController A flag indicating if a project's controller can be changed.
/// @custom:member allowAddAccountingContext A flag indicating if a project can add new accounting contexts for its
/// terminals to use.
/// @custom:member allowAddPriceFeed A flag indicating if a project can add new price feeds to calculate exchange rates
/// between its tokens.
/// @custom:member ownerMustSendPayouts A flag indicating if privileged payout distribution should be
/// enforced, otherwise payouts can be distributed by anyone.
/// @custom:member holdFees A flag indicating if fees should be held during this ruleset.
/// @custom:member useTotalSurplusForCashOuts A flag indicating if cash outs should use the project's balance held
/// in all terminals instead of the project's local terminal balance from which the cash out is being fulfilled.
/// @custom:member useDataHookForPay A flag indicating if the data hook should be used for pay transactions during this
/// ruleset.
/// @custom:member useDataHookForCashOut A flag indicating if the data hook should be used for cash out transactions
/// during
/// this ruleset.
/// @custom:member dataHook The data hook to use during this ruleset.
/// @custom:member metadata Metadata of the metadata, only the 14 least significant bits can be used, the 2 most
/// significant bits are disregarded.
struct JBRulesetMetadata {
uint16 reservedPercent;
uint16 cashOutTaxRate;
uint32 baseCurrency;
bool pausePay;
bool pauseCreditTransfers;
bool allowOwnerMinting;
bool allowSetCustomToken;
bool allowTerminalMigration;
bool allowSetTerminals;
bool allowSetController;
bool allowAddAccountingContext;
bool allowAddPriceFeed;
bool ownerMustSendPayouts;
bool holdFees;
bool useTotalSurplusForCashOuts;
bool useDataHookForPay;
bool useDataHookForCashOut;
address dataHook;
uint16 metadata;
}
JBRulesetWithMetadata.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBRuleset} from "./JBRuleset.sol";
import {JBRulesetMetadata} from "./JBRulesetMetadata.sol";
/// @custom:member ruleset The ruleset.
/// @custom:member metadata The ruleset's metadata.
struct JBRulesetWithMetadata {
JBRuleset ruleset;
JBRulesetMetadata metadata;
}
JBSplit.sol 35 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IJBSplitHook} from "./../interfaces/IJBSplitHook.sol";
/// @notice Splits are used to send a percentage of a total token amount to a specific contract, project, or address.
/// Splits are used to send payouts and reserved tokens.
/// @dev 1. If a non-zero split hook contract is specified, this split's tokens are sent there along with this split's
/// properties.
/// @dev 2. Otherwise, if a non-zero project ID is specified, this split's tokens are used to `pay` it through its
/// terminal if possible, or sent to the project's owner if not. If this payment yields tokens, those go to the split's
/// `beneficiary`.
/// @dev 3. Otherwise, this split's tokens are sent directly to the `beneficiary`.
/// @dev To summarize, this split's tokens are sent according to the following priority: `split hook` > `projectId` >
/// `beneficiary`.
/// @custom:member percent The percent of the total token amount that this split sends. This number is out of
/// `JBConstants.SPLITS_TOTAL_PERCENT`.
/// @custom:member projectId The ID of a project to `pay`, if applicable. Resulting tokens will be routed to the
/// `beneficiary`.
/// @custom:member beneficiary Receives this split's tokens if the `hook` and `projectId` are zero. If the `projectId`
/// is specified, the `beneficiary` receives any project tokens minted by this split.
/// @custom:member preferAddToBalance If this split were to `pay` a project through its terminal, this flag indicates
/// whether it should prefer using the terminal's `addToBalance` function instead.
/// @custom:member lockedUntil The split cannot be changed until this timestamp. The `lockedUntil` timestamp can be
/// increased while a split is locked. If `lockedUntil` is zero, this split can be changed at any time.
/// @custom:member hook A contract which will receive this split's tokens and properties, and can define custom
/// behavior.
struct JBSplit {
uint32 percent;
uint64 projectId;
address payable beneficiary;
bool preferAddToBalance;
uint48 lockedUntil;
IJBSplitHook hook;
}
JBSplitGroup.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBSplit} from "./JBSplit.sol";
/// @custom:member groupId An identifier for the group. By convention, this ID is `uint256(uint160(tokenAddress))` for
/// payouts and `1` for reserved tokens.
/// @custom:member splits The splits in the group.
struct JBSplitGroup {
uint256 groupId;
JBSplit[] splits;
}
JBSplitHookContext.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBSplit} from "./JBSplit.sol";
/// @custom:member token The token being sent to the split hook.
/// @custom:member amount The amount being sent to the split hook, as a fixed point number.
/// @custom:member decimals The number of decimals in the amount.
/// @custom:member projectId The project the split belongs to.
/// @custom:member groupId The group the split belongs to. By convention, this ID is `uint256(uint160(tokenAddress))`
/// for payouts and `1` for reserved tokens.
/// @custom:member split The split which specified the hook.
struct JBSplitHookContext {
address token;
uint256 amount;
uint256 decimals;
uint256 projectId;
uint256 groupId;
JBSplit split;
}
JBTerminalConfig.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {JBAccountingContext} from "./JBAccountingContext.sol";
import {IJBTerminal} from "./../interfaces/IJBTerminal.sol";
/// @custom:member terminal The terminal to configure.
/// @custom:member accountingContextsToAccept The accounting contexts to accept from the terminal.
struct JBTerminalConfig {
IJBTerminal terminal;
JBAccountingContext[] accountingContextsToAccept;
}
JBTokenAmount.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @custom:member token The token the payment was made in.
/// @custom:member decimals The number of decimals included in the value fixed point number.
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
/// @custom:member value The amount of tokens that was paid, as a fixed point number.
struct JBTokenAmount {
address token;
uint8 decimals;
uint32 currency;
uint256 value;
}
Read Contract
DIRECTORY 0x88bc2ef3 → address
FUND_ACCESS_LIMITS 0xffa08244 → address
OMNICHAIN_RULESET_OPERATOR 0x2fdb77e9 → address
PERMISSIONS 0xf434c914 → address
PRICES 0x1eabcd34 → address
PROJECTS 0x293c4999 → address
RULESETS 0xd4a1b4b1 → address
SPLITS 0x1f47ce69 → address
TOKENS 0x1d831d5c → address
allRulesetsOf 0x6567b406 → tuple[]
currentRulesetOf 0x41929626 → tuple, tuple
getRulesetOf 0x25a61d5c → tuple, tuple
isTrustedForwarder 0x572b6c05 → bool
latestQueuedRulesetOf 0xc1ec61ee → tuple, tuple, uint8
pendingReservedTokenBalanceOf 0x39975571 → uint256
setControllerAllowed 0x99d25a34 → bool
setTerminalsAllowed 0xb1a50e33 → bool
supportsInterface 0x01ffc9a7 → bool
totalTokenSupplyWithReservedTokensOf 0x4da781a9 → uint256
trustedForwarder 0x7da0a877 → address
upcomingRulesetOf 0xc02c63ad → tuple, tuple
uriOf 0xa312889b → string
Write Contract 16 functions
These functions modify contract state and require a wallet transaction to execute.
addPriceFeed 0x2fa90203
uint256 projectId
uint256 pricingCurrency
uint256 unitCurrency
address feed
beforeReceiveMigrationFrom 0xf0118e18
address from
uint256 projectId
burnTokensOf 0xa2d532e6
address holder
uint256 projectId
uint256 tokenCount
string memo
claimTokensFor 0x303f5dfa
address holder
uint256 projectId
uint256 tokenCount
address beneficiary
deployERC20For 0x58178191
uint256 projectId
string name
string symbol
bytes32 salt
returns: address
executePayReservedTokenToTerminal 0xfb61b4e3
address terminal
uint256 projectId
address token
uint256 splitTokenCount
address beneficiary
bytes metadata
launchProjectFor 0x7ab807ae
address owner
string projectUri
tuple[] rulesetConfigurations
tuple[] terminalConfigurations
string memo
returns: uint256
launchRulesetsFor 0x63e8fde4
uint256 projectId
tuple[] rulesetConfigurations
tuple[] terminalConfigurations
string memo
returns: uint256
migrate 0x405b84fa
uint256 projectId
address to
mintTokensOf 0xc7fb92de
uint256 projectId
uint256 tokenCount
address beneficiary
string memo
bool useReservedPercent
returns: uint256
queueRulesetsOf 0xcb04ec34
uint256 projectId
tuple[] rulesetConfigurations
string memo
returns: uint256
sendReservedTokensToSplitsOf 0x090db2f1
uint256 projectId
returns: uint256
setSplitGroupsOf 0x5b249385
uint256 projectId
uint256 rulesetId
tuple[] splitGroups
setTokenFor 0xf12b64a5
uint256 projectId
address token
setUriOf 0x702a3977
uint256 projectId
string uri
transferCreditsFrom 0xb1e6d2a1
address holder
uint256 projectId
address recipient
uint256 creditCount
Recent Transactions
No transactions found for this address