Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x1c74d8C8FE37B0fA47deBc82E0AB6925A3DC4a2F
Balance 0 ETH
Nonce 1
Code Size 10303 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

10303 bytes
0x6080604052600436106102305760003560e01c8063871c42b71161012e578063c5be2bc7116100ab578063e2ce1ac71161006f578063e2ce1ac7146106e1578063ec28438a146106f7578063f2fde38b1461070a578063f36aa6071461072a578063ff0087761461073d57600080fd5b8063c5be2bc71461058f578063c6af580b146105bf578063dd62ed3e146105d2578063dfa8bbeb14610618578063e06174e41461064857600080fd5b8063960bfe04116100f2578063960bfe0414610506578063a614ff7514610519578063a9059cbb1461052c578063b17b658d1461054c578063b9a6672c1461057c57600080fd5b8063871c42b71461047a5780638da5cb5b146104aa5780638fbf1e93146104c8578063918f8674146104db57806395d89b41146104f157600080fd5b80632febd2ae116101bc578063541958ff11610180578063541958ff146103f65780635afde063146104095780636cec0ceb1461041c57806370a082311461042f578063715018a61461046557600080fd5b80632febd2ae1461037f578063313ce5671461039257806339a91a15146103ae5780633d3d1141146103b65780634ff0b1d2146103c957600080fd5b80631f6976a6116102035780631f6976a6146102df57806323b872dd1461031757806327a14fc21461033757806327bf24e21461034c5780632b06dbbb1461035f57600080fd5b806306fdde0314610235578063095ea7b31461026057806318160ddd14610290578063181b72aa146102af575b600080fd5b34801561024157600080fd5b5061024a61076d565b60405161025791906120aa565b60405180910390f35b34801561026c57600080fd5b5061028061027b3660046120e2565b6107ff565b6040519015158152602001610257565b34801561029c57600080fd5b506002545b604051908152602001610257565b3480156102bb57600080fd5b506102806102ca36600461210e565b60126020526000908152604090205460ff1681565b3480156102eb57600080fd5b506019546102ff906001600160a01b031681565b6040516001600160a01b039091168152602001610257565b34801561032357600080fd5b5061028061033236600461212b565b610819565b61034a61034536600461216c565b610881565b005b61034a61035a36600461216c565b6108e8565b34801561036b57600080fd5b506102ff61037a36600461216c565b610925565b61034a61038d36600461219e565b61094f565b34801561039e57600080fd5b5060405160128152602001610257565b61034a6109e2565b61034a6103c436600461219e565b6109f4565b3480156103d557600080fd5b506102a16103e436600461210e565b60176020526000908152604090205481565b61034a6104043660046121d7565b610a58565b61034a61041736600461219e565b610aa9565b61034a61042a36600461216c565b610b0d565b34801561043b57600080fd5b506102a161044a36600461210e565b6001600160a01b031660009081526020819052604090205490565b34801561047157600080fd5b5061034a610b4a565b34801561048657600080fd5b5061028061049536600461210e565b60136020526000908152604090205460ff1681565b3480156104b657600080fd5b506005546001600160a01b03166102ff565b61034a6104d636600461210e565b610b5c565b3480156104e757600080fd5b506102a160105481565b3480156104fd57600080fd5b5061024a610bd9565b61034a61051436600461216c565b610be8565b61034a6105273660046121d7565b610c25565b34801561053857600080fd5b506102806105473660046120e2565b610c78565b34801561055857600080fd5b5061028061056736600461210e565b60156020526000908152604090205460ff1681565b61034a61058a36600461219e565b610cce565b34801561059b57600080fd5b506105af6105aa36600461216c565b610d32565b60405161025794939291906121f4565b61034a6105cd3660046121d7565b610e2d565b3480156105de57600080fd5b506102a16105ed366004612243565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561062457600080fd5b5061028061063336600461210e565b60146020526000908152604090205460ff1681565b34801561065457600080fd5b50600854600954600a54600b54600c54600d54600e54600f54610691979695949392919060ff80821691610100810482169162010000909104168a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925260a086015260c0850152151560e08401521515610100830152151561012082015261014001610257565b3480156106ed57600080fd5b506102a160075481565b61034a61070536600461216c565b610e76565b34801561071657600080fd5b5061034a61072536600461210e565b610ed6565b61034a610738366004612271565b610f19565b34801561074957600080fd5b5061028061075836600461210e565b60166020526000908152604090205460ff1681565b60606003805461077c906122f7565b80601f01602080910402602001604051908101604052809291908181526020018280546107a8906122f7565b80156107f55780601f106107ca576101008083540402835291602001916107f5565b820191906000526020600020905b8154815290600101906020018083116107d857829003601f168201915b5050505050905090565b60003361080d818585611119565b60019150505b92915050565b60003361082785828561112b565b60115460009060ff1660010361085f576011805460ff1916600217905561084f8686866111a9565b6011805460ff1916600117905590505b610873868661086e8488612347565b6118b9565b6001925050505b9392505050565b610889611918565b600e548110156108ac576040516307f02b7960e51b815260040160405180910390fd5b600d8190556040518181527f0176e9211818debdc4483c2bb0972798b7eb106239c8e465d4f1cee4ce5ae6e7906020015b60405180910390a150565b6108f0611918565b60098190556040518181527f933cdf8eb45e2bf17bff01bdf25b6516f3e3eda7bb81120c41bff9285008dac0906020016108dd565b6018818154811061093557600080fd5b6000918252602090912001546001600160a01b0316905081565b610957611918565b6001600160a01b03821661097e5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216600081815260156020908152604091829020805460ff19168515159081179091558251938452908301527f8b4bb68e253154bb2e75802b8914dddd9ecfaa965eca8e5a323553017b6bcc0d91015b60405180910390a15050565b6109ea611918565b6109f2611945565b565b6109fc611918565b6001600160a01b038216600081815260136020908152604091829020805460ff19168515159081179091558251938452908301527ff06306d03b4f240d8198e91f68418777423bb61df08b8d71032a9cfa211b4ae191016109d6565b610a60611918565b600f80548215156101000261ff00199091161790556040517ff65dac9e0e14b7aec57d4f1fea4ffce1fa2e22a81d90693329df834fbabbb789906108dd90831515815260200190565b610ab1611918565b6001600160a01b038216600081815260126020908152604091829020805460ff19168515159081179091558251938452908301527f8f3675e5a31b083483e5a782db4130316da1e3c5fca72fc2398f59692286d8a591016109d6565b610b15611918565b60108190556040518181527f4082bc252f347d223f4e804c3c4e90818ad544b959ffa807149351ad158bf016906020016108dd565b610b52611918565b6109f26000611c1b565b610b64611918565b6001600160a01b038116610b8b5760405163d92e233d60e01b815260040160405180910390fd5b601980546001600160a01b0319166001600160a01b0383169081179091556040519081527ff02c250c2f604285964f748fa097cd5c7fbf0bbd759efc47e3cc8851c4bfd89b906020016108dd565b60606004805461077c906122f7565b610bf0611918565b60088190556040518181527f46e8115bf463f9c29a9424fe152addef1bfaf2b43180d19bb7c2c78cc0ff1ebf906020016108dd565b610c2d611918565b600f8054821515620100000262ff0000199091161790556040517fa90851d18400a589974d1c5356d645068ab372fc9d53ed5f382f9209e8a504a7906108dd90831515815260200190565b6011546000903390829060ff16600103610cb4576011805460ff19166002179055610ca48286866111a9565b6011805460ff1916600117905590505b610cc3828661086e8488612347565b506001949350505050565b610cd6611918565b6001600160a01b038216600081815260146020908152604091829020805460ff19168515159081179091558251938452908301527f2a57b1eacb5962c472bd7a96baec43231b4ecc3ba3cffd4abf8186734102312d91016109d6565b60068181548110610d4257600080fd5b9060005260206000209060050201600091509050806000018054610d65906122f7565b80601f0160208091040260200160405190810160405280929190818152602001828054610d91906122f7565b8015610dde5780601f10610db357610100808354040283529160200191610dde565b820191906000526020600020905b815481529060010190602001808311610dc157829003601f168201915b50506040805160608101825260018701548152600287015460208201526003870154918101919091526004909501549394936001600160a01b0381169350600160a01b900460ff169150859050565b610e35611918565b600f805460ff19168215159081179091556040519081527fa3da88a45043f093f32d7cb1b95474f4f2ff653758ad43d6e512872081307fc0906020016108dd565b610e7e611918565b600c54811015610ea157604051635672035f60e11b815260040160405180910390fd5b600b8190556040518181527f4a02caf9e7317d663463d3d976767ba90289279dd55c0a46f962536efc87a9a6906020016108dd565b610ede611918565b6001600160a01b038116610f0d57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610f1681611c1b565b50565b610f21611918565b8015610f2f57610f2f611945565b610f3b60066000611f8e565b60008080805b85811015611095576000878783818110610f5d57610f5d61235a565b9050602002810190610f6f9190612370565b610f809060a081019060800161210e565b6001600160a01b031603610fa75760405163a79afef960e01b815260040160405180910390fd5b6006878783818110610fbb57610fbb61235a565b9050602002810190610fcd9190612370565b815460018101835560009283526020909220909160050201610fef8282612410565b50508686828181106110035761100361235a565b90506020028101906110159190612370565b611023906020013585612574565b93508686828181106110375761103761235a565b90506020028101906110499190612370565b611057906040013584612574565b925086868281811061106b5761106b61235a565b905060200281019061107d9190612370565b61108b906060013583612574565b9150600101610f41565b506007859055600a548311806110ac5750600a5482115b806110b85750600a5481115b156110d657604051630b323bcb60e11b815260040160405180910390fd5b7fe8831bf32b04c19859d9916dbd57a89d041caf02ab126d86dc4edbbdb8fff57086868660405161110993929190612587565b60405180910390a1505050505050565b6111268383836001611c6d565b505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146111a3578181101561119457604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610f04565b6111a384848484036000611c6d565b50505050565b6001600160a01b03831660009081526015602052604081205481908190819060ff16156111d557600192505b6001600160a01b03861660009081526015602052604090205460ff16156111fb57600191505b82158015611207575081155b15611210575060015b61121d8787878686611d42565b6112278686611dda565b82801561124c57506001600160a01b03861660009081526012602052604090205460ff165b1561125d576000935050505061087a565b81801561128257506001600160a01b03871660009081526012602052604090205460ff165b15611293576000935050505061087a565b80156112e9576001600160a01b03871660009081526012602052604090205460ff16806112d857506001600160a01b03861660009081526012602052604090205460ff165b156112e9576000935050505061087a565b600f5460ff166112ff576000935050505061087a565b6019546001600160a01b0390811690881681148061132e5750806001600160a01b0316876001600160a01b0316145b1561134057600094505050505061087a565b600654600090156118ad5760005b60065460ff8216101561186d57600086156113e157600060068360ff168154811061137b5761137b61235a565b90600052602060002090600502016001016000015411156113dc5760105460068360ff16815481106113af576113af61235a565b9060005260206000209060050201600101600001548a6113cf91906126b6565b6113d991906126cd565b90505b6114d2565b851561145357600060068360ff16815481106113ff576113ff61235a565b90600052602060002090600502016001016001015411156113dc5760105460068360ff16815481106114335761143361235a565b9060005260206000209060050201600101600101548a6113cf91906126b6565b84156114d257600060068360ff16815481106114715761147161235a565b90600052602060002090600502016001016002015411156114d25760105460068360ff16815481106114a5576114a561235a565b9060005260206000209060050201600101600201548a6114c591906126b6565b6114cf91906126cd565b90505b6114dc8184612574565b9250801561185c5760068260ff16815481106114fa576114fa61235a565b906000526020600020906005020160040160149054906101000a900460ff166116425761155a8b60068460ff16815481106115375761153761235a565b60009182526020909120600460059092020101546001600160a01b031683611e64565b60068260ff16815481106115705761157061235a565b906000526020600020906005020160040160009054906101000a90046001600160a01b03166001600160a01b03168b6001600160a01b03167f897726b6cfaff25a3bddca812f59ae0ed3a3d07ef84476ccd17cdefbffe10e11838a8a8a60068960ff16815481106115e3576115e361235a565b906000526020600020906005020160040160149054906101000a900460ff1660405161163595949392919094855292151560208501529015156040840152151560608301521515608082015260a00190565b60405180910390a361185c565b806017600060068560ff168154811061165d5761165d61235a565b60009182526020808320600460059093020191909101546001600160a01b031683528201929092526040018120805490919061169a908490612574565b925050819055506016600060068460ff16815481106116bb576116bb61235a565b60009182526020808320600460059093020191909101546001600160a01b0316835282019290925260400190205460ff166117a757601860068360ff16815481106117085761170861235a565b600091825260208083206004600590930201919091015483546001818101865594845291832090910180546001600160a01b0319166001600160a01b0390921691909117905560068054601692919060ff871690811061176a5761176a61235a565b60009182526020808320600592909202909101600401546001600160a01b031683528201929092526040019020805460ff19169115159190911790555b6117b28b8583611e64565b836001600160a01b03168b6001600160a01b03167f897726b6cfaff25a3bddca812f59ae0ed3a3d07ef84476ccd17cdefbffe10e11838a8a8a60068960ff16815481106118015761180161235a565b906000526020600020906005020160040160149054906101000a900460ff1660405161185395949392919094855292151560208501529015156040840152151560608301521515608082015260a00190565b60405180910390a35b50611866816126ef565b905061134e565b5083801561189457506008546001600160a01b038316600090815260208190526040902054115b156118a1576118a1611945565b945061087a9350505050565b50505050509392505050565b6001600160a01b0383166118e357604051634b637e8f60e11b815260006004820152602401610f04565b6001600160a01b03821661190d5760405163ec442f0560e01b815260006004820152602401610f04565b611126838383611e64565b6005546001600160a01b031633146109f25760405163118cdaa760e01b8152336004820152602401610f04565b6019546001600160a01b03166000818152602081905260409020548015611c175760185460009067ffffffffffffffff81111561198457611984612390565b6040519080825280602002602001820160405280156119ad578160200160208202803683370190505b50905060005b601854811015611b5c57600060176000601884815481106119d6576119d661235a565b60009182526020808320909101546001600160a01b0316835282019290925260400190205490508015611b53578360105482611a1291906126b6565b611a1c91906126cd565b838381518110611a2e57611a2e61235a565b60209081029190910101526009548411611ad55760006017600060188581548110611a5b57611a5b61235a565b60009182526020808320909101546001600160a01b0316835282019290925260400181209190915560188054601691839186908110611a9c57611a9c61235a565b6000918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055611b53565b601054838381518110611aea57611aea61235a565b6020026020010151600860010154611b0291906126b6565b611b0c91906126cd565b611b169082612347565b6017600060188581548110611b2d57611b2d61235a565b60009182526020808320909101546001600160a01b031683528201929092526040019020555b506001016119b3565b506010546009546040516337a3292160e01b81526001600160a01b038616926337a3292192611b949230926018928892600401612789565b600060405180830381600087803b158015611bae57600080fd5b505af1158015611bc2573d6000803e3d6000fd5b505050507f70abc2c671179db962e066fe2d431f30e93e030d932704e9acd8fd566486103782601883604051611bfa939291906127d4565b60405180910390a160095482116111265761112660186000611faf565b5050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038416611c975760405163e602df0560e01b815260006004820152602401610f04565b6001600160a01b038316611cc157604051634a1406b160e11b815260006004820152602401610f04565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156111a357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051611d3491815260200190565b60405180910390a350505050565b600f54610100900460ff1615611dd3578115611d79576001600160a01b03841660009081526014602052604090205460ff16611dd3575b8015611da0576001600160a01b03851660009081526014602052604090205460ff16611dd3575b80158015611dac575081155b611dd357600b54831115611dd3576040516329412db560e21b815260040160405180910390fd5b5050505050565b600f5462010000900460ff161515600003611df3575050565b6001600160a01b03821660009081526013602052604090205460ff1615611e18575050565b600d5481611e3b846001600160a01b031660009081526020819052604090205490565b611e459190612574565b1115611c175760405163fd42866160e01b815260040160405180910390fd5b6001600160a01b038316611e8f578060026000828254611e849190612574565b90915550611f019050565b6001600160a01b03831660009081526020819052604090205481811015611ee25760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610f04565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216611f1d57600280548290039055611f3c565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611f8191815260200190565b60405180910390a3505050565b5080546000825560050290600052602060002090810190610f169190611fcd565b5080546000825590600052602060002090810190610f169190612015565b80821115612011576000611fe1828261202a565b506000600182018190556002820181905560038201556004810180546001600160a81b0319169055600501611fcd565b5090565b5b808211156120115760008155600101612016565b508054612036906122f7565b6000825580601f10612046575050565b601f016020900490600052602060002090810190610f169190612015565b6000815180845260005b8181101561208a5760208185018101518683018201520161206e565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061087a6020830184612064565b6001600160a01b0381168114610f1657600080fd5b80356120dd816120bd565b919050565b600080604083850312156120f557600080fd5b8235612100816120bd565b946020939093013593505050565b60006020828403121561212057600080fd5b813561087a816120bd565b60008060006060848603121561214057600080fd5b833561214b816120bd565b9250602084013561215b816120bd565b929592945050506040919091013590565b60006020828403121561217e57600080fd5b5035919050565b8015158114610f1657600080fd5b80356120dd81612185565b600080604083850312156121b157600080fd5b82356121bc816120bd565b915060208301356121cc81612185565b809150509250929050565b6000602082840312156121e957600080fd5b813561087a81612185565b60c08152600061220760c0830187612064565b905084516020830152602085015160408301526040850151606083015260018060a01b038416608083015282151560a083015295945050505050565b6000806040838503121561225657600080fd5b8235612261816120bd565b915060208301356121cc816120bd565b60008060006040848603121561228657600080fd5b833567ffffffffffffffff8082111561229e57600080fd5b818601915086601f8301126122b257600080fd5b8135818111156122c157600080fd5b8760208260051b85010111156122d657600080fd5b602092830195509350508401356122ec81612185565b809150509250925092565b600181811c9082168061230b57607f821691505b60208210810361232b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561081357610813612331565b634e487b7160e01b600052603260045260246000fd5b6000823560be1983360301811261238657600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b601f821115611126576000816000526020600020601f850160051c810160208610156123cf5750805b601f850160051c820191505b818110156123ee578281556001016123db565b505050505050565b60008135610813816120bd565b6000813561081381612185565b8135601e1983360301811261242457600080fd5b8201803567ffffffffffffffff81111561243d57600080fd5b6020813603818401131561245057600080fd5b6124648261245e86546122f7565b866123a6565b6000601f83116001811461249a576000841561248257508482018301355b600019600386901b1c1916600185901b1786556124f7565b600086815260209020601f19851690835b828110156124cc5787850186013582559385019360019091019085016124ab565b50858210156124eb5760001960f88760031b161c198585890101351681555b505060018460011b0186555b50508401803560018501556020810135600285015560400135600384015550506004810161254761252a608085016123f6565b82546001600160a01b0319166001600160a01b0391909116178255565b61112661255660a08501612403565b82805460ff60a01b191691151560a01b60ff60a01b16919091179055565b8082018082111561081357610813612331565b6040808252810183905260006060600585901b8301810190830186835b878110156126a157858403605f190183528135368a900360be190181126125ca57600080fd5b890160c0813536839003601e190181126125e357600080fd5b8201602081810191359067ffffffffffffffff82111561260257600080fd5b81360383131561261157600080fd5b83895281848a015260e093508183858b0137600084838b01015261264d818a018287018035825260208082013590830152604090810135910152565b6080925061265c8386016120d2565b6001600160a01b0381168a8501525060a0925061267a838601612193565b151592890192909252601f01601f19169096010194938401939290920191506001016125a4565b50505083151560208401529050949350505050565b808202811582820484141761081357610813612331565b6000826126ea57634e487b7160e01b600052601260045260246000fd5b500490565b600060ff821660ff810361270557612705612331565b60010192915050565b600081548084526020808501945083600052602060002060005b8381101561274d5781546001600160a01b031687529582019560019182019101612728565b509495945050505050565b60008151808452602080850194506020840160005b8381101561274d5781518752958201959082019060010161276d565b6001600160a01b038616815260a0602082018190526000906127ad9083018761270e565b82810360408401526127bf8187612758565b60608401959095525050608001529392505050565b8381526060602082015260006127ed606083018561270e565b82810360408401526127ff8185612758565b969550505050505056fea264697066735822122006bb97caa25271bd7b117332b16972e977b4647acac4e8f9f2000011e12897ab64736f6c63430008180033

Verified Source Code Partial Match

Compiler: v0.8.24+commit.e11b9ed9 EVM: paris Optimization: Yes (200 runs)
Token.sol 1466 lines
// Sources flattened with hardhat v2.19.5 https://hardhat.org

// SPDX-License-Identifier: MIT

// File contracts/interfaces/IERC20.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity 0.8.24;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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


// File contracts/interfaces/IERC20Metadata.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity 0.8.24;
/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
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 contracts/interfaces/IUniswapV2Router01.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}


// File contracts/interfaces/IUniswapV2Router02.sol

pragma solidity >=0.6.2;
interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}


// File contracts/interfaces/draft-IERC6093.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity 0.8.24;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`ΓÇÖs `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`ΓÇÖs approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`ΓÇÖs approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}


// File contracts/libraries/Context.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity 0.8.24;

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

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}


// File contracts/libraries/ERC20.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity 0.8.24;
/**
 * @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}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * 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.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * 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 returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual 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 default value returned by this function, unless
     * it's 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 returns (uint8) {
        return 18;
    }

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

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual 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 `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

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

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` 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 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        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 `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` 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.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` 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.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

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


// File contracts/libraries/Ownable.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

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

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


// File contracts/TaxHelper.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity 0.8.24;
/// @title TaxHelperUniswapV2
/// @author Boka
/// @notice Contract to convert tokens to ETH and divide among tax wallets using UniswapV2
/// @dev Can be used with multiple tokens
contract TaxHelperUniswapV2 is Ownable {
    address public routerAddress;
    mapping (address => bool) public approvedTokens;

    event ApproveToken(address token, bool value);
    event RouterAddressSet(address routerAddress);
    event ConvertedToEth(address token, uint256 amount, address[] walletsWithTax, uint256[] percentages, uint256 DENOMINATOR, uint256 ethBalance);
    event SentEth(address wallet, uint256 amount);

    error TokenNotApproved(address sender);
    error ZeroAddress();

    constructor(address initialOwner, address _routerAddress)
        Ownable(initialOwner)
    {
        setRouterAddress(_routerAddress);
    }

    /// @notice Approve a token to use this contract
    /// @param token the token to approve
    /// @param value true or false
    function approveToken(address token, bool value) public onlyOwner {
        approvedTokens[token] = value;
        emit ApproveToken(token, value);
    }

    /// @notice Convert a token to ETH and divide among tax wallets
    /// @dev only approve tokens or the owner may call this function
    /// @param token the token to convert
    /// @param walletsWithTax the wallets to divide the ETH among
    /// @param percentages the percentages to divide the ETH among
    /// @param DENOMINATOR the denominator to divide the percentages by
    function convertToEthAndSend(address token, address[] memory walletsWithTax, uint256[] memory percentages, uint256 DENOMINATOR, uint256 maxThresholdSell) external {   
        if(!approvedTokens[msg.sender] && msg.sender != owner()) revert TokenNotApproved(msg.sender);
        
        IERC20 tokenContract = IERC20(token);
        uint256 balance = tokenContract.balanceOf(address(this));
        if(balance > maxThresholdSell) {
            balance = maxThresholdSell;
        }
        IUniswapV2Router02 uniswapRouter = IUniswapV2Router02(routerAddress);
        tokenContract.approve(address(uniswapRouter), balance);
        address[] memory path = new address[](2);
        path[0] = token;
        path[1] = uniswapRouter.WETH();
        if(balance > 0) {
            uniswapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
                balance,
                0, // accept any amount of ETH
                path,
                address(this),
                block.timestamp
            ); 

            uint256 ethBalance = address(this).balance;
            emit ConvertedToEth(token, balance, walletsWithTax, percentages, DENOMINATOR, ethBalance);
            for(uint256 i = 0; i < walletsWithTax.length; ++i) {
                uint256 amountToSend = ethBalance * percentages[i] / DENOMINATOR;
                payable(walletsWithTax[i]).transfer(amountToSend);
                emit SentEth(walletsWithTax[i], amountToSend);
            }
        }
        
    } 

    /// @notice Set the router address
    /// @param _routerAddress the address of the UniswapV2Router02
    function setRouterAddress(address _routerAddress) public onlyOwner {
        if(_routerAddress == address(0)) revert ZeroAddress();
        routerAddress = _routerAddress;
        emit RouterAddressSet(_routerAddress);
    }

    /// @notice Withdraw the ETH from the contract
    function withdraw() public onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }

    /// @notice Receive ETH
    receive() payable external {
    }
}


// File contracts/interfaces/ITaxHelper.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity 0.8.24;

interface ITaxHelper {
    function convertToEthAndSend(address token, address[] memory walletsWithTax, uint256[] memory percentages, uint256 DENOMINATOR, uint256 maxThresholdSell) external;
}


// File contracts/Token.sol

// Original license: SPDX_License_Identifier: MIT

// Website: https://strike-protocol.com/
// Twitter: https://twitter.com/StrikeProtocol1
// TG: https://t.me/StrikeProtocol

pragma solidity 0.8.24;



/// @title Token
/// @author Boka
/// @notice ERC20 token with tax functionality
contract Token is ERC20, Ownable {

    Tax[] public taxes;
    uint256 public taxLength;
    Settings public settings;

    struct Settings {
        uint256 threshold;
        uint256 maxThresholdSell;
        uint256 maxTax;
        uint256 maxTxAmount;
        uint256 minMaxTxAmount;
        uint256 maxWalletAmount;
        uint256 minMaxWalletAmount;
        bool taxEnabled;
        bool maxTxAmountEnabled;
        bool maxWalletAmountEnabled;
    }
 
    struct Fee {
        uint256 buy;
        uint256 sell;
        uint256 transfer;
    }

    struct Tax {
        string name;
        Fee fee;
        address wallet;
        bool withdrawAsGas;
    }

    uint256 public DENOMINATOR = 10000;

    uint8 internal taxReentrancy = 1;

    mapping (address => bool) public taxWhitelist;
    mapping (address => bool) public maxWalletWhitelist;
    mapping (address => bool) public maxTxWhitelist;
    mapping (address => bool) public lpTokens;
    mapping (address => bool) public taxesWithBalance;
    mapping (address => uint256) public taxBalances;
    address[] public walletsWithTax;

    address public taxHelper;

    event UpdatedTaxes(Tax[] _taxes, bool cleanWallets);
    event TaxTransferred(address indexed sender, uint256 fee, address indexed wallet, bool isBuy, bool isSell, bool isTransfer, bool withdrawAsGas);
    event TaxWithdrawn(uint256 amount, address[] walletsWithTax, uint256[] percentages);
    event SetTaxHelper(address _taxHelper);
    event SetDenominator(uint256 _denominator);
    event SetTaxWhitelist(address _address, bool _value);
    event SetLPToken(address _address, bool _value);
    event SetTaxEnabled(bool _value);
    event SetThreshold(uint256 _threshold);
    event SetMaxTxAmount(uint256 _maxTxAmount);
    event SetMaxWalletAmount(uint256 _maxWalletAmount);
    event SetMaxWalletWhitelist(address _address, bool _value);
    event SetMaxTxWhitelist(address _address, bool _value);
    event SetMaxTxEnabled(bool _value);
    event SetMaxWalletEnabled(bool _value);
    event SetMaxThresholdSell(uint256 _maxThresholdSell);

    error ExceedsMaxTax();
    error ZeroAddressWallet();
    error ZeroAddress();
    error ExceedsMaxTxAmount();
    error ExceedsMaxWalletAmount();
    error UnderMinMaxTxAmount();
    error UnderMinMaxWalletAmount();


    constructor(
        string memory name_, 
        string memory symbol_, 
        uint256 totalSupply_, 
        address initialOwner,
        uint256 _maxTax,
        uint256 _minMaxTxAmount,
        uint256 _minMaxWalletAmount
        ) payable
        ERC20(name_, symbol_)
        Ownable(initialOwner)
    {
        _mint(initialOwner, totalSupply_);
        settings.taxEnabled = false;
        settings.maxTxAmountEnabled = false;
        settings.maxWalletAmountEnabled = false;
        settings.maxTax = _maxTax;
        settings.minMaxTxAmount = _minMaxTxAmount;
        settings.minMaxWalletAmount = _minMaxWalletAmount;
    }

    /// @notice enable the maximum transaction amount
    /// @param _value true or false
    function setMaxTxEnabled(bool _value) payable public onlyOwner {
        settings.maxTxAmountEnabled = _value;
        emit SetMaxTxEnabled(_value);
    }

    /// @notice enable the maximum wallet amount
    /// @param _value true or false
    function setMaxWalletEnabled(bool _value) payable public onlyOwner {
        settings.maxWalletAmountEnabled = _value;
        emit SetMaxWalletEnabled(_value);
    }

    /// @notice set the maximum transaction amount
    /// @param _maxTxAmount the maximum transaction amount
    function setMaxTxAmount(uint256 _maxTxAmount) payable public onlyOwner {
        if(_maxTxAmount < settings.minMaxTxAmount) revert UnderMinMaxTxAmount();
        settings.maxTxAmount = _maxTxAmount;
        emit SetMaxTxAmount(_maxTxAmount);
    }

    /// @notice set the maximum wallet amount
    /// @param _maxWalletAmount the maximum wallet amount
    function setMaxWalletAmount(uint256 _maxWalletAmount) payable public onlyOwner {
        if(_maxWalletAmount < settings.minMaxWalletAmount) revert UnderMinMaxWalletAmount();
        settings.maxWalletAmount = _maxWalletAmount;
        emit SetMaxWalletAmount(_maxWalletAmount);
    }

    /// @notice set the minimum balance to trigger the tax conversion
    /// @param _threshold the minimum balance to trigger the tax conversion
    function setThreshold(uint256 _threshold) payable public onlyOwner {
        settings.threshold = _threshold;
        emit SetThreshold(_threshold);
    }

    /// @notice set the maximum sell amount when the threshold is triggered to convert the tax
    /// @param _maxThresholdSell the maximum sell amount
    function setMaxThresholdSell(uint256 _maxThresholdSell) payable public onlyOwner {
        settings.maxThresholdSell = _maxThresholdSell;
        emit SetMaxThresholdSell(_maxThresholdSell);
    }

    /// @notice set the taxEnabled flag
    /// @param _value sets the taxEnabled flag to true or false
    function setTaxEnabled(bool _value) payable public onlyOwner {
        settings.taxEnabled = _value;
        emit SetTaxEnabled(_value);
    }

    /// @notice set the maxWalletWhitelist flag
    /// @param _address the address to adjust the maxWalletWhitelist
    /// @param _value true or false
    function setMaxWalletWhitelist(address _address, bool _value) payable public onlyOwner {
        maxWalletWhitelist[_address] = _value;
        emit SetMaxWalletWhitelist(_address, _value);
    }

    /// @notice set the maxTxWhitelist flag
    /// @param _address the address to adjust the maxTxWhitelist
    /// @param _value true or false
    function setMaxTxWhitelist(address _address, bool _value) payable public onlyOwner {
        maxTxWhitelist[_address] = _value;
        emit SetMaxTxWhitelist(_address, _value);
    }

    /// @notice set the taxWhitelist flag
    /// @param _address the address to adjust the taxWhitelist
    /// @param _value true or false 
    function setTaxWhitelist(address _address, bool _value) payable public onlyOwner {
        taxWhitelist[_address] = _value;
        emit SetTaxWhitelist(_address, _value);
    }

    /// @notice set whether an LP token is used to trigger the tax
    /// @param _address the address of the LP token
    /// @param _value true or false
    function setLPToken(address _address, bool _value) payable public onlyOwner {
        if(_address == address(0)) revert ZeroAddress();
        lpTokens[_address] = _value;
        emit SetLPToken(_address, _value);
    }

    /// @notice set the taxHelper address
    /// @param _taxHelper the address of the taxHelper contract
    function setTaxHelper(address _taxHelper) payable public onlyOwner {
        if(_taxHelper == address(0)) revert ZeroAddress();
        taxHelper = _taxHelper;
        emit SetTaxHelper(_taxHelper);
    }

    /// @notice set the denominator to use for the tax calculation
    /// @param _denominator the denominator to use for the tax calculation
    function setDenominator(uint256 _denominator) payable public onlyOwner {
        DENOMINATOR = _denominator;
        emit SetDenominator(_denominator);
    }

    /// @notice update the taxes for the token
    /// @dev if cleanWallets is true, the tax balances will be converted to ETH. This is useful if the taxes are updated and have different wallet addresses
    /// @param _taxes the new taxes to apply
    /// @param cleanWallets if true, the tax balances will be converted to ETH
    function updateTaxes(Tax[] calldata _taxes, bool cleanWallets) payable public onlyOwner {
        if(cleanWallets) {
            _convertTaxToEth();
        }
        delete taxes;

        uint256 totalTaxBuy;
        uint256 totalTaxSell;
        uint256 totalTaxTransfer;
        for(uint i = 0; i < _taxes.length; ++i) {
            if(_taxes[i].wallet == address(0)) revert ZeroAddressWallet();
            taxes.push(_taxes[i]);
            totalTaxBuy += _taxes[i].fee.buy;
            totalTaxSell += _taxes[i].fee.sell;
            totalTaxTransfer += _taxes[i].fee.transfer;
        }
        taxLength = _taxes.length;
        if(totalTaxBuy > settings.maxTax || totalTaxSell > settings.maxTax || totalTaxTransfer > settings.maxTax) {
            revert ExceedsMaxTax();
        }

        emit UpdatedTaxes(_taxes, cleanWallets);
    }

    /// @notice check the maximum transaction amount
    /// @param from the address the tokens are being transferred from
    /// @param to the address the tokens are being transferred to
    /// @param value the amount of tokens being transferred
    /// @param isBuy true if the transaction is a buy
    /// @param isSell true if the transaction is a sell
    function checkMaxTxAmount(address from, address to, uint256 value, bool isBuy, bool isSell) internal view {
        if(settings.maxTxAmountEnabled == false) {
            return;
        }
        if(isBuy) {
            if(maxTxWhitelist[to]) {
                return;
            }
        }
        if(isSell) {
            if(maxTxWhitelist[from]) {
                return;
            }
        }
        if(!isSell && !isBuy) {
            return;
        }
        if(value > settings.maxTxAmount) {
            revert ExceedsMaxTxAmount();
        }
    }

    /// @notice check the maximum wallet amount
    /// @param to the address the tokens are being transferred to
    /// @param value the amount of tokens being transferred
    function checkMaxWalletAmount(address to, uint256 value) internal view {
        if(settings.maxWalletAmountEnabled == false) {
            return;
        }
        if(maxWalletWhitelist[to]) {
            return;
        }
        if(balanceOf(to) + value > settings.maxWalletAmount) {
            revert ExceedsMaxWalletAmount();
        }
    }

    /// @notice handle the tax for a transfer
    /// @dev if the transaction is a sell, the tax will be converted to ETH if the taxHelper balance is above the threshold
    /// @param from the address the tokens are being transferred from
    /// @param to the address the tokens are being transferred to
    /// @param value the amount of tokens being transferred
    /// @return totalFeeAmount the total fee amount
    function handleTax(address from, address to, uint256 value) internal returns (uint256) {

        bool isBuy = false;
        bool isSell = false;
        bool isTransfer = false;

        if(lpTokens[from]) {
            isBuy = true;
        }
        if(lpTokens[to]) {
            isSell = true;
        }
        if(!isBuy && !isSell) {
            isTransfer = true;
        }

        checkMaxTxAmount(from, to, value, isBuy, isSell);
        checkMaxWalletAmount(to, value);

        if(isBuy && taxWhitelist[to]) {
            return 0;
        }

        if(isSell && taxWhitelist[from]) {
            return 0;
        }

        if(isTransfer) {
            if(taxWhitelist[from] || taxWhitelist[to]) {
                return 0;
            }
        }

        if(!settings.taxEnabled) {
            return 0;
        }

        ITaxHelper TaxHelper = ITaxHelper(taxHelper);
        if(from == address(TaxHelper) || to == address(TaxHelper)) {
            return 0;
        }

        uint256 totalFeeAmount;

        if(taxes.length > 0) {
            for(uint8 i = 0; i < taxes.length; ++i) {
                uint256 fee;
                if(isBuy) {
                    if(taxes[i].fee.buy > 0) {
                        fee = value * taxes[i].fee.buy / DENOMINATOR;
                    }
                } else if(isSell) {
                    if(taxes[i].fee.sell > 0) {
                        fee = value * taxes[i].fee.sell / DENOMINATOR;
                    }
                } else if(isTransfer) {
                    if(taxes[i].fee.transfer > 0) {
                        fee = value * taxes[i].fee.transfer / DENOMINATOR;
                    }
                } 
                totalFeeAmount += fee;
                if(fee != 0) {
                    if(!taxes[i].withdrawAsGas) {
                        _update(from, taxes[i].wallet, fee);
                        emit TaxTransferred(from, fee, taxes[i].wallet, isBuy, isSell, isTransfer, taxes[i].withdrawAsGas);
                    } else { 
                        taxBalances[taxes[i].wallet] += fee;
                        if(!taxesWithBalance[taxes[i].wallet]) {
                            walletsWithTax.push(taxes[i].wallet);
                            taxesWithBalance[taxes[i].wallet] = true;
                        }
                        _update(from, address(TaxHelper), fee);
                        emit TaxTransferred(from, fee, address(TaxHelper), isBuy, isSell, isTransfer, taxes[i].withdrawAsGas);
                    }
                } 
            }
            if(isSell && balanceOf(address(TaxHelper)) > settings.threshold ){
                _convertTaxToEth();
            }
            return totalFeeAmount;
        }    
    }

    /// @notice convert the tax balances to ETH
    /// @dev this is a manual function call to be used to convert the tax balances to ETH if necessary
    function convertTaxToEth() payable public onlyOwner {
        _convertTaxToEth();
    }

    /// @notice convert the tax balances to ETH
    function _convertTaxToEth() internal {
        ITaxHelper TaxHelper = ITaxHelper(taxHelper);
        // calculate percentages from taxHelper balance for each tax wallet
        uint256 totalBalance = balanceOf(address(TaxHelper));
        if(totalBalance > 0) {
            uint256[] memory percentages = new uint256[](walletsWithTax.length);
            for(uint i = 0; i < walletsWithTax.length; ++i) {
                // calculate percentage of totalBalance for each wallet
                uint256 balance = taxBalances[walletsWithTax[i]];
                if(balance > 0) {
                    percentages[i] = balance * DENOMINATOR / totalBalance;
                    if(totalBalance <= settings.maxThresholdSell) {
                        taxBalances[walletsWithTax[i]] = 0;
                        taxesWithBalance[walletsWithTax[i]] = f...

// [truncated — 54457 bytes total]

Read Contract

DENOMINATOR 0x918f8674 → uint256
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
decimals 0x313ce567 → uint8
lpTokens 0xb17b658d → bool
maxTxWhitelist 0xdfa8bbeb → bool
maxWalletWhitelist 0x871c42b7 → bool
name 0x06fdde03 → string
owner 0x8da5cb5b → address
settings 0xe06174e4 → uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool, bool, bool
symbol 0x95d89b41 → string
taxBalances 0x4ff0b1d2 → uint256
taxHelper 0x1f6976a6 → address
taxLength 0xe2ce1ac7 → uint256
taxWhitelist 0x181b72aa → bool
taxes 0xc5be2bc7 → string, tuple, address, bool
taxesWithBalance 0xff008776 → bool
totalSupply 0x18160ddd → uint256
walletsWithTax 0x2b06dbbb → address

Write Contract 20 functions

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

approve 0x095ea7b3
address spender
uint256 value
returns: bool
convertTaxToEth 0x39a91a15
No parameters
renounceOwnership 0x715018a6
No parameters
setDenominator 0x6cec0ceb
uint256 _denominator
setLPToken 0x2febd2ae
address _address
bool _value
setMaxThresholdSell 0x27bf24e2
uint256 _maxThresholdSell
setMaxTxAmount 0xec28438a
uint256 _maxTxAmount
setMaxTxEnabled 0x541958ff
bool _value
setMaxTxWhitelist 0xb9a6672c
address _address
bool _value
setMaxWalletAmount 0x27a14fc2
uint256 _maxWalletAmount
setMaxWalletEnabled 0xa614ff75
bool _value
setMaxWalletWhitelist 0x3d3d1141
address _address
bool _value
setTaxEnabled 0xc6af580b
bool _value
setTaxHelper 0x8fbf1e93
address _taxHelper
setTaxWhitelist 0x5afde063
address _address
bool _value
setThreshold 0x960bfe04
uint256 _threshold
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 value
returns: bool
transferOwnership 0xf2fde38b
address newOwner
updateTaxes 0x258ab864
tuple[] _taxes
bool cleanWallets

Recent Transactions

No transactions found for this address