Address Contract Verified
Address
0x72a495F2FCB1Dd7625A4f03136095fe51D2A3A06
Balance
0 ETH
Nonce
1
Code Size
21400 bytes
Creator
0xf9E30Ba8...2e49 at tx 0x54f7b282...d59406
Indexed Transactions
0
Contract Bytecode
21400 bytes
0x60806040526004361061031e5760003560e01c80637c6285a1116101a5578063bbf52b15116100ec578063e403a25111610095578063ec87621c1161006f578063ec87621c1461097c578063efdcd974146109b0578063f10f537a146109d0578063fc9b5fc8146109e357600080fd5b8063e403a25114610905578063e506dfbe1461093e578063e8a353921461095e57600080fd5b8063c78b616c116100c6578063c78b616c146108b0578063d547741f146108c5578063d9ea9549146108e557600080fd5b8063bbf52b1514610850578063c291537c14610870578063c5275fb01461089057600080fd5b80639c5204711161014e578063a32fa5b311610128578063a32fa5b3146107f0578063a3c8fdd814610810578063b7792b261461083057600080fd5b80639c520471146107a8578063a217fddf146107c6578063a2d40dd5146107db57600080fd5b806391d148541161017f57806391d148541461072b5780639258d45d1461075b57806396b5a7551461078857600080fd5b80637c6285a1146106a0578063802c3a3a146106d35780638635d59b1461070b57600080fd5b80633196415611610269578063567441f81161021257806370b4768e116101ec57806370b4768e14610626578063727622a41461065357806378bd79351461067357600080fd5b8063567441f8146105b957806361b7aafe146105e657806369a74aaf1461060657600080fd5b80633c4de40f116102435780633c4de40f1461053b5780633e723fe61461057957806341896c541461059957600080fd5b806331964156146104c7578063349b5954146104e757806336568abe1461051b57600080fd5b80631fcc5b8a116102cb578063236ed8f3116102a5578063236ed8f31461045a578063248a9ca31461047a5780632f2ff15d146104a757600080fd5b80631fcc5b8a146103fa578063216fd1f51461041a578063218ddb571461043a57600080fd5b80630c0803c8116102fc5780630c0803c81461038e578063107a274a146103ae57806316002f4a146103db57600080fd5b806305013cdc1461032357806306bdf98e146103595780630858e5ad1461037b575b600080fd5b34801561032f57600080fd5b5061034361033e3660046147fb565b610a03565b6040516103509190614814565b60405180910390f35b34801561036557600080fd5b506103796103743660046148b7565b610aa3565b005b610379610389366004614902565b610abd565b34801561039a57600080fd5b506103796103a93660046147fb565b6111f0565b3480156103ba57600080fd5b506103ce6103c93660046147fb565b61122b565b6040516103509190614a51565b3480156103e757600080fd5b506005545b604051908152602001610350565b34801561040657600080fd5b50610379610415366004614a75565b611336565b34801561042657600080fd5b50610379610435366004614aa0565b611360565b34801561044657600080fd5b50610379610455366004614ad9565b6113bc565b34801561046657600080fd5b506103796104753660046147fb565b611430565b34801561048657600080fd5b506103ec6104953660046147fb565b60009081526001602052604090205490565b3480156104b357600080fd5b506103796104c2366004614afe565b6116e4565b3480156104d357600080fd5b506103796104e2366004614afe565b61177c565b3480156104f357600080fd5b506103ec7f940d6b1946ff1d2b5a9f1909219c3c81a370804b5ba0f91ec0828c99a2e6a68181565b34801561052757600080fd5b50610379610536366004614afe565b6117dd565b34801561054757600080fd5b5061056c60405180604001604052806005815260200164189718171960d91b81525081565b6040516103509190614b47565b34801561058557600080fd5b50610379610594366004614b93565b61183f565b3480156105a557600080fd5b506103796105b4366004614bd3565b611d16565b3480156105c557600080fd5b506105d96105d43660046147fb565b611f69565b6040516103509190614bf8565b3480156105f257600080fd5b506103796106013660046147fb565b61211a565b34801561061257600080fd5b506103ec610621366004614c47565b6123de565b34801561063257600080fd5b506106466106413660046147fb565b61266b565b6040516103509190614c82565b34801561065f57600080fd5b5061037961066e3660046148b7565b61278d565b34801561067f57600080fd5b5061069361068e3660046147fb565b6127a2565b6040516103509190614e0f565b3480156106ac57600080fd5b5061056c604051806040016040528060078152602001661350525393915560ca1b81525081565b3480156106df57600080fd5b506106f36106ee3660046147fb565b61291c565b6040516001600160a01b039091168152602001610350565b34801561071757600080fd5b506103436107263660046147fb565b61298d565b34801561073757600080fd5b5061074b610746366004614afe565b612a1f565b6040519015158152602001610350565b34801561076757600080fd5b5061077b6107763660046147fb565b612a4a565b6040516103509190614e1e565b34801561079457600080fd5b506103796107a33660046147fb565b612c5e565b3480156107b457600080fd5b506002546001600160a01b03166106f3565b3480156107d257600080fd5b506103ec600081565b3480156107e757600080fd5b506006546103ec565b3480156107fc57600080fd5b5061074b61080b366004614afe565b612d72565b34801561081c57600080fd5b506103ec61082b3660046147fb565b612dc4565b34801561083c57600080fd5b5061037961084b366004614e61565b612f5c565b34801561085c57600080fd5b506103ec61086b366004614e8d565b612fa7565b34801561087c57600080fd5b5061077b61088b366004614902565b6133a1565b34801561089c57600080fd5b506105d96108ab366004614902565b6135e4565b3480156108bc57600080fd5b506004546103ec565b3480156108d157600080fd5b506103796108e0366004614afe565b6137b4565b3480156108f157600080fd5b50610646610900366004614a75565b6137cd565b34801561091157600080fd5b5061074b610920366004614a75565b6001600160a01b031660009081526010602052604090205460ff1690565b34801561094a57600080fd5b506106f36109593660046147fb565b6138f3565b34801561096a57600080fd5b506003546001600160a01b03166106f3565b34801561098857600080fd5b506103ec7f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0881565b3480156109bc57600080fd5b506103796109cb366004614a75565b613964565b6103796109de366004614ec9565b61398e565b3480156109ef57600080fd5b506103796109fe366004614afe565b613e79565b60008181527f17bc176d2408558f6e4111feebc3cab4e16b63e967be91cde721f4c8a488b55260209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a98576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610a50565b505050509050919050565b610aab613eda565b610ab86001848484613f39565b505050565b6000828152600b6020908152604080832081516101008101909252805466ffffffffffffff811683529192909190830190600160381b900460ff166003811115610b0957610b09614cfd565b6003811115610b1a57610b1a614cfd565b8152815463ffffffff600160401b820481166020840152600160601b82041660408301526001600160401b03600160801b820481166060840152600160c01b909104166080820152600182015460a082015260029091015460c0909101529050600081602001516003811115610b9257610b92614cfd565b03610bb05760405163e6759c6760e01b815260040160405180910390fd5b600181602001516003811115610bc857610bc8614cfd565b14610be6576040516334dc687f60e11b815260040160405180910390fd5b806040015163ffffffff16421015610c2a57604080820151905163ad4db47b60e01b815263ffffffff90911660048201524260248201526044015b60405180910390fd5b42816060015163ffffffff161015610c555760405163dda144a560e01b815260040160405180910390fd5b81600003610c7657604051630d5a8f9960e11b815260040160405180910390fd5b8060c00151821015610cab5760c081015160405163013542db60e31b8152610c21918491600401918252602082015260400190565b348214610cd4576040516334cb937b60e21b815260048101839052346024820152604401610c21565b6000838152600e60205260409020548015610e44576000848152600e602052604081206001908101908290610d099085614f1c565b8152602080820192909252604090810160002081516080808201845282546001600160401b038082168452600160401b820463ffffffff1696840196909652600160601b90046001600160a01b031693820193909352600190910154606082018190529186015190935061271092168102919091040180851015610daa57604051631711707760e31b81526004810186905260248101829052604401610c21565b50600081604001516001600160a01b0316826060015160405160006040518083038185875af1925050503d8060008114610e00576040519150601f19603f3d011682016040523d82523d6000602084013e610e05565b606091505b5050905080610e2757604051634412abcb60e01b815260040160405180910390fd5b6000868152600e60205260409020548314610e4157600080fd5b50505b600e6000858152602001908152602001600020600001600081546001019190508190555060006040518060800160405280866001600160401b031681526020014263ffffffff168152602001336001600160a01b0316815260200185815250905080600e6000878152602001908152602001600020600101600084815260200190815260200160002060008201518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555060208201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550604082015181600001600c6101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600101559050506000600f6000336001600160a01b03166001600160a01b03168152602001908152602001600020600001600081548092919060010191905055905081600f6000336001600160a01b03166001600160a01b03168152602001908152602001600020600101600083815260200190815260200160002060008201518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555060208201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550604082015181600001600c6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060608201518160010155905050508260a001516001600160401b031642846060015163ffffffff166110839190614f1c565b116111a65760a083015160608401805190910163ffffffff1690526000858152600b602090815260409091208451815466ffffffffffffff19811666ffffffffffffff90921691821783559286015186939091839167ffffffffffffffff191617600160381b8360038111156110fb576110fb614cfd565b0217905550604082015181546060840151608085015160a08601516fffffffffffffffff000000000000000019909316600160401b63ffffffff9586160263ffffffff60601b191617600160601b9490921693909302176fffffffffffffffffffffffffffffffff16600160801b6001600160401b03938416026001600160c01b031617600160c01b929091169190910217815560c0820151600182015560e0909101516002909101555b83336001600160a01b0316867f81b76daaaa20e11a350a2cbf4c8e7c229b6b0bb852585e708b3f6ca5dc250466866040516111e19190614f2f565b60405180910390a45050505050565b6111f8613eda565b612710811115611226576040516372d6a00960e01b8152612710600482015260248101829052604401610c21565b600655565b6112336146a4565b506040805180820182528281526000928352600760209081529282902082516101c081018452815462ffffff8116825260ff63010000008204168287015263ffffffff640100000000820481169583019590955261ffff600160401b820481166060840152600160501b80830482166080850152600160601b8304821660a08501526001600160501b03600160701b93849004811660c086015260019095015494851660e0850152840486166101008401529083048516610120830152600160901b8304909416610140820152600160b01b82048416610160820152600160c01b82048416610180820152600160d01b9091049092166101a08301529182015290565b61133e613eda565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6113686140e9565b6001600160a01b038216600081815260106020526040808220805460ff191685151590811790915590519092917f215f66273fb517a22736277e280b3ea8a0b7db6ed54f2edb25b1cbd87e3c28ca91a35050565b6113c4613eda565b806113d05760006113d3565b60015b600083815260076020526040808220805460ff9490941663010000000263ff000000199094169390931790925590518215159184917f3f3590113b880e5ffacda884287cb609f87652a7522ba040e52d072f9179e9b09190a35050565b611438613eda565b6000818152600b60205260408120908154600160381b900460ff16600381111561146457611464614cfd565b036114825760405163e6759c6760e01b815260040160405180910390fd5b60018154600160381b900460ff1660038111156114a1576114a1614cfd565b146114bf576040516334dc687f60e11b815260040160405180910390fd5b8054600160601b900463ffffffff164210156115055780546040516336cc6d4f60e21b8152600160601b90910463ffffffff166004820152426024820152604401610c21565b6000828152600e602052604081205490819003611535576040516359a67b3d60e01b815260040160405180910390fd5b6000838152600e6020526040812060019081019082906115559085614f1c565b81526020808201929092526040908101600020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b03169183019190915260010154606082018190526002850154919250106115ee5760608101516002840154604051637e4b9d7d60e01b815260048101929092526024820152604401610c21565b825460ff60381b1916670200000000000000178355604081810151606083015191516000926001600160a01b0390921691908381818185875af1925050503d8060008114611658576040519150601f19603f3d011682016040523d82523d6000602084013e61165d565b606091505b505090508061167f57604051634412abcb60e01b815260040160405180910390fd5b6060828101516040808501518754825166ffffffffffffff90911681526000602082015260019281019290925291926001600160a01b039092169188917f46b848163e03f83edace353ba36892b6d49697bebcbe7aea9f837c69cd58514791016111e1565b6000828152600160205260409020546116fd9033614145565b6000828152602081815260408083206001600160a01b038516845290915290205460ff161561176e5760405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c79206772616e7420746f206e6f6e20686f6c646572730000006044820152606401610c21565b61177882826141c3565b5050565b611784613eda565b60008281526009602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f7bda5ebb0c6f5079561a878d9b8fa1fd8e2443210022b1e25de894fea02509479190a35050565b336001600160a01b038216146118355760405162461bcd60e51b815260206004820152601a60248201527f43616e206f6e6c792072656e6f756e636520666f722073656c660000000000006044820152606401610c21565b611778828261421c565b611847613eda565b60008281526007602052604081208054909162ffffff909116900361187f576040516335aacf6560e11b815260040160405180910390fd5b61189161012083016101008401614f3e565b63ffffffff166118a961014084016101208501614f3e565b63ffffffff161015611902576118c761012083016101008401614f3e565b6118d961014084016101208501614f3e565b6040516322e2aba560e21b815263ffffffff928316600482015291166024820152604401610c21565b61191461014083016101208401614f3e565b63ffffffff1661192b610100840160e08501614f3e565b63ffffffff16116119825761194861014083016101208401614f3e565b611959610100840160e08501614f3e565b604051637a423a8560e01b815263ffffffff928316600482015291166024820152604401610c21565b6119926060830160408401614f64565b61ffff166119a66040840160208501614f64565b61ffff1610156119f7576119c06060830160408401614f64565b6119d06040840160208501614f64565b604051635789d79160e11b815261ffff928316600482015291166024820152604401610c21565b6001810154600160c01b810461ffff908116600160d01b9092048116919091011680611a296040850160208601614f64565b61ffff161015611a6a57611a436040840160208501614f64565b60405163721750bd60e11b815261ffff909116600482015260248101829052604401610c21565b6001820154600160b01b900461ffff16611a8a6060850160408601614f64565b61ffff161015611ad957611aa46060840160408501614f64565b600183015460405163db50aaff60e01b815261ffff9283166004820152600160b01b9091049091166024820152604401610c21565b50611aec61016083016101408401614f88565b611af7576000611afa565b60015b815460ff9190911663010000000263ff00000019909116178155611b246040830160208401614f64565b815467ffffffff00000000191661ffff9190911664010000000002178155611b526060830160408401614f64565b815461ffff91909116600160401b0261ffff60401b19909116178155611b7e6080830160608401614f64565b815461ffff91909116600160501b0261ffff60501b19909116178155611baa60a0830160808401614f64565b815461ffff91909116600160601b0261ffff60601b19909116178155611bd660c0830160a08401614fa5565b81546001600160501b0391909116600160701b0269ffffffffffffffffffff60701b19909116178155611c0f60e0830160c08401614fa5565b60018201805469ffffffffffffffffffff19166001600160501b0392909216919091179055611c45610100830160e08401614f3e565b60018201805463ffffffff92909216600160501b0263ffffffff60501b19909216919091179055611c7e61012083016101008401614f3e565b60018201805463ffffffff92909216600160701b0263ffffffff60701b19909216919091179055611cb761014083016101208401614f3e565b8160010160126101000a81548163ffffffff021916908363ffffffff160217905550827f27354bd467af48a70cfd84dc6c228d49719c9b2848acfa604e818852c9cc517482604051611d099190614fce565b60405180910390a2505050565b611d1e613eda565b6000828152600b60205260408120908154600160381b900460ff166003811115611d4a57611d4a614cfd565b03611d685760405163e6759c6760e01b815260040160405180910390fd5b60018154600160381b900460ff166003811115611d8757611d87614cfd565b14611da5576040516334dc687f60e11b815260040160405180910390fd5b611db56040830160208401614f3e565b63ffffffff16611dcb6060840160408501614f3e565b63ffffffff1611611e1f57611de66040830160208401614f3e565b611df66060840160408501614f3e565b6040516377acf3f160e11b815263ffffffff928316600482015291166024820152604401610c21565b611e2f60808301606084016150e5565b6001600160401b03166127101015611e5a57604051631594b46760e21b815260040160405180910390fd5b611e6a6040830160208401614f3e565b815463ffffffff91909116600160401b0263ffffffff60401b19909116178155611e9a6060830160408401614f3e565b815463ffffffff91909116600160601b0263ffffffff60601b19909116178155611eca60808301606084016150e5565b81546001600160401b0391909116600160801b0267ffffffffffffffff60801b19909116178155611f0160a08301608084016150e5565b81546001600160401b0391909116600160c01b026001600160c01b0390911617815560a0820135600182015560c0820135600282015560405183907f719a0c86470e9c93a183ded6bca73369f7e28afe0beec0a19f90763aae17323b90611d0990849061510e565b6000818152600860205260409020805460609190806001600160401b03811115611f9557611f956151a0565b604051908082528060200260200182016040528015611fce57816020015b611fbb6146a4565b815260200190600190039081611fb35790505b50925060005b818110156121125760008181526001808501602090815260408084205481518083018352818152818652600784529482902082516101c081018452815462ffffff8116825260ff63010000008204168287015263ffffffff640100000000820481169583019590955261ffff600160401b820481166060840152600160501b80830482166080850152600160601b8304821660a08501526001600160501b03600160701b93849004811660c0860152949098015493841660e0840152968304851661010083015282048416610120820152600160901b8204909316610140840152600160b01b81048516610160840152600160c01b81048516610180840152600160d01b90049093166101a08201529083015285519091908690849081106120fe576120fe6151b6565b602090810291909101015250600101611fd4565b505050919050565b6000818152600b60205260408120908154600160381b900460ff16600381111561214657612146614cfd565b036121645760405163e6759c6760e01b815260040160405180910390fd5b60018154600160381b900460ff16600381111561218357612183614cfd565b146121a1576040516334dc687f60e11b815260040160405180910390fd5b8054600160601b900463ffffffff164210156121e75780546040516336cc6d4f60e21b8152600160601b90910463ffffffff166004820152426024820152604401610c21565b6000828152600e602052604081205490819003612217576040516359a67b3d60e01b815260040160405180910390fd5b6000838152600e6020526040812060019081019082906122379085614f1c565b81526020808201929092526040908101600020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b0316918301919091526001015460608201819052600285015491925010156122d15760608101516002840154604051635cf8b88960e11b815260048101929092526024820152604401610c21565b825460ff60381b19166702000000000000001783556122ef846138f3565b604082810151855491516308934a5f60e31b81526001600160a01b03918216600482015266ffffffffffffff9092166024830152919091169063449a52f890604401600060405180830381600087803b15801561234b57600080fd5b505af115801561235f573d6000803e3d6000fd5b50505050612373600185836060015161427c565b6060818101516040808401518654825166ffffffffffffff909116815260016020820152600081840152915192936001600160a01b039091169288927f46b848163e03f83edace353ba36892b6d49697bebcbe7aea9f837c69cd58514792908290030190a450505050565b60006123e8613eda565b5060058054600101908190556000818152600b60209081526040918290209161241691908701908701614f3e565b63ffffffff1661242c6060870160408801614f3e565b63ffffffff1611612457576124476040860160208701614f3e565b611df66060870160408801614f3e565b61246760808601606087016150e5565b6001600160401b0316612710101561249257604051631594b46760e21b815260040160405180910390fd5b61249f60208601866151cc565b815466ffffffffffffff9190911667ffffffffffffffff1990911617600160381b1781556124d36040860160208701614f3e565b815463ffffffff91909116600160401b0263ffffffff60401b199091161781556125036060860160408701614f3e565b815463ffffffff91909116600160601b0263ffffffff60601b1990911617815561253360808601606087016150e5565b81546001600160401b0391909116600160801b0267ffffffffffffffff60801b1990911617815561256a60a08601608087016150e5565b81546001600160401b0391909116600160c01b026001600160c01b0390911617815560a0850135600182015560c085013560028201556000600c816125b260208901896151cc565b66ffffffffffffff168152602080820192909252604001600090812080546001810190915592508491600c91906125eb908a018a6151cc565b66ffffffffffffff16815260208082019290925260409081016000908120948152600190940190915290912055821561262b5761262b6001838686613f39565b817f6ecb6e63f6645ff9293c33fc77c67f1bc05beff9ff71806d5c759647b3d2d4028260405161265b919061510e565b60405180910390a2509392505050565b6000818152600e6020526040902054606090806001600160401b03811115612695576126956151a0565b6040519080825280602002602001820160405280156126e757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816126b35790505b50915060005b81811015612786576000848152600e602090815260408083208484526001908101835292819020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b0316918301919091529091015460608201528351849083908110612773576127736151b6565b60209081029190910101526001016126ed565b5050919050565b612795613eda565b610ab86000848484613f39565b6127aa614728565b6000828152600e60209081526040808320548151606081018352868152868552600b84529382902082516101008101909352805466ffffffffffffff81168452919493848101939290830190600160381b900460ff16600381111561281157612811614cfd565b600381111561282257612822614cfd565b8152815463ffffffff600160401b82048116602080850191909152600160601b83049091166040808501919091526001600160401b03600160801b840481166060860152600160c01b909304909216608084015260018085015460a085015260029094015460c0909301929092529284526000888152600e82529283209301920190846128b05760006128b5565b600185035b81526020808201929092526040908101600020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b03169183019190915260010154606082015290529392505050565b6000818152600960205260408120546001600160a01b03166129715750506000805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b546001600160a01b031690565b506000908152600960205260409020546001600160a01b031690565b60008181527f4ad3b33220dddc71b994a52d72c06b10862965f7d926534c05c00fb7e819e7b760209081526040808320805482518185028101850190935280835260609492939192909184018215610a98576000848152602090819020604080518082019091526002850290910180546001600160a01b03168252600190810154828401529083529092019101610a50565b6000828152602081815260408083206001600160a01b038516845290915290205460ff165b92915050565b6000818152600c60205260409020805460609190806001600160401b03811115612a7657612a766151a0565b604051908082528060200260200182016040528015612aaf57816020015b612a9c614728565b815260200190600190039081612a945790505b50925060005b81811015612112576000818152600184016020908152604080832054600e8352818420548251606081018452828152828652600b85529483902083516101008101909452805466ffffffffffffff81168552929591949193848301939092830190600160381b900460ff166003811115612b3157612b31614cfd565b6003811115612b4257612b42614cfd565b8152815463ffffffff600160401b82048116602080850191909152600160601b83049091166040808501919091526001600160401b03600160801b840481166060860152600160c01b909304909216608084015260018085015460a085015260029094015460c0909301929092529284526000878152600e8252928320930192019084612bd0576000612bd5565b600185035b81526020808201929092526040908101600020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b03169183019190915260010154606082015290528651879085908110612c4957612c496151b6565b60209081029190910101525050600101612ab5565b612c66613eda565b6000818152600b60205260408120908154600160381b900460ff166003811115612c9257612c92614cfd565b03612cb05760405163e6759c6760e01b815260040160405180910390fd5b60018154600160381b900460ff166003811115612ccf57612ccf614cfd565b14612ced576040516334dc687f60e11b815260040160405180910390fd5b6000828152600e602052604090205415612d2e576000828152600e602052604090819020549051636761e76160e11b81526004810191909152602401610c21565b805460ff60381b191667030000000000000017815560405182907f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df90600090a25050565b60008281526020818152604080832083805290915281205460ff16612dbb57506000828152602081815260408083206001600160a01b038516845290915290205460ff16612a44565b50600192915050565b6000818152600b6020908152604080832081516101008101909252805466ffffffffffffff811683528493830190600160381b900460ff166003811115612e0d57612e0d614cfd565b6003811115612e1e57612e1e614cfd565b8152815463ffffffff600160401b820481166020840152600160601b82041660408301526001600160401b03600160801b820481166060840152600160c01b909104166080820152600182015460a082015260029091015460c0909101529050600081602001516003811115612e9657612e96614cfd565b03612eb45760405163e6759c6760e01b815260040160405180910390fd5b6000838152600e60205260409020548015612f51576000938452600e60209081526040808620600019939093018652600192830182529485902085516080808201885282546001600160401b038082168452600160401b820463ffffffff1695840195909552600160601b90046001600160a01b031697820197909752920154606090920182905291909301516127109116830204909101919050565b5060c0015192915050565b612f646140e9565b6001600160a01b03821660009081526010602052604090205460ff16612f9d5760405163b13347ad60e01b815260040160405180910390fd5b611778828261438e565b6000612fb1613eda565b5060048054600101908190556000818152600760205260409020612fdd61012086016101008701614f3e565b63ffffffff16612ff561014087016101208801614f3e565b63ffffffff1610156130255761301361012086016101008701614f3e565b6118d961014087016101208801614f3e565b61303761014086016101208701614f3e565b63ffffffff1661304e610100870160e08801614f3e565b63ffffffff161161307c5761306b61014086016101208701614f3e565b611959610100870160e08801614f3e565b61308c6060860160408701614f64565b61ffff166130a06040870160208801614f64565b61ffff1610156130ca576130ba6060860160408701614f64565b6119d06040870160208801614f64565b6130d760208601866151f5565b815462ffffff191662ffffff919091161781556130fc61016086016101408701614f88565b61310757600061310a565b60015b815460ff9190911663010000000263ff000000199091161781556131346040860160208701614f64565b815467ffffffff00000000191661ffff91909116640100000000021781556131626060860160408701614f64565b815461ffff91909116600160401b0261ffff60401b1990911617815561318e6080860160608701614f64565b815461ffff91909116600160501b0261ffff60501b199091161781556131ba60a0860160808701614f64565b815461ffff91909116600160601b0261ffff60601b199091161781556131e660c0860160a08701614fa5565b81546001600160501b0391909116600160701b0269ffffffffffffffffffff60701b1990911617815561321f60e0860160c08701614fa5565b60018201805469ffffffffffffffffffff19166001600160501b0392909216919091179055613255610100860160e08701614f3e565b60018201805463ffffffff92909216600160501b0263ffffffff60501b1990921691909117905561328e61012086016101008701614f3e565b60018201805463ffffffff92909216600160701b0263ffffffff60701b199092169190911790556132c761014086016101208701614f3e565b60018201805463ffffffff92909216600160901b0263ffffffff60901b19909216919091179055600060088161330060208901896151f5565b62ffffff16815260208082019290925260400160009081208054600181019091559250849160089190613335908a018a6151f5565b62ffffff168152602080820192909252604090810160009081209481526001909401909152909120558215613371576133716000838686613f39565b817fc94c0cbf25d6fd3a743d867ba1108f4a8a84dec0254eb483d2e66652b712f4f48260405161265b9190614fce565b60608215806133af57508282105b156133cd576040516304d8557760e31b815260040160405180910390fd5b600060055483116133de57826133e2565b6005545b60010190508381036001600160401b03811115613401576134016151a0565b60405190808252806020026020018201604052801561343a57816020015b613427614728565b81526020019060019003908161341f5790505b509150835b818110156135dc576000818152600e60209081526040808320548151606081018352858152858552600b84529382902082516101008101909352805466ffffffffffffff81168452919493848101939290830190600160381b900460ff1660038111156134ae576134ae614cfd565b60038111156134bf576134bf614cfd565b8152815463ffffffff600160401b82048116602080850191909152600160601b83049091166040808501919091526001600160401b03600160801b840481166060860152600160c01b909304909216608084015260018085015460a085015260029094015460c0909301929092529284526000878152600e825292832093019201908461354d576000613552565b600185035b81526020808201929092526040908101600020815160808101835281546001600160401b0381168252600160401b810463ffffffff1694820194909452600160601b9093046001600160a01b0316918301919091526001015460608201529052845185908885039081106135c8576135c86151b6565b60209081029190910101525060010161343f565b505092915050565b60608215806135f257508282105b15613610576040516313e95aa760e21b815260040160405180910390fd5b600060045483116136215782613625565b6004545b60010190508381036001600160401b03811115613644576136446151a0565b60405190808252806020026020018201604052801561367d57816020015b61366a6146a4565b8152602001906001900390816136625790505b509150835b818110156135dc576040805180820182528281526000838152600760209081529083902083516101c081018552815462ffffff8116825260ff63010000008204168285015263ffffffff640100000000820481169683019690965261ffff600160401b820481166060840152600160501b80830482166080850152600160601b8304821660a08501526001600160501b03600160701b93849004811660c086015260019095015494851660e0850152840487166101008401529083048616610120830152600160901b8304909516610140820152600160b01b82048516610160820152600160c01b82048516610180820152600160d01b9091049093166101a0840152810191909152835184908784039081106137a1576137a16151b6565b6020908102919091010152600101613682565b6000828152600160205260409020546118359033614145565b6001600160a01b0381166000908152600f6020526040902054606090806001600160401b03811115613801576138016151a0565b60405190808252806020026020018201604052801561385357816020015b60408051608081018252600080825260208083018290529282018190526060820152825260001990920191018161381f5790505b50915060005b81811015612786576001600160a01b038085166000908152600f602090815260408083208584526001908101835292819020815160808101835281546001600160401b038116825263ffffffff600160401b82041694820194909452600160601b90930490941690820152910154606082015283518490839081106138e0576138e06151b6565b6020908102919091010152600101613859565b6000818152600d60205260408120546001600160a01b031661394857505060008052600d6020527f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ee546001600160a01b031690565b506000908152600d60205260409020546001600160a01b031690565b61396c613eda565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60008481526007602052604081208054909162ffffff90911690036139c6576040516335aacf6560e11b815260040160405180910390fd5b80546301000000900460ff166000036139f257604051635acda82f60e01b815260040160405180910390fd5b348214613a1b57604051631162ee2d60e21b815260048101839052346024820152604401610c21565b600181015442600160501b90910463ffffffff161015613a4e576040516389d4186960e01b815260040160405180910390fd5b60018101548154600160c01b820461ffff908116600160d01b90930481169290920190911663ffffffff6401000000009092048216031683811015613ab057604051630d27c2b960e41b81526004810185905260248101829052604401610c21565b506000858152600a60209081526040808320338452909152812054613ad690859061521a565b9050613ae28633614469565b15613c7a576001820154600160701b900463ffffffff16421015613b33576001820154604051637283b3fb60e01b8152600160701b90910463ffffffff166004820152426024820152604401610c21565b8154600160501b900461ffff16811115613b76578154604051632fda893760e21b815260048101839052600160501b90910461ffff166024820152604401610c21565b8154600090613b96908690600160701b90046001600160501b031661522d565b9050838114613bc257604051630bf76b4560e41b81526004810185905260248101829052604401610c21565b6001830154600160901b900463ffffffff16421015613c4e576001830154835461ffff600160b01b9092048216600160401b9091048216031685811015613c2657604051631386b05760e01b81526004810187905260248101829052604401610c21565b5060018301805461ffff600160b01b808304821689019091160261ffff60b01b199091161790555b5060018201805461ffff600160c01b808304821688019091160261ffff60c01b19909116179055613d79565b6001820154600160901b900463ffffffff16421015613cc65760018201546040516381c5e80b60e01b8152600160901b90910463ffffffff166004820152426024820152604401610c21565b8154600160601b900461ffff16811115613d0957815460405163180da9c560e31b815260048101839052600160601b90910461ffff166024820152604401610c21565b6001820154600090613d259086906001600160501b031661522d565b9050838114613d51576040516396e80d5560e01b81526004810185905260248101829052604401610c21565b5060018201805461ffff600160d01b808304821688019091160261ffff60d01b199091161790555b6000868152600a602090815260408083203384529091529020819055613d9e8661291c565b8254604051632c7ef07760e01b81526001600160a01b03888116600483015262ffffff909216602482015260448101879052911690632c7ef07790606401600060405180830381600087803b158015613df657600080fd5b505af1158015613e0a573d6000803e3d6000fd5b50505050613e1a6000878561427c565b81546040805162ffffff90921682526020820186905281018490526001600160a01b03861690339088907f964be453e8b19c8fc2d856baaaeb5c6db9607b1f52fdff3f0a1e6cef6ac3bd019060600160405180910390a4505050505050565b613e81613eda565b6000828152600d602052604080822080546001600160a01b0319166001600160a01b0385169081179091559051909184917f8829ff1f8d6f20e53e317d9e72d94b852e0d669afb69b39a2b7d1923da57f5c09190a35050565b613ee5600033612a1f565b158015613f195750613f177f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0833612a1f565b155b15613f37576040516349349c6360e11b815260040160405180910390fd5b565b60008481526011602090815260408083208684529091528120613f5b916147ad565b60008060005b838110156140705760008781526011602090815260408083208984529091529020858583818110613f9457613f946151b6565b835460018101855560009485526020909420604090910292909201926002029091019050613fc28282615244565b50506003546001600160a01b0316858583818110613fe257613fe26151b6565b613ff89260206040909202019081019150614a75565b6001600160a01b03160361403457848482818110614018576140186151b6565b905060400201602001358261402d919061521a565b915061405e565b848482818110614046576140466151b6565b905060400201602001358361405b919061521a565b92505b806140688161527e565b915050613f61565b5060065482111561409757604051632060c15360e11b815260048101839052602401610c21565b6127106140a4828461521a565b11156140e1576127106140b7828461521a565b6040516372d6a00960e01b81526001600160401b0390921660048301526024820152604401610c21565b505050505050565b6140f4600033612a1f565b15801561412857506141267f940d6b1946ff1d2b5a9f1909219c3c81a370804b5ba0f91ec0828c99a2e6a68133612a1f565b155b15613f375760405162afd36160e01b815260040160405180910390fd5b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661177857614181816001600160a01b03166014614502565b61418c836020614502565b60405160200161419d929190615297565b60408051601f198184030181529082905262461bcd60e51b8252610c2191600401614b47565b6000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6142268282614145565b6000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000838152601160209081526040808320858452825280832080548251818502810185019093528083529192909190849084015b828210156142f8576000848152602090819020604080518082019091526002850290910180546001600160a01b031682526001908101548284015290835290920191016142b0565b50505050905060005b81518110156143875760006127106001600160401b031683838151811061432a5761432a6151b6565b60200260200101516020015185614341919061522d565b61434b919061530c565b9050614374838381518110614362576143626151b6565b6020026020010151600001518261438e565b508061437f8161527e565b915050614301565b5050505050565b804710156143b857604051635f938ce560e11b815260048101829052476024820152604401610c21565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614405576040519150601f19603f3d011682016040523d82523d6000602084013e61440a565b606091505b505090508061442c5760405163df108a3b60e01b815260040160405180910390fd5b60405182906001600160a01b0385169033907fd1b078762514fc24641f0f647e92ba3f15f4cb8e732e84ce1d2686f15542837190600090a4505050565b6002546000906001600160a01b0316156144f957600254604051636c096c6d60e11b8152600481018590526001600160a01b0384811660248301529091169063d812d8da90604401602060405180830381865afa1580156144ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144f2919061532e565b9050612a44565b50600092915050565b6060600061451183600261522d565b61451c90600261521a565b6001600160401b03811115614533576145336151a0565b6040519080825280601f01601f19166020018201604052801561455d576020820181803683370190505b509050600360fc1b81600081518110614578576145786151b6565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106145a7576145a76151b6565b60200101906001600160f81b031916908160001a90535060006145cb84600261522d565b6145d690600161521a565b90505b600181111561464e576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061460a5761460a6151b6565b1a60f81b828281518110614620576146206151b6565b60200101906001600160f81b031916908160001a90535060049490941c936146478161534b565b90506145d9565b50831561469d5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610c21565b9392505050565b604080518082018252600080825282516101c0810184528181526020818101839052938101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a0810191909152909182015290565b60405180606001604052806000815260200161478360408051610100810190915260008082526020820190815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b81526040805160808101825260008082526020828101829052928201819052606082015291015290565b50805460008255600202906000526020600020908101906147ce91906147d1565b50565b5b808211156147f75780546001600160a01b0319168155600060018201556002016147d2565b5090565b60006020828403121561480d57600080fd5b5035919050565b602080825282518282018190526000919060409081850190868401855b8281101561485f57815180516001600160a01b03168552860151868501529284019290850190600101614831565b5091979650505050505050565b60008083601f84011261487e57600080fd5b5081356001600160401b0381111561489557600080fd5b6020830191508360208260061b85010111156148b057600080fd5b9250929050565b6000806000604084860312156148cc57600080fd5b8335925060208401356001600160401b038111156148e957600080fd5b6148f58682870161486c565b9497909650939450505050565b6000806040838503121561491557600080fd5b50508035926020909101359150565b80518252602081015161493f60208401825162ffffff169052565b602081015160ff8116604085015250604081015163ffffffff8116606085015250606081015161ffff8116608085015250608081015161ffff811660a08501525060a081015161ffff811660c08501525060c08101516001600160501b03811660e08501525060e08101516101006149c1818601836001600160501b03169052565b82015190506101206149da8582018363ffffffff169052565b82015190506101406149f38582018363ffffffff169052565b8201519050610160614a0c8582018363ffffffff169052565b8201519050610180614a238582018361ffff169052565b82015190506101a0614a3a8582018361ffff169052565b919091015161ffff81166101c08501529050505050565b6101e08101612a448284614924565b6001600160a01b03811681146147ce57600080fd5b600060208284031215614a8757600080fd5b813561469d81614a60565b80151581146147ce57600080fd5b60008060408385031215614ab357600080fd5b8235614abe81614a60565b91506020830135614ace81614a92565b809150509250929050565b60008060408385031215614aec57600080fd5b823591506020830135614ace81614a92565b60008060408385031215614b1157600080fd5b823591506020830135614ace81614a60565b60005b83811015614b3e578181015183820152602001614b26565b50506000910152565b6020815260008251806020840152614b66816040850160208701614b23565b601f01601f19169190910160400192915050565b60006101608284031215614b8d57600080fd5b50919050565b6000806101808385031215614ba757600080fd5b82359150614bb88460208501614b7a565b90509250929050565b600060e08284031215614b8d57600080fd5b6000806101008385031215614be757600080fd5b82359150614bb88460208501614bc1565b6020808252825182820181905260009190848201906040850190845b81811015614c3b57614c27838551614924565b928401926101e09290920191600101614c14565b50909695505050505050565b60008060006101008486031215614c5d57600080fd5b614c678585614bc1565b925060e08401356001600160401b038111156148e957600080fd5b6020808252825182820181905260009190848201906040850190845b81811015614c3b57614cea8385516001600160401b03815116825263ffffffff60208201511660208301526001600160a01b036040820151166040830152606081015160608301525050565b9284019260809290920191600101614c9e565b634e487b7160e01b600052602160045260246000fd5b60048110614d3157634e487b7160e01b600052602160045260246000fd5b9052565b66ffffffffffffff81511682526020810151614d546020840182614d13565b50604081015163ffffffff8082166040850152806060840151166060850152505060808101516001600160401b0380821660808501528060a08401511660a0850152505060c081015160c083015260e081015160e08301525050565b805182526020810151614dc66020840182614d35565b5060409081015180516001600160401b0316610120840152602081015163ffffffff16610140840152908101516001600160a01b03166101608301526060015161018090910152565b6101a08101612a448284614db0565b6020808252825182820181905260009190848201906040850190845b81811015614c3b57614e4d838551614db0565b928401926101a09290920191600101614e3a565b60008060408385031215614e7457600080fd5b8235614e7f81614a60565b946020939093013593505050565b60008060006101808486031215614ea357600080fd5b614ead8585614b7a565b92506101608401356001600160401b038111156148e957600080fd5b60008060008060808587031215614edf57600080fd5b843593506020850135614ef181614a60565b93969395505050506040820135916060013590565b634e487b7160e01b600052601160045260246000fd5b81810381811115612a4457612a44614f06565b6101008101612a448284614d35565b600060208284031215614f5057600080fd5b813563ffffffff8116811461469d57600080fd5b600060208284031215614f7657600080fd5b813561ffff8116811461469d57600080fd5b600060208284031215614f9a57600080fd5b813561469d81614a92565b600060208284031215614fb757600080fd5b81356001600160501b038116811461469d57600080fd5b815462ffffff811682526101c0820190601881901c60ff16602084015263ffffffff602082901c8116604085015261ffff604083901c8116606086015261502060808601828560501c1661ffff169052565b61503560a08601828560601c1661ffff169052565b6001600160501b0360709390931c831660c0860152600186015492831660e0860152605083901c821663ffffffff166101008601526150826101208601838560701c1663ffffffff169052565b61509a6101408601838560901c1663ffffffff169052565b6150b06101608601828560b01c1661ffff169052565b6150c66101808601828560c01c1661ffff169052565b6150dc6101a08601828560d01c1661ffff169052565b50505092915050565b6000602082840312156150f757600080fd5b81356001600160401b038116811461469d57600080fd5b815466ffffffffffffff8116825261010082019061513660208401603883901c60ff16614d13565b63ffffffff61515260408501828460401c1663ffffffff169052565b61516960608501828460601c1663ffffffff169052565b50608081811c6001600160401b03169084015260c081901c60a084015250600183015460c083015260029092015460e09091015290565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000602082840312156151de57600080fd5b813566ffffffffffffff8116811461469d57600080fd5b60006020828403121561520757600080fd5b813562ffffff8116811461469d57600080fd5b80820180821115612a4457612a44614f06565b8082028115828204841417612a4457612a44614f06565b813561524f81614a60565b6001600160a01b0381166bffffffffffffffffffffffff60a01b83541617825550602082013560018201555050565b60006001820161529057615290614f06565b5060010190565b7f5065726d697373696f6e733a206163636f756e742000000000000000000000008152600083516152cf816015850160208801614b23565b7001034b99036b4b9b9b4b733903937b6329607d1b6015918401918201528351615300816026840160208801614b23565b01602601949350505050565b60008261532957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561534057600080fd5b815161469d81614a92565b60008161535a5761535a614f06565b50600019019056fea2646970667358221220b79279b341608ba1feeb3f672ebdbf57b3b6a03b88e66bfbcfe18fbe4304a28f64736f6c63430008140033
Verified Source Code Full Match
Compiler: v0.8.20+commit.a1b79de6
EVM: paris
Optimization: Yes (300 runs)
IPermissions.sol 88 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IPermissions {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
Permissions.sol 168 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "./interface/IPermissions.sol";
import "../lib/TWStrings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
contract Permissions is IPermissions {
/// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
mapping(bytes32 => mapping(address => bool)) private _hasRole;
/// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
mapping(bytes32 => bytes32) private _getRoleAdmin;
/// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @dev Modifier that checks if an account has the specified role; reverts otherwise.
modifier onlyRole(bytes32 role) {
_checkRole(role, msg.sender);
_;
}
/**
* @notice Checks whether an account has a particular role.
* @dev Returns `true` if `account` has been granted `role`.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _hasRole[role][account];
}
/**
* @notice Checks whether an account has a particular role;
* role restrictions can be swtiched on and off.
*
* @dev Returns `true` if `account` has been granted `role`.
* Role restrictions can be swtiched on and off:
* - If address(0) has ROLE, then the ROLE restrictions
* don't apply.
* - If address(0) does not have ROLE, then the ROLE
* restrictions will apply.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
if (!_hasRole[role][address(0)]) {
return _hasRole[role][account];
}
return true;
}
/**
* @notice Returns the admin role that controls the specified role.
* @dev See {grantRole} and {revokeRole}.
* To change a role's admin, use {_setRoleAdmin}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
return _getRoleAdmin[role];
}
/**
* @notice Grants a role to an account, if not previously granted.
* @dev Caller must have admin role for the `role`.
* Emits {RoleGranted Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account to which the role is being granted.
*/
function grantRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);
if (_hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
/**
* @notice Revokes role from an account.
* @dev Caller must have admin role for the `role`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function revokeRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);
_revokeRole(role, account);
}
/**
* @notice Revokes role from the account.
* @dev Caller must have the `role`, with caller being the same as `account`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function renounceRole(bytes32 role, address account) public virtual override {
if (msg.sender != account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
/// @dev Sets `adminRole` as `role`'s admin role.
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = _getRoleAdmin[role];
_getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
_hasRole[role][account] = true;
emit RoleGranted(role, account, msg.sender);
}
/// @dev Revokes `role` from `account`
function _revokeRole(bytes32 role, address account) internal virtual {
_checkRole(role, account);
delete _hasRole[role][account];
emit RoleRevoked(role, account, msg.sender);
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRole(bytes32 role, address account) internal view virtual {
if (!_hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
TWStrings.toHexString(uint160(account), 20),
" is missing role ",
TWStrings.toHexString(uint256(role), 32)
)
)
);
}
}
}
TWAddress.sol 222 lines
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev Collection of functions related to the address type
*/
library TWAddress {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* [EIP1884](https://eips.ethereum.org/EIPS/eip-1884) increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
TWStrings.sol 67 lines
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev String operations.
*/
library TWStrings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
IProductMarket.sol 307 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @author Syky - Nathan Rempel
interface IProductMarket {
/*//////////////////////////////////////////////////////////////
Structs
//////////////////////////////////////////////////////////////*/
/**
* @notice A data structure to configure Product Listings
* @dev Should compress to 512 bytes.
*
* @param productId The productId of the asset being sold. (max 16,777,215)
* @param quantity The total quantity listed for sale. (max 65,535)
* @param reserved The quantity availablein the VIP window. (max 65,535)
* @param vipLimit The purchase limit for VIPs. (max 65,535)
* @param pubLimit The purchase limit for public. (max 65,535)
* @param vipPrice The price in ETH per item for VIPs. (max 1,208,925.8 ETH)
* @param pubPrice The price in ETH per item for public. (max 1,208,925.8 ETH)
* @param endTimestamp The sale end timestamp for everyone.
* @param vipStartTimestamp The sale start timestamp for VIPs.
* @param pubStartTimestamp The sale start timestamp for public.
* @param enabled The listing is enabled
*/
struct ListingParams {
uint24 productId;
uint16 quantity;
uint16 reserved;
uint16 vipLimit;
uint16 pubLimit;
uint80 vipPrice;
uint80 pubPrice;
uint32 endTimestamp;
uint32 vipStartTimestamp;
uint32 pubStartTimestamp;
bool enabled;
//spare 160 bytes space capacity
//compresses to one 256
}
/**
* @notice A data structure to store Product Listings
* @dev Should compress to 512 bytes.
*
* @param productId The productId of the asset being sold. (max 16,777,215)
* @param enabled The listing is enabled (value > 0 = true)
* @param quantity The total quantity listed for sale. (max 65,535)
* @param reserved The quantity availablein the VIP window. (max 65,535)
* @param vipLimit The purchase limit for VIPs. (max 65,535)
* @param pubLimit The purchase limit for public. (max 65,535)
* @param vipPrice The price in ETH per item for VIPs. (max 1,208,925.8 ETH)
* @param pubPrice The price in ETH per item for public. (max 1,208,925.8 ETH)
* @param endTimestamp The sale end timestamp for everyone.
* @param vipStartTimestamp The sale start timestamp for VIPs.
* @param pubStartTimestamp The sale start timestamp for public.
* @param resPurchased The VIP purchase quantity in the VIP window.
* @param vipPurchased The VIP purchase quantity of the sale in any window.
* @param pubPurchased The public purchase quantity of the sale.
*/
struct Listing {
uint24 productId;
uint8 enabled;
uint32 quantity;
uint16 reserved;
uint16 vipLimit;
uint16 pubLimit;
uint80 vipPrice;
uint80 pubPrice;
uint32 endTimestamp;
uint32 vipStartTimestamp;
uint32 pubStartTimestamp;
uint16 resPurchased;
uint16 vipPurchased;
uint16 pubPurchased;
}
/// @notice A data structure to return a set of listings
struct ListingQuery {
uint256 listingId;
Listing listingData;
}
struct PayoutReceiver {
address payable receiver;
uint256 percentage;
}
enum AuctionStatus {
UNSET,
CREATED,
COMPLETED,
CANCELLED
}
struct AuctionParams {
uint56 productId;
uint32 startTimestamp;
uint32 endTimestamp;
uint64 bidBufferBps;
uint64 timeBufferSeconds;
uint256 minimumBidAmount;
uint256 reserveBidAmount;
}
struct Auction {
uint56 productId;
AuctionStatus status;
uint32 startTimestamp;
uint32 endTimestamp;
uint64 bidBufferBps;
uint64 timeBufferSeconds;
uint256 minimumBidAmount;
uint256 reserveBidAmount;
}
struct AuctionQuery {
uint256 auctionId;
Auction auctionData;
Bid winningBid;
}
struct Bid {
uint64 auctionId;
uint32 bidTimestamp;
address bidder;
uint256 bidAmount;
}
struct BidHistory {
uint256 count;
mapping(uint256 => Bid) bids;
}
struct ProductLookup {
uint256 count;
mapping(uint256 => uint256) id;
}
/*//////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @dev Emitted when a new listing is created.
event ListingAdded(uint256 indexed listingId, Listing listing);
/// @dev Emitted when the parameters of a listing are updated.
event ListingUpdated(uint256 indexed listingId, Listing listing);
/// @dev Emitted when a listing is enabled or disabled.
event ListingEnabled(uint256 indexed listingId, bool indexed enabled);
/// @dev Emitted when a listing token contract is updated.
event ListingContract(uint256 indexed listingId, address indexed tokenContract);
/// @dev Emitted when a new sale occurs for a listing.
event NewSale(
uint256 indexed listingId,
address indexed buyer,
address indexed recipient,
uint256 productId,
uint256 quantity,
uint256 price
);
/// @dev Emitted when withdrawal recipient is approved or unapproved.
event WithdrawalRecipientApproved(address indexed recipient, bool indexed approved);
/// @dev Emitted when market income is withdrawn.
event IncomeWithdrawal(
address indexed operator,
address indexed recipient,
uint256 indexed amount
);
event AuctionAdded(uint256 indexed auctionId, Auction auction);
event AuctionUpdated(uint256 indexed auctionId, Auction auction);
event AuctionCancelled(uint256 indexed auctionId);
/// @dev Emitted when a listing token contract is updated.
event AuctionContract(uint256 indexed auctionId, address indexed tokenContract);
event AuctionClosed(
uint256 indexed auctionId,
address indexed bidder,
uint256 indexed bidAmount,
uint256 productId,
bool tokenAwarded,
bool bidRefunded
);
event NewBid(
uint256 indexed auctionId,
address indexed bidder,
uint256 indexed bidAmount,
Auction auction
);
/*//////////////////////////////////////////////////////////////
Errors
//////////////////////////////////////////////////////////////*/
/// @dev Action requires the finance or admin role
error FinanceRoleRequired();
/// @dev Action requires the manager or admin role
error ManagerRoleRequired();
/// @dev VIP Sale start must be before or equal to Public Sale start
error ListingVipStartAfterPubStart(
uint32 vipStartTimestamp,
uint32 pubStartTimestamp
);
/// @dev Public Sale start must be before sale close
error ListingPubStartAfterEnd(uint32 pubStartTimestamp, uint32 endTimestamp);
error ListingReserveExceedsQuantity(uint16 reserved, uint16 quantity);
error ListingDoesNotExist();
error ListingPurchasesExceedsQuantity(uint16 quantity, uint256 purchased);
error ListingPurchasesExceedsReserve(uint16 reserve, uint256 purchased);
error ListingNotEnabled();
error ListingHasEnded();
error ListingQueryInvalidRange();
error ListingExpectedPriceNotEqualValue(
uint256 expectedTotalPrice,
uint256 transactionValue
);
error ListingInsufficientQuantity(
uint256 requestedQuantity,
uint256 availableQuantity
);
error ListingVipSaleNotStarted(uint64 vipStartTime, uint256 currentTimestamp);
error ListingPublicSaleNotStarted(uint64 publicStartTime, uint256 currentTimestamp);
error ListingVipLimitExceeded(uint256 purchases, uint256 limit);
error ListingVipReserveExceeded(uint256 requestedQuantity, uint256 availableQuantity);
error ListingPublicLimitExceeded(uint256 purchases, uint256 limit);
error ListingVipExpectedPriceInvalid(
uint256 expectedTotalPrice,
uint256 actualTotalPrice
);
error ListingPublicExpectedPriceInvalid(
uint256 expectedTotalPrice,
uint256 actualTotalPrice
);
error ListingPercentageOverflow(uint256 total);
error PayoutPercentageExceedsMax(uint256 percentage, uint256 max);
error AuctionQueryInvalidRange();
error AuctionStartAfterEnd(uint32 startTimestamp, uint32 endTimestamp);
error AuctionBufferBpsExceedsMax();
error AuctionDoesNotExist();
error AuctionNotActive();
error AuctionNotEnded(uint32 endTimestamp, uint256 currentTimestamp);
error AuctionHasBids(uint256 numberOfBids);
error AuctionHasNoBids();
error AuctionReserveNotMet(uint256 highestBidAmount, uint256 reserveBidAmount);
error AuctionReserveWasMet(uint256 highestBidAmount, uint256 reserveBidAmount);
error AuctionPreviousBidRefundRejected();
error AuctionNotStarted(uint32 startTimestamp, uint256 currentTimestamp);
error AuctionHasEnded();
error AuctionBidAmountZero();
error AuctionBidBelowMinimum(uint256 bidAmount, uint256 minimumBidAmount);
error AuctionBidAmountNotEqualValue(uint256 bidAmount, uint256 transactionValue);
error AuctionBidAmountInsufficient(uint256 bidAmount, uint256 requiredBidAmount);
error WithdrawalRecipientNotApproved();
error WithdrawalRecipientRejectedTransfer();
error WithdrawalInsufficientBalance(uint256 requested, uint256 available);
}
IProductToken.sol 75 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @author Syky - Nathan Rempel
interface IProductToken {
/*//////////////////////////////////////////////////////////////
Methods
//////////////////////////////////////////////////////////////*/
/// @notice Lets an authorized address mint single NFTs to a recipient.
function mintTo(address _to, uint256 _productId) external;
function mintTo(address _to, uint256 _productId, bytes memory _data) external;
function mintTo(
address _to,
uint256 _productId,
string calldata _uri,
bytes memory _data
) external;
/// @notice Lets an authorized address mint multiple NFTs at once to a recipient.
function batchMintTo(address _to, uint256 _productId, uint256 _quantity) external;
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
bytes memory _data
) external;
function batchMintTo(
address _to,
uint256 _productId,
uint256 _quantity,
string[] calldata _uris,
bytes memory _data
) external;
/*//////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @dev Emitted when all minting is enabled or disabled
event GlobalMintingRestricted(bool restricted);
/// @dev Emitted when all transfers are enabled or disabled
event GlobalTransfersRestricted(bool restricted);
/// @dev Emitted when all burning is enabled or disabled
event GlobalBurningRestricted(bool restricted);
/*//////////////////////////////////////////////////////////////
Errors
//////////////////////////////////////////////////////////////*/
/// @dev URIs array length for batch mint must match _quantity
error BatchMintURICountMismatch();
/// @dev Action requires the manager or admin role
error ManagerRoleRequired();
/// @dev Action requires the minting or admin role
error MintingRoleRequired();
/// @dev Minting has been disabled via address(0) role
error GlobalMintingDisabled();
/// @dev Transfers have been disabled via address(0) role
error GlobalTransfersDisabled();
/// @dev Burning has been disabled via address(0) role
error GlobalBurningDisabled();
}
IVipManager.sol 65 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @author Syky - Nathan Rempel
interface IVipManager {
struct VipConditions {
GroupConditions groupConditions;
ProductConditions[] productConditions;
ERC721Conditions[] erc721Conditions;
ERC1155Conditions[] erc1155Conditions;
}
struct VipConditionsData {
uint256 productLength;
uint256 erc721Length;
uint256 erc1155Length;
GroupConditions groupConditions;
mapping(uint256 => ERC721Conditions) erc721Conditions;
mapping(uint256 => ERC1155ConditionsData) erc1155Conditions;
mapping(uint256 => ProductConditionsData) productConditions;
}
struct GroupConditions {
address groupContract;
uint256 groupId;
}
struct ERC721Conditions {
address tokenContract;
}
struct ProductConditions {
address tokenContract;
uint256[] productIds;
}
struct ERC1155Conditions {
address tokenContract;
uint256[] tokenIds;
}
struct ERC1155ConditionsData {
address tokenContract;
uint96 length;
mapping(uint256 => uint256) tokenIds;
}
struct ProductConditionsData {
address tokenContract;
uint96 length;
mapping(uint256 => uint256) productIds;
}
function isVip(uint256 _selectorId, address _member) external view returns (bool);
error ManagerRoleRequired();
event VipSelectorConditionsUpdated(
uint256 indexed selectorId,
uint256 indexed conditionsId
);
event VipConditionsUpdated(uint256 indexed conditionsId, VipConditions conditions);
}
ProductMarket.sol 866 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @author Syky - Nathan Rempel
import "./interface/IProductMarket.sol";
import "./interface/IProductToken.sol";
import "./interface/IVipManager.sol";
import "@thirdweb-dev/contracts/extension/Permissions.sol";
import "@thirdweb-dev/contracts/lib/TWAddress.sol";
contract ProductMarket is IProductMarket, Permissions {
using TWAddress for address;
/*//////////////////////////////////////////////////////////////
Constants
//////////////////////////////////////////////////////////////*/
bytes32 public constant FINANCE_ROLE = keccak256("FINANCE_ROLE");
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
/// @dev The max bps of the contract. So, 10_000 == 100 %
uint64 private constant MAX_BPS = 10_000;
/*//////////////////////////////////////////////////////////////
Mappings
//////////////////////////////////////////////////////////////*/
address private _vipContract;
address private _feeReceiver;
//counter for total listings created
uint256 private _totalListings;
//counter for total auctions created
uint256 private _totalAuctions;
//max payout distribution for artists
uint256 private _maxPayoutsDistribution;
//mapping of sale parameters to listingId
mapping(uint256 => Listing) private _listings;
//reverse lookup of listings by productId
mapping(uint256 => ProductLookup) private _productListings;
//mapping of product token address to listingId
mapping(uint256 => address) private _listingContracts;
//mapping of purchases made by an address to listingId
mapping(uint256 => mapping(address => uint256)) private _listingPurchases;
//mapping of auction parameters to auctionId
mapping(uint256 => Auction) private _auctions;
//reverse lookup of auctions by productId
mapping(uint256 => ProductLookup) private _productAuctions;
//mapping of product token address to auctionId
mapping(uint256 => address) private _auctionContracts;
//mapping of auction bids to auctionId
mapping(uint256 => BidHistory) private _auctionBids;
//mapping of auction bids to address
mapping(address => BidHistory) private _addressBids;
//mapping of approved withdrawal addresses
mapping(address => bool) private _withdrawalApproved;
//listing receivers for payouts (0 - Listings / 1 - Auctions)
mapping(uint256 => mapping(uint256 => PayoutReceiver[])) private _payouts;
/*//////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(
address defaultAdmin_,
address defaultToken_,
address vipContract_,
address feeReceiver_
) {
_listingContracts[0] = defaultToken_;
_auctionContracts[0] = defaultToken_;
_vipContract = vipContract_;
_maxPayoutsDistribution = 9_000; // 90% for artists - 10% SYKY fee
_feeReceiver = feeReceiver_;
_setupRole(DEFAULT_ADMIN_ROLE, defaultAdmin_);
_setRoleAdmin(FINANCE_ROLE, DEFAULT_ADMIN_ROLE);
_setRoleAdmin(MANAGER_ROLE, DEFAULT_ADMIN_ROLE);
}
/*//////////////////////////////////////////////////////////////
Admin functions
//////////////////////////////////////////////////////////////*/
function setVipContract(address _vipContract_) external onlyManager {
_vipContract = _vipContract_;
}
function setFeeReceiver(address _feeReceiver_) external onlyManager {
_feeReceiver = _feeReceiver_;
}
function createListing(
ListingParams calldata _params,
PayoutReceiver[] calldata receivers
) external onlyManager returns (uint256 listingId) {
// overflow is impossible short of 2**256-1 listings being created
unchecked {
listingId = ++_totalListings;
}
Listing storage listing = _listings[listingId];
if (_params.pubStartTimestamp < _params.vipStartTimestamp)
revert ListingVipStartAfterPubStart(
_params.vipStartTimestamp,
_params.pubStartTimestamp
);
if (_params.endTimestamp <= _params.pubStartTimestamp)
revert ListingPubStartAfterEnd(
_params.pubStartTimestamp,
_params.endTimestamp
);
if (_params.quantity < _params.reserved)
revert ListingReserveExceedsQuantity(_params.reserved, _params.quantity);
listing.productId = _params.productId;
listing.enabled = _params.enabled ? 1 : 0;
listing.quantity = _params.quantity;
listing.reserved = _params.reserved;
listing.vipLimit = _params.vipLimit;
listing.pubLimit = _params.pubLimit;
listing.vipPrice = _params.vipPrice;
listing.pubPrice = _params.pubPrice;
listing.endTimestamp = _params.endTimestamp;
listing.vipStartTimestamp = _params.vipStartTimestamp;
listing.pubStartTimestamp = _params.pubStartTimestamp;
//reverse lookup
unchecked {
uint256 reverseIdx = _productListings[_params.productId].count++;
_productListings[_params.productId].id[reverseIdx] = listingId;
}
if (receivers.length > 0) {
_setPayouts(0, listingId, receivers);
}
emit ListingAdded(listingId, listing);
}
function setListingPayouts(
uint256 _listingId,
PayoutReceiver[] calldata receivers
) external onlyManager {
_setPayouts(0, _listingId, receivers);
}
function setAuctionPayouts(
uint256 _auctionId,
PayoutReceiver[] calldata receivers
) external onlyManager {
_setPayouts(1, _auctionId, receivers);
}
function _setPayouts(
uint256 _index,
uint256 _id,
PayoutReceiver[] calldata receivers
) internal {
delete _payouts[_index][_id];
uint256 percForDesigners;
uint256 percForSYKY;
for (uint256 i = 0; i < receivers.length; i++) {
_payouts[_index][_id].push(receivers[i]);
if (receivers[i].receiver == _feeReceiver) {
percForSYKY += receivers[i].percentage;
} else {
percForDesigners += receivers[i].percentage;
}
}
if (percForDesigners > _maxPayoutsDistribution) {
revert ListingPercentageOverflow(percForDesigners);
}
if ((percForDesigners + percForSYKY) > MAX_BPS) {
revert PayoutPercentageExceedsMax(MAX_BPS, (percForDesigners + percForSYKY));
}
}
function updateListing(
uint256 _listingId,
ListingParams calldata _params
) external onlyManager {
Listing storage listing = _listings[_listingId];
if (listing.productId == 0) revert ListingDoesNotExist();
if (_params.pubStartTimestamp < _params.vipStartTimestamp)
revert ListingVipStartAfterPubStart(
_params.vipStartTimestamp,
_params.pubStartTimestamp
);
if (_params.endTimestamp <= _params.pubStartTimestamp)
revert ListingPubStartAfterEnd(
_params.pubStartTimestamp,
_params.endTimestamp
);
if (_params.quantity < _params.reserved)
revert ListingReserveExceedsQuantity(_params.reserved, _params.quantity);
unchecked {
uint256 totalPurchased = listing.vipPurchased + listing.pubPurchased;
if (_params.quantity < totalPurchased)
revert ListingPurchasesExceedsQuantity(_params.quantity, totalPurchased);
if (_params.reserved < listing.resPurchased)
revert ListingPurchasesExceedsReserve(
_params.reserved,
listing.resPurchased
);
}
listing.enabled = _params.enabled ? 1 : 0;
listing.quantity = _params.quantity;
listing.reserved = _params.reserved;
listing.vipLimit = _params.vipLimit;
listing.pubLimit = _params.pubLimit;
listing.vipPrice = _params.vipPrice;
listing.pubPrice = _params.pubPrice;
listing.endTimestamp = _params.endTimestamp;
listing.vipStartTimestamp = _params.vipStartTimestamp;
listing.pubStartTimestamp = _params.pubStartTimestamp;
emit ListingUpdated(_listingId, listing);
}
function enableListing(uint256 _listingId, bool _enabled) external onlyManager {
_listings[_listingId].enabled = _enabled ? 1 : 0;
emit ListingEnabled(_listingId, _enabled);
}
function setListingContract(
uint256 _listingId,
address _tokenContract
) external onlyManager {
_listingContracts[_listingId] = _tokenContract;
emit ListingContract(_listingId, _tokenContract);
}
function setAuctionContract(
uint256 _auctionId,
address _tokenContract
) external onlyManager {
_auctionContracts[_auctionId] = _tokenContract;
emit AuctionContract(_auctionId, _tokenContract);
}
function createAuction(
AuctionParams calldata _params,
PayoutReceiver[] calldata receivers
) external onlyManager returns (uint256 auctionId) {
unchecked {
auctionId = ++_totalAuctions;
}
Auction storage auction = _auctions[auctionId];
if (_params.endTimestamp <= _params.startTimestamp)
revert AuctionStartAfterEnd(_params.startTimestamp, _params.endTimestamp);
if (MAX_BPS < _params.bidBufferBps) revert AuctionBufferBpsExceedsMax();
auction.productId = _params.productId;
auction.status = AuctionStatus.CREATED;
auction.startTimestamp = _params.startTimestamp;
auction.endTimestamp = _params.endTimestamp;
auction.bidBufferBps = _params.bidBufferBps;
auction.timeBufferSeconds = _params.timeBufferSeconds;
auction.minimumBidAmount = _params.minimumBidAmount;
auction.reserveBidAmount = _params.reserveBidAmount;
unchecked {
uint256 reverseIdx = _productAuctions[_params.productId].count++;
_productAuctions[_params.productId].id[reverseIdx] = auctionId;
}
if (receivers.length > 0) {
_setPayouts(1, auctionId, receivers);
}
emit AuctionAdded(auctionId, auction);
}
function updateAuction(
uint256 _auctionId,
AuctionParams calldata _params
) external onlyManager {
Auction storage auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
if (auction.status != AuctionStatus.CREATED) revert AuctionNotActive();
if (_params.endTimestamp <= _params.startTimestamp)
revert AuctionStartAfterEnd(_params.startTimestamp, _params.endTimestamp);
if (MAX_BPS < _params.bidBufferBps) revert AuctionBufferBpsExceedsMax();
auction.startTimestamp = _params.startTimestamp;
auction.endTimestamp = _params.endTimestamp;
auction.bidBufferBps = _params.bidBufferBps;
auction.timeBufferSeconds = _params.timeBufferSeconds;
auction.minimumBidAmount = _params.minimumBidAmount;
auction.reserveBidAmount = _params.reserveBidAmount;
emit AuctionUpdated(_auctionId, auction);
}
function cancelAuction(uint256 _auctionId) external onlyManager {
Auction storage auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
if (auction.status != AuctionStatus.CREATED) revert AuctionNotActive();
if (_auctionBids[_auctionId].count != 0)
revert AuctionHasBids(_auctionBids[_auctionId].count);
auction.status = AuctionStatus.CANCELLED;
emit AuctionCancelled(_auctionId);
}
function rewardAuction(uint256 _auctionId) external {
Auction storage auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
if (auction.status != AuctionStatus.CREATED) revert AuctionNotActive();
if (block.timestamp < auction.endTimestamp)
revert AuctionNotEnded(auction.endTimestamp, block.timestamp);
uint256 numberOfBids = _auctionBids[_auctionId].count;
if (numberOfBids == 0) revert AuctionHasNoBids();
Bid memory winningBid = _auctionBids[_auctionId].bids[numberOfBids - 1];
if (winningBid.bidAmount < auction.reserveBidAmount)
revert AuctionReserveNotMet(winningBid.bidAmount, auction.reserveBidAmount);
//reentrancy protection
auction.status = AuctionStatus.COMPLETED;
IProductToken(getAuctionContract(_auctionId)).mintTo(
winningBid.bidder,
auction.productId
);
_processPayment(1, _auctionId, winningBid.bidAmount);
emit AuctionClosed(
_auctionId,
winningBid.bidder,
winningBid.bidAmount,
auction.productId,
true,
false
);
}
function closeAuction(uint256 _auctionId) external onlyManager {
Auction storage auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
if (auction.status != AuctionStatus.CREATED) revert AuctionNotActive();
if (block.timestamp < auction.endTimestamp)
revert AuctionNotEnded(auction.endTimestamp, block.timestamp);
uint256 numberOfBids = _auctionBids[_auctionId].count;
if (numberOfBids == 0) revert AuctionHasNoBids();
Bid memory winningBid = _auctionBids[_auctionId].bids[numberOfBids - 1];
if (auction.reserveBidAmount <= winningBid.bidAmount)
revert AuctionReserveWasMet(winningBid.bidAmount, auction.reserveBidAmount);
//reentrancy protection
auction.status = AuctionStatus.COMPLETED;
(bool success, ) = winningBid.bidder.call{value: winningBid.bidAmount}("");
if (!success) revert AuctionPreviousBidRefundRejected();
emit AuctionClosed(
_auctionId,
winningBid.bidder,
winningBid.bidAmount,
auction.productId,
false,
true
);
}
/// @dev Sets `_recipient` as `_approved` for withdrawing income.
function approveWithdrawalRecipient(
address _recipient,
bool _approved
) external onlyFinance {
_withdrawalApproved[_recipient] = _approved;
emit WithdrawalRecipientApproved(_recipient, _approved);
}
/// @dev Transfers `_amount` of native token to `_account`. `_account` must be approved.
function withdrawIncome(
address payable _recipient,
uint256 _amount
) external onlyFinance {
if (!_withdrawalApproved[_recipient]) revert WithdrawalRecipientNotApproved();
_processWithdrawal(_recipient, _amount);
}
function _processWithdrawal(address payable _recipient, uint256 _amount) internal {
if (address(this).balance < _amount)
revert WithdrawalInsufficientBalance(_amount, address(this).balance);
(bool success, ) = _recipient.call{value: _amount}("");
if (!success) revert WithdrawalRecipientRejectedTransfer();
emit IncomeWithdrawal(msg.sender, _recipient, _amount);
}
function _processPayment(uint256 _index, uint256 _id, uint256 _value) internal {
// Distribute the funds of the sale - 0: listing / 1: auction
PayoutReceiver[] memory receivers = _payouts[_index][_id];
for (uint256 i = 0; i < receivers.length; i++) {
uint256 amount = (_value * receivers[i].percentage) / MAX_BPS;
_processWithdrawal(receivers[i].receiver, amount);
}
}
/*//////////////////////////////////////////////////////////////
Public functions
//////////////////////////////////////////////////////////////*/
function buyFromListing(
uint256 _listingId,
address _buyFor,
uint256 _quantity,
uint256 _expectedTotalPrice
) external payable {
Listing storage listing = _listings[_listingId];
if (listing.productId == 0) revert ListingDoesNotExist();
if (listing.enabled == 0) revert ListingNotEnabled();
if (_expectedTotalPrice != msg.value)
revert ListingExpectedPriceNotEqualValue(_expectedTotalPrice, msg.value);
if (listing.endTimestamp < block.timestamp) revert ListingHasEnded();
unchecked {
uint256 availableQuantity = listing.quantity -
(listing.vipPurchased + listing.pubPurchased);
if (availableQuantity < _quantity)
revert ListingInsufficientQuantity(_quantity, availableQuantity);
}
uint256 listingPurchases = _listingPurchases[_listingId][msg.sender] + _quantity;
//usually prefer non-duplicate code but this allows for custom messages and less memory use
if (_checkListingVip(_listingId, msg.sender)) {
if (block.timestamp < listing.vipStartTimestamp)
revert ListingVipSaleNotStarted(
listing.vipStartTimestamp,
block.timestamp
);
if (listing.vipLimit < listingPurchases)
revert ListingVipLimitExceeded(listingPurchases, listing.vipLimit);
uint256 actualTotalPrice = listing.vipPrice * _quantity;
if (actualTotalPrice != _expectedTotalPrice)
revert ListingVipExpectedPriceInvalid(
_expectedTotalPrice,
actualTotalPrice
);
unchecked {
//if VIP purchases are occuring BEFORE the external window, use the reserve
if (block.timestamp < listing.pubStartTimestamp) {
//not allowed in creation or update to exceed
uint256 reserveAvailable = listing.reserved - listing.resPurchased;
if (reserveAvailable < _quantity)
revert ListingVipReserveExceeded(_quantity, reserveAvailable);
listing.resPurchased += uint16(_quantity);
}
listing.vipPurchased += uint16(_quantity);
}
} else {
if (block.timestamp < listing.pubStartTimestamp)
revert ListingPublicSaleNotStarted(
listing.pubStartTimestamp,
block.timestamp
);
if (listing.pubLimit < listingPurchases)
revert ListingPublicLimitExceeded(listingPurchases, listing.pubLimit);
uint256 actualTotalPrice = listing.pubPrice * _quantity;
if (actualTotalPrice != _expectedTotalPrice)
revert ListingPublicExpectedPriceInvalid(
_expectedTotalPrice,
actualTotalPrice
);
unchecked {
listing.pubPurchased += uint16(_quantity);
}
}
//perform updates before transfer to avoid re-entrancy
_listingPurchases[_listingId][msg.sender] = listingPurchases;
IProductToken(getListingContract(_listingId)).batchMintTo(
_buyFor,
listing.productId,
_quantity
);
_processPayment(0, _listingId, _expectedTotalPrice);
emit NewSale(
_listingId,
msg.sender,
_buyFor,
listing.productId,
_quantity,
_expectedTotalPrice
);
}
function bidInAuction(uint256 _auctionId, uint256 _bidAmount) external payable {
Auction memory auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
if (auction.status != AuctionStatus.CREATED) revert AuctionNotActive();
if (block.timestamp < auction.startTimestamp)
revert AuctionNotStarted(auction.startTimestamp, block.timestamp);
if (auction.endTimestamp < block.timestamp) revert AuctionHasEnded();
if (_bidAmount == 0) revert AuctionBidAmountZero();
if (_bidAmount < auction.minimumBidAmount)
revert AuctionBidBelowMinimum(_bidAmount, auction.minimumBidAmount);
if (_bidAmount != msg.value)
revert AuctionBidAmountNotEqualValue(_bidAmount, msg.value);
uint256 numberOfBids = _auctionBids[_auctionId].count;
if (numberOfBids > 0) {
Bid memory previousBid = _auctionBids[_auctionId].bids[numberOfBids - 1];
unchecked {
uint256 requiredBidAmount = previousBid.bidAmount +
((previousBid.bidAmount * auction.bidBufferBps) / MAX_BPS);
if (_bidAmount < requiredBidAmount)
revert AuctionBidAmountInsufficient(_bidAmount, requiredBidAmount);
}
(bool success, ) = previousBid.bidder.call{value: previousBid.bidAmount}("");
if (!success) revert AuctionPreviousBidRefundRejected();
// Reentrancy protection
if (_auctionBids[_auctionId].count != numberOfBids) revert();
}
unchecked {
++_auctionBids[_auctionId].count;
}
Bid memory newBid = Bid({
auctionId: uint64(_auctionId),
bidTimestamp: uint32(block.timestamp),
bidder: msg.sender,
bidAmount: _bidAmount
});
_auctionBids[_auctionId].bids[numberOfBids] = newBid;
unchecked {
uint256 addressBids = _addressBids[msg.sender].count++;
_addressBids[msg.sender].bids[addressBids] = newBid;
}
if (auction.endTimestamp - block.timestamp <= auction.timeBufferSeconds) {
unchecked {
auction.endTimestamp += uint32(auction.timeBufferSeconds);
}
_auctions[_auctionId] = auction;
}
emit NewBid(_auctionId, msg.sender, _bidAmount, auction);
}
/// @notice Sets the max payout distribution percentage for artists.
/// @param _newMaxPayoutsDistribution The new max payout distribution value.
/// @dev Only callable by users with the manager role.
function setPayoutsMaxDistribution(
uint256 _newMaxPayoutsDistribution
) external onlyManager {
if (_newMaxPayoutsDistribution > MAX_BPS) {
revert PayoutPercentageExceedsMax(MAX_BPS, _newMaxPayoutsDistribution);
}
_maxPayoutsDistribution = _newMaxPayoutsDistribution;
}
/*//////////////////////////////////////////////////////////////
Public getters
//////////////////////////////////////////////////////////////*/
function getVipContract() external view returns (address) {
return _vipContract;
}
function totalListings() external view returns (uint256) {
return _totalListings;
}
function getListingContract(uint256 _listingId) public view returns (address) {
if (_listingContracts[_listingId] == address(0)) {
return _listingContracts[0];
} else {
return _listingContracts[_listingId];
}
}
function getListing(
uint256 _listingId
) external view returns (ListingQuery memory _listing) {
return ListingQuery({listingId: _listingId, listingData: _listings[_listingId]});
}
function getListingPayouts(
uint256 _listingId
) external view returns (PayoutReceiver[] memory) {
return _payouts[0][_listingId];
}
function getAuctionPayouts(
uint256 _auctionId
) external view returns (PayoutReceiver[] memory) {
return _payouts[1][_auctionId];
}
function getAllProductListings(
uint256 _productId
) external view returns (ListingQuery[] memory _allListings) {
ProductLookup storage productLookup = _productListings[_productId];
uint256 count = productLookup.count;
_allListings = new ListingQuery[](count);
for (uint256 i; i < count; ) {
uint256 listingId = productLookup.id[i];
_allListings[i] = ListingQuery({
listingId: listingId,
listingData: _listings[listingId]
});
unchecked {
++i;
}
}
}
function getAllListings(
uint256 _startId,
uint256 _endId
) external view returns (ListingQuery[] memory _allListings) {
if (_startId == 0 || _endId < _startId) revert ListingQueryInvalidRange();
unchecked {
uint256 maxId = (_endId > _totalListings ? _totalListings : _endId) + 1;
_allListings = new ListingQuery[](maxId - _startId);
for (uint256 i = _startId; i < maxId; ) {
_allListings[i - _startId] = ListingQuery({
listingId: i,
listingData: _listings[i]
});
++i;
}
}
}
function getWithdrawalApproved(address _recipient) external view returns (bool) {
return _withdrawalApproved[_recipient];
}
function totalAuctions() external view returns (uint256) {
return _totalAuctions;
}
function getAuctionContract(uint256 _auctionId) public view returns (address) {
if (_auctionContracts[_auctionId] == address(0)) {
return _auctionContracts[0];
} else {
return _auctionContracts[_auctionId];
}
}
function getAuction(
uint256 _auctionId
) external view returns (AuctionQuery memory _auction) {
unchecked {
uint256 numberOfBids = _auctionBids[_auctionId].count;
return
AuctionQuery({
auctionId: _auctionId,
auctionData: _auctions[_auctionId],
winningBid: _auctionBids[_auctionId].bids[
numberOfBids > 0 ? numberOfBids - 1 : 0
]
});
}
}
function getAllProductAuctions(
uint256 _productId
) external view returns (AuctionQuery[] memory _allAuctions) {
ProductLookup storage productLookup = _productAuctions[_productId];
uint256 count = productLookup.count;
_allAuctions = new AuctionQuery[](count);
for (uint256 i; i < count; ) {
uint256 auctionId = productLookup.id[i];
uint256 numberOfBids = _auctionBids[i].count;
unchecked {
_allAuctions[i] = AuctionQuery({
auctionId: auctionId,
auctionData: _auctions[auctionId],
winningBid: _auctionBids[auctionId].bids[
numberOfBids > 0 ? numberOfBids - 1 : 0
]
});
++i;
}
}
}
function getAllAuctions(
uint256 _startId,
uint256 _endId
) external view returns (AuctionQuery[] memory _allAuctions) {
if (_startId == 0 || _endId < _startId) revert AuctionQueryInvalidRange();
unchecked {
uint256 maxId = (_endId > _totalAuctions ? _totalAuctions : _endId) + 1;
_allAuctions = new AuctionQuery[](maxId - _startId);
for (uint256 i = _startId; i < maxId; ) {
uint256 numberOfBids = _auctionBids[i].count;
_allAuctions[i - _startId] = AuctionQuery({
auctionId: i,
auctionData: _auctions[i],
winningBid: _auctionBids[i].bids[
numberOfBids > 0 ? numberOfBids - 1 : 0
]
});
++i;
}
}
}
function getAuctionBids(
uint256 _auctionId
) external view returns (Bid[] memory _bids) {
uint256 numberOfBids = _auctionBids[_auctionId].count;
_bids = new Bid[](numberOfBids);
for (uint256 i; i < numberOfBids; ) {
_bids[i] = _auctionBids[_auctionId].bids[i];
unchecked {
++i;
}
}
}
function getAddressBids(address _bidder) external view returns (Bid[] memory _bids) {
uint256 numberOfBids = _addressBids[_bidder].count;
_bids = new Bid[](numberOfBids);
for (uint256 i; i < numberOfBids; ) {
_bids[i] = _addressBids[_bidder].bids[i];
unchecked {
++i;
}
}
}
function getWinningBidAmount(uint256 _auctionId) external view returns (uint256) {
Auction memory auction = _auctions[_auctionId];
if (auction.status == AuctionStatus.UNSET) revert AuctionDoesNotExist();
uint256 numberOfBids = _auctionBids[_auctionId].count;
if (numberOfBids > 0) {
unchecked {
Bid memory previousBid = _auctionBids[_auctionId].bids[numberOfBids - 1];
return
previousBid.bidAmount +
((previousBid.bidAmount * auction.bidBufferBps) / MAX_BPS);
}
}
return auction.minimumBidAmount;
}
/// @notice Returns the current max payout distribution percentage for artists.
function getPayoutsMaxDistribution() external view returns (uint256) {
return _maxPayoutsDistribution;
}
/// @notice Returns the address that should receive SYKY fees.
function getFeeReceiver() external view returns (address) {
return _feeReceiver;
}
/*//////////////////////////////////////////////////////////////
Modifiers
//////////////////////////////////////////////////////////////*/
/// @dev Modifier that checks if an account has admin or finance role; reverts otherwise.
modifier onlyFinance() {
_checkFinanceAdmin();
_;
}
/// @dev Modifier that checks if an account has admin or manager role; reverts otherwise.
modifier onlyManager() {
_checkManagerAdmin();
_;
}
/*//////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Function that checks if an account has admin or finance role; reverts otherwise.
function _checkFinanceAdmin() internal view {
if (
!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) && !hasRole(FINANCE_ROLE, msg.sender)
) {
revert FinanceRoleRequired();
}
}
/// @dev Function that checks if an account has admin or manager role; reverts otherwise.
function _checkManagerAdmin() internal view {
if (
!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) && !hasRole(MANAGER_ROLE, msg.sender)
) {
revert ManagerRoleRequired();
}
}
function _checkListingVip(
uint256 _listingId,
address _member
) internal view returns (bool) {
if (_vipContract != address(0))
return IVipManager(_vipContract).isVip(_listingId, _member);
return false;
}
}
SykyMarket.sol 42 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @author Syky - Nathan Rempel
/*
@@@ @@@@@ @@@@@@@ @@@@ @@@@@@@ @@@@@ @@@@@@@ @@@@
@@@@ @@@ @@@@@@ @@ @@@@@@ @@ @@@@@@ @@
@@@@@ @@ @@@@@ @@ @@@@@ @ @@@@@ @@
@@@@@@ @@ @@@@@ @@ @@@@@ @ @@@@ @@
@@@@@@ @ @@@@@ @@ @@@@@ @ @@@@@ @
@@@@@@@ @@@@@ @@ @@@@@ @@@ @@@@@ @
@@@@@@ @@@@@@ @@@@@@@@@@@ @@@@@@
@@@@@@ @@@@@ @@@@@ @@@@@ @@@@@
@@@@@@@ @@@@@ @@@@@ @@@@@ @@@@@
@ @@@@@@ @@@@@ @@@@@ @@@@@ @@@@@
@@ @@@@@ @@@@@ @@@@@ @@@@@ @@@@@
@@@@ @@@@@ @@@@@ @@@@@@ @@@@@@ @@@@@@
@@@@@@ @@@@ @@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
*/
import "../base/ProductMarket.sol";
contract SykyMarket is ProductMarket {
/*//////////////////////////////////////////////////////////////
Version Info
//////////////////////////////////////////////////////////////*/
string public constant ENV = "MAINNET";
string public constant VER = "1.0.2";
/*//////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
constructor(
address defaultAdmin_,
address defaultToken_,
address vipContract_,
address feeReceiver_
) ProductMarket(defaultAdmin_, defaultToken_, vipContract_, feeReceiver_) {}
}
Read Contract
DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
ENV 0x7c6285a1 → string
FINANCE_ROLE 0x349b5954 → bytes32
MANAGER_ROLE 0xec87621c → bytes32
VER 0x3c4de40f → string
getAddressBids 0xd9ea9549 → tuple[]
getAllAuctions 0xc291537c → tuple[]
getAllListings 0xc5275fb0 → tuple[]
getAllProductAuctions 0x9258d45d → tuple[]
getAllProductListings 0x567441f8 → tuple[]
getAuction 0x78bd7935 → tuple
getAuctionBids 0x70b4768e → tuple[]
getAuctionContract 0xe506dfbe → address
getAuctionPayouts 0x05013cdc → tuple[]
getFeeReceiver 0xe8a35392 → address
getListing 0x107a274a → tuple
getListingContract 0x802c3a3a → address
getListingPayouts 0x8635d59b → tuple[]
getPayoutsMaxDistribution 0xa2d40dd5 → uint256
getRoleAdmin 0x248a9ca3 → bytes32
getVipContract 0x9c520471 → address
getWinningBidAmount 0xa3c8fdd8 → uint256
getWithdrawalApproved 0xe403a251 → bool
hasRole 0x91d14854 → bool
hasRoleWithSwitch 0xa32fa5b3 → bool
totalAuctions 0x16002f4a → uint256
totalListings 0xc78b616c → uint256
Write Contract 22 functions
These functions modify contract state and require a wallet transaction to execute.
approveWithdrawalRecipient 0x216fd1f5
address _recipient
bool _approved
bidInAuction 0x0858e5ad
uint256 _auctionId
uint256 _bidAmount
buyFromListing 0xf10f537a
uint256 _listingId
address _buyFor
uint256 _quantity
uint256 _expectedTotalPrice
cancelAuction 0x96b5a755
uint256 _auctionId
closeAuction 0x236ed8f3
uint256 _auctionId
createAuction 0xa24eceff
tuple _params
tuple[] receivers
returns: uint256
createListing 0xd8ed8020
tuple _params
tuple[] receivers
returns: uint256
enableListing 0x218ddb57
uint256 _listingId
bool _enabled
grantRole 0x2f2ff15d
bytes32 role
address account
renounceRole 0x36568abe
bytes32 role
address account
revokeRole 0xd547741f
bytes32 role
address account
rewardAuction 0x61b7aafe
uint256 _auctionId
setAuctionContract 0xfc9b5fc8
uint256 _auctionId
address _tokenContract
setAuctionPayouts 0x0f37cece
uint256 _auctionId
tuple[] receivers
setFeeReceiver 0xefdcd974
address _feeReceiver_
setListingContract 0x31964156
uint256 _listingId
address _tokenContract
setListingPayouts 0xa1e2fc1e
uint256 _listingId
tuple[] receivers
setPayoutsMaxDistribution 0x0c0803c8
uint256 _newMaxPayoutsDistribution
setVipContract 0x1fcc5b8a
address _vipContract_
updateAuction 0xe29fc9bb
uint256 _auctionId
tuple _params
updateListing 0xdd7ad64e
uint256 _listingId
tuple _params
withdrawIncome 0xb7792b26
address _recipient
uint256 _amount
Recent Transactions
No transactions found for this address