Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xa6Ec49E06C25F63292bac1Abc1896451A0f4cFB7
Balance 0 ETH
Nonce 1
Code Size 12055 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

12055 bytes
0x6080604052600436106104265760003560e01c806388993c8111610229578063b0cfbf161161012e578063dd62ed3e116100b6578063f2fde38b1161007a578063f2fde38b14610be9578063f623bb8b14610c09578063f82fa75614610c1f578063f8c0fd2014610c3c578063fbbf8cc314610c5157600080fd5b8063dd62ed3e14610b4f578063dfdedf6914610b6f578063e58306f914610b8f578063e6c6990a14610baf578063e757223014610bc957600080fd5b8063c3cb97c6116100fd578063c3cb97c614610abc578063c6ee6e3514610adc578063cacf084214610aef578063d266f3a914610b0f578063d83ae33214610b2f57600080fd5b8063b0cfbf1614610a47578063b6a3f59a14610a67578063b94b237614610a87578063c326876814610a9c57600080fd5b8063a1af10ca116101b1578063a9059cbb11610180578063a9059cbb146109bf578063a91bd1a9146109df578063ad1203dc146109ff578063af54001e14610a12578063afb16d1814610a2757600080fd5b8063a1af10ca1461093f578063a1db97821461095f578063a457c2d71461097f578063a7593fb71461099f57600080fd5b80638da5cb5b116101f85780638da5cb5b146108b75780638f770ad0146108d557806391b7f5ed146108ea57806395d89b411461090a57806398ad44171461091f57600080fd5b806388993c8114610857578063891bbe731461086c57806389f26d581461088c5780638d859f3e146108a157600080fd5b80634070a0c91161032f578063627255df116102b757806379ab3c891161028657806379ab3c89146107c057806379cc6790146107d55780637fb8c6d3146107f5578063853828b61461082d57806387491c601461084257600080fd5b8063627255df146107405780636d3de8061461076057806370a0823114610775578063715018a6146107ab57600080fd5b8063464c3428116102fe578063464c3428146106be57806346f41ed5146106de5780634783f0ef146106f85780634c23ce91146107185780635e8306561461072d57600080fd5b80634070a0c91461064957806342966c681461066957806343696f181461068957806345f7e06e146106a957600080fd5b806328ff1b51116103b2578063330067861161038157806333006786146105be57806334d00766146105de57806339509351146105f35780633d3f9c57146106135780633e07311c1461063357600080fd5b806328ff1b511461054c5780632b26a6bf1461056c5780632eb4a7ab1461058c578063313ce567146105a257600080fd5b80631963d0cc116103f95780631963d0cc146104c557806320fab142146104dd5780632181384e146104f757806323b872dd1461050c578063286c81371461052c57600080fd5b806306fdde031461042b5780630825850a14610456578063095ea7b31461048657806318160ddd146104a6575b600080fd5b34801561043757600080fd5b50610440610c87565b60405161044d9190612890565b60405180910390f35b34801561046257600080fd5b50610476610471366004612901565b610d19565b604051901515815260200161044d565b34801561049257600080fd5b506104766104a1366004612901565b610d66565b3480156104b257600080fd5b506002545b60405190815260200161044d565b3480156104d157600080fd5b50600a5460ff16610476565b3480156104e957600080fd5b506007546104769060ff1681565b61050a610505366004612977565b610d7e565b005b34801561051857600080fd5b506104766105273660046129e6565b6110d8565b34801561053857600080fd5b506104b7610547366004612a22565b6110fc565b34801561055857600080fd5b5061050a610567366004612b18565b61111d565b34801561057857600080fd5b5061050a610587366004612a22565b61116c565b34801561059857600080fd5b506104b7600f5481565b3480156105ae57600080fd5b506040516012815260200161044d565b3480156105ca57600080fd5b506104766105d9366004612bd3565b611179565b3480156105ea57600080fd5b50600b546104b7565b3480156105ff57600080fd5b5061047661060e366004612901565b611220565b34801561061f57600080fd5b5061047661062e366004612c26565b611242565b34801561063f57600080fd5b506104b760155481565b34801561065557600080fd5b5061050a610664366004612a22565b611265565b34801561067557600080fd5b5061050a610684366004612a22565b611272565b34801561069557600080fd5b5061050a6106a4366004612c26565b61127f565b3480156106b557600080fd5b5061050a6112f9565b3480156106ca57600080fd5b5061050a6106d9366004612c26565b611313565b3480156106ea57600080fd5b506016546104769060ff1681565b34801561070457600080fd5b5061050a610713366004612a22565b61133f565b34801561072457600080fd5b5061047661136f565b61050a61073b366004612901565b611397565b34801561074c57600080fd5b5061047661075b366004612a22565b6114c4565b34801561076c57600080fd5b5061050a6114e7565b34801561078157600080fd5b506104b7610790366004612c26565b6001600160a01b031660009081526020819052604090205490565b3480156107b757600080fd5b5061050a6114fb565b3480156107cc57600080fd5b5061050a61150f565b3480156107e157600080fd5b5061050a6107f0366004612901565b611526565b34801561080157600080fd5b50601354610815906001600160a01b031681565b6040516001600160a01b03909116815260200161044d565b34801561083957600080fd5b5061050a61153b565b34801561084e57600080fd5b5061050a61156a565b34801561086357600080fd5b50610476611580565b34801561087857600080fd5b50610815610887366004612a22565b6115a6565b34801561089857600080fd5b5061050a6115d0565b3480156108ad57600080fd5b506104b7600d5481565b3480156108c357600080fd5b506005546001600160a01b0316610815565b3480156108e157600080fd5b506104b76115e7565b3480156108f657600080fd5b5061050a610905366004612a22565b611602565b34801561091657600080fd5b5061044061160f565b34801561092b57600080fd5b5061050a61093a366004612c4f565b61161e565b34801561094b57600080fd5b5061047661095a366004612c26565b611640565b34801561096b57600080fd5b5061050a61097a366004612901565b61168d565b34801561098b57600080fd5b5061047661099a366004612901565b6117d9565b3480156109ab57600080fd5b5061050a6109ba366004612a22565b611817565b3480156109cb57600080fd5b506104766109da366004612901565b611850565b3480156109eb57600080fd5b5061050a6109fa366004612c26565b61185e565b61050a610a0d366004612c6c565b6118de565b348015610a1e57600080fd5b50600c546104b7565b348015610a3357600080fd5b5061050a610a42366004612cc6565b611a2f565b348015610a5357600080fd5b50610476610a62366004612a22565b611aa6565b348015610a7357600080fd5b5061050a610a82366004612a22565b611adf565b348015610a9357600080fd5b5061050a611b0f565b348015610aa857600080fd5b5061050a610ab7366004612c4f565b611b23565b348015610ac857600080fd5b5061050a610ad7366004612c4f565b611b3e565b61050a610aea366004612d0b565b611b59565b348015610afb57600080fd5b5061050a610b0a366004612c26565b611e89565b348015610b1b57600080fd5b506104b7610b2a366004612c26565b611eb2565b348015610b3b57600080fd5b5061050a610b4a366004612d47565b611ef9565b348015610b5b57600080fd5b506104b7610b6a366004612d86565b611f30565b348015610b7b57600080fd5b5061050a610b8a366004612c26565b611f5b565b348015610b9b57600080fd5b5061050a610baa366004612901565b611fd1565b348015610bbb57600080fd5b506010546104769060ff1681565b348015610bd557600080fd5b506104b7610be4366004612a22565b612028565b348015610bf557600080fd5b5061050a610c04366004612c26565b61208b565b348015610c1557600080fd5b506104b7600e5481565b348015610c2b57600080fd5b50600a54610100900460ff16610476565b348015610c4857600080fd5b5061050a6120c3565b348015610c5d57600080fd5b506104b7610c6c366004612c26565b6001600160a01b031660009081526009602052604090205490565b606060038054610c9690612db9565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc290612db9565b8015610d0f5780601f10610ce457610100808354040283529160200191610d0f565b820191906000526020600020905b815481529060010190602001808311610cf257829003601f168201915b5050505050905090565b600a5460009060ff16610d2e57506001610d60565b600b5482610d51856001600160a01b031660009081526009602052604090205490565b610d5b9190612e0a565b111590505b92915050565b600033610d748185856120de565b5060019392505050565b610d8661136f565b610da3576040516309c7220160e31b815260040160405180910390fd5b670de0b6b3a7640000841015610dcc5760405163b562e8dd60e01b815260040160405180910390fd5b610dd7858484611179565b610df45760405163097b24df60e41b815260040160405180910390fd5b610dfd846114c4565b610e1a576040516393eeb41560e01b815260040160405180910390fd5b610e248585610d19565b610e41576040516366be767160e11b815260040160405180910390fd5b610e4a84611aa6565b610e675760405163a4875a4960e01b815260040160405180910390fd5b600e543414610e895760405163078d696560e31b815260040160405180910390fd5b610e9281611242565b610eaf57604051636c501c9960e11b815260040160405180910390fd5b600084610ebb83611eb2565b610ec59190612e22565b6040516370a0823160e01b81526001600160a01b03888116600483015291925083918391908316906370a082319060240160206040518083038186803b158015610f0e57600080fd5b505afa158015610f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f469190612e41565b1015610f6557604051631642df1760e21b815260040160405180910390fd5b604051636eb1769f60e11b81526001600160a01b03888116600483015230602483015283919083169063dd62ed3e9060440160206040518083038186803b158015610faf57600080fd5b505afa158015610fc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe79190612e41565b10156110065760405163017e286b60e51b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b03888116600483015230602483015260448201849052600091908316906323b872dd90606401602060405180830381600087803b15801561105a57600080fd5b505af115801561106e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110929190612e5a565b9050806110b257604051633c9fd93960e21b815260040160405180910390fd5b6110ba61218d565b6110c488886121cf565b6110ce88886121f1565b5050505050505050565b6000336110e68582856122a1565b6110f18585856122e6565b506001949350505050565b6014818154811061110c57600080fd5b600091825260209091200154905081565b6111256123fe565b611131601260006127bd565b61113d601460006127bd565b81516111509060129060208501906127db565b508051611164906014906020840190612840565b505051601555565b6111746123fe565b600c55565b600f5460009061119c576040516363868c5560e11b815260040160405180910390fd5b6040516bffffffffffffffffffffffff19606086901b16602082015260009060340160405160208183030381529060405280519060200120905061121784848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050600f549150849050612489565b95945050505050565b600033610d748185856112338383611f30565b61123d9190612e0a565b6120de565b6001600160a01b031660009081526011602052604090205460ff16151560011490565b61126d6123fe565b600b55565b61127c338261249f565b50565b61128761257a565b6001600160a01b0381166112ae576040516322646a9760e21b815260040160405180910390fd5b6112b781611640565b156112d557604051638afaeb9d60e01b815260040160405180910390fd5b6001600160a01b03166000908152600660205260409020805460ff19166001179055565b6113016123fe565b6016805462ffff001916610100179055565b61131b6123fe565b6001600160a01b03166000908152601160205260409020805460ff19166001179055565b6113476123fe565b600f5481141561136a5760405163a28a88c160e01b815260040160405180910390fd5b600f55565b60165460009062010000900460ff1680156113925750601654610100900460ff16155b905090565b60165460ff16156113bb576040516306717a3b60e51b815260040160405180910390fd5b670de0b6b3a76400008110156113e45760405163b562e8dd60e01b815260040160405180910390fd5b6113ec611580565b611409576040516306717a3b60e51b815260040160405180910390fd5b611412816114c4565b61142f576040516393eeb41560e01b815260040160405180910390fd5b61143881611aa6565b6114555760405163a4875a4960e01b815260040160405180910390fd5b61145f8282610d19565b61147c576040516366be767160e11b815260040160405180910390fd5b61148581612028565b34146114a45760405163078d696560e31b815260040160405180910390fd5b6114ac61218d565b6114b682826121cf565b6114c082826121f1565b5050565b600a54600090610100900460ff166114de57506001919050565b50600c54101590565b6114ef6123fe565b6010805460ff19169055565b61150361257a565b61150d60006125d4565b565b6115176123fe565b6010805460ff19166001179055565b6115318233836122a1565b6114c0828261249f565b6115436123fe565b47611561576040516363868c5560e11b815260040160405180910390fd5b61150d47612626565b6115726123fe565b6016805462ffff0019169055565b601654600090610100900460ff16801561139257505060165462010000900460ff161590565b601281815481106115b657600080fd5b6000918252602090912001546001600160a01b0316905081565b6115d86123fe565b6016805460ff19166001179055565b60075460009060ff166115fb575060025490565b5060085490565b61160a6123fe565b600d55565b606060048054610c9690612db9565b6116266123fe565b600a80549115156101000261ff0019909216919091179055565b60006001600160a01b038216611669576040516322646a9760e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205460ff16151560011490565b6116956123fe565b806116b3576040516363868c5560e11b815260040160405180910390fd5b6040516370a0823160e01b8152306004820152829082906001600160a01b038316906370a082319060240160206040518083038186803b1580156116f657600080fd5b505afa15801561170a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172e9190612e41565b101561174d57604051631642df1760e21b815260040160405180910390fd5b60135460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018490529082169063a9059cbb90604401602060405180830381600087803b15801561179b57600080fd5b505af11580156117af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d39190612e5a565b50505050565b600033816117e78286611f30565b90508381101561180a57604051631642df1760e21b815260040160405180910390fd5b6110f182868684036120de565b3373a9dac8f3aedc55d0fe707b86b8a45d246858d2e11461184b57604051639b96b05160e01b815260040160405180910390fd5b600e55565b600033610d748185856122e6565b6118666123fe565b6001600160a01b03811661188d576040516322646a9760e21b815260040160405180910390fd5b6013546001600160a01b03828116911614156118bc5760405163a28a88c160e01b815260040160405180910390fd5b601380546001600160a01b0319166001600160a01b0392909216919091179055565b60165460ff1615611902576040516309c7220160e31b815260040160405180910390fd5b670de0b6b3a764000083101561192b5760405163b562e8dd60e01b815260040160405180910390fd5b61193361136f565b611950576040516309c7220160e31b815260040160405180910390fd5b61195b848383611179565b6119785760405163097b24df60e41b815260040160405180910390fd5b611981836114c4565b61199e576040516393eeb41560e01b815260040160405180910390fd5b6119a88484610d19565b6119c5576040516366be767160e11b815260040160405180910390fd5b6119ce83611aa6565b6119eb5760405163a4875a4960e01b815260040160405180910390fd5b6119f483612028565b3414611a135760405163078d696560e31b815260040160405180910390fd5b611a1b61218d565b611a2584846121cf565b6117d384846121f1565b611a376123fe565b670de0b6b3a7640000811015611a605760405163b562e8dd60e01b815260040160405180910390fd5b60005b8251811015611aa157611a8f838281518110611a8157611a81612e77565b6020026020010151836121f1565b80611a9981612e8d565b915050611a63565b505050565b60075460009060ff16611abb57506001919050565b611ac36115e7565b82611acd60025490565b611ad79190612e0a565b111592915050565b611ae76123fe565b600254811015611b0a5760405163cc67044560e01b815260040160405180910390fd5b600855565b611b176123fe565b6016805460ff19169055565b611b2b6123fe565b6007805460ff1916911515919091179055565b611b466123fe565b600a805460ff1916911515919091179055565b670de0b6b3a7640000821015611b825760405163b562e8dd60e01b815260040160405180910390fd5b611b8b82611aa6565b611ba85760405163a4875a4960e01b815260040160405180910390fd5b611bb0611580565b611bcd576040516306717a3b60e51b815260040160405180910390fd5b611bd6826114c4565b611bf3576040516393eeb41560e01b815260040160405180910390fd5b611bfd8383610d19565b611c1a576040516366be767160e11b815260040160405180910390fd5b600e543414611c3c5760405163078d696560e31b815260040160405180910390fd5b611c4581611242565b611c6257604051636c501c9960e11b815260040160405180910390fd5b600082611c6e83611eb2565b611c789190612e22565b6040516370a0823160e01b81526001600160a01b03868116600483015291925083918391908316906370a082319060240160206040518083038186803b158015611cc157600080fd5b505afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190612e41565b1015611d1857604051631642df1760e21b815260040160405180910390fd5b604051636eb1769f60e11b81526001600160a01b03868116600483015230602483015283919083169063dd62ed3e9060440160206040518083038186803b158015611d6257600080fd5b505afa158015611d76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9a9190612e41565b1015611db95760405163017e286b60e51b815260040160405180910390fd5b6040516323b872dd60e01b81526001600160a01b03868116600483015230602483015260448201849052600091908316906323b872dd90606401602060405180830381600087803b158015611e0d57600080fd5b505af1158015611e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e459190612e5a565b905080611e6557604051633c9fd93960e21b815260040160405180910390fd5b611e6d61218d565b611e7786866121cf565b611e8186866121f1565b505050505050565b611e916123fe565b6001600160a01b03166000908152601160205260409020805460ff19169055565b6000611ebd82611242565b611eda57604051636c501c9960e11b815260040160405180910390fd5b506001600160a01b031660009081526011602052604090206001015490565b611f016123fe565b6001600160a01b03929092166000908152601160205260409020805460ff191691151591909117815560010155565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b611f6361257a565b6001600160a01b038116611f8a576040516322646a9760e21b815260040160405180910390fd5b611f9381611640565b611fb057604051638afaeb9d60e01b815260040160405180910390fd5b6001600160a01b03166000908152600660205260409020805460ff19169055565b611fd96123fe565b670de0b6b3a76400008110156120025760405163b562e8dd60e01b815260040160405180910390fd5b61200b81611aa6565b6114b65760405163a4875a4960e01b815260040160405180910390fd5b6000670de0b6b3a764000082101561205357604051631cdaa1ed60e31b815260040160405180910390fd5b6000612067670de0b6b3a764000084612ea8565b9050600e5481600d5461207a9190612e22565b6120849190612e0a565b9392505050565b61209361257a565b6001600160a01b0381166120ba576040516322646a9760e21b815260040160405180910390fd5b61127c816125d4565b6120cb6123fe565b6016805462ffff00191662010000179055565b6001600160a01b038316612105576040516322646a9760e21b815260040160405180910390fd5b6001600160a01b03821661212c576040516322646a9760e21b815260040160405180910390fd5b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600e5460405173a9dac8f3aedc55d0fe707b86b8a45d246858d2e19180156108fc02916000818181858888f1935050505015801561127c573d6000803e3d6000fd5b6001600160a01b03909116600090815260096020526040902080549091019055565b6001600160a01b038216612218576040516322646a9760e21b815260040160405180910390fd5b806002600082825461222a9190612e0a565b90915550506001600160a01b03821660009081526020819052604081208054839290612257908490612e0a565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b60006122ad8484611f30565b905060001981146117d357818110156122d957604051631642df1760e21b815260040160405180910390fd5b6117d384848484036120de565b6001600160a01b03831661230d576040516322646a9760e21b815260040160405180910390fd5b6001600160a01b038216612334576040516322646a9760e21b815260040160405180910390fd5b6001600160a01b0383166000908152602081905260409020548181101561236e57604051631642df1760e21b815260040160405180910390fd5b6001600160a01b038085166000908152602081905260408082208585039055918516815290812080548492906123a5908490612e0a565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516123f191815260200190565b60405180910390a36117d3565b6005546001600160a01b0316339081149060009061241b90611640565b905081806124265750805b6114c05760405162461bcd60e51b815260206004820152602960248201527f5465616d3a2063616c6c6572206973206e6f7420746865206f776e6572206f726044820152681034b7102a32b0b69760b91b60648201526084015b60405180910390fd5b60008261249685846126b3565b14949350505050565b6001600160a01b0382166124c6576040516322646a9760e21b815260040160405180910390fd5b6001600160a01b0382166000908152602081905260409020548181101561250057604051631642df1760e21b815260040160405180910390fd5b6001600160a01b038316600090815260208190526040812083830390556002805484929061252f908490612eca565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b6005546001600160a01b0316331461150d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401612480565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60005b6015548110156114c0576126a16012828154811061264957612649612e77565b9060005260206000200160009054906101000a90046001600160a01b031660646014848154811061267c5761267c612e77565b9060005260206000200154856126929190612e22565b61269c9190612ea8565b612727565b806126ab81612e8d565b915050612629565b600081815b845181101561271f5760008582815181106126d5576126d5612e77565b602002602001015190508083116126fb576000838152602082905260409020925061270c565b600081815260208490526040902092505b508061271781612e8d565b9150506126b8565b509392505050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612774576040519150601f19603f3d011682016040523d82523d6000602084013e612779565b606091505b5050905080611aa15760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b6044820152606401612480565b508054600082559060005260206000209081019061127c919061287b565b828054828255906000526020600020908101928215612830579160200282015b8281111561283057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906127fb565b5061283c92915061287b565b5090565b828054828255906000526020600020908101928215612830579160200282015b82811115612830578251825591602001919060010190612860565b5b8082111561283c576000815560010161287c565b600060208083528351808285015260005b818110156128bd578581018301518582016040015282016128a1565b818111156128cf576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b03811681146128fc57600080fd5b919050565b6000806040838503121561291457600080fd5b61291d836128e5565b946020939093013593505050565b60008083601f84011261293d57600080fd5b50813567ffffffffffffffff81111561295557600080fd5b6020830191508360208260051b850101111561297057600080fd5b9250929050565b60008060008060006080868803121561298f57600080fd5b612998866128e5565b945060208601359350604086013567ffffffffffffffff8111156129bb57600080fd5b6129c78882890161292b565b90945092506129da9050606087016128e5565b90509295509295909350565b6000806000606084860312156129fb57600080fd5b612a04846128e5565b9250612a12602085016128e5565b9150604084013590509250925092565b600060208284031215612a3457600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612a7a57612a7a612a3b565b604052919050565b600067ffffffffffffffff821115612a9c57612a9c612a3b565b5060051b60200190565b600082601f830112612ab757600080fd5b81356020612acc612ac783612a82565b612a51565b82815260059290921b84018101918181019086841115612aeb57600080fd5b8286015b84811015612b0d57612b00816128e5565b8352918301918301612aef565b509695505050505050565b60008060408385031215612b2b57600080fd5b823567ffffffffffffffff80821115612b4357600080fd5b612b4f86838701612aa6565b9350602091508185013581811115612b6657600080fd5b85019050601f81018613612b7957600080fd5b8035612b87612ac782612a82565b81815260059190911b82018301908381019088831115612ba657600080fd5b928401925b82841015612bc457833582529284019290840190612bab565b80955050505050509250929050565b600080600060408486031215612be857600080fd5b612bf1846128e5565b9250602084013567ffffffffffffffff811115612c0d57600080fd5b612c198682870161292b565b9497909650939450505050565b600060208284031215612c3857600080fd5b612084826128e5565b801515811461127c57600080fd5b600060208284031215612c6157600080fd5b813561208481612c41565b60008060008060608587031215612c8257600080fd5b612c8b856128e5565b935060208501359250604085013567ffffffffffffffff811115612cae57600080fd5b612cba8782880161292b565b95989497509550505050565b60008060408385031215612cd957600080fd5b823567ffffffffffffffff811115612cf057600080fd5b612cfc85828601612aa6565b95602094909401359450505050565b600080600060608486031215612d2057600080fd5b612d29846128e5565b925060208401359150612d3e604085016128e5565b90509250925092565b600080600060608486031215612d5c57600080fd5b612d65846128e5565b92506020840135612d7581612c41565b929592945050506040919091013590565b60008060408385031215612d9957600080fd5b612da2836128e5565b9150612db0602084016128e5565b90509250929050565b600181811c90821680612dcd57607f821691505b60208210811415612dee57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612e1d57612e1d612df4565b500190565b6000816000190483118215151615612e3c57612e3c612df4565b500290565b600060208284031215612e5357600080fd5b5051919050565b600060208284031215612e6c57600080fd5b815161208481612c41565b634e487b7160e01b600052603260045260246000fd5b6000600019821415612ea157612ea1612df4565b5060010190565b600082612ec557634e487b7160e01b600052601260045260246000fd5b500490565b600082821015612edc57612edc612df4565b50039056fea26469706673582212209af33394c65b1c033c9856392d32857f08225a976a16f5f311f0a5ea6cb4736864736f6c63430008090033

Verified Source Code Partial Match

Compiler: v0.8.9+commit.e5eed63a EVM: london Optimization: Yes (200 runs)
ERC20Plus.sol 1300 lines
// SPDX-License-Identifier: MIT
error TransactionCapExceeded();
error ExcessiveOwnedMints();
error MintZeroQuantity();
error InvalidPayment();
error CapExceeded();
error ValueCannotBeZero();
error CannotBeNullAddress();
error InvalidTeamChange();
error InvalidInputValue();
error NoStateChange();

error PublicMintingClosed();
error AllowlistMintClosed();

error AddressNotAllowlisted();

error OnlyERC20MintingEnabled();
error ERC20TokenNotApproved();
error ERC20InsufficientBalance();
error ERC20InsufficientAllowance();
error ERC20TransferFailed();
error ERC20CappedInvalidValue();
error NotMaintainer();

pragma solidity ^0.8.0;

/**
* @dev These functions deal with verification of Merkle Trees proofs.
*
* The proofs can be generated using the JavaScript library
* https://github.com/miguelmota/merkletreejs[merkletreejs].
* Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
*
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
*/
library MerkleProof {
    /**
    * @dev Returns true if a 'leaf' can be proved to be a part of a Merkle tree
    * defined by 'root'. For this, a 'proof' must be provided, containing
    * sibling hashes on the branch from the leaf to the root of the tree. Each
    * pair of leaves and each pair of pre-images are assumed to be sorted.
    */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
    * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
    * from 'leaf' using 'proof'. A 'proof' is valid if and only if the rebuilt
    * hash matches the root of the tree. When processing the proof, the pairs
    * of leafs & pre-images are assumed to be sorted.
    *
    * _Available since v4.4._
    */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;


/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// File: @openzeppelin/contracts/token/ERC20/ERC20.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;




/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 private _totalSupply;
    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        if(currentAllowance < subtractedValue) revert ERC20InsufficientBalance();
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        if(from == address(0)) revert CannotBeNullAddress();
        if(to == address(0)) revert CannotBeNullAddress();

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        if(fromBalance < amount) revert ERC20InsufficientBalance();
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        if(account == address(0)) revert CannotBeNullAddress();

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        if(account == address(0)) revert CannotBeNullAddress();

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        if(accountBalance < amount) revert ERC20InsufficientBalance();
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        if(owner == address(0)) revert CannotBeNullAddress();
        if(spender == address(0)) revert CannotBeNullAddress();

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if(currentAllowance < amount) revert ERC20InsufficientBalance();
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// File: contracts/erc20.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.0;



/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        _spendAllowance(account, _msgSender(), amount);
        _burn(account, amount);
    }
}

// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if(newOwner == address(0)) revert CannotBeNullAddress();
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// Rampp Contracts v2.1 (Teams.sol)

pragma solidity ^0.8.0;

/**
* Teams is a contract implementation to extend upon Ownable that allows multiple controllers
* of a single contract to modify specific mint settings but not have overall ownership of the contract.
* This will easily allow cross-collaboration via Mintplex.xyz.
**/
abstract contract Teams is Ownable{
  mapping (address => bool) internal team;

  /**
  * @dev Adds an address to the team. Allows them to execute protected functions
  * @param _address the ETH address to add, cannot be 0x and cannot be in team already
  **/
  function addToTeam(address _address) public onlyOwner {
    if(_address == address(0)) revert CannotBeNullAddress();
    if(inTeam(_address)) revert InvalidTeamChange();
  
    team[_address] = true;
  }

  /**
  * @dev Removes an address to the team.
  * @param _address the ETH address to remove, cannot be 0x and must be in team
  **/
  function removeFromTeam(address _address) public onlyOwner {
    if(_address == address(0)) revert CannotBeNullAddress();
    if(!inTeam(_address)) revert InvalidTeamChange();
  
    team[_address] = false;
  }

  /**
  * @dev Check if an address is valid and active in the team
  * @param _address ETH address to check for truthiness
  **/
  function inTeam(address _address)
    public
    view
    returns (bool)
  {
    if(_address == address(0)) revert CannotBeNullAddress();
    return team[_address] == true;
  }

  /**
  * @dev Throws if called by any account other than the owner or team member.
  */
  function _onlyTeamOrOwner() private view {
    bool _isOwner = owner() == _msgSender();
    bool _isTeam = inTeam(_msgSender());
    require(_isOwner || _isTeam, "Team: caller is not the owner or in Team.");
  }

  modifier onlyTeamOrOwner() {
    _onlyTeamOrOwner();
    _;
  }
}

// @dev Allows the contract to have an enforceable supply cap.
// @notice This is toggleable by the team, so supply can be unlimited/limited at will.
abstract contract ERC20Capped is ERC20, Teams {
    bool public _capEnabled;
    uint256 internal _cap; // Supply Cap of entire token contract

    function setCapStatus(bool _capStatus) public onlyTeamOrOwner {
        _capEnabled = _capStatus;
    }

    function canMintAmount(uint256 _amount) public view returns (bool) {
        if(!_capEnabled){ return true; }
        return ERC20.totalSupply() + _amount <= supplyCap();
    }

    // @dev Update the total possible supply to a new value.
    // @notice _newCap must be greater than or equal to the currently minted supply
    // @param _newCap is the new amount of tokens available in wei
    function setSupplyCap(uint256 _newCap) public onlyTeamOrOwner {
        if(_newCap < ERC20.totalSupply()) revert ERC20CappedInvalidValue();
        _cap = _newCap;
    }

    function supplyCap() public view virtual returns (uint256) {
        if(!_capEnabled){ return ERC20.totalSupply(); }
        return _cap;
    }
}

abstract contract Feeable is Teams {
  uint256 public PRICE = 0 ether;
  uint256 public PROVIDER_FEE = 0.000777 ether;  
  address private constant PROVIDER = 0xa9dAC8f3aEDC55D0FE707B86B8A45d246858d2E1;

  function setPrice(uint256 _feeInWei) public onlyTeamOrOwner {
    PRICE = _feeInWei;
  }

  // @dev quickly calculate the fee that will be required for a given qty to mint
  // @notice _count is the value in wei, not in human readable count
  // @param _count is representation of quantity in wei. it will be converted to eth to arrive at proper value
  function getPrice(uint256 _count) public view returns (uint256) {
    if(_count < 1 ether) revert InvalidInputValue();
    uint256 countHuman = _count / 1 ether;
    return (PRICE * countHuman) + PROVIDER_FEE;
  }

  function sendProviderFee() internal {
    payable(PROVIDER).transfer(PROVIDER_FEE);
  }

  function setProviderFee(uint256 _fee) public {
    if(_msgSender() != PROVIDER) revert NotMaintainer();
    PROVIDER_FEE = _fee;
  }
}

// File: Allowlist.sol

pragma solidity ^0.8.0;

abstract contract Allowlist is Teams {
    bytes32 public merkleRoot;
    bool public onlyAllowlistMode = false;

    /**
        * @dev Update merkle root to reflect changes in Allowlist
        * @param _newMerkleRoot new merkle root to reflect most recent Allowlist
        */
    function updateMerkleRoot(bytes32 _newMerkleRoot) public onlyTeamOrOwner {
        if(_newMerkleRoot == merkleRoot) revert NoStateChange();
        merkleRoot = _newMerkleRoot;
    }

    /**
        * @dev Check the proof of an address if valid for merkle root
        * @param _to address to check for proof
        * @param _merkleProof Proof of the address to validate against root and leaf
        */
    function isAllowlisted(address _to, bytes32[] calldata _merkleProof) public view returns(bool) {
        if(merkleRoot == 0) revert ValueCannotBeZero();
        bytes32 leaf = keccak256(abi.encodePacked(_to));

        return MerkleProof.verify(_merkleProof, merkleRoot, leaf);
    }


    function enableAllowlistOnlyMode() public onlyTeamOrOwner {
        onlyAllowlistMode = true;
    }

    function disableAllowlistOnlyMode() public onlyTeamOrOwner {
        onlyAllowlistMode = false;
    }
}

// File: WithdrawableV2
// This abstract allows the contract to be able to mint and ingest ERC-20 payments for mints.
// ERC-20 Payouts are limited to a single payout address.
abstract contract WithdrawableV2 is Teams {
  struct acceptedERC20 {
    bool isActive;
    uint256 chargeAmount;
  }
  mapping(address => acceptedERC20) private allowedTokenContracts;
  address[] public payableAddresses;
  address public erc20Payable;
  uint256[] public payableFees;
  uint256 public payableAddressCount;
  bool public onlyERC20MintingMode;

  function withdrawAll() public onlyTeamOrOwner {
      if(address(this).balance == 0) revert ValueCannotBeZero();
      _withdrawAll(address(this).balance);
  }

  function _withdrawAll(uint256 balance) private {
      for(uint i=0; i < payableAddressCount; i++ ) {
          _widthdraw(
              payableAddresses[i],
              (balance * payableFees[i]) / 100
          );
      }
  }
  
  function _widthdraw(address _address, uint256 _amount) private {
      (bool success, ) = _address.call{value: _amount}("");
      require(success, "Transfer failed.");
  }

  /**
  * @dev Allow contract owner to withdraw ERC-20 balance from contract
  * in the event ERC-20 tokens are paid to the contract for mints.
  * @param _tokenContract contract of ERC-20 token to withdraw
  * @param _amountToWithdraw balance to withdraw according to balanceOf of ERC-20 token in wei
  */
  function withdrawERC20(address _tokenContract, uint256 _amountToWithdraw) public onlyTeamOrOwner {
    if(_amountToWithdraw == 0) revert ValueCannotBeZero();
    IERC20 tokenContract = IERC20(_tokenContract);
    if(tokenContract.balanceOf(address(this)) < _amountToWithdraw) revert ERC20InsufficientBalance();
    tokenContract.transfer(erc20Payable, _amountToWithdraw); // Payout ERC-20 tokens to recipient
  }

  /**
  * @dev check if an ERC-20 contract is a valid payable contract for executing a mint.
  * @param _erc20TokenContract address of ERC-20 contract in question
  */
  function isApprovedForERC20Payments(address _erc20TokenContract) public view returns(bool) {
    return allowedTokenContracts[_erc20TokenContract].isActive == true;
  }

  /**
  * @dev get the value of tokens to transfer for user of an ERC-20
  * @param _erc20TokenContract address of ERC-20 contract in question
  */
  function chargeAmountForERC20(address _erc20TokenContract) public view returns(uint256) {
    if(!isApprovedForERC20Payments(_erc20TokenContract)) revert ERC20TokenNotApproved();
    return allowedTokenContracts[_erc20TokenContract].chargeAmount;
  }

  /**
  * @dev Explicity sets and ERC-20 contract as an allowed payment method for minting
  * @param _erc20TokenContract address of ERC-20 contract in question
  * @param _isActive default status of if contract should be allowed to accept payments
  * @param _chargeAmountInTokens fee (in tokens) to charge for mints for this specific ERC-20 token
  */
  function addOrUpdateERC20ContractAsPayment(address _erc20TokenContract, bool _isActive, uint256 _chargeAmountInTokens) public onlyTeamOrOwner {
    allowedTokenContracts[_erc20TokenContract].isActive = _isActive;
    allowedTokenContracts[_erc20TokenContract].chargeAmount = _chargeAmountInTokens;
  }

  /**
  * @dev Add an ERC-20 contract as being a valid payment method. If passed a contract which has not been added
  * it will assume the default value of zero. This should not be used to create new payment tokens.
  * @param _erc20TokenContract address of ERC-20 contract in question
  */
  function enableERC20ContractAsPayment(address _erc20TokenContract) public onlyTeamOrOwner {
    allowedTokenContracts[_erc20TokenContract].isActive = true;
  }

  /**
  * @dev Disable an ERC-20 contract as being a valid payment method. If passed a contract which has not been added
  * it will assume the default value of zero. This should not be used to create new payment tokens.
  * @param _erc20TokenContract address of ERC-20 contract in question
  */
  function disableERC20ContractAsPayment(address _erc20TokenContract) public onlyTeamOrOwner {
    allowedTokenContracts[_erc20TokenContract].isActive = false;
  }

  /**
  * @dev Enable only ERC-20 payments for minting on this contract
  */
  function enableERC20OnlyMinting() public onlyTeamOrOwner {
    onlyERC20MintingMode = true;
  }

  /**
  * @dev Disable only ERC-20 payments for minting on this contract
  */
  function disableERC20OnlyMinting() public onlyTeamOrOwner {
    onlyERC20MintingMode = false;
  }

  /**
  * @dev Set the payout of the ERC-20 token payout to a specific address
  * @param _newErc20Payable new payout addresses of ERC-20 tokens
  */
  function setERC20PayableAddress(address _newErc20Payable) public onlyTeamOrOwner {
    if(_newErc20Payable == address(0)) revert CannotBeNullAddress();
    if(_newErc20Payable == erc20Payable) revert NoStateChange();
    erc20Payable = _newErc20Payable;
  }

  function definePayables(address[] memory _newPayables, uint256[] memory _newFees) public onlyTeamOrOwner {
      delete payableAddresses;
      delete payableFees;
      payableAddresses = _newPayables;
      payableFees = _newFees;
      payableAddressCount = _newPayables.length;
  }
}

// @dev Allows us to add per wallet and per transaction caps to the minting aspect of this ERC20
abstract contract ERC20MintCaps is Teams {
    mapping(address => uint256) private _minted;
    bool internal _mintCapEnabled; // per wallet mint cap
    bool internal _batchSizeEnabled; // txn batch size limit
    uint256 internal mintCap; // in wei
    uint256 internal maxBatchSize; // in wei

    function setMintCap(uint256 _newMintCap) public onlyTeamOrOwner {
        mintCap = _newMintCap;
    }

    function setMintCapStatus(bool _newStatus) public onlyTeamOrOwner {
        _mintCapEnabled = _newStatus;
    }

    function setMaxBatchSize(uint256 _maxBatchSize) public onlyTeamOrOwner {
        maxBatchSize = _maxBatchSize;
    }

    function setMaxBatchSizeStatus(bool _newStatus) public onlyTeamOrOwner {
        _batchSizeEnabled = _newStatus;
    }

    // @dev Check if amount of tokens is possible to be minted
    // @param _amount is the amount of tokens in wei
    function canMintBatch(uint256 _amount) public view returns (bool) {
        if(!_batchSizeEnabled){ return true; }
        return _amount <= maxBatchSize;
    }

    // @dev returns if current mint caps are enabled (mints per wallet)
    // @return bool if mint caps per wallet are enforced
    function mintCapEnabled() public view returns (bool) {
        return _mintCapEnabled;
    }

    // @dev the current mintCap in decimals value
    // @return uint256 of mint caps per wallet. mintCapEnabled can be disabled and this value be non-zero.
    function maxWalletMints() public view returns(uint256) {
        return mintCap;
    }

    // @dev returns if current batch size caps are enabled (mints per txn)
    // @return bool if mint caps per transaction are enforced
    function mintBatchSizeEnabled() public view returns (bool) {
        return _batchSizeEnabled;
    }

    // @dev the current cap for a single txn in decimals value
    // @return uint256 the current cap for a single txn in decimals value
    function maxMintsPerTxn() public view returns (uint256) {
        return maxBatchSize;
    }

    // @dev checks if the mint count of an account is within the proper range
    // @notice if maxWalletMints is false it will always return true
    // @param _account is address to check
    // @param _amount is the amount of tokens in wei to be added to current minted supply
    function canAccountMintAmount(address _account, uint256 _amount) public view returns (bool) {
        if(!_mintCapEnabled){ return true; }
        return mintedAmount(_account) + _amount <= mintCap;
    }

    // @dev gets currently minted amount for an account
    // @return uint256 of tokens owned in base decimal value (wei)
    function mintedAmount(address _account) public view returns (uint256) {
        return _minted[_account];
    }

    // @dev helper function that increased the mint amount for an account
    // @notice this is not the same as _balances, as that can vary as trades occur.
    // @param _account is address to add to
    // @param _amount is the amount of tokens in wei to be added to current minted amount
    function addMintsToAccount(address _account, uint256 _amount) internal {
        unchecked {
            _minted[_account] += _amount;
        }
    }
}

abstract contract SingleStateMintable is Teams {
    bool internal publicMintOpen = false;
    bool internal allowlistMintOpen = false;

    function inPublicMint() public view returns (bool){
        return publicMintOpen && !allowlistMintOpen;
    }

    function inAllowlistMint() public view returns (bool){
        return allowlistMintOpen && !publicMintOpen;
    }

    function openPublicMint() public onlyTeamOrOwner {
        publicMintOpen = true;
        allowlistMintOpen = false;
    }

    function openAllowlistMint() public onlyTeamOrOwner {
        allowlistMintOpen = true;
        publicMintOpen = false;
    }

    // @notice This will set close all minting to public regardless of previous state
    function closeMinting() public onlyTeamOrOwner {
        allowlistMintOpen = false;
        publicMintOpen = false;
    }
}


// File: contracts/ERC20Plus.sol
pragma solidity ^0.8.0;

contract ERC20Plus is 
    Ownable,
    ERC20Burnable,
    ERC20Capped,
    ERC20MintCaps,
    Feeable,
    Allowlist,
    WithdrawableV2,
    SingleStateMintable
    {
    uint8 immutable CONTRACT_VERSION = 1;
    constructor(
        string memory name,
        string memory symbol,
        address[] memory _payableAddresses,
        address _erc20Payable,
        uint256[] memory _payableFees,
        bool[3] memory mintSettings, // hasMaxSupply, mintCapEnabled, maxBatchEnabled
        uint256[3] memory mintValues, // initMaxSupply, initMintCap, initBatchSize
        uint256 initPrice
    ) ERC20(name, symbol) {
        // Payable settings
        payableAddresses = _payableAddresses;
        erc20Payable = _erc20Payable;
        payableFees = _payableFees;
        payableAddressCount = _payableAddresses.length;

        // Set inital Supply cap settings
        _capEnabled = mintSettings[0];
        _cap = mintValues[0];
        
        // Per wallet minting settings
        _mintCapEnabled = mintSettings[1];
        mintCap = mintValues[1];

        // Per txn minting settings
        _batchSizeEnabled = mintSettings[2];
        maxBatchSize = mintValues[2];

        // setup price
        PRICE = initPrice;
    }

    /////////////// Admin Mint Functions
    /**
    * @dev Mints tokens to an address.
    * This is owner only and allows a fee-free drop
    * @param _to address of the future owner of the token
    * @param _qty amount of tokens to drop the owner in decimal value (wei typically 1e18)
    */
    function adminMint(address _to, uint256 _qty) public onlyTeamOrOwner{
        if(_qty < 1 ether) revert MintZeroQuantity();
        if(!canMintAmount(_qty)) revert CapExceeded();
        _mint(_to, _qty);
    }

    function adminMintBulk(address[] memory _tos, uint256 _qty) public onlyTeamOrOwner{
        if(_qty < 1 ether) revert MintZeroQuantity();
        for(uint i=0; i < _tos.length; i++ ) {
            _mint(_tos[i], _qty);
        }
    }

    /////////////// GENERIC MINT FUNCTIONS
    /**
    * @dev Mints tokens to an address in batch.
    * fee may or may not be required*
    * @param _to address of the future owner of the token
    * @param _amount number of tokens to mint in wei
    */
    function mintMany(address _to, uint256 _amount) public payable {
        if(onlyERC20MintingMode) revert PublicMintingClosed();
        if(_amount < 1 ether) revert MintZeroQuantity();
        if(!inPublicMint()) revert PublicMintingClosed();
        if(!canMintBatch(_amount)) revert TransactionCapExceeded();
        if(!canMintAmount(_amount)) revert CapExceeded();
        if(!canAccountMintAmount(_to, _amount)) revert ExcessiveOwnedMints();
        if(msg.value != getPrice(_amount)) revert InvalidPayment();
        
        sendProviderFee();
        addMintsToAccount(_to, _amount);
        _mint(_to, _amount);
    }

    /**
     * @dev Mints tokens to an address in batch using an ERC-20 token for payment
     * fee may or may not be required*
     * @param _to address of the future owner of the token
     * @param _amount number of tokens to mint in wei
     * @param _erc20TokenContract erc-20 token contract to mint with
     */
    function mintManyERC20(address _to, uint256 _amount, address _erc20TokenContract) public payable {
        if(_amount < 1 ether) revert MintZeroQuantity();
        if(!canMintAmount(_amount)) revert CapExceeded();
        if(!inPublicMint()) revert PublicMintingClosed();
        if(!canMintBatch(_amount)) revert TransactionCapExceeded();
        if(!canAccountMintAmount(_to, _amount)) revert ExcessiveOwnedMints();
        if(msg.value != PROVIDER_FEE) revert InvalidPayment();

        // ERC-20 Specific pre-flight checks
        if(!isApprovedForERC20Payments(_erc20TokenContract)) revert ERC20TokenNotApproved();
        uint256 tokensQtyToTransfer = chargeAmountForERC20(_erc20TokenContract) * _amount;
        IERC20 payableToken = IERC20(_erc20TokenContract);

        if(payableToken.balanceOf(_to) < tokensQtyToTransfer) revert ERC20InsufficientBalance();
        if(payableToken.allowance(_to, address(this)) < tokensQtyToTransfer) revert ERC20InsufficientAllowance();
        bool transferComplete = payableToken.transferFrom(_to, address(this), tokensQtyToTransfer);
        if(!transferComplete) revert ERC20TransferFailed();
        
        sendProviderFee();
        addMintsToAccount(_to, _amount);
        _mint(_to, _amount);
    }

    /**
    * @dev Mints tokens to an address using an allowlist.
    * fee may or may not be required*
    * @param _to address of the future owner of the token
    * @param _amount number of tokens to mint in wei
    * @param _merkleProof merkle proof array
    */
    function mintManyAL(address _to, uint256 _amount, bytes32[] calldata _merkleProof) public payable {
        if(onlyERC20MintingMode) revert AllowlistMintClosed();
        if(_amount < 1 ether) revert MintZeroQuantity();
        if(!inAllowlistMint()) revert AllowlistMintClosed();
        if(!isAllowlisted(_to, _merkleProof)) revert AddressNotAllowlisted();
        if(!canMintBatch(_amount)) revert TransactionCapExceeded();
        if(!canAccountMintAmount(_to, _amount)) revert ExcessiveOwnedMints();
        if(!canMintAmount(_amount)) revert CapExceeded();
        if(msg.value != getPrice(_amount)) revert InvalidPayment();
        
        sendProviderFee();
        addMintsToAccount(_to, _amount);
        _mint(_to, _amount);
    }

    /**
    * @dev Mints tokens to an address using an allowlist.
    * fee may or may not be required*
    * @param _to address of the future owner of the token
    * @param _amount number of tokens to mint in wei
    * @param _merkleProof merkle proof array
    * @param _erc20TokenContract erc-20 token contract to mint with
    */
    function mintManyERC20AL(address _to, uint256 _amount, bytes32[] calldata _merkleProof, address _erc20TokenContract) public payable {
        if(!inAllowlistMint()) revert AllowlistMintClosed();
        if(_amount < 1 ether) revert MintZeroQuantity();
        if(!isAllowlisted(_to, _merkleProof)) revert AddressNotAllowlisted();
        if(!canMintBatch(_amount)) revert TransactionCapExceeded();
        if(!canAccountMintAmount(_to, _amount)) revert ExcessiveOwnedMints();
        if(!canMintAmount(_amount)) revert CapExceeded();
        if(msg.value != PROVIDER_FEE) revert InvalidPayment();
        
        // ERC-20 Specific pre-flight checks
        if(!isApprovedForERC20Payments(_erc20TokenContract)) revert ERC20TokenNotApproved();
        uint256 tokensQtyToTransfer = chargeAmountForERC20(_erc20TokenContract) * _amount;
        IERC20 payableToken = IERC20(_erc20TokenContract);
        
        if(payableToken.balanceOf(_to) < tokensQtyToTransfer) revert ERC20InsufficientBalance();
        if(payableToken.allowance(_to, address(this)) < tokensQtyToTransfer) revert ERC20InsufficientAllowance();
        
        bool transferComplete = payableToken.transferFrom(_to, address(this), tokensQtyToTransfer);
        if(!transferComplete) revert ERC20TransferFailed();

        sendProviderFee();
        addMintsToAccount(_to, _amount);
        _mint(_to, _amount);
    }
}

Read Contract

PRICE 0x8d859f3e → uint256
PROVIDER_FEE 0xf623bb8b → uint256
_capEnabled 0x20fab142 → bool
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
canAccountMintAmount 0x0825850a → bool
canMintAmount 0xb0cfbf16 → bool
canMintBatch 0x627255df → bool
chargeAmountForERC20 0xd266f3a9 → uint256
decimals 0x313ce567 → uint8
erc20Payable 0x7fb8c6d3 → address
getPrice 0xe7572230 → uint256
inAllowlistMint 0x4c23ce91 → bool
inPublicMint 0x88993c81 → bool
inTeam 0xa1af10ca → bool
isAllowlisted 0x33006786 → bool
isApprovedForERC20Payments 0x3d3f9c57 → bool
maxMintsPerTxn 0xaf54001e → uint256
maxWalletMints 0x34d00766 → uint256
merkleRoot 0x2eb4a7ab → bytes32
mintBatchSizeEnabled 0xf82fa756 → bool
mintCapEnabled 0x1963d0cc → bool
mintedAmount 0xfbbf8cc3 → uint256
name 0x06fdde03 → string
onlyAllowlistMode 0xe6c6990a → bool
onlyERC20MintingMode 0x46f41ed5 → bool
owner 0x8da5cb5b → address
payableAddressCount 0x3e07311c → uint256
payableAddresses 0x891bbe73 → address
payableFees 0x286c8137 → uint256
supplyCap 0x8f770ad0 → uint256
symbol 0x95d89b41 → string
totalSupply 0x18160ddd → uint256

Write Contract 40 functions

These functions modify contract state and require a wallet transaction to execute.

addOrUpdateERC20ContractAsPayment 0xd83ae332
address _erc20TokenContract
bool _isActive
uint256 _chargeAmountInTokens
addToTeam 0x43696f18
address _address
adminMint 0xe58306f9
address _to
uint256 _qty
adminMintBulk 0xafb16d18
address[] _tos
uint256 _qty
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
burn 0x42966c68
uint256 amount
burnFrom 0x79cc6790
address account
uint256 amount
closeMinting 0x87491c60
No parameters
decreaseAllowance 0xa457c2d7
address spender
uint256 subtractedValue
returns: bool
definePayables 0x28ff1b51
address[] _newPayables
uint256[] _newFees
disableAllowlistOnlyMode 0x6d3de806
No parameters
disableERC20ContractAsPayment 0xcacf0842
address _erc20TokenContract
disableERC20OnlyMinting 0xb94b2376
No parameters
enableAllowlistOnlyMode 0x79ab3c89
No parameters
enableERC20ContractAsPayment 0x464c3428
address _erc20TokenContract
enableERC20OnlyMinting 0x89f26d58
No parameters
increaseAllowance 0x39509351
address spender
uint256 addedValue
returns: bool
mintMany 0x5e830656
address _to
uint256 _amount
mintManyAL 0xad1203dc
address _to
uint256 _amount
bytes32[] _merkleProof
mintManyERC20 0xc6ee6e35
address _to
uint256 _amount
address _erc20TokenContract
mintManyERC20AL 0x2181384e
address _to
uint256 _amount
bytes32[] _merkleProof
address _erc20TokenContract
openAllowlistMint 0xf8c0fd20
No parameters
openPublicMint 0x45f7e06e
No parameters
removeFromTeam 0xdfdedf69
address _address
renounceOwnership 0x715018a6
No parameters
setCapStatus 0xc3268768
bool _capStatus
setERC20PayableAddress 0xa91bd1a9
address _newErc20Payable
setMaxBatchSize 0x2b26a6bf
uint256 _maxBatchSize
setMaxBatchSizeStatus 0x98ad4417
bool _newStatus
setMintCap 0x4070a0c9
uint256 _newMintCap
setMintCapStatus 0xc3cb97c6
bool _newStatus
setPrice 0x91b7f5ed
uint256 _feeInWei
setProviderFee 0xa7593fb7
uint256 _fee
setSupplyCap 0xb6a3f59a
uint256 _newCap
transfer 0xa9059cbb
address to
uint256 amount
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 amount
returns: bool
transferOwnership 0xf2fde38b
address newOwner
updateMerkleRoot 0x4783f0ef
bytes32 _newMerkleRoot
withdrawAll 0x853828b6
No parameters
withdrawERC20 0xa1db9782
address _tokenContract
uint256 _amountToWithdraw

Recent Transactions

No transactions found for this address