Address Contract Verified
Address
0x99054220d02acc8C608EE9dF7d5909Eb5A5DD7fb
Balance
0 ETH
Nonce
2
Code Size
23858 bytes
Creator
0x744b41B3...1895 at tx 0x39001103...169fd3
Indexed Transactions
0
Contract Bytecode
23858 bytes
0x6080604052600436106101c8575f3560e01c8063715018a6116100f2578063a8b0898211610092578063d03153aa11610062578063d03153aa146104f0578063efda182d14610505578063f2fde38b14610524578063f887ea4014610543575f5ffd5b8063a8b0898214610489578063b7c6b7c8146104a8578063c3ef17f3146104bd578063ccba2ddb146104dc575f5ffd5b80638da5cb5b116100cd5780638da5cb5b146104165780638ffb62d2146104345780639d159568146104555780639d76ea581461046a575f5ffd5b8063715018a6146103ba5780637fcd0e8d146103ce578063857620e1146103e2575f5ffd5b80634177b66f1161016857806346ebbdb01161013857806346ebbdb01461035f5780634cdff2fe1461037357806354f2679a146103885780635e3be34d1461039b575f5ffd5b80634177b66f146102e457806342af18841461030d5780634348b59b1461032c578063452d003f14610340575f5ffd5b80631b51fbb1116101a35780631b51fbb1146102275780631baaf4bd1461026157806324cc076614610284578063392e53cd146102bb575f5ffd5b80630a0a4189146101d35780630f9da743146101f4578063186e2d7714610213575f5ffd5b366101cf57005b5f5ffd5b3480156101de575f5ffd5b506101f26101ed366004612b1e565b610562565b005b3480156101ff575f5ffd5b506101f261020e366004612b1e565b61072f565b34801561021e575f5ffd5b506101f26107da565b348015610232575f5ffd5b50610241600754600654600292565b604080519384526020840192909252908201526060015b60405180910390f35b34801561026c575f5ffd5b5061027660075481565b604051908152602001610258565b34801561028f575f5ffd5b506102a361029e366004612b1e565b610963565b6040516001600160a01b039091168152602001610258565b3480156102c6575f5ffd5b506005546102d49060ff1681565b6040519015158152602001610258565b3480156102ef575f5ffd5b506102f861098b565b60408051928352901515602083015201610258565b348015610318575f5ffd5b506101f2610327366004612b1e565b610999565b348015610337575f5ffd5b506101f2610a83565b34801561034b575f5ffd5b506101f261035a366004612b1e565b611057565b34801561036a575f5ffd5b50610276600281565b34801561037e575f5ffd5b5061027660085481565b6101f2610396366004612be6565b61121d565b3480156103a6575f5ffd5b506101f26103b5366004612b1e565b611c27565b3480156103c5575f5ffd5b506101f2611ce3565b3480156103d9575f5ffd5b506101f2611d1d565b3480156103ed575f5ffd5b506104016103fc366004612c64565b611ef3565b60408051928352602083019190915201610258565b348015610421575f5ffd5b505f546102a3906001600160a01b031681565b34801561043f575f5ffd5b5061044861216d565b6040516102589190612c8d565b348015610460575f5ffd5b5061027660095481565b348015610475575f5ffd5b506001546102a3906001600160a01b031681565b348015610494575f5ffd5b506002546102a3906001600160a01b031681565b3480156104b3575f5ffd5b50610276600a5481565b3480156104c8575f5ffd5b506101f26104d7366004612cd8565b6121cd565b3480156104e7575f5ffd5b50610276612310565b3480156104fb575f5ffd5b5061027660065481565b348015610510575f5ffd5b506101f261051f366004612cd8565b61231e565b34801561052f575f5ffd5b506101f261053e366004612d0f565b6128d4565b34801561054e575f5ffd5b506003546102a3906001600160a01b031681565b5f546001600160a01b031633146105945760405162461bcd60e51b815260040161058b90612d31565b60405180910390fd5b600554610100900460ff16156105bc5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff0019166101001790556002546001600160a01b03166105f35760405162461bcd60e51b815260040161058b90612d81565b5f81116106125760405162461bcd60e51b815260040161058b90612da2565b5f61061b612966565b90508181101561063d5760405162461bcd60e51b815260040161058b90612dce565b60025460405163a9059cbb60e01b815261dead6004820181905260248201859052916001600160a01b03169063a9059cbb906044016020604051808303815f875af115801561068e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b29190612e05565b6106ec5760405162461bcd60e51b815260206004820152600b60248201526a109d5c9b8819985a5b195960aa1b604482015260640161058b565b6040518381527f599e3c1445f5d3f97307a24763cc7d200c7c523b685562a5df07759410a411ec9060200160405180910390a150506005805461ff001916905550565b5f546001600160a01b031633146107585760405162461bcd60e51b815260040161058b90612d31565b603281111561079e5760405162461bcd60e51b81526020600482015260126024820152710a8ded8cae4c2dcc6ca40e8dede40d0d2ced60731b604482015260640161058b565b60068190556040518181527fa3370f7fc7573d713f27ae89ba2f193d4b43991622ff969b0475e2f911aacf1a906020015b60405180910390a150565b5f546001600160a01b031633146108035760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff161561082b5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff001916610100179055478061087c5760405162461bcd60e51b815260206004820152601160248201527027379022aa24103a37903932b1b7bb32b960791b604482015260640161058b565b5f80546040516001600160a01b039091169083908381818185875af1925050503d805f81146108c6576040519150601f19603f3d011682016040523d82523d5f602084013e6108cb565b606091505b50509050806109125760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015260640161058b565b5f546040518381526001600160a01b03909116907f0923a1159e4557a4252f468d636ab7daefb6370b599dec7f60a961fa9fb58be7906020015b60405180910390a250506005805461ff0019169055565b60048181548110610972575f80fd5b5f918252602090912001546001600160a01b0316905081565b600a545f815a101590509091565b5f546001600160a01b031633146109c25760405162461bcd60e51b815260040161058b90612d31565b600f811015610a085760405162461bcd60e51b8152602060048201526012602482015271111958591b1a5b99481d1bdbc81cda1bdc9d60721b604482015260640161058b565b610258811115610a4e5760405162461bcd60e51b8152602060048201526011602482015270446561646c696e6520746f6f206c6f6e6760781b604482015260640161058b565b60088190556040518181527fdb00f0341e024be397e058a193a27b85cc3e7f921640be77ddf155c9f8d37c5a906020016107cf565b6001546001600160a01b03163314610ad35760405162461bcd60e51b815260206004820152601360248201527213db9b1e481d1bdad95b8818d85b8818d85b1b606a1b604482015260640161058b565b6001546001600160a01b0316610b235760405162461bcd60e51b8152602060048201526015602482015274151bdad95b881b9bdd081a5b9a5d1a585b1a5e9959605a1b604482015260640161058b565b600554610100900460ff1615610b4b5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff001916610100179055475f819003610b69575061104a565b5f5a9050600954600a54610b7d9190612e38565b811015610bd5577f1796228003433d7e098ed8c6a104e057ae3bc44e514af8cce440a16d88a72bd681600954600a54610bb69190612e38565b6040805192835260208301919091520160405180910390a1505061104a565b5f5b6002811161104657479250825f03610bf15750505061104a565b5f60075482610c009190612e4b565b600654610c0d9190612e38565b90506032811115610c1c575060325b5f610c2785836129e7565b90505f60085442610c389190612e38565b90507fbd87b7fd36ca10216ecd84ec6b511a2b6a32701cc22007462dbe03a6954972dc610c66856001612e38565b604080519182526020820189905281018590526060810184905260800160405180910390a16001546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610cd1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf59190612e62565b60035460405163b6f9de9560e01b81529192506001600160a01b03169063b6f9de95908990610d2e908790600490309089908301612ebf565b5f604051808303818588803b158015610d45575f5ffd5b505af193505050508015610d57575060015b610e2b57610d63612ef3565b806308c379a003610de75750610d77612f0c565b80610d825750610de9565b6002861015610d95575050505050611034565b7fa1da5bd9d62e3afc7dab61bfacb9b20a2b09422413e8b005da62529623881fe888610dc2886001612e38565b6040805192835260208301919091520160405180910390a1505050505050505061104a565b505b3d808015610e12576040519150601f19603f3d011682016040523d82523d5f602084013e610e17565b606091505b506002861015610d95575050505050611034565b6001546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015610e71573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e959190612e62565b90505f610ea28383612f90565b905084811015610ec45760405162461bcd60e51b815260040161058b90612fa3565b80156110265760015460405163a9059cbb60e01b815261dead6004820181905260248201849052916001600160a01b03169063a9059cbb906044016020604051808303815f875af1158015610f1b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3f9190612e05565b610f825760405162461bcd60e51b8152602060048201526014602482015273109d5c9b881d1c985b9cd9995c8819985a5b195960621b604482015260640161058b565b5f5a610f8e908b612f90565b90507f58a9be6ff5fc8bc43bfb8eef8aba0eadd1ca1f7f65402a356b623a5a31de300f8b8483610fbf8d6001612e38565b6040805194855260208501939093529183015260608201526080810189905260a0810188905260c00160405180910390a16040518381527f6ef4855b666dcc7884561072e4358b28dfe01feb1b7f4dcebc00e62d50394ac79060200160405180910390a150505b50505050505050505061104a565b8061103e81612fce565b915050610bd7565b5050505b6005805461ff0019169055565b5f546001600160a01b031633146110805760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff16156110a85760405162461bcd60e51b815260040161058b90612d54565b6005805461ff0019166101001790556002546001600160a01b03166110df5760405162461bcd60e51b815260040161058b90612d81565b5f81116110fe5760405162461bcd60e51b815260040161058b90612da2565b5f611107612966565b9050818110156111295760405162461bcd60e51b815260040161058b90612dce565b6002545f5460405163a9059cbb60e01b81526001600160a01b0391821660048201526024810185905291169063a9059cbb906044016020604051808303815f875af115801561117a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061119e9190612e05565b6111df5760405162461bcd60e51b81526020600482015260126024820152711314081d1c985b9cd9995c8819985a5b195960721b604482015260640161058b565b5f546040518381526001600160a01b03909116907fd0f180543559f70d2d58da088e6bf2ffb4e5d8a40d4c0eda25612a2e1a4dd0bc9060200161094c565b5f546001600160a01b031633146112465760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff161561126e5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff001981166101001790915560ff16156112c55760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b604482015260640161058b565b5f341161130d5760405162461bcd60e51b81526020600482015260166024820152754e6565642045544820666f72206c697175696469747960501b604482015260640161058b565b8282111561135d5760405162461bcd60e51b815260206004820152601760248201527f4c5020746f6b656e732065786365656420737570706c79000000000000000000604482015260640161058b565b5f82116113a45760405162461bcd60e51b815260206004820152601560248201527404c5020746f6b656e73206d757374206265203e203605c1b604482015260640161058b565b5f604051806020016113b590612b11565b6020820181038252601f19601f8201166040525090505f8686863060035f9054906101000a90046001600160a01b03166001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611420573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114449190612fe6565b60035f9054906101000a90046001600160a01b03166001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611494573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b89190612fe6565b6040516020016114cd9695949392919061302f565b60405160208183030381529060405290505f82826040516020016114f292919061309b565b60405160208183030381529060405290505f848251602084015ff59050803b611519575f5ffd5b6001600160a01b03811661156f5760405162461bcd60e51b815260206004820152601760248201527f546f6b656e206465706c6f796d656e74206661696c6564000000000000000000604482015260640161058b565b600180546001600160a01b0319166001600160a01b0383169081178255600480549192909181106115a2576115a26130b7565b5f918252602082200180546001600160a01b0319166001600160a01b0393909316929092179091556004805482906115dc576115dc6130b7565b5f918252602090912001546001600160a01b0316036116345760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840ae8aa89040d2dc40e0c2e8d60631b604482015260640161058b565b60018054600480546001600160a01b039092169290918110611658576116586130b7565b5f918252602090912001546001600160a01b0316146116b15760405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840e8ded6cadc40d2dc40e0c2e8d605b1b604482015260640161058b565b7f479310ca8888d8a8ac0aa6365bc4df9c6b0a4c655b5b050dfdd4ed74e585d39060045f815481106116e5576116e56130b7565b5f91825260209091200154600480546001600160a01b03909216916001908110611711576117116130b7565b5f9182526020909120015460405161174892916001600160a01b0316906001600160a01b0392831681529116602082015260400190565b60405180910390a160015460035460405163095ea7b360e01b81526001600160a01b0391821660048201526024810189905291169063095ea7b3906044016020604051808303815f875af11580156117a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c69190612e05565b6118045760405162461bcd60e51b815260206004820152600f60248201526e105c1c1c9bdd985b0819985a5b1959608a1b604482015260640161058b565b6003546001545f91829182916001600160a01b039081169163f305d719913491168c606461183382605f612e4b565b61183d91906130cb565b606461184a34605f612e4b565b61185491906130cb565b30600854426118639190612e38565b6040518863ffffffff1660e01b8152600401611884969594939291906130ea565b60606040518083038185885af11580156118a0573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906118c59190613125565b9250925092505f831180156118d957505f82115b61191c5760405162461bcd60e51b8152602060048201526014602482015273131a5c5d5a591a5d1e481859190819985a5b195960621b604482015260640161058b565b5f81116119635760405162461bcd60e51b8152602060048201526015602482015274139bc81314081d1bdad95b9cc81c9958d95a5d9959605a1b604482015260640161058b565b60035f9054906101000a90046001600160a01b03166001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119b3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119d79190612fe6565b600154600354604080516315ab88c960e31b815290516001600160a01b039485169463e6a4390594811693169163ad5c46489160048083019260209291908290030181865afa158015611a2c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a509190612fe6565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015611a99573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abd9190612fe6565b600280546001600160a01b0319166001600160a01b03929092169182179055611b1f5760405162461bcd60e51b815260206004820152601460248201527314185a5c8818dc99585d1a5bdb8819985a5b195960621b604482015260640161058b565b60015460025460405163485cc95560e01b81526001600160a01b03918216600482015230602482015291169063485cc955906044015f604051808303815f87803b158015611b6b575f5ffd5b505af1158015611b7d573d5f5f3e3d5ffd5b50506005805460ff1916600190811790915560025490546040516001600160a01b039283169450911691507ff9a44e6db3fb6e0eb31c4013bda8c662fecef1768dd2412270cc8f8821cbccf3905f90a360408051848152602081018490529081018290527fd7f28048575eead8851d024ead087913957dfb4fd1a02b4d1573f5352a5a2be39060600160405180910390a150506005805461ff001916905550505050505050505050565b5f546001600160a01b03163314611c505760405162461bcd60e51b815260040161058b90612d31565b60018110158015611c625750600a8111155b611cae5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420736c69707061676520696e63726561736500000000000000604482015260640161058b565b60078190556040518181527f2d2fdcebdfe0f0fa3cc3d883df5b786570a00ef479f509a3a8a5503af08e5b6e906020016107cf565b5f546001600160a01b03163314611d0c5760405162461bcd60e51b815260040161058b90612d31565b5f80546001600160a01b0319169055565b5f546001600160a01b03163314611d465760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff1615611d6e5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff0019166101001790556002546001600160a01b0316611da55760405162461bcd60e51b815260040161058b90612d81565b5f611dae612966565b90505f8111611dee5760405162461bcd60e51b815260206004820152600c60248201526b4e6f204c5020746f6b656e7360a01b604482015260640161058b565b6002545f5460405163a9059cbb60e01b81526001600160a01b0391821660048201526024810184905291169063a9059cbb906044016020604051808303815f875af1158015611e3f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e639190612e05565b611ea45760405162461bcd60e51b81526020600482015260126024820152711314081d1c985b9cd9995c8819985a5b195960721b604482015260640161058b565b5f546040518281526001600160a01b03909116907fd0f180543559f70d2d58da088e6bf2ffb4e5d8a40d4c0eda25612a2e1a4dd0bc9060200160405180910390a2506005805461ff0019169055565b5f805481906001600160a01b03163314611f1f5760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff1615611f475760405162461bcd60e51b815260040161058b90612d54565b6005805461ff0019166101001790556002546001600160a01b0316611f7e5760405162461bcd60e51b815260040161058b90612d81565b5f8511611f9d5760405162461bcd60e51b815260040161058b90612da2565b5f611fa6612966565b905085811015611fc85760405162461bcd60e51b815260040161058b90612dce565b60025460035460405163095ea7b360e01b81526001600160a01b0391821660048201526024810189905291169063095ea7b3906044016020604051808303815f875af115801561201a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061203e9190612e05565b61207f5760405162461bcd60e51b8152602060048201526012602482015271131408185c1c1c9bdd985b0819985a5b195960721b604482015260640161058b565b6003546001545f546008546001600160a01b03938416936302751cec938116928b928b928b9216906120b19042612e38565b6040518763ffffffff1660e01b81526004016120d2969594939291906130ea565b60408051808303815f875af11580156120ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121119190613150565b604080518381526020810183905290810189905291945092507fd7f28048575eead8851d024ead087913957dfb4fd1a02b4d1573f5352a5a2be39060600160405180910390a1506005805461ff00191690559094909350915050565b606060048054806020026020016040519081016040528092919081815260200182805480156121c357602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116121a5575b5050505050905090565b5f546001600160a01b031633146121f65760405162461bcd60e51b815260040161058b90612d31565b61c35082101561223a5760405162461bcd60e51b815260206004820152600f60248201526e5265736572766520746f6f206c6f7760881b604482015260640161058b565b62030d408110156122815760405162461bcd60e51b8152602060048201526011602482015270476173206c696d697420746f6f206c6f7760781b604482015260640161058b565b6207a1208111156122c95760405162461bcd60e51b815260206004820152601260248201527108ec2e640d8d2dad2e840e8dede40d0d2ced60731b604482015260640161058b565b6009829055600a81905560408051838152602081018390527f6bd79799f132160c1d0959f0684be5841c1a56641de803805011bcd87c561d8c910160405180910390a15050565b5f612319612966565b905090565b5f546001600160a01b031633146123475760405162461bcd60e51b815260040161058b90612d31565b600554610100900460ff161561236f5760405162461bcd60e51b815260040161058b90612d54565b6005805461ff001916610100179055816123c25760405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081b5a5b905b5bdd5b9d13dd5d60621b604482015260640161058b565b600f81101580156123d557506102588111155b6124145760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420646561646c696e6560801b604482015260640161058b565b47806124575760405162461bcd60e51b81526020600482015260126024820152714e6f2045544820666f72206275796261636b60701b604482015260640161058b565b5f5a9050600a548110156124ad5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74206761732070726f766964656400000000000000604482015260640161058b565b5f5b600281116128c157479250825f036124c9575050506128c5565b5f600754826124d89190612e4b565b6006546124e59190612e38565b905060328111156124f4575060325b5f821561250a5761250585836129e7565b61250c565b865b90505f6125198742612e38565b6001546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015612564573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125889190612e62565b60035460405163b6f9de9560e01b81529192506001600160a01b03169063b6f9de959089906125c1908790600490309089908301612ebf565b5f604051808303818588803b1580156125d8575f5ffd5b505af1935050505080156125ea575060015b6126e8577fbd87b7fd36ca10216ecd84ec6b511a2b6a32701cc22007462dbe03a6954972dc61261a866001612e38565b60408051918252602082018a905281018690526060810185905260800160405180910390a1600285036126e3577fa1da5bd9d62e3afc7dab61bfacb9b20a2b09422413e8b005da62529623881fe887612674876001612e38565b6040805192835260208301919091520160405180910390a160405162461bcd60e51b815260206004820152602660248201527f4d616e75616c207265747279206661696c656420616674657220616c6c20617460448201526574656d70747360d01b606482015260840161058b565b6128aa565b6001546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa15801561272e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127529190612e62565b90505f61275f8383612f90565b9050848110156127815760405162461bcd60e51b815260040161058b90612fa3565b801561289c5760015460405163a9059cbb60e01b815261dead6004820181905260248201849052916001600160a01b03169063a9059cbb906044016020604051808303815f875af11580156127d8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127fc9190612e05565b507f58a9be6ff5fc8bc43bfb8eef8aba0eadd1ca1f7f65402a356b623a5a31de300f8a835a61282b908d612f90565b6128368c6001612e38565b6040805194855260208501939093529183015260608201526080810188905260a0810187905260c00160405180910390a16040518281527f6ef4855b666dcc7884561072e4358b28dfe01feb1b7f4dcebc00e62d50394ac79060200160405180910390a1505b5050505050505050506128c5565b5050505080806128b990612fce565b9150506124af565b5050505b50506005805461ff0019169055565b5f546001600160a01b031633146128fd5760405162461bcd60e51b815260040161058b90612d31565b6001600160a01b0381166129455760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015260640161058b565b5f80546001600160a01b0319166001600160a01b0392909216919091179055565b6002545f906001600160a01b031661297d57505f90565b6002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156129c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123199190612e62565b5f6032821115612a095760405162461bcd60e51b815260040161058b90612fa3565b60035460405163d06ca61f60e01b81525f916001600160a01b03169063d06ca61f90612a3b9087906004908101613172565b5f60405180830381865afa158015612a55573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612a7c919081019061318a565b90505f81600181518110612a9257612a926130b7565b602002602001015190505f6064856064612aac9190612f90565b612ab69084612e4b565b612ac091906130cb565b90505f8111612b065760405162461bcd60e51b81526020600482015260126024820152714d696e20746f6b656e7320746f6f206c6f7760701b604482015260640161058b565b925050505b92915050565b612ac68061323783390190565b5f60208284031215612b2e575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f1916810167ffffffffffffffff81118282101715612b6f57612b6f612b35565b6040525050565b5f82601f830112612b85575f5ffd5b813567ffffffffffffffff811115612b9f57612b9f612b35565b604051612bb6601f8301601f191660200182612b49565b818152846020838601011115612bca575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f60a08688031215612bfa575f5ffd5b853567ffffffffffffffff811115612c10575f5ffd5b612c1c88828901612b76565b955050602086013567ffffffffffffffff811115612c38575f5ffd5b612c4488828901612b76565b959895975050505060408401359360608101359360809091013592509050565b5f5f5f60608486031215612c76575f5ffd5b505081359360208301359350604090920135919050565b602080825282518282018190525f918401906040840190835b81811015612ccd5783516001600160a01b0316835260209384019390920191600101612ca6565b509095945050505050565b5f5f60408385031215612ce9575f5ffd5b50508035926020909101359150565b6001600160a01b0381168114612d0c575f5ffd5b50565b5f60208284031215612d1f575f5ffd5b8135612d2a81612cf8565b9392505050565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b6020808252601390820152721499595b9d1c985b98de4819195d1958dd1959606a1b604082015260600190565b6020808252600790820152662737903830b4b960c91b604082015260600190565b6020808252601290820152710416d6f756e74206d757374206265203e20360741b604082015260600190565b60208082526017908201527f496e73756666696369656e74204c502062616c616e6365000000000000000000604082015260600190565b5f60208284031215612e15575f5ffd5b81518015158114612d2a575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b80820180821115612b0b57612b0b612e24565b8082028115828204841417612b0b57612b0b612e24565b5f60208284031215612e72575f5ffd5b5051919050565b5f8154808452602084019350825f5260205f205f5b82811015612eb55781546001600160a01b0316865260209095019460019182019101612e8e565b5093949350505050565b848152608060208201525f612ed76080830186612e79565b6001600160a01b03949094166040830152506060015292915050565b5f60033d1115612f095760045f5f3e505f5160e01c5b90565b5f60443d1015612f195790565b6040513d600319016004823e80513d602482011167ffffffffffffffff82111715612f4357505090565b808201805167ffffffffffffffff811115612f5f575050505090565b3d8401600319018282016020011115612f79575050505090565b612f8860208285010185612b49565b509392505050565b81810381811115612b0b57612b0b612e24565b6020808252601190820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604082015260600190565b5f60018201612fdf57612fdf612e24565b5060010190565b5f60208284031215612ff6575f5ffd5b8151612d2a81612cf8565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60c081525f61304160c0830189613001565b82810360208401526130538189613001565b604084019790975250506001600160a01b039384166060820152918316608083015290911660a09091015292915050565b5f81518060208401855e5f93019283525090919050565b5f6130af6130a98386613084565b84613084565b949350505050565b634e487b7160e01b5f52603260045260245ffd5b5f826130e557634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160a01b039687168152602081019590955260408501939093526060840191909152909216608082015260a081019190915260c00190565b5f5f5f60608486031215613137575f5ffd5b5050815160208301516040909301519094929350919050565b5f5f60408385031215613161575f5ffd5b505080516020909101519092909150565b828152604060208201525f6130af6040830184612e79565b5f6020828403121561319a575f5ffd5b815167ffffffffffffffff8111156131b0575f5ffd5b8201601f810184136131c0575f5ffd5b805167ffffffffffffffff8111156131da576131da612b35565b8060051b6040516131ee6020830182612b49565b918252602081840181019290810187841115613208575f5ffd5b6020850194505b8385101561322b5784518082526020958601959093500161320f565b50969550505050505056fe60e06040526004600555600460065562086470600955348015610020575f5ffd5b50604051612ac6380380612ac683398101604081905261003f916102b5565b6001600160a01b03831661008c5760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b21036b0b730b3b2b960891b60448201526064015b60405180910390fd5b6001600160a01b0382166100d15760405162461bcd60e51b815260206004820152600c60248201526b092dcecc2d8d2c840ae8aa8960a31b6044820152606401610083565b6001600160a01b0381166101195760405162461bcd60e51b815260206004820152600f60248201526e496e76616c696420666163746f727960881b6044820152606401610083565b5f61012487826103d6565b50600161013186826103d6565b506002849055600a80546001600160a01b0319166001600160a01b03858116919091179091553360c052828116608052811660a05261017261271085610490565b6007556001600e8190556001600160a01b0384165f818152600360209081526040808320899055600c8252808320805460ff19908116871790915530845281842080549091169095179094559251878152919290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050505050506104af565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112610220575f5ffd5b81516001600160401b03811115610239576102396101fd565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610267576102676101fd565b60405281815283820160200185101561027e575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b80516001600160a01b03811681146102b0575f5ffd5b919050565b5f5f5f5f5f5f60c087890312156102ca575f5ffd5b86516001600160401b038111156102df575f5ffd5b6102eb89828a01610211565b602089015190975090506001600160401b03811115610308575f5ffd5b61031489828a01610211565b9550506040870151935061032a6060880161029a565b92506103386080880161029a565b915061034660a0880161029a565b90509295509295509295565b600181811c9082168061036657607f821691505b60208210810361038457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103d157805f5260205f20601f840160051c810160208510156103af5750805b601f840160051c820191505b818110156103ce575f81556001016103bb565b50505b505050565b81516001600160401b038111156103ef576103ef6101fd565b610403816103fd8454610352565b8461038a565b6020601f821160018114610435575f831561041e5750848201515b5f19600385901b1c1916600184901b1784556103ce565b5f84815260208120601f198516915b828110156104645787850151825560209485019460019092019101610444565b508482101561048157868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f826104aa57634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c0516125b861050e5f395f50505f818161055701528181610d4a01528181611aa90152611c2901525f81816104f001528181610cd601528181610d11015281816119a7015281816119e20152611a7f01526125b85ff3fe6080604052600436106101de575f3560e01c806395d89b41116100fd578063c45a015511610092578063e89d4d7d11610062578063e89d4d7d146105f1578063f1a8c48314610605578063f8b91abe14610624578063fc73854914610638575f5ffd5b8063c45a015514610546578063cc1776d314610579578063d83567ab1461058e578063dd62ed3e146105ad575f5ffd5b8063ab6a8b1c116100cd578063ab6a8b1c146104c0578063ad5c4648146104df578063b7c6b7c814610512578063c024666814610527575f5ffd5b806395d89b4114610459578063a367f5c21461046d578063a8b0898214610482578063a9059cbb146104a1575f5ffd5b80634ada218b1161017357806370a082311161014357806370a08231146103a95780638a8c523c146103dd5780638b8dbfd4146103f15780638d32ca8b14610422575f5ffd5b80634ada218b146102fe5780634f7041a5146103175780635342acb41461032c57806356b35b0e1461035a575f5ffd5b8063186e2d77116101ae578063186e2d771461028657806323b872dd1461029a578063313ce567146102b9578063485cc955146102df575f5ffd5b806306fdde03146101e9578063095ea7b3146102135780630d0c278f1461024257806318160ddd14610263575f5ffd5b366101e557005b5f5ffd5b3480156101f4575f5ffd5b506101fd61064c565b60405161020a919061219b565b60405180910390f35b34801561021e575f5ffd5b5061023261022d3660046121cb565b6106d7565b604051901515815260200161020a565b34801561024d575f5ffd5b5061026161025c3660046121f5565b6106ed565b005b34801561026e575f5ffd5b5061027860025481565b60405190815260200161020a565b348015610291575f5ffd5b506102616107eb565b3480156102a5575f5ffd5b506102326102b436600461220c565b6108f1565b3480156102c4575f5ffd5b506102cd601281565b60405160ff909116815260200161020a565b3480156102ea575f5ffd5b506102616102f936600461224a565b610992565b348015610309575f5ffd5b50600d546102329060ff1681565b348015610322575f5ffd5b5061027860055481565b348015610337575f5ffd5b50610232610346366004612281565b600c6020525f908152604090205460ff1681565b348015610365575f5ffd5b5061036e610aff565b604080516001600160a01b0396871681529486166020860152928516928401929092529092166060820152901515608082015260a00161020a565b3480156103b4575f5ffd5b506102786103c3366004612281565b6001600160a01b03165f9081526003602052604090205490565b3480156103e8575f5ffd5b50610261610da4565b3480156103fc575f5ffd5b50610405610e6a565b60408051931515845260208401929092529082015260600161020a565b34801561042d575f5ffd5b50600a54610441906001600160a01b031681565b6040516001600160a01b03909116815260200161020a565b348015610464575f5ffd5b506101fd610e8d565b348015610478575f5ffd5b5061027860075481565b34801561048d575f5ffd5b50600b54610441906001600160a01b031681565b3480156104ac575f5ffd5b506102326104bb3660046121cb565b610e9a565b3480156104cb575f5ffd5b506102616104da36600461229c565b610ea6565b3480156104ea575f5ffd5b506104417f000000000000000000000000000000000000000000000000000000000000000081565b34801561051d575f5ffd5b5061027860095481565b348015610532575f5ffd5b506102616105413660046122bc565b610f28565b348015610551575f5ffd5b506104417f000000000000000000000000000000000000000000000000000000000000000081565b348015610584575f5ffd5b5061027860065481565b348015610599575f5ffd5b506102616105a83660046121f5565b610f7c565b3480156105b8575f5ffd5b506102786105c736600461224a565b6001600160a01b039182165f90815260046020908152604080832093909416825291909152205490565b3480156105fc575f5ffd5b50610261611031565b348015610610575f5ffd5b5061026161061f3660046121cb565b611091565b34801561062f575f5ffd5b506102616111c8565b348015610643575f5ffd5b50610261611204565b5f8054610658906122ec565b80601f0160208091040260200160405190810160405280929190818152602001828054610684906122ec565b80156106cf5780601f106106a6576101008083540402835291602001916106cf565b820191905f5260205f20905b8154815290600101906020018083116106b257829003601f168201915b505050505081565b5f6106e33384846112cc565b5060015b92915050565b600a546001600160a01b031633146107205760405162461bcd60e51b815260040161071790612324565b60405180910390fd5b62061a808110156107675760405162461bcd60e51b8152602060048201526011602482015270476173206c696d697420746f6f206c6f7760781b6044820152606401610717565b620f42408111156107af5760405162461bcd60e51b815260206004820152601260248201527108ec2e640d8d2dad2e840e8dede40d0d2ced60731b6044820152606401610717565b60098190556040518181527fc55bc88e18ef7c8487ab567aff00704b2c2a16637de3c20160452e108e167e4c906020015b60405180910390a150565b600a546001600160a01b031633146108155760405162461bcd60e51b815260040161071790612324565b47806108575760405162461bcd60e51b815260206004820152601160248201527027379022aa24103a37903932b1b7bb32b960791b6044820152606401610717565b600a546040515f916001600160a01b03169083908381818185875af1925050503d805f81146108a1576040519150601f19603f3d011682016040523d82523d5f602084013e6108a6565b606091505b50509050806108ed5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610717565b5050565b5f6108fd8484846113d8565b6001600160a01b0384165f9081526004602090815260408083203384529091529020548281101561097a5760405162461bcd60e51b815260206004820152602160248201527f5472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636044820152606560f81b6064820152608401610717565b61098785338584036112cc565b506001949350505050565b600a546001600160a01b031633146109bc5760405162461bcd60e51b815260040161071790612324565b600b546001600160a01b031615610a0b5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b6044820152606401610717565b6001600160a01b038216610a585760405162461bcd60e51b8152602060048201526014602482015273496e76616c69642070616972206164647265737360601b6044820152606401610717565b6001600160a01b038116610aae5760405162461bcd60e51b815260206004820152601760248201527f496e76616c6964206d616e6167657220616464726573730000000000000000006044820152606401610717565b610ab7826117e4565b600b80546001600160a01b039384166001600160a01b03199182168117909255600a8054939094169216919091179091555f908152600c60205260409020805460ff19169055565b600b545f9081908190819081906001600160a01b0316610b2c57505f935083925082915081905080610d9d565b600b5460408051630dfe168160e01b815290516001600160a01b03909216918291630dfe16819160048083019260209291908290030181865afa925050508015610b93575060408051601f3d908101601f19168201909252610b909181019061234a565b60015b610bb6575050600b546001600160a01b031693505f925082915081905080610d9d565b9450806001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610c12575060408051601f3d908101601f19168201909252610c0f9181019061234a565b60015b610c32575050600b546001600160a01b031693505f915081905080610d9d565b9350806001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610c8e575060408051601f3d908101601f19168201909252610c8b9181019061234a565b60015b610cab575050600b546001600160a01b031693505f905080610d9d565b92505f6001600160a01b038616301480610ccd57506001600160a01b03851630145b8015610d4557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b03161480610d4557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316145b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316149050818015610d895750805b600b546001600160a01b0316985093505050505b9091929394565b600a546001600160a01b03163314610dce5760405162461bcd60e51b815260040161071790612324565b600d5460ff1615610e215760405162461bcd60e51b815260206004820152601760248201527f54726164696e6720616c726561647920656e61626c65640000000000000000006044820152606401610717565b600d805460ff191660011790556040517fb3da2db3dfc3778f99852546c6e9ab39ec253f9de7b0847afec61bd27878e92390610e609042815260200190565b60405180910390a1565b5f5f5f5a905060095461c350610e809190612379565b9150818110159250909192565b60018054610658906122ec565b5f6106e33384846113d8565b600a546001600160a01b03163314610ed05760405162461bcd60e51b815260040161071790612324565b600a8211158015610ee25750600a8111155b610f1d5760405162461bcd60e51b815260206004820152600c60248201526b0a8c2f040e8dede40d0d2ced60a31b6044820152606401610717565b600591909155600655565b600a546001600160a01b03163314610f525760405162461bcd60e51b815260040161071790612324565b6001600160a01b03919091165f908152600c60205260409020805460ff1916911515919091179055565b600a546001600160a01b03163314610fa65760405162461bcd60e51b815260040161071790612324565b6103e8600254610fb6919061238c565b811115610ffc5760405162461bcd60e51b815260206004820152601460248201527309ad2dc40c4c2d8c2dcc6ca40e8dede40d0d2ced60631b6044820152606401610717565b60078190556040518181527f4e1cd0a17dbc393262d4d9b66380671f5273c5f0a34fed0ed36c50ba6b1f0e16906020016107e0565b600a546001600160a01b0316331461105b5760405162461bcd60e51b815260040161071790612324565b5f60078190556040519081527f4e1cd0a17dbc393262d4d9b66380671f5273c5f0a34fed0ed36c50ba6b1f0e1690602001610e60565b3330146110cc5760405162461bcd60e51b815260206004820152600960248201526827b7363c9039b2b63360b91b6044820152606401610717565b4281101561110f5760405162461bcd60e51b815260206004820152601060248201526f111958591b1a5b9948195e1c1a5c995960821b6044820152606401610717565b60095460408051600481526024810182526020810180516001600160e01b0316634348b59b60e01b17905290515f9283926001600160a01b0387169261115591906123ab565b5f604051808303815f8787f1925050503d805f811461118f576040519150601f19603f3d011682016040523d82523d5f602084013e611194565b606091505b5091509150816111a382611ca8565b906111c15760405162461bcd60e51b8152600401610717919061219b565b5050505050565b600a546001600160a01b031633146111f25760405162461bcd60e51b815260040161071790612324565b600a80546001600160a01b0319169055565b600a546001600160a01b0316331461122e5760405162461bcd60e51b815260040161071790612324565b60085460ff16156112735760405162461bcd60e51b815260206004820152600f60248201526e0416c726561647920696e207377617608c1b6044820152606401610717565b305f908152600360205260409020546112c25760405162461bcd60e51b815260206004820152601160248201527004e6f20746f6b656e7320746f207377617607c1b6044820152606401610717565b6112ca611d07565b565b6001600160a01b0383166113225760405162461bcd60e51b815260206004820152601960248201527f417070726f76652066726f6d207a65726f2061646472657373000000000000006044820152606401610717565b6001600160a01b0382166113785760405162461bcd60e51b815260206004820152601760248201527f417070726f766520746f207a65726f20616464726573730000000000000000006044820152606401610717565b6001600160a01b038381165f8181526004602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b03831661142e5760405162461bcd60e51b815260206004820152601a60248201527f5472616e736665722066726f6d207a65726f20616464726573730000000000006044820152606401610717565b6001600160a01b0382166114845760405162461bcd60e51b815260206004820152601860248201527f5472616e7366657220746f207a65726f206164647265737300000000000000006044820152606401610717565b6001600160a01b0383165f908152600360205260409020548111156114e25760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610717565b600d5460ff168061150a57506001600160a01b0383165f908152600c602052604090205460ff165b8061152c57506001600160a01b0382165f908152600c602052604090205460ff165b6115785760405162461bcd60e51b815260206004820152601760248201527f54726164696e67206e6f7420656e61626c6564207965740000000000000000006044820152606401610717565b305f908152600360205260409020546007548110801590819061159e575060085460ff16155b80156115b85750600b546001600160a01b03868116911614155b156115c5576115c5611d07565b6001600160a01b0385165f908152600c602052604090205460019060ff168061160557506001600160a01b0385165f908152600c602052604090205460ff165b1561160d57505f5b60085460ff161561161b57505f5b5f811561172357600b546001600160a01b0390811688821681149188161481156116605760646005548861164f91906123c1565b611659919061238c565b9250611683565b80156116835760646006548861167691906123c1565b611680919061238c565b92505b821561172057305f90815260036020526040812080548592906116a7908490612379565b909155505060405183815230906001600160a01b038b16907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36040518381527f092c6768ba45dfdc937f94a27a0c5be8334952f1558bc7dd41b3e8707502e1b69060200160405180910390a15b50505b5f61172e82876123d8565b6001600160a01b0389165f9081526003602052604081208054929350889290919061175a9084906123d8565b90915550506001600160a01b0387165f9081526003602052604081208054839290611786908490612379565b92505081905550866001600160a01b0316886001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516117d291815260200190565b60405180910390a35050505050505050565b5f8190505f5f826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611844575060408051601f3d908101601f191682019092526118419181019061234a565b60015b6118905760405162461bcd60e51b815260206004820181905260248201527f496e76616c696420706169723a20746f6b656e302063616c6c206661696c65646044820152606401610717565b9150826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156118ec575060408051601f3d908101601f191682019092526118e99181019061234a565b60015b6119385760405162461bcd60e51b815260206004820181905260248201527f496e76616c696420706169723a20746f6b656e312063616c6c206661696c65646044820152606401610717565b90506001600160a01b03821630148061195957506001600160a01b03811630145b6119a55760405162461bcd60e51b815260206004820181905260248201527f5061697220646f6573206e6f7420636f6e7461696e207468697320746f6b656e6044820152606401610717565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480611a1657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316145b611a625760405162461bcd60e51b815260206004820152601a60248201527f5061697220646f6573206e6f7420636f6e7461696e20574554480000000000006044820152606401610717565b60405163e6a4390560e01b81523060048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063e6a4390590604401602060405180830381865afa158015611af0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b14919061234a565b9050846001600160a01b0316816001600160a01b031614611b775760405162461bcd60e51b815260206004820152601e60248201527f50616972206e6f74207265676973746572656420696e20666163746f727900006044820152606401610717565b836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611bd1575060408051601f3d908101601f19168201909252611bce9181019061234a565b60015b611c275760405162461bcd60e51b815260206004820152602160248201527f496e76616c696420706169723a20666163746f72792063616c6c206661696c656044820152601960fa1b6064820152608401610717565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614611ca05760405162461bcd60e51b81526020600482015260156024820152740a0c2d2e440ccc2c6e8dee4f240dad2e6dac2e8c6d605b1b6044820152606401610717565b505050505050565b6060604482511015611ced57505060408051808201909152601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b600482019150818060200190518101906106e7919061242c565b6002600e5403611d595760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610717565b6002600e55305f9081526003602052604081205490819003611d7b5750612166565b6008805460ff191660011790555f5a90505f6064600254611d9c919061238c565b905080831115611daa578092505b305f9081526003602052604081208054859290611dc89084906123d8565b9091555050600a546001600160a01b03165f9081526003602052604081208054859290611df6908490612379565b9091555050600a546040518481526001600160a01b039091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3478015611f5757600a546040515f916001600160a01b03169083908381818185875af1925050503d805f8114611e90576040519150601f19603f3d011682016040523d82523d5f602084013e611e95565b606091505b5050905080611f5557600a54604080518481526001600160a01b0390921660208301527f0d4cd95169a26aee182a4ccf703957332b0124f339d2df71fca46b9860152702910160405180910390a17f1ee26af29c98a78de89a0efdcde8c7e768e077383fe7189c5e1f52ff58282fbd5a604051611f4c91906040808252601e908201527f455448207472616e7366657220746f206d616e61676572206661696c656400006060820152602081019190915260800190565b60405180910390a15b505b5f611f644261012c612379565b600954600a5460405163f1a8c48360e01b81526001600160a01b03909116600482015260248101839052919250309163f1a8c48391906044015f604051808303815f88803b158015611fb4575f5ffd5b5087f193505050508015611fc6575060015b61210457611fd26124c4565b806308c379a0036120745750611fe66124dd565b80611ff15750612076565b5f5a90507f1ee26af29c98a78de89a0efdcde8c7e768e077383fe7189c5e1f52ff58282fbd8282604051612026929190612561565b60405180910390a1604080518881525f602082018190528183015290517f6321922449d3b78d6e111db6ff7fa0b0963798d0b026d2d90df032a1706f5f069181900360600190a15050612156565b505b3d80801561209f576040519150601f19603f3d011682016040523d82523d5f602084013e6120a4565b606091505b505f5a90507f1ee26af29c98a78de89a0efdcde8c7e768e077383fe7189c5e1f52ff58282fbd8160405161202691906040808252600f908201526e2637bb96b632bb32b61032b93937b960891b6060820152602081019190915260800190565b5f5a61211090866123d8565b60408051888152600160208201529081018290529091507f6321922449d3b78d6e111db6ff7fa0b0963798d0b026d2d90df032a1706f5f069060600160405180910390a1505b50506008805460ff191690555050505b6001600e55565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6121ad602083018461216d565b9392505050565b6001600160a01b03811681146121c8575f5ffd5b50565b5f5f604083850312156121dc575f5ffd5b82356121e7816121b4565b946020939093013593505050565b5f60208284031215612205575f5ffd5b5035919050565b5f5f5f6060848603121561221e575f5ffd5b8335612229816121b4565b92506020840135612239816121b4565b929592945050506040919091013590565b5f5f6040838503121561225b575f5ffd5b8235612266816121b4565b91506020830135612276816121b4565b809150509250929050565b5f60208284031215612291575f5ffd5b81356121ad816121b4565b5f5f604083850312156122ad575f5ffd5b50508035926020909101359150565b5f5f604083850312156122cd575f5ffd5b82356122d8816121b4565b915060208301358015158114612276575f5ffd5b600181811c9082168061230057607f821691505b60208210810361231e57634e487b7160e01b5f52602260045260245ffd5b50919050565b6020808252600c908201526b27b7363c9036b0b730b3b2b960a11b604082015260600190565b5f6020828403121561235a575f5ffd5b81516121ad816121b4565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106e7576106e7612365565b5f826123a657634e487b7160e01b5f52601260045260245ffd5b500490565b5f82518060208501845e5f920191825250919050565b80820281158282048414176106e7576106e7612365565b818103818111156106e7576106e7612365565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f1916810167ffffffffffffffff81118282101715612425576124256123eb565b6040525050565b5f6020828403121561243c575f5ffd5b815167ffffffffffffffff811115612452575f5ffd5b8201601f81018413612462575f5ffd5b805167ffffffffffffffff81111561247c5761247c6123eb565b604051612493601f8301601f1916602001826123ff565b8181528560208385010111156124a7575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f60033d11156124da5760045f5f3e505f5160e01c5b90565b5f60443d10156124ea5790565b6040513d600319016004823e80513d602482011167ffffffffffffffff8211171561251457505090565b808201805167ffffffffffffffff811115612530575050505090565b3d840160031901828201602001111561254a575050505090565b612559602082850101856123ff565b509392505050565b604081525f612573604083018561216d565b9050826020830152939250505056fea264697066735822122025e6d122f521a71de120ea70a004ea7ffb4ed98d44ebd97b85a1a05719b72c1164736f6c634300081e0033a264697066735822122010f2865de0f6782edb245490d66edae32c770da3020381ccacc144950c99d06864736f6c634300081e0033
Verified Source Code Full Match
Compiler: v0.8.30+commit.73712a01
EVM: prague
Optimization: Yes (200 runs)
BuyBackManagerFixed.sol 562 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./Token.sol";
/**
* @title Manager
*/
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
interface IUniswapV2Router02 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
}
interface IBuybackToken {
function initialize(address _pair, address _buybackManager) external;
}
contract BuybackManagerFixed {
// State variables
address public owner;
address public tokenAddress;
address public pairAddress;
IUniswapV2Router02 public router;
// Validated swap path
address[] public swapPath;
bool public isInitialized;
bool private locked;
// Security settings
uint256 public slippageTolerance = 10;
uint256 public constant MAX_RETRIES = 2;
uint256 public slippageIncreasePerRetry = 5;
// Deadline configuration
uint256 public defaultDeadlineSeconds = 60;
// Gas management
uint256 public minGasReserve = 200000;
uint256 public buybackGasLimit = 300000;
// Events
event TokenDeployed(address indexed tokenAddress, address indexed pair);
event LiquidityAdded(uint256 tokenAmount, uint256 ethAmount, uint256 lpTokens);
event BuybackExecuted(
uint256 ethAmount,
uint256 tokensBought,
uint256 gasUsed,
uint256 attemptNumber,
uint256 minAmountOut,
uint256 deadline
);
event TokensBurned(uint256 amount);
event LPTokensBurned(uint256 amount);
event LPTokensWithdrawn(uint256 amount, address indexed to);
event SlippageToleranceUpdated(uint256 newTolerance);
event DeadlineUpdated(uint256 newDeadline);
event GasSettingsUpdated(uint256 minReserve, uint256 gasLimit);
event InsufficientGasForBuyback(uint256 available, uint256 required);
event EmergencyETHRecovered(uint256 amount, address indexed to);
event BuybackRetryAttempt(uint256 attemptNumber, uint256 ethBalance, uint256 appliedSlippage, uint256 minAmountOut);
event BuybackFailedAllRetries(uint256 finalEthBalance, uint256 totalAttempts);
event RetryConfigUpdated(uint256 slippageIncrease);
event SwapPathValidated(address weth, address token);
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier onlyToken() {
require(msg.sender == tokenAddress, "Only token can call");
require(tokenAddress != address(0), "Token not initialized");
_;
}
modifier nonReentrant() {
require(!locked, "Reentrancy detected");
locked = true;
_;
locked = false;
}
constructor(address _router) {
require(_router != address(0), "Invalid router");
owner = msg.sender;
router = IUniswapV2Router02(_router);
// Validate WETH
address weth = router.WETH();
require(weth != address(0), "Invalid WETH address");
// Initialize path (token will be set during deployment)
swapPath = new address[](2);
swapPath[0] = weth;
}
/**
* @dev Get fresh LP token balance (no manual tracking)
*/
function _getLPBalance() internal view returns (uint256) {
if (pairAddress == address(0)) return 0;
return IERC20(pairAddress).balanceOf(address(this));
}
/**
* @dev Calculate minAmountOut with explicit slippage
*/
function _calculateMinAmountOut(uint256 ethAmount, uint256 slippage) internal view returns (uint256) {
require(slippage <= 50, "Slippage too high");
uint256[] memory amountsOut = router.getAmountsOut(ethAmount, swapPath);
uint256 expectedTokens = amountsOut[1];
uint256 minTokens = expectedTokens * (100 - slippage) / 100;
require(minTokens > 0, "Min tokens too low");
return minTokens;
}
/**
* ✅ FIX #1 & #2: Deploy token directly with correct parameters
* This is a placeholder - in actual implementation, you need to either:
* 1. Import BuybackTokenSecured and use: new BuybackTokenSecured(...)
* 2. Use a factory pattern
*
* For this example, we'll show the CREATE2 approach with proper parameters
*/
function deployTokenAndAddLiquidity(
string memory name,
string memory symbol,
uint256 totalSupply,
uint256 tokensForLP,
bytes32 salt // Optional: for CREATE2 deterministic deployment
) external payable onlyOwner nonReentrant {
require(!isInitialized, "Already initialized");
require(msg.value > 0, "Need ETH for liquidity");
require(tokensForLP <= totalSupply, "LP tokens exceed supply");
require(tokensForLP > 0, "LP tokens must be > 0");
// ✅ FIX #1: Deploy token directly (not from arbitrary bytecode)
// Get the bytecode of BuybackTokenSecured
bytes memory bytecode = type(BuybackTokenSecured).creationCode;
// ✅ FIX #2: Encode ALL required constructor parameters
bytes memory constructorArgs = abi.encode(
name,
symbol,
totalSupply,
address(this), // buyback manager
router.WETH(), // ✅ WETH address
router.factory() // ✅ Factory address
);
bytes memory deploymentData = abi.encodePacked(bytecode, constructorArgs);
address deployedToken;
// Deploy with CREATE2 for deterministic address
assembly {
deployedToken := create2(
0,
add(deploymentData, 0x20),
mload(deploymentData),
salt
)
if iszero(extcodesize(deployedToken)) {
revert(0, 0)
}
}
require(deployedToken != address(0), "Token deployment failed");
tokenAddress = deployedToken;
// Complete and validate swap path
swapPath[1] = tokenAddress;
require(swapPath[0] != address(0), "Invalid WETH in path");
require(swapPath[1] == tokenAddress, "Invalid token in path");
emit SwapPathValidated(swapPath[0], swapPath[1]);
// Approve router
require(
IERC20(tokenAddress).approve(address(router), tokensForLP),
"Approval failed"
);
(uint256 amountToken, uint256 amountETH, uint256 liquidity) = router.addLiquidityETH{value: msg.value}(
tokenAddress,
tokensForLP,
tokensForLP * 95 / 100,
msg.value * 95 / 100,
address(this),
block.timestamp + defaultDeadlineSeconds
);
require(amountToken > 0 && amountETH > 0, "Liquidity add failed");
require(liquidity > 0, "No LP tokens received");
pairAddress = IUniswapV2Factory(router.factory()).getPair(
tokenAddress,
router.WETH()
);
require(pairAddress != address(0), "Pair creation failed");
// Initialize the token with correct pair address
IBuybackToken(tokenAddress).initialize(pairAddress, address(this));
isInitialized = true;
emit TokenDeployed(tokenAddress, pairAddress);
emit LiquidityAdded(amountToken, amountETH, liquidity);
}
/**
* @dev Execute buyback and burn - called by token contract
*/
function executeBuybackAndBurn() external onlyToken nonReentrant {
uint256 ethBalance = address(this).balance;
if (ethBalance == 0) return;
uint256 gasStart = gasleft();
// Check gas availability
if (gasStart < buybackGasLimit + minGasReserve) {
emit InsufficientGasForBuyback(gasStart, buybackGasLimit + minGasReserve);
return;
}
// Progressive retry logic with increasing slippage
for (uint256 attempt = 0; attempt <= MAX_RETRIES; attempt++) {
// Fresh balance check on each iteration
ethBalance = address(this).balance;
if (ethBalance == 0) return;
// Progressive slippage
uint256 currentSlippage = slippageTolerance + (attempt * slippageIncreasePerRetry);
if (currentSlippage > 50) currentSlippage = 50;
// Calculate minimum amount for this attempt
uint256 minAmountOut = _calculateMinAmountOut(ethBalance, currentSlippage);
// Calculate deadline for this swap
uint256 deadline = block.timestamp + defaultDeadlineSeconds;
emit BuybackRetryAttempt(attempt + 1, ethBalance, currentSlippage, minAmountOut);
// Get token balance before swap
uint256 tokenBalanceBefore = IERC20(tokenAddress).balanceOf(address(this));
try router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: ethBalance}(
minAmountOut,
swapPath,
address(this),
deadline
) {
// Get actual tokens received
uint256 tokenBalanceAfter = IERC20(tokenAddress).balanceOf(address(this));
uint256 tokensBought = tokenBalanceAfter - tokenBalanceBefore;
// Validate we got at least minimum
require(tokensBought >= minAmountOut, "Slippage too high");
if (tokensBought > 0) {
// Burn tokens by sending to dead address
address deadAddress = 0x000000000000000000000000000000000000dEaD;
require(
IERC20(tokenAddress).transfer(deadAddress, tokensBought),
"Burn transfer failed"
);
uint256 gasUsed = gasStart - gasleft();
emit BuybackExecuted(ethBalance, tokensBought, gasUsed, attempt + 1, minAmountOut, deadline);
emit TokensBurned(tokensBought);
}
return;
} catch Error(string memory reason) {
// If not last attempt, continue to next iteration
if (attempt < MAX_RETRIES) {
continue;
}
// All retries failed
emit BuybackFailedAllRetries(ethBalance, attempt + 1);
return;
} catch (bytes memory) {
// Low-level error
if (attempt < MAX_RETRIES) {
continue;
}
emit BuybackFailedAllRetries(ethBalance, attempt + 1);
return;
}
}
}
/**
* @dev Manual retry with explicit parameters
*/
function retryBuyback(
uint256 minAmountOut,
uint256 customDeadlineSeconds
) external onlyOwner nonReentrant {
require(minAmountOut > 0, "Invalid minAmountOut");
require(customDeadlineSeconds >= 15 && customDeadlineSeconds <= 600, "Invalid deadline");
uint256 ethBalance = address(this).balance;
require(ethBalance > 0, "No ETH for buyback");
uint256 gasStart = gasleft();
require(gasStart >= buybackGasLimit, "Insufficient gas provided");
// Retry loop with explicit parameters
for (uint256 attempt = 0; attempt <= MAX_RETRIES; attempt++) {
// Fresh balance check
ethBalance = address(this).balance;
if (ethBalance == 0) return;
// Progressive slippage
uint256 currentSlippage = slippageTolerance + (attempt * slippageIncreasePerRetry);
if (currentSlippage > 50) currentSlippage = 50;
// Calculate min amount for this attempt (or use provided)
uint256 attemptMinAmount = (attempt == 0) ? minAmountOut : _calculateMinAmountOut(ethBalance, currentSlippage);
// Explicit deadline for this attempt
uint256 deadline = block.timestamp + customDeadlineSeconds;
uint256 tokenBalanceBefore = IERC20(tokenAddress).balanceOf(address(this));
try router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: ethBalance}(
attemptMinAmount,
swapPath,
address(this),
deadline
) {
uint256 tokenBalanceAfter = IERC20(tokenAddress).balanceOf(address(this));
uint256 tokensBought = tokenBalanceAfter - tokenBalanceBefore;
// Validate output
require(tokensBought >= attemptMinAmount, "Slippage too high");
if (tokensBought > 0) {
address deadAddress = 0x000000000000000000000000000000000000dEaD;
IERC20(tokenAddress).transfer(deadAddress, tokensBought);
emit BuybackExecuted(ethBalance, tokensBought, gasStart - gasleft(), attempt + 1, attemptMinAmount, deadline);
emit TokensBurned(tokensBought);
}
return;
} catch {
emit BuybackRetryAttempt(attempt + 1, ethBalance, currentSlippage, attemptMinAmount);
if (attempt == MAX_RETRIES) {
emit BuybackFailedAllRetries(ethBalance, attempt + 1);
revert("Manual retry failed after all attempts");
}
}
}
}
/**
* @dev Withdraw LP tokens with fresh balance
*/
function withdrawLPTokens(uint256 amount) external onlyOwner nonReentrant {
require(pairAddress != address(0), "No pair");
require(amount > 0, "Amount must be > 0");
uint256 actualBalance = _getLPBalance();
require(actualBalance >= amount, "Insufficient LP balance");
require(
IERC20(pairAddress).transfer(owner, amount),
"LP transfer failed"
);
emit LPTokensWithdrawn(amount, owner);
}
function withdrawAllLPTokens() external onlyOwner nonReentrant {
require(pairAddress != address(0), "No pair");
uint256 balance = _getLPBalance();
require(balance > 0, "No LP tokens");
require(
IERC20(pairAddress).transfer(owner, balance),
"LP transfer failed"
);
emit LPTokensWithdrawn(balance, owner);
}
function removeLiquidity(
uint256 lpAmount,
uint256 minToken,
uint256 minETH
) external onlyOwner nonReentrant returns (uint256 amountToken, uint256 amountETH) {
require(pairAddress != address(0), "No pair");
require(lpAmount > 0, "Amount must be > 0");
uint256 actualBalance = _getLPBalance();
require(actualBalance >= lpAmount, "Insufficient LP balance");
require(
IERC20(pairAddress).approve(address(router), lpAmount),
"LP approval failed"
);
(amountToken, amountETH) = router.removeLiquidityETH(
tokenAddress,
lpAmount,
minToken,
minETH,
owner,
block.timestamp + defaultDeadlineSeconds
);
emit LiquidityAdded(amountToken, amountETH, lpAmount);
}
function burnLPTokens(uint256 amount) external onlyOwner nonReentrant {
require(pairAddress != address(0), "No pair");
require(amount > 0, "Amount must be > 0");
uint256 actualBalance = _getLPBalance();
require(actualBalance >= amount, "Insufficient LP balance");
address deadAddress = 0x000000000000000000000000000000000000dEaD;
require(
IERC20(pairAddress).transfer(deadAddress, amount),
"Burn failed"
);
emit LPTokensBurned(amount);
}
function updateSlippageTolerance(uint256 _tolerance) external onlyOwner {
require(_tolerance <= 50, "Tolerance too high");
slippageTolerance = _tolerance;
emit SlippageToleranceUpdated(_tolerance);
}
function updateDeadline(uint256 _seconds) external onlyOwner {
require(_seconds >= 15, "Deadline too short");
require(_seconds <= 600, "Deadline too long");
defaultDeadlineSeconds = _seconds;
emit DeadlineUpdated(_seconds);
}
function updateRetryConfig(uint256 _slippageIncrease) external onlyOwner {
require(_slippageIncrease >= 1 && _slippageIncrease <= 10, "Invalid slippage increase");
slippageIncreasePerRetry = _slippageIncrease;
emit RetryConfigUpdated(_slippageIncrease);
}
function updateGasSettings(uint256 _minReserve, uint256 _gasLimit) external onlyOwner {
require(_minReserve >= 50000, "Reserve too low");
require(_gasLimit >= 200000, "Gas limit too low");
require(_gasLimit <= 500000, "Gas limit too high");
minGasReserve = _minReserve;
buybackGasLimit = _gasLimit;
emit GasSettingsUpdated(_minReserve, _gasLimit);
}
function estimateBuybackGas() external view returns (uint256 estimatedGas, bool hasEnoughGas) {
estimatedGas = buybackGasLimit;
hasEnoughGas = gasleft() >= estimatedGas;
return (estimatedGas, hasEnoughGas);
}
/**
* ✅ FIX #3: Improved ETH recovery using call instead of transfer
*/
function emergencyRecoverETH() external onlyOwner nonReentrant {
uint256 balance = address(this).balance;
require(balance > 0, "No ETH to recover");
// ✅ Use call for better compatibility
(bool success, ) = payable(owner).call{value: balance}("");
require(success, "ETH transfer failed");
emit EmergencyETHRecovered(balance, owner);
}
receive() external payable {}
function renounceOwnership() external onlyOwner {
owner = address(0);
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Invalid address");
owner = newOwner;
}
function getCurrentLPBalance() external view returns (uint256) {
return _getLPBalance();
}
function getRetryConfig() external view returns (
uint256 currentMaxRetries,
uint256 currentSlippageIncrease,
uint256 baseSlippage
) {
return (MAX_RETRIES, slippageIncreasePerRetry, slippageTolerance);
}
function getSwapPath() external view returns (address[] memory) {
return swapPath;
}
}
Token.sol 489 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title Token
*/
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function factory() external view returns (address);
}
interface IUniswapV2Factory {
function getPair(address tokenA, address tokenB) external view returns (address);
}
contract BuybackTokenSecured {
// Token details
string public name;
string public symbol;
uint8 public constant decimals = 18;
uint256 public totalSupply;
// Balances and allowances
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// Tax configuration
uint256 public buyTax = 4;
uint256 public sellTax = 4;
uint256 private constant TAX_DENOMINATOR = 100;
// Buyback configuration
uint256 public minBalanceForBuyback;
bool private inSwap;
// Gas management for buyback calls
uint256 public buybackGasLimit = 550000;
// Addresses
address public buybackManager;
address public pairAddress;
address public immutable WETH;
address public immutable factory;
address private immutable deployer;
// Exclusions
mapping(address => bool) public isExcludedFromFee;
// Trading control
bool public tradingEnabled;
// Reentrancy guard
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
// Events
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event TradingEnabled(uint256 timestamp);
event BuybackTriggered(uint256 tokensSwapped, bool success, uint256 gasUsed);
event TaxCollected(uint256 amount);
event BuybackGasLimitUpdated(uint256 newLimit);
event BuybackFailed(string reason, uint256 gasLeft);
event MinBalanceUpdated(uint256 newMinBalance);
event PairValidated(address indexed pair, address token0, address token1);
event ETHTransferFailed(uint256 amount, address recipient);
// Modifiers
modifier onlyManager() {
require(msg.sender == buybackManager, "Only manager");
_;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
constructor(
string memory _name,
string memory _symbol,
uint256 _totalSupply,
address _buybackManager,
address _weth,
address _factory
) {
require(_buybackManager != address(0), "Invalid manager");
require(_weth != address(0), "Invalid WETH");
require(_factory != address(0), "Invalid factory");
name = _name;
symbol = _symbol;
totalSupply = _totalSupply;
buybackManager = _buybackManager;
deployer = msg.sender;
WETH = _weth;
factory = _factory;
// Set minimal threshold (0.01% of supply)
minBalanceForBuyback = _totalSupply / 10000;
// Initialize reentrancy guard
_status = _NOT_ENTERED;
// Mint entire supply to buyback manager
_balances[_buybackManager] = _totalSupply;
// Exclude manager and token contract from fees
isExcludedFromFee[_buybackManager] = true;
isExcludedFromFee[address(this)] = true;
emit Transfer(address(0), _buybackManager, _totalSupply);
}
/**
* @dev Validate pair address during initialization
*/
function initialize(address _pair, address _manager) external {
require(msg.sender == buybackManager, "Only manager");
require(pairAddress == address(0), "Already initialized");
require(_pair != address(0), "Invalid pair address");
require(_manager != address(0), "Invalid manager address");
// Validate that _pair is a real Uniswap pair
_validatePairAddress(_pair);
pairAddress = _pair;
buybackManager = _manager;
isExcludedFromFee[_pair] = false;
}
/**
* @dev Validate pair is legitimate Uniswap pair
*/
function _validatePairAddress(address _pair) internal view {
IUniswapV2Pair pair = IUniswapV2Pair(_pair);
// Get tokens from pair
address token0;
address token1;
try pair.token0() returns (address _token0) {
token0 = _token0;
} catch {
revert("Invalid pair: token0 call failed");
}
try pair.token1() returns (address _token1) {
token1 = _token1;
} catch {
revert("Invalid pair: token1 call failed");
}
// Verify one of the tokens is this token
require(
token0 == address(this) || token1 == address(this),
"Pair does not contain this token"
);
// Verify the other token is WETH
require(
token0 == WETH || token1 == WETH,
"Pair does not contain WETH"
);
// Verify pair exists in factory
address expectedPair = IUniswapV2Factory(factory).getPair(address(this), WETH);
require(expectedPair == _pair, "Pair not registered in factory");
// Verify pair's factory matches
try pair.factory() returns (address pairFactory) {
require(pairFactory == factory, "Pair factory mismatch");
} catch {
revert("Invalid pair: factory call failed");
}
// emit PairValidated(_pair, token0, token1);
}
function enableTrading() external onlyManager {
require(!tradingEnabled, "Trading already enabled");
tradingEnabled = true;
emit TradingEnabled(block.timestamp);
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][msg.sender];
require(currentAllowance >= amount, "Transfer amount exceeds allowance");
unchecked {
_approve(sender, msg.sender, currentAllowance - amount);
}
return true;
}
/**
* ✅ FIX #1: Added trading enabled check
*/
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "Transfer from zero address");
require(recipient != address(0), "Transfer to zero address");
require(_balances[sender] >= amount, "Insufficient balance");
// ✅ FIX #1: CHECK TRADING ENABLED
// Allow transfers if:
// 1. Trading is enabled, OR
// 2. Sender is excluded (manager, token contract), OR
// 3. Recipient is excluded
require(
tradingEnabled ||
isExcludedFromFee[sender] ||
isExcludedFromFee[recipient],
"Trading not enabled yet"
);
// Check if we should trigger buyback
uint256 contractTokenBalance = _balances[address(this)];
bool canSwap = contractTokenBalance >= minBalanceForBuyback;
if (canSwap && !inSwap && sender != pairAddress) {
_triggerBuyback();
}
// Determine if we should take tax
bool takeFee = true;
if (isExcludedFromFee[sender] || isExcludedFromFee[recipient]) {
takeFee = false;
}
if (inSwap) {
takeFee = false;
}
// Calculate tax amount
uint256 taxAmount = 0;
if (takeFee) {
bool isBuy = sender == pairAddress;
bool isSell = recipient == pairAddress;
if (isBuy) {
taxAmount = (amount * buyTax) / TAX_DENOMINATOR;
} else if (isSell) {
taxAmount = (amount * sellTax) / TAX_DENOMINATOR;
}
if (taxAmount > 0) {
_balances[address(this)] += taxAmount;
emit Transfer(sender, address(this), taxAmount);
emit TaxCollected(taxAmount);
}
}
// Transfer remaining amount
uint256 amountAfterTax = amount - taxAmount;
_balances[sender] -= amount;
_balances[recipient] += amountAfterTax;
emit Transfer(sender, recipient, amountAfterTax);
}
function _triggerBuyback() internal nonReentrant {
uint256 contractTokenBalance = _balances[address(this)];
if (contractTokenBalance == 0) return;
// Set inSwap flag to prevent tax during buyback
inSwap = true;
uint256 gasBefore = gasleft();
// Cap at 1% of supply per swap
uint256 maxSwap = totalSupply / 100;
if (contractTokenBalance > maxSwap) {
contractTokenBalance = maxSwap;
}
// Update state BEFORE external calls
_balances[address(this)] -= contractTokenBalance;
_balances[buybackManager] += contractTokenBalance;
emit Transfer(address(this), buybackManager, contractTokenBalance);
uint256 ethBalance = address(this).balance;
if (ethBalance > 0) {
(bool ethSent,) = payable(buybackManager).call{value: ethBalance}("");
if (!ethSent) {
// Log but don't revert - ETH can be recovered later
emit ETHTransferFailed(ethBalance, buybackManager);
emit BuybackFailed("ETH transfer to manager failed", gasleft());
}
}
uint256 deadline = block.timestamp + 300; // 5 minute deadline
// Call manager to execute buyback with SUFFICIENT GAS and DEADLINE
try this.executeBuybackCall{gas: buybackGasLimit}(buybackManager, deadline) {
uint256 gasUsed = gasBefore - gasleft();
emit BuybackTriggered(contractTokenBalance, true, gasUsed);
} catch Error(string memory reason) {
uint256 gasLeft = gasleft();
emit BuybackFailed(reason, gasLeft);
emit BuybackTriggered(contractTokenBalance, false, 0);
} catch (bytes memory) {
uint256 gasLeft = gasleft();
emit BuybackFailed("Low-level error", gasLeft);
emit BuybackTriggered(contractTokenBalance, false, 0);
}
// Reset inSwap flag
inSwap = false;
}
/**
* @dev External function with deadline parameter
*/
function executeBuybackCall(address manager, uint256 deadline) external {
require(msg.sender == address(this), "Only self");
require(deadline >= block.timestamp, "Deadline expired");
(bool success, bytes memory returnData) = manager.call{
gas: buybackGasLimit
}(
abi.encodeWithSignature("executeBuybackAndBurn()")
);
require(success, _getRevertMsg(returnData));
}
/**
* @dev Extract revert message from return data
*/
function _getRevertMsg(bytes memory returnData) internal pure returns (string memory) {
if (returnData.length < 68) return "Transaction reverted silently";
assembly {
returnData := add(returnData, 0x04)
}
return abi.decode(returnData, (string));
}
/**
* @dev Manual trigger buyback - Can be called by manager
*/
function manualBuyback() external onlyManager {
require(!inSwap, "Already in swap");
require(_balances[address(this)] > 0, "No tokens to swap");
_triggerBuyback();
}
/**
* @dev Update gas limit for buyback calls
*/
function updateBuybackGasLimit(uint256 _gasLimit) external onlyManager {
require(_gasLimit >= 400000, "Gas limit too low");
require(_gasLimit <= 1000000, "Gas limit too high");
buybackGasLimit = _gasLimit;
emit BuybackGasLimitUpdated(_gasLimit);
}
/**
* @dev Update minimal balance threshold for buyback trigger
*/
function updateMinBalance(uint256 _minBalance) external onlyManager {
require(_minBalance <= totalSupply / 1000, "Min balance too high");
minBalanceForBuyback = _minBalance;
emit MinBalanceUpdated(_minBalance);
}
/**
* @dev Disable minimal balance check (trigger on ANY amount)
*/
function disableMinBalance() external onlyManager {
minBalanceForBuyback = 0;
emit MinBalanceUpdated(0);
}
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "Approve from zero address");
require(spender != address(0), "Approve to zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function excludeFromFees(address account, bool excluded) external onlyManager {
isExcludedFromFee[account] = excluded;
}
function updateTaxRates(uint256 _buyTax, uint256 _sellTax) external onlyManager {
require(_buyTax <= 10 && _sellTax <= 10, "Tax too high");
buyTax = _buyTax;
sellTax = _sellTax;
}
function renounceManager() external onlyManager {
buybackManager = address(0);
}
/**
* @dev Check remaining gas and estimate if buyback will succeed
*/
function estimateGasForBuyback() external view returns (bool sufficient, uint256 required, uint256 available) {
available = gasleft();
required = buybackGasLimit + 50000;
sufficient = available >= required;
}
/**
* @dev Get pair validation info
*/
function getPairInfo() external view returns (
address pair,
address token0,
address token1,
address pairFactory,
bool isValid
) {
if (pairAddress == address(0)) {
return (address(0), address(0), address(0), address(0), false);
}
IUniswapV2Pair pairContract = IUniswapV2Pair(pairAddress);
try pairContract.token0() returns (address _token0) {
token0 = _token0;
} catch {
return (pairAddress, address(0), address(0), address(0), false);
}
try pairContract.token1() returns (address _token1) {
token1 = _token1;
} catch {
return (pairAddress, token0, address(0), address(0), false);
}
try pairContract.factory() returns (address _factory) {
pairFactory = _factory;
} catch {
return (pairAddress, token0, token1, address(0), false);
}
// Validate
bool validTokens = (token0 == address(this) || token1 == address(this)) &&
(token0 == WETH || token1 == WETH);
bool validFactory = pairFactory == factory;
isValid = validTokens && validFactory;
return (pairAddress, token0, token1, pairFactory, isValid);
}
/**
* @dev Emergency ETH recovery (if ETH transfer fails during buyback)
*/
function emergencyRecoverETH() external onlyManager {
uint256 balance = address(this).balance;
require(balance > 0, "No ETH to recover");
(bool success, ) = payable(buybackManager).call{value: balance}("");
require(success, "ETH transfer failed");
}
receive() external payable {}
}
Read Contract
MAX_RETRIES 0x46ebbdb0 → uint256
buybackGasLimit 0xb7c6b7c8 → uint256
defaultDeadlineSeconds 0x4cdff2fe → uint256
estimateBuybackGas 0x4177b66f → uint256, bool
getCurrentLPBalance 0xccba2ddb → uint256
getRetryConfig 0x1b51fbb1 → uint256, uint256, uint256
getSwapPath 0x8ffb62d2 → address[]
isInitialized 0x392e53cd → bool
minGasReserve 0x9d159568 → uint256
owner 0x8da5cb5b → address
pairAddress 0xa8b08982 → address
router 0xf887ea40 → address
slippageIncreasePerRetry 0x1baaf4bd → uint256
slippageTolerance 0xd03153aa → uint256
swapPath 0x24cc0766 → address
tokenAddress 0x9d76ea58 → address
Write Contract 14 functions
These functions modify contract state and require a wallet transaction to execute.
burnLPTokens 0x0a0a4189
uint256 amount
deployTokenAndAddLiquidity 0x54f2679a
string name
string symbol
uint256 totalSupply
uint256 tokensForLP
bytes32 salt
emergencyRecoverETH 0x186e2d77
No parameters
executeBuybackAndBurn 0x4348b59b
No parameters
removeLiquidity 0x857620e1
uint256 lpAmount
uint256 minToken
uint256 minETH
returns: uint256, uint256
renounceOwnership 0x715018a6
No parameters
retryBuyback 0xefda182d
uint256 minAmountOut
uint256 customDeadlineSeconds
transferOwnership 0xf2fde38b
address newOwner
updateDeadline 0x42af1884
uint256 _seconds
updateGasSettings 0xc3ef17f3
uint256 _minReserve
uint256 _gasLimit
updateRetryConfig 0x5e3be34d
uint256 _slippageIncrease
updateSlippageTolerance 0x0f9da743
uint256 _tolerance
withdrawAllLPTokens 0x7fcd0e8d
No parameters
withdrawLPTokens 0x452d003f
uint256 amount
Recent Transactions
No transactions found for this address