Address Contract Verified
Address
0x8659EEFF31CFcff580D37AF8e7Af250F8998aA83
Balance
0 ETH
Nonce
600
Code Size
10183 bytes
Creator
0x6C74FDa1...0Dc8 at tx 0xfcb09ebd...8de937
Indexed Transactions
0
Contract Bytecode
10183 bytes
0x608060405260043610620000a95760003560e01c806379ba5097116200006c57806379ba5097146200019c5780638da5cb5b14620001b45780639cbb7b0a14620001d4578063e30c397814620001f9578063ebe2b2551462000219578063f2fde38b146200023e57600080fd5b80633a4741bd14620000ae5780633f62e9b71462000101578063608c54d414620001265780636d70f7ae146200013d578063715018a61462000182575b600080fd5b348015620000bb57600080fd5b50620000e47f0000000000000000000000002f0bb99ffc519a37c3ba3d128e51b29a70c64e8481565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156200010e57600080fd5b50620000e46200012036600462000843565b62000263565b620000e462000137366004620008d5565b620002e1565b3480156200014a57600080fd5b50620001716200015c36600462000950565b60026020526000908152604090205460ff1681565b6040519015158152602001620000f8565b3480156200018f57600080fd5b506200019a62000391565b005b348015620001a957600080fd5b506200019a620003a9565b348015620001c157600080fd5b506000546001600160a01b0316620000e4565b348015620001e157600080fd5b50620000e4620001f336600462000977565b620003f1565b3480156200020657600080fd5b506001546001600160a01b0316620000e4565b3480156200022657600080fd5b50620000e462000238366004620009ee565b62000408565b3480156200024b57600080fd5b506200019a6200025d36600462000950565b620004d6565b6040516bffffffffffffffffffffffff19606085811b8216602084015284901b16603482015260488101829052600090620002d9907f0000000000000000000000002f0bb99ffc519a37c3ba3d128e51b29a70c64e8490606801604051602081830303815290604052805190602001206200054a565b949350505050565b6000620002ef8686620005ab565b9050600080856001600160a01b03163486866040516200031192919062000abc565b60006040518083038185875af1925050503d806000811462000350576040519150601f19603f3d011682016040523d82523d6000602084013e62000355565b606091505b509150915081620003865780604051634e306ee560e11b81526004016200037d919062000acc565b60405180910390fd5b505095945050505050565b6200039b62000716565b620003a7600062000745565b565b60015433906001600160a01b03168114620003e35760405163118cdaa760e01b81526001600160a01b03821660048201526024016200037d565b620003ee8162000745565b50565b6000620003ff8383620005ab565b90505b92915050565b60006200041462000716565b8989898989898989896040516200042b906200081f565b6200043f9998979695949392919062000b9d565b604051809103906000f0801580156200045c573d6000803e3d6000fd5b506001600160a01b03811660009081526002602052604090819020805460ff19166001179055519091507f3c73f8e346b8759b8d82f81c582c6132b3db0899938f8592ed97ee12a406386e90620004c19083908d908b908a908a908a908a9062000c21565b60405180910390a19998505050505050505050565b620004e062000716565b600180546001600160a01b0383166001600160a01b03199091168117909155620005126000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040513060388201526f5af43d82803e903d91602b57fd5bf3ff602482015260148101839052733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018290526037600c82012060788201526055604390910120600090620003ff565b6001600160a01b03821660009081526002602052604081205460ff16620005e55760405163eb32d3bf60e01b815260040160405180910390fd5b6040516bffffffffffffffffffffffff19606085811b8216602084015233901b1660348201526048810183905262000658907f0000000000000000000000002f0bb99ffc519a37c3ba3d128e51b29a70c64e84906068016040516020818303038152906040528051906020012062000760565b60405163784d200b60e11b81526001600160a01b0385811660048301523360248301529192509082169063f09a401690604401600060405180830381600087803b158015620006a657600080fd5b505af1158015620006bb573d6000803e3d6000fd5b5050604080516001600160a01b0385811682528716602082015233818301526060810186905290517f6b9607678a8bd153de7b782ffd4347da2276707e2a589e5a620d6b4b861926bc9350908190036080019150a192915050565b6000546001600160a01b03163314620003a75760405163118cdaa760e01b81523360048201526024016200037d565b600180546001600160a01b0319169055620003ee81620007cf565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b03811662000402576040516330be1a3d60e21b815260040160405180910390fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611b178062000c7b83390190565b6001600160a01b0381168114620003ee57600080fd5b6000806000606084860312156200085957600080fd5b833562000866816200082d565b9250602084013562000878816200082d565b929592945050506040919091013590565b60008083601f8401126200089c57600080fd5b50813567ffffffffffffffff811115620008b557600080fd5b602083019150836020828501011115620008ce57600080fd5b9250929050565b600080600080600060808688031215620008ee57600080fd5b8535620008fb816200082d565b945060208601359350604086013562000914816200082d565b9250606086013567ffffffffffffffff8111156200093157600080fd5b6200093f8882890162000889565b969995985093965092949392505050565b6000602082840312156200096357600080fd5b813562000970816200082d565b9392505050565b600080604083850312156200098b57600080fd5b823562000998816200082d565b946020939093013593505050565b60008083601f840112620009b957600080fd5b50813567ffffffffffffffff811115620009d257600080fd5b6020830191508360208260051b8501011115620008ce57600080fd5b600080600080600080600080600060c08a8c03121562000a0d57600080fd5b893562000a1a816200082d565b985060208a013567ffffffffffffffff8082111562000a3857600080fd5b62000a468d838e0162000889565b909a50985060408c0135975060608c0135965060808c013591508082111562000a6e57600080fd5b62000a7c8d838e01620009a6565b909650945060a08c013591508082111562000a9657600080fd5b5062000aa58c828d01620009a6565b915080935050809150509295985092959850929598565b8183823760009101908152919050565b60006020808352835180602085015260005b8181101562000afc5785810183015185820160400152820162000ade565b506000604082860101526040601f19601f8301168501019250505092915050565b8183526000602080850194508260005b8581101562000b5f57813562000b43816200082d565b6001600160a01b03168752958201959082019060010162000b2d565b509495945050505050565b81835260006001600160fb1b0383111562000b8457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b038a16815260c0602082018190528101889052878960e0830137600060e089830101526000601f19601f8a0116820188604084015287606084015260e083820301608084015262000bfa60e08201878962000b1d565b905082810360a084015262000c1181858762000b6a565b9c9b505050505050505050505050565b6001600160a01b038881168252871660208201526040810186905260a06060820181905260009062000c57908301868862000b1d565b828103608084015262000c6c81858762000b6a565b9a995050505050505050505056fe60a06040523480156200001157600080fd5b5060405162001b1738038062001b178339810160408190526200003491620006b9565b856001600160a01b0381166200006557604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6200007081620000ff565b506127108311156200009957604051631994fc9960e11b8152600481018490526024016200005c565b60808390526040518381527ff92db49e11b51e4b633bc5ae75293799a2e16c1b3bc928383410edc9d611b2aa9060200160405180910390a1620000dc846200011d565b620000e8828262000181565b620000f385620003af565b50505050505062000a45565b600180546001600160a01b03191690556200011a8162000412565b50565b6080518111156200014557604051631994fc9960e11b8152600481018290526024016200005c565b60028190556040518181527f57440952be1d084f9c741cb2abace1de0405cc2cb932b97595e31e433af4f7b5906020015b60405180910390a150565b81516000819003620001a657604051631b56ca0d60e11b815260040160405180910390fd5b81518114620001c8576040516301b36a6760e71b815260040160405180910390fd5b6000805b828110156200031e57838181518110620001ea57620001ea620007cd565b602002602001015182620001ff9190620007f9565b9150600081118015620002685750846200021b60018362000815565b815181106200022e576200022e620007cd565b60200260200101516001600160a01b0316858281518110620002545762000254620007cd565b60200260200101516001600160a01b031611155b156200028757604051630811cbcd60e01b815260040160405180910390fd5b60006001600160a01b0316858281518110620002a757620002a7620007cd565b60200260200101516001600160a01b031603620002d75760405163d92e233d60e01b815260040160405180910390fd5b838181518110620002ec57620002ec620007cd565b60200260200101516000036200031557604051634572ccbf60e11b815260040160405180910390fd5b600101620001cc565b506127108114620003425760405163174a32eb60e11b815260040160405180910390fd5b83516200035790600390602087019062000462565b5082516200036d906004906020860190620004cc565b507fdaf3393bf19500a23f26fb16a5651a6c79f5b61684cf4832ac9de30e18ab02028484604051620003a19291906200082b565b60405180910390a150505050565b8051600003620003d257604051638d46fe0560e01b815260040160405180910390fd5b6005620003e0828262000944565b507f9f03e20aa3dcfb755ca419f492ab33e90abb98a7e77bafac16322662a9495f738160405162000176919062000a10565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054828255906000526020600020908101928215620004ba579160200282015b82811115620004ba57825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000483565b50620004c89291506200050a565b5090565b828054828255906000526020600020908101928215620004ba579160200282015b82811115620004ba578251825591602001919060010190620004ed565b5b80821115620004c857600081556001016200050b565b80516001600160a01b03811681146200053957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200057f576200057f6200053e565b604052919050565b60005b83811015620005a45781810151838201526020016200058a565b50506000910152565b60006001600160401b03821115620005c957620005c96200053e565b5060051b60200190565b600082601f830112620005e557600080fd5b81516020620005fe620005f883620005ad565b62000554565b8083825260208201915060208460051b8701019350868411156200062157600080fd5b602086015b8481101562000648576200063a8162000521565b835291830191830162000626565b509695505050505050565b600082601f8301126200066557600080fd5b8151602062000678620005f883620005ad565b8083825260208201915060208460051b8701019350868411156200069b57600080fd5b602086015b84811015620006485780518352918301918301620006a0565b60008060008060008060c08789031215620006d357600080fd5b620006de8762000521565b60208801519096506001600160401b0380821115620006fc57600080fd5b818901915089601f8301126200071157600080fd5b8151818111156200072657620007266200053e565b6200073b601f8201601f191660200162000554565b8181528b60208386010111156200075157600080fd5b6200076482602083016020870162000587565b8098505050604089015195506060890151945060808901519150808211156200078c57600080fd5b6200079a8a838b01620005d3565b935060a0890151915080821115620007b157600080fd5b50620007c089828a0162000653565b9150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156200080f576200080f620007e3565b92915050565b818103818111156200080f576200080f620007e3565b604080825283519082018190526000906020906060840190828701845b828110156200086f5781516001600160a01b03168452928401929084019060010162000848565b5050508381038285015284518082528583019183019060005b81811015620008a65783518352928401929184019160010162000888565b5090979650505050505050565b600181811c90821680620008c857607f821691505b602082108103620008e957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200093f576000816000526020600020601f850160051c810160208610156200091a5750805b601f850160051c820191505b818110156200093b5782815560010162000926565b5050505b505050565b81516001600160401b038111156200096057620009606200053e565b6200097881620009718454620008b3565b84620008ef565b602080601f831160018114620009b05760008415620009975750858301515b600019600386901b1c1916600185901b1785556200093b565b600085815260208120601f198616915b82811015620009e157888601518255948401946001909101908401620009c0565b508582101562000a005787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000825180602084015262000a3181604085016020870162000587565b601f01601f19169190910160400192915050565b6080516110af62000a68600039600081816101f0015261076a01526110af6000f3fe6080604052600436106100d55760003560e01c80638db1342d11610079578063c47f002711610056578063c47f002714610232578063d1bc76a114610252578063e30c397814610272578063f2fde38b1461029057005b80638db1342d146101be5780638e72bce2146101de578063ae373c1b1461021257005b8063715018a6116100b2578063715018a61461013e57806379ba50971461015357806389afc0f1146101685780638da5cb5b1461018c57005b806306fdde03146100de5780631d095805146101095780634e71d92d1461012957005b366100dc57005b005b3480156100ea57600080fd5b506100f36102b0565b6040516101009190610c7b565b60405180910390f35b34801561011557600080fd5b506100dc610124366004610c8e565b61033e565b34801561013557600080fd5b506100dc610352565b34801561014a57600080fd5b506100dc610564565b34801561015f57600080fd5b506100dc610578565b34801561017457600080fd5b5061017e60025481565b604051908152602001610100565b34801561019857600080fd5b506000546001600160a01b03165b6040516001600160a01b039091168152602001610100565b3480156101ca57600080fd5b5061017e6101d9366004610c8e565b6105b9565b3480156101ea57600080fd5b5061017e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561021e57600080fd5b506100dc61022d366004610cf3565b6105da565b34801561023e57600080fd5b506100dc61024d366004610d5f565b610655565b34801561025e57600080fd5b506101a661026d366004610c8e565b6106a0565b34801561027e57600080fd5b506001546001600160a01b03166101a6565b34801561029c57600080fd5b506100dc6102ab366004610dd1565b6106ca565b600580546102bd90610dfa565b80601f01602080910402602001604051908101604052809291908181526020018280546102e990610dfa565b80156103365780601f1061030b57610100808354040283529160200191610336565b820191906000526020600020905b81548152906001019060200180831161031957829003601f168201915b505050505081565b61034661073b565b61034f81610768565b50565b476000805b60035461036690600190610e4a565b81101561047b576000610399846004848154811061038657610386610e63565b90600052602060002001546127106107e8565b9050600080600384815481106103b1576103b1610e63565b60009182526020822001546040516001600160a01b039091169185919081818185875af1925050503d8060008114610405576040519150601f19603f3d011682016040523d82523d6000602084013e61040a565b606091505b509150915081610461576003848154811061042757610427610e63565b60009182526020909120015460405163438638a360e01b8152610458916001600160a01b0316908390600401610e79565b60405180910390fd5b61046b8386610ea5565b9450836001019350505050610357565b5060038054600091829161049190600190610e4a565b815481106104a1576104a1610e63565b6000918252602090912001546001600160a01b03166104c08486610e4a565b604051600081818185875af1925050503d80600081146104fc576040519150601f19603f3d011682016040523d82523d6000602084013e610501565b606091505b50915091508161052b576003805461051b90600190610e4a565b8154811061042757610427610e63565b50506040518281527f7a355715549cfe7c1cba26304350343fbddc4b4f72d3ce3e7c27117dd20b5cb89060200160405180910390a15050565b61056c61073b565b61057660006108ad565b565b60015433906001600160a01b031681146105b05760405163118cdaa760e01b81526001600160a01b0382166004820152602401610458565b61034f816108ad565b600481815481106105c957600080fd5b600091825260209091200154905081565b6105e261073b565b61064f848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506108c692505050565b50505050565b61065d61073b565b61069c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ad292505050565b5050565b600381815481106106b057600080fd5b6000918252602090912001546001600160a01b0316905081565b6106d261073b565b600180546001600160a01b0383166001600160a01b031990911681179091556107036000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b031633146105765760405163118cdaa760e01b8152336004820152602401610458565b7f00000000000000000000000000000000000000000000000000000000000000008111156107ac57604051631994fc9960e11b815260048101829052602401610458565b60028190556040518181527f57440952be1d084f9c741cb2abace1de0405cc2cb932b97595e31e433af4f7b5906020015b60405180910390a150565b600083830281600019858709828110838203039150508060000361081f5783828161081557610815610eb8565b04925050506108a6565b80841161083f5760405163227bc15360e01b815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b600180546001600160a01b031916905561034f81610b30565b815160008190036108ea57604051631b56ca0d60e11b815260040160405180910390fd5b8151811461090b576040516301b36a6760e71b815260040160405180910390fd5b6000805b82811015610a485783818151811061092957610929610e63565b60200260200101518261093c9190610ea5565b915060008111801561099c575084610955600183610e4a565b8151811061096557610965610e63565b60200260200101516001600160a01b031685828151811061098857610988610e63565b60200260200101516001600160a01b031611155b156109ba57604051630811cbcd60e01b815260040160405180910390fd5b60006001600160a01b03168582815181106109d7576109d7610e63565b60200260200101516001600160a01b031603610a065760405163d92e233d60e01b815260040160405180910390fd5b838181518110610a1857610a18610e63565b6020026020010151600003610a4057604051634572ccbf60e11b815260040160405180910390fd5b60010161090f565b506127108114610a6b5760405163174a32eb60e11b815260040160405180910390fd5b8351610a7e906003906020870190610b80565b508251610a92906004906020860190610be5565b507fdaf3393bf19500a23f26fb16a5651a6c79f5b61684cf4832ac9de30e18ab02028484604051610ac4929190610ece565b60405180910390a150505050565b8051600003610af457604051638d46fe0560e01b815260040160405180910390fd5b6005610b008282610fb9565b507f9f03e20aa3dcfb755ca419f492ab33e90abb98a7e77bafac16322662a9495f73816040516107dd9190610c7b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054828255906000526020600020908101928215610bd5579160200282015b82811115610bd557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610ba0565b50610be1929150610c20565b5090565b828054828255906000526020600020908101928215610bd5579160200282015b82811115610bd5578251825591602001919060010190610c05565b5b80821115610be15760008155600101610c21565b6000815180845260005b81811015610c5b57602081850181015186830182015201610c3f565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006108a66020830184610c35565b600060208284031215610ca057600080fd5b5035919050565b60008083601f840112610cb957600080fd5b50813567ffffffffffffffff811115610cd157600080fd5b6020830191508360208260051b8501011115610cec57600080fd5b9250929050565b60008060008060408587031215610d0957600080fd5b843567ffffffffffffffff80821115610d2157600080fd5b610d2d88838901610ca7565b90965094506020870135915080821115610d4657600080fd5b50610d5387828801610ca7565b95989497509550505050565b60008060208385031215610d7257600080fd5b823567ffffffffffffffff80821115610d8a57600080fd5b818501915085601f830112610d9e57600080fd5b813581811115610dad57600080fd5b866020828501011115610dbf57600080fd5b60209290920196919550909350505050565b600060208284031215610de357600080fd5b81356001600160a01b03811681146108a657600080fd5b600181811c90821680610e0e57607f821691505b602082108103610e2e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610e5d57610e5d610e34565b92915050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0383168152604060208201819052600090610e9d90830184610c35565b949350505050565b80820180821115610e5d57610e5d610e34565b634e487b7160e01b600052601260045260246000fd5b604080825283519082018190526000906020906060840190828701845b82811015610f105781516001600160a01b031684529284019290840190600101610eeb565b5050508381038285015284518082528583019183019060005b81811015610f4557835183529284019291840191600101610f29565b5090979650505050505050565b634e487b7160e01b600052604160045260246000fd5b601f821115610fb4576000816000526020600020601f850160051c81016020861015610f915750805b601f850160051c820191505b81811015610fb057828155600101610f9d565b5050505b505050565b815167ffffffffffffffff811115610fd357610fd3610f52565b610fe781610fe18454610dfa565b84610f68565b602080601f83116001811461101c57600084156110045750858301515b600019600386901b1c1916600185901b178555610fb0565b600085815260208120601f198616915b8281101561104b5788860151825594840194600190910190840161102c565b50858210156110695787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220f1f6ae81b18ac4f7c4c99a47e03a1c9f6b3b8a5adb70adf46304fa0c97b2212464736f6c63430008160033a264697066735822122068f8d27a1e072e7d1a26cc65acd41034a4fd842343892eae5a5d4c464c390ee764736f6c63430008160033
Verified Source Code Full Match
Compiler: v0.8.22+commit.4fc1097e
EVM: paris
Optimization: Yes (200 runs)
Factory.sol 137 lines
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2024 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.22; import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {Splitter} from "./Splitter.sol"; import {Operator} from "./Operator.sol"; /// @title Factory /// @notice Helper contract in charge of creating new Operator and Splitter contracts contract Factory is Ownable2Step { /// @notice The implementation of the Splitter contract /// @dev Used with the Clones library to create new Splitter instances Splitter public immutable IMPLEMENTATION; /// @notice The list of Operator contracts mapping(address => bool) public isOperator; /// @notice Emitted when a new Splitter is created /// @param splitter The new Splitter contract /// @param operator The Operator contract that will receive a portion of the funds /// @param owner The owner of the contract /// @param salt The salt used to create the deterministic address event NewSplitter(Splitter splitter, Operator operator, address owner, bytes32 salt); /// @notice Emitted when a new Operator is created /// @param operator The new Operator contract /// @param owner The owner of the contract /// @param operatorFee The fee that is taken on each Splitter /// @param recipients The list of recipients /// @param percents The list of percentages for each recipient event NewOperator(Operator operator, address owner, uint256 operatorFee, address[] recipients, uint256[] percents); /// @notice Emitted when the provided operator address is invalid error InvalidOperatorAddress(); /// @notice Emitted when a subcall reverts /// @param revertData The revert data error SubCallRevert(bytes revertData); /// @notice Emitted when the provided implementation address is invalid error InvalidImplementationAddress(); /// @param _owner The owner of the contract /// @param implementation The implementation of the Splitter contract constructor(address _owner, Splitter implementation) Ownable(_owner) { if (address(implementation) == address(0) || address(implementation).code.length == 0) { revert InvalidImplementationAddress(); } IMPLEMENTATION = implementation; } /// @notice Creates a new Operator contract /// @param _owner The owner of the contract /// @param _name The name of the Operator /// @param _operatorFee The fee that is taken on each Splitter /// @param _maximumOperatorFee The maximum fee that can be configured on the Operator /// @param _recipients The list of recipients, sorted in ascending order without duplicates /// @param _percents The list of percentages for each recipient function createOperator( address _owner, string calldata _name, uint256 _operatorFee, uint256 _maximumOperatorFee, address[] calldata _recipients, uint256[] calldata _percents ) external onlyOwner returns (Operator newOperator) { newOperator = new Operator(_owner, _name, _operatorFee, _maximumOperatorFee, _recipients, _percents); isOperator[address(newOperator)] = true; emit NewOperator(newOperator, _owner, _operatorFee, _recipients, _percents); } /// @notice Creates a new Splitter contract /// @param operator The Operator contract that will receive a portion of the funds /// @param salt The salt used to create the deterministic address /// @return The new Splitter contract function createSplitter(Operator operator, bytes32 salt) external returns (Splitter) { return _createSplitter(operator, salt); } /// @notice Creates a new Splitter contract and calls an address with the provided data and value /// @param operator The Operator contract that will receive a portion of the funds /// @param salt The salt used to create the deterministic address /// @param callAddress The address to call /// @param data The calldata to send /// @return newSplitter The new Splitter contract function createSplitterAndCall(Operator operator, bytes32 salt, address callAddress, bytes calldata data) external payable returns (Splitter newSplitter) { newSplitter = _createSplitter(operator, salt); (bool success, bytes memory rdata) = callAddress.call{value: msg.value}(data); if (!success) { revert SubCallRevert(rdata); } } /// @notice Predicts the address of a new Splitter contract /// @param operator The Operator contract that will receive a portion of the funds /// @param owner The owner of the contract /// @return The Splitter contract address for the given parameters function predictSplitter(Operator operator, address owner, bytes32 salt) external view returns (address) { return Clones.predictDeterministicAddress( address(IMPLEMENTATION), keccak256(abi.encodePacked(operator, owner, salt)) ); } /// @notice Internal utility function to create a new Splitter contract /// @param operator The Operator contract that will receive a portion of the funds /// @param salt The salt used to create the deterministic address /// @return newSplitter The new Splitter contract function _createSplitter(Operator operator, bytes32 salt) internal returns (Splitter newSplitter) { if (!isOperator[address(operator)]) { revert InvalidOperatorAddress(); } newSplitter = Splitter( payable( Clones.cloneDeterministic( address(IMPLEMENTATION), keccak256(abi.encodePacked(operator, msg.sender, salt)) ) ) ); newSplitter.init(operator, msg.sender); emit NewSplitter(newSplitter, operator, msg.sender, salt); } }
Operator.sol 221 lines
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2024 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.22; import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; /// @title Operator /// @notice The Operator contract is used to store a commission distribution scheme for one or several Splitter instances /// @notice It stores a list of recipients alongside their respective percentages, and a fee that is taken on each Splitter /// @notice It then handles the dispatching of the commission between the configured recipient contract Operator is Ownable2Step { /// @notice The fee that is taken on each Splitter uint256 public operatorFee; /// @notice The maximum fee that can be configured on the Operator // solhint-disable-next-line immutable-vars-naming uint256 public immutable maximumOperatorFee; /// @notice The list of recipients address[] public recipients; /// @notice The list of percentages for each recipient uint256[] public percents; /// @notice The name of the operator string public name; /// @notice The maximum value for a percentage in bps uint256 internal constant MAX_BPS = 10000; /// @notice Emitted when the recipients are updated /// @param recipients The new list of recipients /// @param percentsBps The new list of percentages event UpdatedRecipients(address[] recipients, uint256[] percentsBps); /// @notice Emitted when the operator fee is updated /// @param operatorFee The new operator fee event UpdatedOperatorFee(uint256 operatorFee); /// @notice Emitted when the operator name is updated /// @param name The new operator name event UpdatedOperatorName(string name); /// @notice Emitted when the maximum operator fee is updated /// @param maximumOperatorFee The new maximum operator fee event UpdatedMaximumOperatorFee(uint256 maximumOperatorFee); /// @notice Emitted when the commission is claimed /// @param amount The amount that was claimed event Claimed(uint256 amount); /// @notice Thrown when the provided recipient list is empty error NoRecipients(); /// @notice Thrown when the provided recipient is null error ZeroAddress(); /// @notice Thrown when the provided percent value is zero error ZeroPercentBps(); /// @notice Thrown when the transfer to a recipient fails /// @param recipient The recipient that failed to receive the funds /// @param errorData The error data returned by the transfer error RecipientTransferFailed(address recipient, bytes errorData); /// @notice Thrown when the provided recipient list is empty error EmptyRecipientArguments(); /// @notice Thrown when the provided recipient list and percentage list have different lengths error InvalidArgumentLengths(); /// @notice Thrown when the provided percentages do not sum up to 10000 error InvalidPercentSum(); /// @notice Thrown when the provided fee is invalid /// @param feeBps The provided fee error InvalidFeeBps(uint256 feeBps); /// @notice Thrown when the provided name is empty error InvalidEmptyString(); /// @notice Thrown when the provided recipients are not sorted error InvalidUnsortedRecipients(); /// @param _owner The owner of the contract /// @param _operatorFee The fee that is taken on each Splitter /// @param _recipients The list of recipients, sorted in ascending order without duplicates /// @param _percents The list of percentages for each recipient constructor( address _owner, string memory _name, uint256 _operatorFee, uint256 _maximumOperatorFee, address[] memory _recipients, uint256[] memory _percents ) Ownable(_owner) { if (_maximumOperatorFee > MAX_BPS) { revert InvalidFeeBps(_maximumOperatorFee); } maximumOperatorFee = _maximumOperatorFee; emit UpdatedMaximumOperatorFee(_maximumOperatorFee); _setOperatorFee(_operatorFee); _setRecipients(_recipients, _percents); _setName(_name); } /// @notice The receive function is used to receive ETH receive() external payable { // do nothing } /// @notice The fallback function is used to receive ETH when there is additional calldata fallback() external payable { // do nothing } /// @notice Changes the operator fee /// @param _operatorFee The new operator fee function setOperatorFee(uint256 _operatorFee) external onlyOwner { _setOperatorFee(_operatorFee); } /// @notice Changes the recipients and their respective percentages /// @param _recipients The new list of recipients, sorted in ascending order without duplicates /// @param _percents The new list of percentages function setRecipients(address[] calldata _recipients, uint256[] calldata _percents) external onlyOwner { _setRecipients(_recipients, _percents); } /// @notice Changes the operator name /// @param _name The new operator name function setName(string calldata _name) external onlyOwner { _setName(_name); } /// @notice Claims the commission for all the recipients function claim() external { uint256 balance = address(this).balance; uint256 totalSent = 0; for (uint256 i = 0; i < recipients.length - 1;) { uint256 value = Math.mulDiv(balance, percents[i], MAX_BPS); (bool success, bytes memory rdata) = recipients[i].call{value: value}(""); if (!success) { revert RecipientTransferFailed(recipients[i], rdata); } totalSent += value; unchecked { ++i; } } { (bool success, bytes memory rdata) = recipients[recipients.length - 1].call{value: balance - totalSent}(""); if (!success) { revert RecipientTransferFailed(recipients[recipients.length - 1], rdata); } } emit Claimed(balance); } /// @notice Internal utility function to set the operator fee /// @param _operatorFee The new operator fee function _setOperatorFee(uint256 _operatorFee) internal { if (_operatorFee > maximumOperatorFee) { revert InvalidFeeBps(_operatorFee); } operatorFee = _operatorFee; emit UpdatedOperatorFee(_operatorFee); } /// @notice Internal utility function to set the recipients and their respective percentages /// @param _recipients The new list of recipients, sorted in ascending order without duplicates /// @param _percentsBps The new list of percentages function _setRecipients(address[] memory _recipients, uint256[] memory _percentsBps) internal { uint256 recipientsLength = _recipients.length; if (recipientsLength == 0) { revert EmptyRecipientArguments(); } if (recipientsLength != _percentsBps.length) { revert InvalidArgumentLengths(); } uint256 totalPercentsBps = 0; for (uint256 i = 0; i < recipientsLength; ++i) { totalPercentsBps += _percentsBps[i]; if (i > 0 && uint160(_recipients[i]) <= uint160(_recipients[i - 1])) { revert InvalidUnsortedRecipients(); } if (_recipients[i] == address(0)) { revert ZeroAddress(); } if (_percentsBps[i] == 0) { revert ZeroPercentBps(); } } if (totalPercentsBps != MAX_BPS) { revert InvalidPercentSum(); } recipients = _recipients; percents = _percentsBps; emit UpdatedRecipients(_recipients, _percentsBps); } /// @notice Internal utility function to set the operator name /// @param _name The new operator name function _setName(string memory _name) internal { if (bytes(_name).length == 0) { revert InvalidEmptyString(); } name = _name; emit UpdatedOperatorName(_name); } }
Splitter.sol 142 lines
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2024 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.22; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Operator} from "./Operator.sol"; /// @title Splitter /// @notice The Splitter contract is used to directly split any funds it receives between its owner and linked Operator contract Splitter { /// @notice The Operator contract that will receive a portion of the funds Operator public operator; /// @notice The owner of the contract address public owner; /// @notice The maximum value for a percentage in bps uint256 internal constant MAX_BPS = 10000; /// @notice Emitted when the contract is configured /// @param operator The Operator contract that will receive a portion of the funds /// @param owner The owner of the contract event Configured(address indexed operator, address indexed owner); /// @notice Emitted when the received funds are split /// @param operator The operator of the contract /// @param recipient The recipient of the funds /// @param operatorAmount The amount of funds that were sent to the operator /// @param recipientAmount The amount of funds that were sent to the recipient event Split(address indexed operator, address indexed recipient, uint256 operatorAmount, uint256 recipientAmount); /// @notice Emitted when the transfer to the owner fails and we explicitly do not revert /// @param errorData The error data returned by the transfer event OwnerTransferFailureCaught(bytes errorData); /// @notice Thrown when the contract is already initialized error AlreadyInitialized(); /// @notice Thrown when the sender is not the owner /// @param sender The sender of the transaction error Unauthorized(address sender); /// @notice Thrown when the transfer to the owner fails /// @param recipient The recipient of the transfer /// @param errorData The error data returned by the transfer error OwnerTransferFailed(address recipient, bytes errorData); /// @notice Thrown when the transfer to the operator fails /// @param errorData The error data returned by the transfer error OperatorTransferFailed(bytes errorData); /// @notice Thrown when the provided address is zero error InvalidZeroAddress(); /// @notice Thrown when the provided operator address is not a contract error InvalidOperatorAddress(); /// @notice Thrown when the initialization is performed more than once modifier uninitialized() { if (address(operator) != address(0) || address(owner) != address(0)) { revert AlreadyInitialized(); } _; } constructor() { operator = Operator(payable(address(uint160(uint256(bytes32("implem initialized")))))); } /// @notice The receive function is used to receive ETH receive() external payable { _split(owner, false); } /// @notice The fallback function is used to receive ETH when there is additional calldata fallback() external payable { _split(owner, false); } /// @notice Initializes the contract /// @param _operator The Operator contract that will receive a portion of the funds /// @param _owner The owner of the contract function init(Operator _operator, address _owner) external uninitialized { if (address(_operator) == address(0) || address(_owner) == address(0)) { revert InvalidZeroAddress(); } if (address(_operator).code.length == 0) { revert InvalidOperatorAddress(); } operator = _operator; owner = _owner; emit Configured(address(_operator), _owner); } /// @notice Claims the funds from the contract function claim() external { _split(owner, true); } /// @notice Claims the funds from the contract and sends them to the provided recipient /// @param recipient The recipient of the funds function claim(address recipient) external { if (msg.sender != owner) { revert Unauthorized(msg.sender); } _split(recipient, true); } /// @notice Claims the funds from the contract and sends them to the provided recipients /// @param recipient The recipient that receives the funds for the owner function _split(address recipient, bool revertOnTransferFail) internal { uint256 balance = address(this).balance; if (balance == 0) { return; } uint256 operatorFee = operator.operatorFee(); uint256 operatorAmount = operatorFee > 0 ? Math.mulDiv(balance, operatorFee, MAX_BPS) : 0; uint256 ownerAmount = balance - operatorAmount; (bool success, bytes memory rdata) = recipient.call{value: ownerAmount}(""); if (!success) { if (revertOnTransferFail) { revert OwnerTransferFailed(recipient, rdata); } else { emit OwnerTransferFailureCaught(rdata); return; } } (success, rdata) = address(operator).call{value: operatorAmount}(""); if (!success) { revert OperatorTransferFailed(rdata); } emit Split(address(operator), recipient, operatorAmount, ownerAmount); } }
Clones.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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;
}
}
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Math.sol 415 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// 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;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// 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 + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
Ownable2Step.sol 59 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
Read Contract
IMPLEMENTATION 0x3a4741bd → address
isOperator 0x6d70f7ae → bool
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
predictSplitter 0x3f62e9b7 → address
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
createOperator 0xebe2b255
address _owner
string _name
uint256 _operatorFee
uint256 _maximumOperatorFee
address[] _recipients
uint256[] _percents
returns: address
createSplitter 0x9cbb7b0a
address operator
bytes32 salt
returns: address
createSplitterAndCall 0x608c54d4
address operator
bytes32 salt
address callAddress
bytes data
returns: address
renounceOwnership 0x715018a6
No parameters
transferOwnership 0xf2fde38b
address newOwner
Recent Transactions
No transactions found for this address