{"abi":[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data1","type":"uint256"},{"indexed":true,"internalType":"bytes20","name":"btcAddr","type":"bytes20"},{"indexed":true,"internalType":"address","name":"claimToAddr","type":"address"},{"indexed":true,"internalType":"address","name":"referrerAddr","type":"address"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data2","type":"uint256"},{"indexed":true,"internalType":"address","name":"senderAddr","type":"address"}],"name":"ClaimAssist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":true,"internalType":"address","name":"updaterAddr","type":"address"}],"name":"DailyDataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":true,"internalType":"uint40","name":"stakeId","type":"uint40"}],"name":"ShareRateChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data1","type":"uint256"},{"indexed":true,"internalType":"address","name":"stakerAddr","type":"address"},{"indexed":true,"internalType":"uint40","name":"stakeId","type":"uint40"}],"name":"StakeEnd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"data1","type":"uint256"},{"indexed":true,"internalType":"address","name":"stakerAddr","type":"address"},{"indexed":true,"internalType":"uint40","name":"stakeId","type":"uint40"},{"indexed":true,"internalType":"address","name":"senderAddr","type":"address"}],"name":"StakeGoodAccounting","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":true,"internalType":"address","name":"stakerAddr","type":"address"},{"indexed":true,"internalType":"uint40","name":"stakeId","type":"uint40"}],"name":"StakeStart","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":true,"internalType":"address","name":"memberAddr","type":"address"},{"indexed":true,"internalType":"uint256","name":"entryId","type":"uint256"},{"indexed":true,"internalType":"address","name":"referrerAddr","type":"address"}],"name":"XfLobbyEnter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"data0","type":"uint256"},{"indexed":true,"internalType":"address","name":"memberAddr","type":"address"},{"indexed":true,"internalType":"uint256","name":"entryId","type":"uint256"},{"indexed":true,"internalType":"address","name":"referrerAddr","type":"address"}],"name":"XfLobbyExit","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"allocatedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"rawSatoshis","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"claimToAddr","type":"address"},{"internalType":"bytes32","name":"pubKeyX","type":"bytes32"},{"internalType":"bytes32","name":"pubKeyY","type":"bytes32"},{"internalType":"uint8","name":"claimFlags","type":"uint8"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"autoStakeDays","type":"uint256"},{"internalType":"address","name":"referrerAddr","type":"address"}],"name":"btcAddressClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"name":"btcAddressClaims","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes20","name":"btcAddr","type":"bytes20"},{"internalType":"uint256","name":"rawSatoshis","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"btcAddressIsClaimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes20","name":"btcAddr","type":"bytes20"},{"internalType":"uint256","name":"rawSatoshis","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"btcAddressIsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"claimToAddr","type":"address"},{"internalType":"bytes32","name":"claimParamHash","type":"bytes32"},{"internalType":"bytes32","name":"pubKeyX","type":"bytes32"},{"internalType":"bytes32","name":"pubKeyY","type":"bytes32"},{"internalType":"uint8","name":"claimFlags","type":"uint8"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"claimMessageMatchesSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"currentDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"dailyData","outputs":[{"internalType":"uint72","name":"dayPayoutTotal","type":"uint72"},{"internalType":"uint72","name":"dayStakeSharesTotal","type":"uint72"},{"internalType":"uint56","name":"dayUnclaimedSatoshisTotal","type":"uint56"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"beginDay","type":"uint256"},{"internalType":"uint256","name":"endDay","type":"uint256"}],"name":"dailyDataRange","outputs":[{"internalType":"uint256[]","name":"list","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"beforeDay","type":"uint256"}],"name":"dailyDataUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"globalInfo","outputs":[{"internalType":"uint256[13]","name":"","type":"uint256[13]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"globals","outputs":[{"internalType":"uint72","name":"lockedHeartsTotal","type":"uint72"},{"internalType":"uint72","name":"nextStakeSharesTotal","type":"uint72"},{"internalType":"uint40","name":"shareRate","type":"uint40"},{"internalType":"uint72","name":"stakePenaltyTotal","type":"uint72"},{"internalType":"uint16","name":"dailyDataCount","type":"uint16"},{"internalType":"uint72","name":"stakeSharesTotal","type":"uint72"},{"internalType":"uint40","name":"latestStakeId","type":"uint40"},{"internalType":"uint128","name":"claimStats","type":"uint128"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"merkleLeaf","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"merkleProofIsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"pubKeyX","type":"bytes32"},{"internalType":"bytes32","name":"pubKeyY","type":"bytes32"},{"internalType":"uint8","name":"claimFlags","type":"uint8"}],"name":"pubKeyToBtcAddress","outputs":[{"internalType":"bytes20","name":"","type":"bytes20"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"pubKeyX","type":"bytes32"},{"internalType":"bytes32","name":"pubKeyY","type":"bytes32"}],"name":"pubKeyToEthAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"stakerAddr","type":"address"}],"name":"stakeCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"stakeIndex","type":"uint256"},{"internalType":"uint40","name":"stakeIdParam","type":"uint40"}],"name":"stakeEnd","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"stakerAddr","type":"address"},{"internalType":"uint256","name":"stakeIndex","type":"uint256"},{"internalType":"uint40","name":"stakeIdParam","type":"uint40"}],"name":"stakeGoodAccounting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakeLists","outputs":[{"internalType":"uint40","name":"stakeId","type":"uint40"},{"internalType":"uint72","name":"stakedHearts","type":"uint72"},{"internalType":"uint72","name":"stakeShares","type":"uint72"},{"internalType":"uint16","name":"lockedDay","type":"uint16"},{"internalType":"uint16","name":"stakedDays","type":"uint16"},{"internalType":"uint16","name":"unlockedDay","type":"uint16"},{"internalType":"bool","name":"isAutoStake","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newStakedHearts","type":"uint256"},{"internalType":"uint256","name":"newStakedDays","type":"uint256"}],"name":"stakeStart","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"xfLobby","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"referrerAddr","type":"address"}],"name":"xfLobbyEnter","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"memberAddr","type":"address"},{"internalType":"uint256","name":"entryId","type":"uint256"}],"name":"xfLobbyEntry","outputs":[{"internalType":"uint256","name":"rawAmount","type":"uint256"},{"internalType":"address","name":"referrerAddr","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"enterDay","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"xfLobbyExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"xfLobbyFlush","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"xfLobbyMembers","outputs":[{"internalType":"uint40","name":"headIndex","type":"uint40"},{"internalType":"uint40","name":"tailIndex","type":"uint40"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"memberAddr","type":"address"}],"name":"xfLobbyPendingDays","outputs":[{"internalType":"uint256[2]","name":"words","type":"uint256[2]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"beginDay","type":"uint256"},{"internalType":"uint256","name":"endDay","type":"uint256"}],"name":"xfLobbyRange","outputs":[{"internalType":"uint256[]","name":"list","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"}],"additional_sources":[],"can_be_visualized_via_sol2uml":false,"compiler_settings":null,"compiler_version":"v0.5.13+commit.5b0b510c","constructor_args":null,"creation_bytecode":"0x60806040523480156200001157600080fd5b506003805464ffffffffff60901b1916740186a00000000000000000000000000000000000001790556004805461ffff191660011790556200005d60008066066c277de83e9c6200008d565b600480546001600160801b039283167001000000000000000000000000000000000292169190911790556200009e565b60669290921b60339190911b171790565b6151fd80620000ae6000396000f3fe6080604052600436106102305760003560e01c80636a210a0e1161012e578063a9059cbb116100ab578063d5a373ff1161006f578063d5a373ff14610bff578063dd62ed3e14610c64578063ec9a191714610c9f578063f04b5fa014610d30578063f57a1b3c14610d5b57610230565b8063a9059cbb14610a9b578063bd926ed314610ad4578063c312452514610b2e578063cbb151d314610ba9578063ce7d1f7714610bd957610230565b80638f1c65c0116100f25780638f1c65c01461091357806390de68711461093d57806395d89b411461023257806396f62b9d1461099a578063a457c2d714610a6257610230565b80636a210a0e1461077157806370a08231146107f15780637c4266201461082457806387a0f31c146108585780638e21aa011461088257610230565b806333060d90116101bc57806344f0de751161018057806344f0de751461066357806352a438b8146106d15780635ac1f357146107015780635c9302c91461071657806365cf71b21461072b57610230565b806333060d901461054e578063343009a21461058157806339509351146105b85780633a70a5ca146105f157806344203faf1461060657610230565b80632607443b116102035780632607443b1461037357806327aa6018146103ff578063283a5baf1461048157806330c1a785146104d7578063313ce5671461052357610230565b806306fdde0314610232578063095ea7b3146102bc57806318160ddd1461030957806323b872dd14610330575b005b34801561023e57600080fd5b50610247610d8b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610281578181015183820152602001610269565b50505050905090810190601f1680156102ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102c857600080fd5b506102f5600480360360408110156102df57600080fd5b506001600160a01b038135169060200135610daa565b604080519115158252519081900360200190f35b34801561031557600080fd5b5061031e610dc7565b60408051918252519081900360200190f35b34801561033c57600080fd5b506102f56004803603606081101561035357600080fd5b506001600160a01b03813581169160208101359091169060400135610dcd565b34801561037f57600080fd5b506103ac6004803603604081101561039657600080fd5b506001600160a01b038135169060200135610e5b565b6040805164ffffffffff90981688526001600160481b039687166020890152949095168685015261ffff928316606087015290821660808601521660a084015290151560c0830152519081900360e00190f35b34801561040b57600080fd5b506102f56004803603604081101561042257600080fd5b81359190810190604081016020820135600160201b81111561044357600080fd5b82018360208201111561045557600080fd5b803590602001918460208302840111600160201b8311171561047657600080fd5b509092509050610ed4565b34801561048d57600080fd5b506104ba600480360360608110156104a457600080fd5b508035906020810135906040013560ff16610f1b565b604080516001600160601b03199092168252519081900360200190f35b3480156104e357600080fd5b50610507600480360360408110156104fa57600080fd5b50803590602001356110d9565b604080516001600160a01b039092168252519081900360200190f35b34801561052f57600080fd5b50610538611105565b6040805160ff9092168252519081900360200190f35b34801561055a57600080fd5b5061031e6004803603602081101561057157600080fd5b50356001600160a01b031661110a565b34801561058d57600080fd5b50610230600480360360408110156105a457600080fd5b508035906020013564ffffffffff16611129565b3480156105c457600080fd5b506102f5600480360360408110156105db57600080fd5b506001600160a01b0381351690602001356113e7565b3480156105fd57600080fd5b5061031e61143b565b34801561061257600080fd5b5061063f6004803603604081101561062957600080fd5b50803590602001356001600160a01b0316611458565b6040805164ffffffffff938416815291909216602082015281519081900390910190f35b34801561066f57600080fd5b506106966004803603602081101561068657600080fd5b50356001600160a01b0316611487565b6040518082600260200280838360005b838110156106be5781810151838201526020016106a6565b5050505090500191505060405180910390f35b3480156106dd57600080fd5b50610230600480360360408110156106f457600080fd5b5080359060200135611521565b34801561070d57600080fd5b506102306115ab565b34801561072257600080fd5b5061031e611632565b34801561073757600080fd5b506102306004803603606081101561074e57600080fd5b5080356001600160a01b0316906020810135906040013564ffffffffff16611641565b34801561077d57600080fd5b506107a16004803603604081101561079457600080fd5b5080359060200135611895565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156107dd5781810151838201526020016107c5565b505050509050019250505060405180910390f35b3480156107fd57600080fd5b5061031e6004803603602081101561081457600080fd5b50356001600160a01b03166119b1565b34801561083057600080fd5b506102f56004803603602081101561084757600080fd5b50356001600160601b0319166119cc565b34801561086457600080fd5b5061031e6004803603602081101561087b57600080fd5b50356119e1565b34801561088e57600080fd5b506102f5600480360360608110156108a557600080fd5b6001600160601b031982351691602081013591810190606081016040820135600160201b8111156108d557600080fd5b8201836020820111156108e757600080fd5b803590602001918460208302840111600160201b8311171561090857600080fd5b5090925090506119f3565b34801561091f57600080fd5b506102306004803603602081101561093657600080fd5b5035611b0a565b34801561094957600080fd5b506109676004803603602081101561096057600080fd5b5035611bea565b604080516001600160481b03948516815292909316602083015266ffffffffffffff168183015290519081900360600190f35b3480156109a657600080fd5b5061031e60048036036101608110156109be57600080fd5b81359190810190604081016020820135600160201b8111156109df57600080fd5b8201836020820111156109f157600080fd5b803590602001918460208302840111600160201b83111715610a1257600080fd5b91935091506001600160a01b03813581169160208101359160408201359160ff606082013581169260808301359091169160a08101359160c08201359160e0810135916101009091013516611c23565b348015610a6e57600080fd5b506102f560048036036040811015610a8557600080fd5b506001600160a01b038135169060200135611eb3565b348015610aa757600080fd5b506102f560048036036040811015610abe57600080fd5b506001600160a01b038135169060200135611f21565b348015610ae057600080fd5b50610b0d60048036036040811015610af757600080fd5b506001600160a01b038135169060200135611f35565b604080519283526001600160a01b0390911660208301528051918290030190f35b348015610b3a57600080fd5b50610b43611ff1565b604080516001600160481b03998a168152978916602089015264ffffffffff96871688820152948816606088015261ffff9093166080870152951660a08501529390911660c08301526001600160801b0390921660e08201529051908190036101000190f35b348015610bb557600080fd5b5061023060048036036040811015610bcc57600080fd5b5080359060200135612055565b61023060048036036020811015610bef57600080fd5b50356001600160a01b03166122d2565b348015610c0b57600080fd5b506102f56004803603610100811015610c2357600080fd5b506001600160a01b038135169060208101359060408101359060608101359060ff608082013581169160a08101359091169060c08101359060e00135612443565b348015610c7057600080fd5b5061031e60048036036040811015610c8757600080fd5b506001600160a01b038135811691602001351661254f565b348015610cab57600080fd5b506102f560048036036060811015610cc257600080fd5b6001600160601b031982351691602081013591810190606081016040820135600160201b811115610cf257600080fd5b820183602082011115610d0457600080fd5b803590602001918460208302840111600160201b83111715610d2557600080fd5b50909250905061257a565b348015610d3c57600080fd5b50610d456125c3565b6040518151815280826101a080838360206106a6565b348015610d6757600080fd5b506107a160048036036040811015610d7e57600080fd5b50803590602001356126c4565b604051806040016040528060038152602001620908ab60eb1b81525081565b6000610dbe610db76127a2565b84846127a6565b50600192915050565b60025490565b6000610dda848484612892565b610e5084610de66127a2565b610e4b856040518060600160405280602881526020016150a2602891396001600160a01b038a16600090815260016020526040812090610e246127a2565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6129ee16565b6127a6565b5060015b9392505050565b60076020528160005260406000208181548110610e7457fe5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b9091041687565b6000610f1384848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a8592505050565b949350505050565b600080606060028416158015906004861615159060088716151590610fe657818015610f445750805b15610f90576040805162461bcd60e51b81526020600482015260176024820152761211560e8818db185a5b519b1859dcc81a5b9d985b1a59604a1b604482015290519081900360640190fd5b600160f81b60f889901b1615610fa7576003610faa565b60025b604080516001600160f81b031960f884901b16602082015260218082018d90528251808303909101815260419091019091529095509350611073565b81158015610ff2575080155b61103d576040805162461bcd60e51b81526020600482015260176024820152761211560e8818db185a5b519b1859dcc81a5b9d985b1a59604a1b604482015290519081900360640190fd5b60408051600160fa1b6020820152602181018b905260418082018b90528251808303909101815260619091019091526004955093505b600061107e85612ab2565b905082156110cc5760408051600560f21b60208201526001600160601b0319831660228201528151601681830301815260369091019091526110bf90612ab2565b9650505050505050610e54565b9998505050505050505050565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b600881565b6001600160a01b0381166000908152600760205260409020545b919050565b611131614e43565b611139614e43565b6111438282612bd7565b336000908152600760205260409020805461119d576040805162461bcd60e51b81526020600482015260156024820152741211560e88115b5c1d1e481cdd185ad9481b1a5cdd605a1b604482015290519081900360640190fd5b805485106111ec576040805162461bcd60e51b81526020600482015260176024820152761211560e881cdd185ad9525b99195e081a5b9d985b1a59604a1b604482015290519081900360640190fd5b6111f4614ea4565b61121482878154811061120357fe5b906000526020600020018683612c89565b61121d84612d5c565b60a081015160608201516101408601516000921515918391829182918291116112fd57841561125257866080015195506112e3565b61125c8a88612d6d565b86606001518a6101400151039550866080015186111561128257866080015195506112e3565b61015e8610156112e3578660c00151156112e3576040805162461bcd60e51b815260206004820152601c60248201527f4845583a204175746f2d7374616b65207374696c6c206c6f636b656400000000604482015290519081900360640190fd5b6112ee8a8888612d8c565b9296509094509250905061136d565b8660c0015115611354576040805162461bcd60e51b815260206004820152601c60248201527f4845583a204175746f2d7374616b65207374696c6c206c6f636b656400000000604482015290519081900360640190fd5b60408701516020808c0180519290920390915287015193505b6113848b8860200151896040015186868b8b612e30565b8015801590611391575084155b156113a0576113a08a82612eed565b83156113bb576113b03385612f28565b6113bb8a8886613018565b60208701518a51038a526113cf888d613084565b6113d98a8a6131e2565b505050505050505050505050565b6000610dbe6113f46127a2565b84610e4b85600160006114056127a2565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6133d516565b6003546000906001600160481b0316611452610dc7565b01905090565b600960209081526000928352604080842090915290825290205464ffffffffff80821691600160281b90041682565b61148f614eea565b600061149961342f565b600101905061015f8111156114ad575061015f5b6000198101901561151b5760008181526009602090815260408083206001600160a01b038716845290915290205464ffffffffff808216600160281b90920416111561151657600160ff82161b82600883901c6002811061150a57fe5b60200201805190911790525b6114ad565b50919050565b611529614e43565b611531614e43565b61153b8282612bd7565b600183101561157b5760405162461bcd60e51b815260040180806020018281038252602581526020018061517f6025913960400191505060405180910390fd5b61158482612d5c565b611591828585600061343f565b61159b3385613560565b6115a582826131e2565b50505050565b30316115ee576040805162461bcd60e51b815260206004820152600d60248201526c4845583a204e6f2076616c756560981b604482015290519081900360640190fd5b60405173dec9f2793e3c17cd26eefb21c4762fa5128e039990303180156108fc02916000818181858888f1935050505015801561162f573d6000803e3d6000fd5b50565b600061163c61342f565b905090565b611649614e43565b611651614e43565b61165b8282612bd7565b6001600160a01b0385166000908152600760205260409020546116bd576040805162461bcd60e51b81526020600482015260156024820152741211560e88115b5c1d1e481cdd185ad9481b1a5cdd605a1b604482015290519081900360640190fd5b6001600160a01b0385166000908152600760205260409020548410611723576040805162461bcd60e51b81526020600482015260176024820152761211560e881cdd185ad9525b99195e081a5b9d985b1a59604a1b604482015290519081900360640190fd5b6001600160a01b038516600090815260076020526040812080548690811061174757fe5b90600052602060002001905061175b614ea4565b611766828683612c89565b806080015181606001510184610140015110156117ca576040805162461bcd60e51b815260206004820152601b60248201527f4845583a205374616b65206e6f742066756c6c79207365727665640000000000604482015290519081900360640190fd5b60a081015115611821576040805162461bcd60e51b815260206004820152601b60248201527f4845583a205374616b6520616c726561647920756e6c6f636b65640000000000604482015290519081900360640190fd5b61182a84612d5c565b6118348482612d6d565b600080600061184887858660800151612d8c565b935093509350506118658a8986602001518760400151878761365c565b8015611875576118758782612eed565b61187f85856136f9565b61188987876131e2565b50505050505050505050565b606081831080156118ac575060045461ffff168211155b6118f2576040805162461bcd60e51b81526020600482015260126024820152711211560e881c985b99d9481a5b9d985b1a5960721b604482015290519081900360640190fd5b82820360405190808252806020026020018201604052801561191e578160200160208202803883390190505b509050826000805b5060008281526006602052604090205483516001830192600160901b830460901b66ffffffffffffff60901b16600160481b840460481b71ffffffffffffffffff00000000000000000016176001600160481b0390931692909217918291869190811061198f57fe5b6020026020010181815250508483600101935083106119265750505092915050565b6001600160a01b031660009081526020819052604090205490565b60056020526000908152604090205460ff1681565b60086020526000908152604090205481565b6000806119fe61342f565b90506001811015611a405760405162461bcd60e51b8152600401808060200182810382526024815260200180614fd66024913960400191505060405180910390fd5b61015f8110611a96576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20436c61696d2070686173652068617320656e646564000000000000604482015290519081900360640190fd5b6001600160601b0319861660009081526005602052604090205460ff1615611ac2576000915050610f13565b611b0086868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b9695505050505050565b611b12614e43565b611b1a614e43565b611b248282612bd7565b600182610140015111611b6f576040805162461bcd60e51b815260206004820152600e60248201526d4845583a20546f6f206561726c7960901b604482015290519081900360640190fd5b8215611bca57816101400151831115611bb95760405162461bcd60e51b8152600401808060200182810382526026815260200180614f6c6026913960400191505060405180910390fd5b611bc5828460006138e1565b611bdb565b611bdb8283610140015160006138e1565b611be582826131e2565b505050565b6006602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b600065173cdf6f6e318d1115611c78576040805162461bcd60e51b81526020600482015260156024820152744845583a2043484b3a207261775361746f7368697360581b604482015290519081900360640190fd5b61015e831015611cb95760405162461bcd60e51b81526004018080602001828103825260258152602001806151116025913960400191505060405180910390fd5b60006001600160a01b038b163314611d2b5750604080517f4e831acb4223b66de3b3d2e54a2edeefb0de3d7916e2886a4b134d9764d41bec602080830191909152818301869052606085811b6001600160601b0319169083015282518083036054018152607490920190925280519101205b611d3b8b828c8c8c8c8c8c612443565b611d8c576040805162461bcd60e51b815260206004820152601760248201527f4845583a205369676e6174757265206d69736d61746368000000000000000000604482015290519081900360640190fd5b506000611d9a8a8a8a610f1b565b6001600160601b0319811660009081526005602052604090205490915060ff1615611df65760405162461bcd60e51b815260040180806020018281038252602881526020018061507a6028913960400191505060405180910390fd5b611e34818f8f8f808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b611e6f5760405162461bcd60e51b81526004018080602001828103825260238152602001806150576023913960400191505060405180910390fd5b6001600160601b031981166000908152600560205260409020805460ff19166001179055611ea18e8c838b8888613993565b9e9d5050505050505050505050505050565b6000610dbe611ec06127a2565b84610e4b856040518060600160405280602581526020016151a46025913960016000611eea6127a2565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6129ee16565b6000610dbe611f2e6127a2565b8484612892565b602881901c60008181526009602090815260408083206001600160a01b0387168452825280832064ffffffffff861680855260019091019092528220805492938493909291906001600160601b0316611fca576040805162461bcd60e51b81526020600482015260126024820152711211560e8814185c985b481a5b9d985b1a5960721b604482015290519081900360640190fd5b546001600160601b03811697600160601b9091046001600160a01b03169650945050505050565b6003546004546001600160481b0380831692600160481b810482169264ffffffffff600160901b8304811693600160b81b90930483169261ffff83169262010000810490911691600160581b820416906001600160801b03600160801b9091041688565b61205d61342f565b82106120b0576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20526f756e64206973206e6f7420636f6d706c657465000000000000604482015290519081900360640190fd5b600082815260096020908152604080832033845290915281208054909164ffffffffff909116908315612142578254600160281b900464ffffffffff16829003841115612139576040805162461bcd60e51b81526020600482015260126024820152711211560e8818dbdd5b9d081a5b9d985b1a5960721b604482015290519081900360640190fd5b5080830161219c565b508154600160281b900464ffffffffff1680821061219c576040805162461bcd60e51b81526020600482015260126024820152711211560e8818dbdd5b9d081a5b9d985b1a5960721b604482015290519081900360640190fd5b60006121a7866139d6565b600087815260086020526040812054919250805b600086815260018801602052604081208054908290556001600160601b03811691600160601b9091046001600160a01b03169085878402816121f957fe5b0490506001600160a01b03821661221b576122168c8a8385613a4e565b61226a565b600a81049081019060058204336001600160a01b038516141561224d57918201916122488e8c8587613a4e565b612263565b6122598e8c8587613a4e565b6122638482612f28565b0193909301925b600190980197939093019250508486106121bb57865464ffffffffff191664ffffffffff871617875580156122b7576122b7739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b81156122c7576122c73383612f28565b505050505050505050565b60006122dc61342f565b905061015f8110612334576040805162461bcd60e51b815260206004820152601760248201527f4845583a204c6f6262696573206861766520656e646564000000000000000000604482015290519081900360640190fd5b348061237e576040805162461bcd60e51b81526020600482015260146024820152731211560e88105b5bdd5b9d081c995c5d5a5c995960621b604482015290519081900360640190fd5b600082815260096020908152604080832033845282528083208054600164ffffffffff600160281b80840482168381019092160269ffffffffff000000000019909316929092178355835180850185526001600160601b0380891682526001600160a01b038b8116838901908152858a529386018852868920925183549451909116600160601b029082166001600160601b031990941693909317169190911790558685526008909352922080548401905561243c84828588613abc565b5050505050565b6000601b8460ff161015801561245d5750601e8460ff1611155b61249f576040805162461bcd60e51b815260206004820152600e60248201526d1211560e881d881a5b9d985b1a5960921b604482015290519081900360640190fd5b60006124ab88886110d9565b905060006124c26124bd8c8c8a613b2a565b613e66565b9050816001600160a01b031660018288888860405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561252b573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149250505098975050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60006125ba85858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b95945050505050565b6125cb614f08565b600454600090819081906125ee90600160801b90046001600160801b0316613f97565b604080516101a0810182526003546001600160481b038082168352600160481b82048116602084015264ffffffffff600160901b8304811694840194909452600160b81b9091048116606083015260045461ffff8116608084015262010000810490911660a0830152600160581b900490911660c082015260e08101829052610100810183905261012081018490524261014082015292955090935091506101608101612699610dc7565b8152602001600860006126aa61342f565b815260200190815260200160002054815250935050505090565b606081831080156126d7575061015f8211155b80156126ea57506126e661342f565b8211155b612730576040805162461bcd60e51b81526020600482015260126024820152714845583a20696e76616c69642072616e676560701b604482015290519081900360640190fd5b82820360405190808252806020026020018201604052801561275c578160200160208202803883390190505b5090508260005b60008281526008602052604090205483516001938401938301928591811061278757fe5b60200260200101818152505083821061276357505092915050565b3390565b6001600160a01b0383166127eb5760405162461bcd60e51b815260040180806020018281038252602481526020018061515b6024913960400191505060405180910390fd5b6001600160a01b0382166128305760405162461bcd60e51b8152600401808060200182810382526022815260200180614fb46022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166128d75760405162461bcd60e51b81526004018080602001828103825260258152602001806151366025913960400191505060405180910390fd5b6001600160a01b03821661291c5760405162461bcd60e51b8152600401808060200182810382526023815260200180614f496023913960400191505060405180910390fd5b61295f81604051806060016040528060268152602001615031602691396001600160a01b038616600090815260208190526040902054919063ffffffff6129ee16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612994908263ffffffff6133d516565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115612a7d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612a42578181015183820152602001612a2a565b50505050905090810190601f168015612a6f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000610e54827f4e831acb4223b66de3b3d2e54a2edeefb0de3d7916e2886a4b134d9764d41bec85613fb7565b600060036002836040518082805190602001908083835b60208310612ae85780518252601f199092019160209182019101612ac9565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015612b27573d6000803e3d6000fd5b5050506040513d6020811015612b3c57600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b60208310612b885780518252601f199092019160209182019101612b69565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015612bc7573d6000803e3d6000fd5b50506040515160601b9392505050565b6003546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260045461ffff8116608086015262010000810490911660a0850152600160581b810490911660c0840152612c5c906001600160801b03600160801b90910416613f97565b60e0850152610100840152610120830152612c7561342f565b610140830152612c858282614061565b5050565b825464ffffffffff838116911614612ce8576040805162461bcd60e51b815260206004820152601e60248201527f4845583a207374616b654964506172616d206e6f7420696e207374616b650000604482015290519081900360640190fd5b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b82041660a084015260ff600160e81b90910416151560c09092019190915250565b61162f8182610140015160016138e1565b604081015160a080840180519290920390915261014090920151910152565b6000806000808560800151851015612dca57612db78787606001518860800151888a604001516140c9565b6020880151820195509093509150612e08565b60408601516060870151612de2918991888101614172565b9250828660200151019350612e05866060015187608001518860a0015187614240565b91505b8115612e275783821115612e1f5750600092612e27565b509182900391805b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff1617171784612ea4576000612eaa565b600160581b5b6001600160601b031660488761ffff16901b886001600160481b03161717604051808381526020018281526020019250505060405180910390a350505050505050565b600281048015612f1557612f15739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b6060909201805192909103919091019052565b6001600160a01b038216612f83576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600254612f96908263ffffffff6133d516565b6002556001600160a01b038216600090815260208190526040902054612fc2908263ffffffff6133d516565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b8160200151811115611be557600061303482846080015161426c565b905060008360400151620186a0838501028161304c57fe5b04905064ffffffffff811115613064575064ffffffffff5b846040015181111561243c5760408501819052835161243c9082906142de565b8154600019018181146131b15782818154811061309d57fe5b906000526020600020018383815481106130b357fe5b6000918252602090912082549101805464ffffffffff90921664ffffffffff199092169190911780825582546dffffffffffffffffff000000000019909116600160281b918290046001600160481b0390811690920217808355835468ffffffffffffffffff60701b19909116600160701b918290049092160217808255825461ffff60b81b19909116600160b81b9182900461ffff90811690920217808355835461ffff60c81b19909116600160c81b91829004831690910217808355835461ffff60d81b19909116600160d81b918290049092160217808255915460ff60e81b19909216600160e81b9283900460ff1615159092029190911790555b828054806131bb57fe5b600082815260209020810160001990810180546001600160f01b0319169055019055505050565b805182511415806131fb57508060200151826020015114155b8061320e57508060400151826040015114155b8061322157508060600151826060015114155b156132af5781516003805460208501516040860151606087015168ffffffffffffffffff199093166001600160481b039586161768ffffffffffffffffff60481b1916600160481b928616929092029190911764ffffffffff60901b1916600160901b64ffffffffff90921691909102176001600160b81b0316600160b81b93909116929092029190911790555b806080015182608001511415806132ce57508060a001518260a0015114155b806132ef57508060c0015164ffffffffff168260c0015164ffffffffff1614155b8061330257508060e001518260e0015114155b80613317575080610100015182610100015114155b8061332c575080610120015182610120015114155b15612c855760808201516004805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffff00001961ffff90961661ffff199094169390931794909416919091171691909117905561012082015161010083015160e08401516133b4929190614335565b600480546001600160801b03928316600160801b0292169190911790555050565b600082820183811015610e54576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6201518042635de5a57f19010490565b6115b38211156134805760405162461bcd60e51b81526004018080602001828103825260268152602001806150ca6026913960400191505060405180910390fd5b600061348c848461426c565b905060008560400151620186a083870102816134a457fe5b049050806134e35760405162461bcd60e51b8152600401808060200182810382526037815260200180614ffa6037913960400191505060405180910390fd5b600060018761014001511061350057866101400151600101613503565b60025b60c08801805160010164ffffffffff16908190523360009081526007602052604090209192509061353990828986868b8b614346565b6135468188858989614474565b505060208601805190910190525050825190910190915250565b6001600160a01b0382166135a55760405162461bcd60e51b81526004018080602001828103825260218152602001806150f06021913960400191505060405180910390fd5b6135e881604051806060016040528060228152602001614f92602291396001600160a01b038516600090815260208190526040902054919063ffffffff6129ee16565b6001600160a01b038316600090815260208190526040902055600254613614908263ffffffff61450616565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b038416602083015282513393918916926001600160a01b038b16927fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b4692918290030190a4505050505050565b80518254602083015160408401516060850151608086015160a087015160c09097015164ffffffffff1990951664ffffffffff909616959095176dffffffffffffffffff00000000001916600160281b6001600160481b03948516021768ffffffffffffffffff60701b1916600160701b93909216929092021761ffff60b81b1916600160b81b61ffff928316021761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b92909316919091029190911760ff60e81b1916600160e81b91151591909102179055565b80516000906bffffffffffffe0000000000090839083906137ee57fe5b602002602001015160001c16600014613843576040805162461bcd60e51b81526020600482015260126024820152711211560e881c1c9bdbd9881a5b9d985b1a5960721b604482015290519081900360640190fd5b60015b82518110156138c95782516bffffffffffffe000000000009084908390811061386b57fe5b602002602001015160001c16600014156138c1576040805162461bcd60e51b81526020600482015260126024820152711211560e881c1c9bdbd9881a5b9d985b1a5960721b604482015290519081900360640190fd5b600101613846565b506001600160601b0319841683176125ba8184612a85565b818360800151106138f157611be5565b6138f9614f27565b8351613903610dc7565b0181526080840151613916858383614548565b6020850151156139365760208501805160a0870180519091019052600090525b600101838110156139515761394c858383614548565b613936565b613960856080015182856145d3565b6080850181905260208201511561243c5761243c739a6a414d6f3497c05e3b1de90520765fa1e07c038360200151612f28565b600061399d614e43565b6139a5614e43565b6139af8282612bd7565b6139be828a8a8a8a8a8a61464a565b92506139ca82826131e2565b50509695505050505050565b600060018210613a3f576139e8614e43565b6139f0614e43565b6139fa8282612bd7565b613a0382612d5c565b600084815260066020526040902054600160901b900466ffffffffffffff1661015e6127108202049350613a3783836131e2565b505050611124565b5067016345785d8a0000919050565b806001600160a01b031683602886901b17336001600160a01b03167fa6b19fa7f41317a186e1d58e9d81f86a52f1102b6bce10b4eca83f37aaa584686028866001600160481b0316901b4264ffffffffff16176040518082815260200191505060405180910390a450505050565b806001600160a01b031683602886901b17336001600160a01b03167f25ecdb937d5c5cc78f0d18dfb1ac82c44086b5dc608380ba357d06c9868f0b1d6028866001600160601b0316901b4264ffffffffff16176040518082815260200191505060405180910390a450505050565b60608060018316613b62576040518060400160405280600f81526020016e086d8c2d2dabe908ab0bee8debe60f608b1b815250613b92565b60405180604001604052806016815260200175086d8c2d2dabe84d2e8c6ded2dc908ab0bee8debe60f60531b8152505b905060108316156060613ba587836147b5565b905085613cca576018772134ba31b7b4b71029b4b3b732b21026b2b9b9b0b3b29d0560411b60146002028551018584604051602001808660ff1660ff1660f81b81526001018567ffffffffffffffff191667ffffffffffffffff191681526018018460ff1660ff1660f81b815260010183805190602001908083835b60208310613c405780518252601f199092019160209182019101613c21565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310613c885780518252601f199092019160209182019101613c69565b6001836020036101000a038019825116818451168082178552505050505050905001955050505050506040516020818303038152906040529350505050610e54565b604080516018808252818301909252606091602082018180388339019050509050613cf78188600c614858565b8351604051600360fb1b6020808301918252772134ba31b7b4b71029b4b3b732b21026b2b9b9b0b3b29d0560411b60218401819052604190940160f881901b6001600160f81b031916603985015288516018959491938a9389938993603a909101918601908083835b60208310613d7f5780518252601f199092019160209182019101613d60565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b60208310613dc75780518252601f199092019160209182019101613da8565b6001836020036101000a03801982511681845116808217855250505050505090500180605f60f81b81525060010182805190602001908083835b60208310613e205780518252601f199092019160209182019101613e01565b6001836020036101000a03801982511681845116808217855250505050505090500196505050505050506040516020818303038152906040529450505050509392505050565b6000600280836040518082805190602001908083835b60208310613e9b5780518252601f199092019160209182019101613e7c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015613eda573d6000803e3d6000fd5b5050506040513d6020811015613eef57600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b60208310613f3b5780518252601f199092019160209182019101613f1c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015613f7a573d6000803e3d6000fd5b5050506040513d6020811015613f8f57600080fd5b505192915050565b606681901c6303ffffff16916607ffffffffffff603383901c8116921690565b600081815b8551811015614056576000868281518110613fd357fe5b602002602001015190508083101561401b578281604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120925061404d565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b50600101613fbc565b509092149392505050565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c08083015164ffffffffff169082015260e08083015190820152610100808301519082015261012091820151910152565b60008083860160026001870104605a8110156140e35750605a5b856141035760006140f58a878b614920565b919091029250614168915050565b858110156141385787810161411a8a878b84614172565b9350600061412a8b888487614172565b850195506141689350505050565b61414489868a85614172565b93508581141561415657839250614165565b858185028161416157fe5b0492505b50505b9550959350505050565b6000825b828110156141b7576000818152600660205260409020546001600160481b03600160481b8204811691168602816141a957fe5b049190910190600101614176565b5061016083118015906141cb575061016082115b15610f1357610160600090815260066020527f5bc747bd71b549e015c2e31a0d21c276f82136338c6c7203a3f9911f7240314a54600160481b90046001600160481b0316856127106305f5e1008004028860e0015102028161422957fe5b04905061423686826149b3565b0101949350505050565b6000848401600e01808411614259576000915050610f13565b6102bc8185038402049695505050505050565b600080600183111561429257610e3883111561428a57610e3861428f565b600183035b90505b600066354a6ba7a180008511156142b05766354a6ba7a180006142b2565b845b670214e8348c4f0000830261071c82020193509050680ecca2d59581a400008584020495945050505050565b8064ffffffffff167f9861fa0ed101659f7a59b4583fcc798dfa4f3b419bea371c8ee2ad0ffe13a31e60288464ffffffffff16901b4264ffffffffff16176040518082815260200191505060405180910390a25050565b60669290921b60339190911b171790565b6040805160e08101825264ffffffffff97881681526001600160481b03968716602080830191825296881692820192835261ffff9586166060830190815294861660808301908152600060a0840181815295151560c085019081528c54600181018e559c8252989020925192909a0180549151935195519a519451975164ffffffffff1990921692909916919091176dffffffffffffffffff00000000001916600160281b928816929092029190911768ffffffffffffffffff60701b1916600160701b93909616929092029490941761ffff60b81b1916600160b81b968316969096029590951761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b91909216021760ff60e81b1916600160e81b92151592909202919091179055565b64ffffffffff8516337f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef836144aa5760006144b0565b600160c81b5b6001600160d01b031660b88661ffff16901b6070886001600160481b0316901b60288a6001600160481b0316901b4264ffffffffff16171717176040518082815260200191505060405180910390a35050505050565b6000610e5483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129ee565b6145538383836149f3565b60409182015160009182526006602052919020805460a084015160e09094015168ffffffffffffffffff199091166001600160481b039384161768ffffffffffffffffff60481b1916600160481b93909416929092029290921766ffffffffffffff60901b1916600160901b66ffffffffffffff90921691909102179055565b337fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc94482614601576000614607565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff161717176040518082815260200191505060405180910390a2505050565b6000600188610140015110156146915760405162461bcd60e51b8152600401808060200182810382526024815260200180614fd66024913960400191505060405180910390fd5b61014088015161015f116146ec576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20436c61696d2070686173652068617320656e646564000000000000604482015290519081900360640190fd5b6146f588612d5c565b6301ab362e88610120015110614752576040805162461bcd60e51b815260206004820152601e60248201527f4845583a2043484b3a205f636c61696d656442746341646472436f756e740000604482015290519081900360640190fd5b60008060006147618b8b614a8d565b6101208e0180516001019052919450925090506147848989898d8787878c614b47565b93506064605a85020461479a8c8289600161343f565b6147a68a828703612f28565b50505050979650505050505050565b60408051602880825260608281019093526020820181803883390190505090506147ef816001600160601b0319606086901b166014614858565b811561485257805160208201206000805b601481101561484e57600083826020811061481757fe5b600185019491901a9150614831908690600484901c614bf4565b614845858480600101955083600f16614bf4565b50600101614800565b5050505b92915050565b6000805b8281101561243c57600084826020811061487257fe5b1a90506f181899199a1a9b1b9c1cb0b131b232b360811b600482901c60ff166010811061489b57fe5b1a60f81b8684806001019550815181106148b157fe5b60200101906001600160f81b031916908160001a9053506f181899199a1a9b1b9c1cb0b131b232b360811b600f8216601081106148ea57fe5b1a60f81b86848060010195508151811061490057fe5b60200101906001600160f81b031916908160001a9053505060010161485c565b600061492a614e43565b6149348582614061565b61493c614f27565b8551614946610dc7565b0181526149548282866149f3565b60a082018051860190819052604082015186028161496e57fe5b0492506101608414156149aa5760a082015160e0830151600091908702612710028161499657fe5b0490506149a383826149b3565b0192909201915b50509392505050565b6000806301ab362e8461012001518402816149ca57fe5b049050600066033bb85fc52d998561010001518502816149e657fe5b0491909101949350505050565b81516305fcbae3906127100204604083015261015f811015614a695760e083015160009061015e90612710020490506000614a3485838660400151016149b3565b60208501805191840191820190528451810185526040850151909150614a5b9086906149b3565b604085018051909101905250505b606083015115611be557606083018051604084018051909101905260009052505050565b6000806000614a9b84614c60565b925066033bb85fc52d9983866101000151011115614b00576040805162461bcd60e51b815260206004820152601f60248201527f4845583a2043484b3a205f636c61696d65645361746f73686973546f74616c00604482015290519081900360640190fd5b610100850180518401905261014085015161015f03614b1f8482614cac565b60e0870180518290039052935061271084029250614b3d8382614cbd565b9150509250925092565b828201826001600160a01b038316614b6d57614b688a8a8a8a8a8789614cce565b614bc9565b600a8204918201916005830480820192909201916001600160a01b03858116908d161415614bad5792830192614ba88c8c8c8c8c898b614cce565b614bc6565b614bbc8c8c8c8c8c898b614cce565b614bc68582612f28565b50505b614be7739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b5098975050505050505050565b6000838381518110614c0257fe5b01602001516001600160f81b0319169050606160f81b8110801590614c2b575060088260ff1610155b156115a55780602060f81b18848481518110614c4357fe5b60200101906001600160f81b031916908160001a90535050505050565b600064174876e800821015614c76575080611124565b64e8d4a510008210614c8c575060048104611124565b65034630b8a000826501ba60d3380003830281614ca557fe5b0492915050565b600061015e8383025b049392505050565b60006106d160001983018402614cb5565b6040805164ffffffffff42166bffffffffffffff0000000000602888901b161766ffffffffffffff60601b606087901b161760ff60981b609889901b161768ffffffffffffffffff60a01b60a086901b1617815233602082015281516001600160a01b0380851693908b16926001600160601b03198b16927f41e3c7dc6eebc97a48a437ff2afdc629613f12c48ba37a2c94563f80acba9725929181900390910190a46001600160a01b038716331415614d8757614e3a565b336001600160a01b03167f3a84b2d9dac24683628d63034c6949797f15fab735e16232518ee4e753fd49b760c88666ffffffffffffff16901b60288960601c6001600160a01b0316901b4264ffffffffff16171760d88860ff16901b60388b6001600160a01b0316901b8766ffffffffffffff1617176048856001600160a01b0316901b866001600160481b03161760405180848152602001838152602001828152602001935050505060405180910390a25b50505050505050565b604051806101600160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6040518060e00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b60405180604001604052806002906020820280388339509192915050565b604051806101a00160405280600d906020820280388339509192915050565b6040518060600160405280600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573734845583a206265666f72654461792063616e6e6f7420626520696e207468652066757475726545524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f20616464726573734845583a20436c61696d20706861736520686173206e6f742079657420737461727465644845583a206e65775374616b6564486561727473206d757374206265206174206c65617374206d696e696d756d2073686172655261746545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654845583a204254432061646472657373206f722062616c616e636520756e6b6e6f776e4845583a2042544320616464726573732062616c616e636520616c726561647920636c61696d656445524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654845583a206e65775374616b65644461797320686967686572207468616e206d6178696d756d45524332303a206275726e2066726f6d20746865207a65726f20616464726573734845583a206175746f5374616b6544617973206c6f776572207468616e206d696e696d756d45524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573734845583a206e65775374616b656444617973206c6f776572207468616e206d696e696d756d45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820e1386410ff82a380822a5c5fb950ec31ad42ac34f1e670c4d9b8c7329878472b64736f6c634300050d0032","decoded_constructor_args":null,"deployed_bytecode":"0x6080604052600436106102305760003560e01c80636a210a0e1161012e578063a9059cbb116100ab578063d5a373ff1161006f578063d5a373ff14610bff578063dd62ed3e14610c64578063ec9a191714610c9f578063f04b5fa014610d30578063f57a1b3c14610d5b57610230565b8063a9059cbb14610a9b578063bd926ed314610ad4578063c312452514610b2e578063cbb151d314610ba9578063ce7d1f7714610bd957610230565b80638f1c65c0116100f25780638f1c65c01461091357806390de68711461093d57806395d89b411461023257806396f62b9d1461099a578063a457c2d714610a6257610230565b80636a210a0e1461077157806370a08231146107f15780637c4266201461082457806387a0f31c146108585780638e21aa011461088257610230565b806333060d90116101bc57806344f0de751161018057806344f0de751461066357806352a438b8146106d15780635ac1f357146107015780635c9302c91461071657806365cf71b21461072b57610230565b806333060d901461054e578063343009a21461058157806339509351146105b85780633a70a5ca146105f157806344203faf1461060657610230565b80632607443b116102035780632607443b1461037357806327aa6018146103ff578063283a5baf1461048157806330c1a785146104d7578063313ce5671461052357610230565b806306fdde0314610232578063095ea7b3146102bc57806318160ddd1461030957806323b872dd14610330575b005b34801561023e57600080fd5b50610247610d8b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610281578181015183820152602001610269565b50505050905090810190601f1680156102ae5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102c857600080fd5b506102f5600480360360408110156102df57600080fd5b506001600160a01b038135169060200135610daa565b604080519115158252519081900360200190f35b34801561031557600080fd5b5061031e610dc7565b60408051918252519081900360200190f35b34801561033c57600080fd5b506102f56004803603606081101561035357600080fd5b506001600160a01b03813581169160208101359091169060400135610dcd565b34801561037f57600080fd5b506103ac6004803603604081101561039657600080fd5b506001600160a01b038135169060200135610e5b565b6040805164ffffffffff90981688526001600160481b039687166020890152949095168685015261ffff928316606087015290821660808601521660a084015290151560c0830152519081900360e00190f35b34801561040b57600080fd5b506102f56004803603604081101561042257600080fd5b81359190810190604081016020820135600160201b81111561044357600080fd5b82018360208201111561045557600080fd5b803590602001918460208302840111600160201b8311171561047657600080fd5b509092509050610ed4565b34801561048d57600080fd5b506104ba600480360360608110156104a457600080fd5b508035906020810135906040013560ff16610f1b565b604080516001600160601b03199092168252519081900360200190f35b3480156104e357600080fd5b50610507600480360360408110156104fa57600080fd5b50803590602001356110d9565b604080516001600160a01b039092168252519081900360200190f35b34801561052f57600080fd5b50610538611105565b6040805160ff9092168252519081900360200190f35b34801561055a57600080fd5b5061031e6004803603602081101561057157600080fd5b50356001600160a01b031661110a565b34801561058d57600080fd5b50610230600480360360408110156105a457600080fd5b508035906020013564ffffffffff16611129565b3480156105c457600080fd5b506102f5600480360360408110156105db57600080fd5b506001600160a01b0381351690602001356113e7565b3480156105fd57600080fd5b5061031e61143b565b34801561061257600080fd5b5061063f6004803603604081101561062957600080fd5b50803590602001356001600160a01b0316611458565b6040805164ffffffffff938416815291909216602082015281519081900390910190f35b34801561066f57600080fd5b506106966004803603602081101561068657600080fd5b50356001600160a01b0316611487565b6040518082600260200280838360005b838110156106be5781810151838201526020016106a6565b5050505090500191505060405180910390f35b3480156106dd57600080fd5b50610230600480360360408110156106f457600080fd5b5080359060200135611521565b34801561070d57600080fd5b506102306115ab565b34801561072257600080fd5b5061031e611632565b34801561073757600080fd5b506102306004803603606081101561074e57600080fd5b5080356001600160a01b0316906020810135906040013564ffffffffff16611641565b34801561077d57600080fd5b506107a16004803603604081101561079457600080fd5b5080359060200135611895565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156107dd5781810151838201526020016107c5565b505050509050019250505060405180910390f35b3480156107fd57600080fd5b5061031e6004803603602081101561081457600080fd5b50356001600160a01b03166119b1565b34801561083057600080fd5b506102f56004803603602081101561084757600080fd5b50356001600160601b0319166119cc565b34801561086457600080fd5b5061031e6004803603602081101561087b57600080fd5b50356119e1565b34801561088e57600080fd5b506102f5600480360360608110156108a557600080fd5b6001600160601b031982351691602081013591810190606081016040820135600160201b8111156108d557600080fd5b8201836020820111156108e757600080fd5b803590602001918460208302840111600160201b8311171561090857600080fd5b5090925090506119f3565b34801561091f57600080fd5b506102306004803603602081101561093657600080fd5b5035611b0a565b34801561094957600080fd5b506109676004803603602081101561096057600080fd5b5035611bea565b604080516001600160481b03948516815292909316602083015266ffffffffffffff168183015290519081900360600190f35b3480156109a657600080fd5b5061031e60048036036101608110156109be57600080fd5b81359190810190604081016020820135600160201b8111156109df57600080fd5b8201836020820111156109f157600080fd5b803590602001918460208302840111600160201b83111715610a1257600080fd5b91935091506001600160a01b03813581169160208101359160408201359160ff606082013581169260808301359091169160a08101359160c08201359160e0810135916101009091013516611c23565b348015610a6e57600080fd5b506102f560048036036040811015610a8557600080fd5b506001600160a01b038135169060200135611eb3565b348015610aa757600080fd5b506102f560048036036040811015610abe57600080fd5b506001600160a01b038135169060200135611f21565b348015610ae057600080fd5b50610b0d60048036036040811015610af757600080fd5b506001600160a01b038135169060200135611f35565b604080519283526001600160a01b0390911660208301528051918290030190f35b348015610b3a57600080fd5b50610b43611ff1565b604080516001600160481b03998a168152978916602089015264ffffffffff96871688820152948816606088015261ffff9093166080870152951660a08501529390911660c08301526001600160801b0390921660e08201529051908190036101000190f35b348015610bb557600080fd5b5061023060048036036040811015610bcc57600080fd5b5080359060200135612055565b61023060048036036020811015610bef57600080fd5b50356001600160a01b03166122d2565b348015610c0b57600080fd5b506102f56004803603610100811015610c2357600080fd5b506001600160a01b038135169060208101359060408101359060608101359060ff608082013581169160a08101359091169060c08101359060e00135612443565b348015610c7057600080fd5b5061031e60048036036040811015610c8757600080fd5b506001600160a01b038135811691602001351661254f565b348015610cab57600080fd5b506102f560048036036060811015610cc257600080fd5b6001600160601b031982351691602081013591810190606081016040820135600160201b811115610cf257600080fd5b820183602082011115610d0457600080fd5b803590602001918460208302840111600160201b83111715610d2557600080fd5b50909250905061257a565b348015610d3c57600080fd5b50610d456125c3565b6040518151815280826101a080838360206106a6565b348015610d6757600080fd5b506107a160048036036040811015610d7e57600080fd5b50803590602001356126c4565b604051806040016040528060038152602001620908ab60eb1b81525081565b6000610dbe610db76127a2565b84846127a6565b50600192915050565b60025490565b6000610dda848484612892565b610e5084610de66127a2565b610e4b856040518060600160405280602881526020016150a2602891396001600160a01b038a16600090815260016020526040812090610e246127a2565b6001600160a01b03168152602081019190915260400160002054919063ffffffff6129ee16565b6127a6565b5060015b9392505050565b60076020528160005260406000208181548110610e7457fe5b60009182526020909120015464ffffffffff811692506001600160481b03600160281b820481169250600160701b8204169061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b9091041687565b6000610f1384848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612a8592505050565b949350505050565b600080606060028416158015906004861615159060088716151590610fe657818015610f445750805b15610f90576040805162461bcd60e51b81526020600482015260176024820152761211560e8818db185a5b519b1859dcc81a5b9d985b1a59604a1b604482015290519081900360640190fd5b600160f81b60f889901b1615610fa7576003610faa565b60025b604080516001600160f81b031960f884901b16602082015260218082018d90528251808303909101815260419091019091529095509350611073565b81158015610ff2575080155b61103d576040805162461bcd60e51b81526020600482015260176024820152761211560e8818db185a5b519b1859dcc81a5b9d985b1a59604a1b604482015290519081900360640190fd5b60408051600160fa1b6020820152602181018b905260418082018b90528251808303909101815260619091019091526004955093505b600061107e85612ab2565b905082156110cc5760408051600560f21b60208201526001600160601b0319831660228201528151601681830301815260369091019091526110bf90612ab2565b9650505050505050610e54565b9998505050505050505050565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b600881565b6001600160a01b0381166000908152600760205260409020545b919050565b611131614e43565b611139614e43565b6111438282612bd7565b336000908152600760205260409020805461119d576040805162461bcd60e51b81526020600482015260156024820152741211560e88115b5c1d1e481cdd185ad9481b1a5cdd605a1b604482015290519081900360640190fd5b805485106111ec576040805162461bcd60e51b81526020600482015260176024820152761211560e881cdd185ad9525b99195e081a5b9d985b1a59604a1b604482015290519081900360640190fd5b6111f4614ea4565b61121482878154811061120357fe5b906000526020600020018683612c89565b61121d84612d5c565b60a081015160608201516101408601516000921515918391829182918291116112fd57841561125257866080015195506112e3565b61125c8a88612d6d565b86606001518a6101400151039550866080015186111561128257866080015195506112e3565b61015e8610156112e3578660c00151156112e3576040805162461bcd60e51b815260206004820152601c60248201527f4845583a204175746f2d7374616b65207374696c6c206c6f636b656400000000604482015290519081900360640190fd5b6112ee8a8888612d8c565b9296509094509250905061136d565b8660c0015115611354576040805162461bcd60e51b815260206004820152601c60248201527f4845583a204175746f2d7374616b65207374696c6c206c6f636b656400000000604482015290519081900360640190fd5b60408701516020808c0180519290920390915287015193505b6113848b8860200151896040015186868b8b612e30565b8015801590611391575084155b156113a0576113a08a82612eed565b83156113bb576113b03385612f28565b6113bb8a8886613018565b60208701518a51038a526113cf888d613084565b6113d98a8a6131e2565b505050505050505050505050565b6000610dbe6113f46127a2565b84610e4b85600160006114056127a2565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6133d516565b6003546000906001600160481b0316611452610dc7565b01905090565b600960209081526000928352604080842090915290825290205464ffffffffff80821691600160281b90041682565b61148f614eea565b600061149961342f565b600101905061015f8111156114ad575061015f5b6000198101901561151b5760008181526009602090815260408083206001600160a01b038716845290915290205464ffffffffff808216600160281b90920416111561151657600160ff82161b82600883901c6002811061150a57fe5b60200201805190911790525b6114ad565b50919050565b611529614e43565b611531614e43565b61153b8282612bd7565b600183101561157b5760405162461bcd60e51b815260040180806020018281038252602581526020018061517f6025913960400191505060405180910390fd5b61158482612d5c565b611591828585600061343f565b61159b3385613560565b6115a582826131e2565b50505050565b30316115ee576040805162461bcd60e51b815260206004820152600d60248201526c4845583a204e6f2076616c756560981b604482015290519081900360640190fd5b60405173dec9f2793e3c17cd26eefb21c4762fa5128e039990303180156108fc02916000818181858888f1935050505015801561162f573d6000803e3d6000fd5b50565b600061163c61342f565b905090565b611649614e43565b611651614e43565b61165b8282612bd7565b6001600160a01b0385166000908152600760205260409020546116bd576040805162461bcd60e51b81526020600482015260156024820152741211560e88115b5c1d1e481cdd185ad9481b1a5cdd605a1b604482015290519081900360640190fd5b6001600160a01b0385166000908152600760205260409020548410611723576040805162461bcd60e51b81526020600482015260176024820152761211560e881cdd185ad9525b99195e081a5b9d985b1a59604a1b604482015290519081900360640190fd5b6001600160a01b038516600090815260076020526040812080548690811061174757fe5b90600052602060002001905061175b614ea4565b611766828683612c89565b806080015181606001510184610140015110156117ca576040805162461bcd60e51b815260206004820152601b60248201527f4845583a205374616b65206e6f742066756c6c79207365727665640000000000604482015290519081900360640190fd5b60a081015115611821576040805162461bcd60e51b815260206004820152601b60248201527f4845583a205374616b6520616c726561647920756e6c6f636b65640000000000604482015290519081900360640190fd5b61182a84612d5c565b6118348482612d6d565b600080600061184887858660800151612d8c565b935093509350506118658a8986602001518760400151878761365c565b8015611875576118758782612eed565b61187f85856136f9565b61188987876131e2565b50505050505050505050565b606081831080156118ac575060045461ffff168211155b6118f2576040805162461bcd60e51b81526020600482015260126024820152711211560e881c985b99d9481a5b9d985b1a5960721b604482015290519081900360640190fd5b82820360405190808252806020026020018201604052801561191e578160200160208202803883390190505b509050826000805b5060008281526006602052604090205483516001830192600160901b830460901b66ffffffffffffff60901b16600160481b840460481b71ffffffffffffffffff00000000000000000016176001600160481b0390931692909217918291869190811061198f57fe5b6020026020010181815250508483600101935083106119265750505092915050565b6001600160a01b031660009081526020819052604090205490565b60056020526000908152604090205460ff1681565b60086020526000908152604090205481565b6000806119fe61342f565b90506001811015611a405760405162461bcd60e51b8152600401808060200182810382526024815260200180614fd66024913960400191505060405180910390fd5b61015f8110611a96576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20436c61696d2070686173652068617320656e646564000000000000604482015290519081900360640190fd5b6001600160601b0319861660009081526005602052604090205460ff1615611ac2576000915050610f13565b611b0086868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b9695505050505050565b611b12614e43565b611b1a614e43565b611b248282612bd7565b600182610140015111611b6f576040805162461bcd60e51b815260206004820152600e60248201526d4845583a20546f6f206561726c7960901b604482015290519081900360640190fd5b8215611bca57816101400151831115611bb95760405162461bcd60e51b8152600401808060200182810382526026815260200180614f6c6026913960400191505060405180910390fd5b611bc5828460006138e1565b611bdb565b611bdb8283610140015160006138e1565b611be582826131e2565b505050565b6006602052600090815260409020546001600160481b0380821691600160481b810490911690600160901b900466ffffffffffffff1683565b600065173cdf6f6e318d1115611c78576040805162461bcd60e51b81526020600482015260156024820152744845583a2043484b3a207261775361746f7368697360581b604482015290519081900360640190fd5b61015e831015611cb95760405162461bcd60e51b81526004018080602001828103825260258152602001806151116025913960400191505060405180910390fd5b60006001600160a01b038b163314611d2b5750604080517f4e831acb4223b66de3b3d2e54a2edeefb0de3d7916e2886a4b134d9764d41bec602080830191909152818301869052606085811b6001600160601b0319169083015282518083036054018152607490920190925280519101205b611d3b8b828c8c8c8c8c8c612443565b611d8c576040805162461bcd60e51b815260206004820152601760248201527f4845583a205369676e6174757265206d69736d61746368000000000000000000604482015290519081900360640190fd5b506000611d9a8a8a8a610f1b565b6001600160601b0319811660009081526005602052604090205490915060ff1615611df65760405162461bcd60e51b815260040180806020018281038252602881526020018061507a6028913960400191505060405180910390fd5b611e34818f8f8f808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b611e6f5760405162461bcd60e51b81526004018080602001828103825260238152602001806150576023913960400191505060405180910390fd5b6001600160601b031981166000908152600560205260409020805460ff19166001179055611ea18e8c838b8888613993565b9e9d5050505050505050505050505050565b6000610dbe611ec06127a2565b84610e4b856040518060600160405280602581526020016151a46025913960016000611eea6127a2565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff6129ee16565b6000610dbe611f2e6127a2565b8484612892565b602881901c60008181526009602090815260408083206001600160a01b0387168452825280832064ffffffffff861680855260019091019092528220805492938493909291906001600160601b0316611fca576040805162461bcd60e51b81526020600482015260126024820152711211560e8814185c985b481a5b9d985b1a5960721b604482015290519081900360640190fd5b546001600160601b03811697600160601b9091046001600160a01b03169650945050505050565b6003546004546001600160481b0380831692600160481b810482169264ffffffffff600160901b8304811693600160b81b90930483169261ffff83169262010000810490911691600160581b820416906001600160801b03600160801b9091041688565b61205d61342f565b82106120b0576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20526f756e64206973206e6f7420636f6d706c657465000000000000604482015290519081900360640190fd5b600082815260096020908152604080832033845290915281208054909164ffffffffff909116908315612142578254600160281b900464ffffffffff16829003841115612139576040805162461bcd60e51b81526020600482015260126024820152711211560e8818dbdd5b9d081a5b9d985b1a5960721b604482015290519081900360640190fd5b5080830161219c565b508154600160281b900464ffffffffff1680821061219c576040805162461bcd60e51b81526020600482015260126024820152711211560e8818dbdd5b9d081a5b9d985b1a5960721b604482015290519081900360640190fd5b60006121a7866139d6565b600087815260086020526040812054919250805b600086815260018801602052604081208054908290556001600160601b03811691600160601b9091046001600160a01b03169085878402816121f957fe5b0490506001600160a01b03821661221b576122168c8a8385613a4e565b61226a565b600a81049081019060058204336001600160a01b038516141561224d57918201916122488e8c8587613a4e565b612263565b6122598e8c8587613a4e565b6122638482612f28565b0193909301925b600190980197939093019250508486106121bb57865464ffffffffff191664ffffffffff871617875580156122b7576122b7739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b81156122c7576122c73383612f28565b505050505050505050565b60006122dc61342f565b905061015f8110612334576040805162461bcd60e51b815260206004820152601760248201527f4845583a204c6f6262696573206861766520656e646564000000000000000000604482015290519081900360640190fd5b348061237e576040805162461bcd60e51b81526020600482015260146024820152731211560e88105b5bdd5b9d081c995c5d5a5c995960621b604482015290519081900360640190fd5b600082815260096020908152604080832033845282528083208054600164ffffffffff600160281b80840482168381019092160269ffffffffff000000000019909316929092178355835180850185526001600160601b0380891682526001600160a01b038b8116838901908152858a529386018852868920925183549451909116600160601b029082166001600160601b031990941693909317169190911790558685526008909352922080548401905561243c84828588613abc565b5050505050565b6000601b8460ff161015801561245d5750601e8460ff1611155b61249f576040805162461bcd60e51b815260206004820152600e60248201526d1211560e881d881a5b9d985b1a5960921b604482015290519081900360640190fd5b60006124ab88886110d9565b905060006124c26124bd8c8c8a613b2a565b613e66565b9050816001600160a01b031660018288888860405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561252b573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149250505098975050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60006125ba85858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506137d192505050565b95945050505050565b6125cb614f08565b600454600090819081906125ee90600160801b90046001600160801b0316613f97565b604080516101a0810182526003546001600160481b038082168352600160481b82048116602084015264ffffffffff600160901b8304811694840194909452600160b81b9091048116606083015260045461ffff8116608084015262010000810490911660a0830152600160581b900490911660c082015260e08101829052610100810183905261012081018490524261014082015292955090935091506101608101612699610dc7565b8152602001600860006126aa61342f565b815260200190815260200160002054815250935050505090565b606081831080156126d7575061015f8211155b80156126ea57506126e661342f565b8211155b612730576040805162461bcd60e51b81526020600482015260126024820152714845583a20696e76616c69642072616e676560701b604482015290519081900360640190fd5b82820360405190808252806020026020018201604052801561275c578160200160208202803883390190505b5090508260005b60008281526008602052604090205483516001938401938301928591811061278757fe5b60200260200101818152505083821061276357505092915050565b3390565b6001600160a01b0383166127eb5760405162461bcd60e51b815260040180806020018281038252602481526020018061515b6024913960400191505060405180910390fd5b6001600160a01b0382166128305760405162461bcd60e51b8152600401808060200182810382526022815260200180614fb46022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166128d75760405162461bcd60e51b81526004018080602001828103825260258152602001806151366025913960400191505060405180910390fd5b6001600160a01b03821661291c5760405162461bcd60e51b8152600401808060200182810382526023815260200180614f496023913960400191505060405180910390fd5b61295f81604051806060016040528060268152602001615031602691396001600160a01b038616600090815260208190526040902054919063ffffffff6129ee16565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612994908263ffffffff6133d516565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115612a7d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612a42578181015183820152602001612a2a565b50505050905090810190601f168015612a6f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000610e54827f4e831acb4223b66de3b3d2e54a2edeefb0de3d7916e2886a4b134d9764d41bec85613fb7565b600060036002836040518082805190602001908083835b60208310612ae85780518252601f199092019160209182019101612ac9565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015612b27573d6000803e3d6000fd5b5050506040513d6020811015612b3c57600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b60208310612b885780518252601f199092019160209182019101612b69565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015612bc7573d6000803e3d6000fd5b50506040515160601b9392505050565b6003546001600160481b038082168452600160481b82048116602085015264ffffffffff600160901b830481166040860152600160b81b9092048116606085015260045461ffff8116608086015262010000810490911660a0850152600160581b810490911660c0840152612c5c906001600160801b03600160801b90910416613f97565b60e0850152610100840152610120830152612c7561342f565b610140830152612c858282614061565b5050565b825464ffffffffff838116911614612ce8576040805162461bcd60e51b815260206004820152601e60248201527f4845583a207374616b654964506172616d206e6f7420696e207374616b650000604482015290519081900360640190fd5b915464ffffffffff811683526001600160481b03600160281b820481166020850152600160701b820416604084015261ffff600160b81b820481166060850152600160c81b820481166080850152600160d81b82041660a084015260ff600160e81b90910416151560c09092019190915250565b61162f8182610140015160016138e1565b604081015160a080840180519290920390915261014090920151910152565b6000806000808560800151851015612dca57612db78787606001518860800151888a604001516140c9565b6020880151820195509093509150612e08565b60408601516060870151612de2918991888101614172565b9250828660200151019350612e05866060015187608001518860a0015187614240565b91505b8115612e275783821115612e1f5750600092612e27565b509182900391805b93509350935093565b8664ffffffffff16336001600160a01b03167f72d9c5a7ab13846e08d9c838f9e866a1bb4a66a2fd3ba3c9e7da3cf9e394dfd760b8876001600160481b0316901b6070896001600160481b0316901b60288b6001600160481b0316901b4264ffffffffff1617171784612ea4576000612eaa565b600160581b5b6001600160601b031660488761ffff16901b886001600160481b03161717604051808381526020018281526020019250505060405180910390a350505050505050565b600281048015612f1557612f15739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b6060909201805192909103919091019052565b6001600160a01b038216612f83576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b600254612f96908263ffffffff6133d516565b6002556001600160a01b038216600090815260208190526040902054612fc2908263ffffffff6133d516565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b8160200151811115611be557600061303482846080015161426c565b905060008360400151620186a0838501028161304c57fe5b04905064ffffffffff811115613064575064ffffffffff5b846040015181111561243c5760408501819052835161243c9082906142de565b8154600019018181146131b15782818154811061309d57fe5b906000526020600020018383815481106130b357fe5b6000918252602090912082549101805464ffffffffff90921664ffffffffff199092169190911780825582546dffffffffffffffffff000000000019909116600160281b918290046001600160481b0390811690920217808355835468ffffffffffffffffff60701b19909116600160701b918290049092160217808255825461ffff60b81b19909116600160b81b9182900461ffff90811690920217808355835461ffff60c81b19909116600160c81b91829004831690910217808355835461ffff60d81b19909116600160d81b918290049092160217808255915460ff60e81b19909216600160e81b9283900460ff1615159092029190911790555b828054806131bb57fe5b600082815260209020810160001990810180546001600160f01b0319169055019055505050565b805182511415806131fb57508060200151826020015114155b8061320e57508060400151826040015114155b8061322157508060600151826060015114155b156132af5781516003805460208501516040860151606087015168ffffffffffffffffff199093166001600160481b039586161768ffffffffffffffffff60481b1916600160481b928616929092029190911764ffffffffff60901b1916600160901b64ffffffffff90921691909102176001600160b81b0316600160b81b93909116929092029190911790555b806080015182608001511415806132ce57508060a001518260a0015114155b806132ef57508060c0015164ffffffffff168260c0015164ffffffffff1614155b8061330257508060e001518260e0015114155b80613317575080610100015182610100015114155b8061332c575080610120015182610120015114155b15612c855760808201516004805460a085015160c086015164ffffffffff16600160581b0264ffffffffff60581b196001600160481b0390921662010000026affffffffffffffffff00001961ffff90961661ffff199094169390931794909416919091171691909117905561012082015161010083015160e08401516133b4929190614335565b600480546001600160801b03928316600160801b0292169190911790555050565b600082820183811015610e54576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6201518042635de5a57f19010490565b6115b38211156134805760405162461bcd60e51b81526004018080602001828103825260268152602001806150ca6026913960400191505060405180910390fd5b600061348c848461426c565b905060008560400151620186a083870102816134a457fe5b049050806134e35760405162461bcd60e51b8152600401808060200182810382526037815260200180614ffa6037913960400191505060405180910390fd5b600060018761014001511061350057866101400151600101613503565b60025b60c08801805160010164ffffffffff16908190523360009081526007602052604090209192509061353990828986868b8b614346565b6135468188858989614474565b505060208601805190910190525050825190910190915250565b6001600160a01b0382166135a55760405162461bcd60e51b81526004018080602001828103825260218152602001806150f06021913960400191505060405180910390fd5b6135e881604051806060016040528060228152602001614f92602291396001600160a01b038516600090815260208190526040902054919063ffffffff6129ee16565b6001600160a01b038316600090815260208190526040902055600254613614908263ffffffff61450616565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b604080514264ffffffffff9081166dffffffffffffffffff0000000000602889901b161768ffffffffffffffffff60701b607088901b16176001600160b81b031960b887901b161782526001600160481b038416602083015282513393918916926001600160a01b038b16927fd824970a2cf19cc2b630c87ce5b00f67301cac3ac60513d027c7a39129f93b4692918290030190a4505050505050565b80518254602083015160408401516060850151608086015160a087015160c09097015164ffffffffff1990951664ffffffffff909616959095176dffffffffffffffffff00000000001916600160281b6001600160481b03948516021768ffffffffffffffffff60701b1916600160701b93909216929092021761ffff60b81b1916600160b81b61ffff928316021761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b92909316919091029190911760ff60e81b1916600160e81b91151591909102179055565b80516000906bffffffffffffe0000000000090839083906137ee57fe5b602002602001015160001c16600014613843576040805162461bcd60e51b81526020600482015260126024820152711211560e881c1c9bdbd9881a5b9d985b1a5960721b604482015290519081900360640190fd5b60015b82518110156138c95782516bffffffffffffe000000000009084908390811061386b57fe5b602002602001015160001c16600014156138c1576040805162461bcd60e51b81526020600482015260126024820152711211560e881c1c9bdbd9881a5b9d985b1a5960721b604482015290519081900360640190fd5b600101613846565b506001600160601b0319841683176125ba8184612a85565b818360800151106138f157611be5565b6138f9614f27565b8351613903610dc7565b0181526080840151613916858383614548565b6020850151156139365760208501805160a0870180519091019052600090525b600101838110156139515761394c858383614548565b613936565b613960856080015182856145d3565b6080850181905260208201511561243c5761243c739a6a414d6f3497c05e3b1de90520765fa1e07c038360200151612f28565b600061399d614e43565b6139a5614e43565b6139af8282612bd7565b6139be828a8a8a8a8a8a61464a565b92506139ca82826131e2565b50509695505050505050565b600060018210613a3f576139e8614e43565b6139f0614e43565b6139fa8282612bd7565b613a0382612d5c565b600084815260066020526040902054600160901b900466ffffffffffffff1661015e6127108202049350613a3783836131e2565b505050611124565b5067016345785d8a0000919050565b806001600160a01b031683602886901b17336001600160a01b03167fa6b19fa7f41317a186e1d58e9d81f86a52f1102b6bce10b4eca83f37aaa584686028866001600160481b0316901b4264ffffffffff16176040518082815260200191505060405180910390a450505050565b806001600160a01b031683602886901b17336001600160a01b03167f25ecdb937d5c5cc78f0d18dfb1ac82c44086b5dc608380ba357d06c9868f0b1d6028866001600160601b0316901b4264ffffffffff16176040518082815260200191505060405180910390a450505050565b60608060018316613b62576040518060400160405280600f81526020016e086d8c2d2dabe908ab0bee8debe60f608b1b815250613b92565b60405180604001604052806016815260200175086d8c2d2dabe84d2e8c6ded2dc908ab0bee8debe60f60531b8152505b905060108316156060613ba587836147b5565b905085613cca576018772134ba31b7b4b71029b4b3b732b21026b2b9b9b0b3b29d0560411b60146002028551018584604051602001808660ff1660ff1660f81b81526001018567ffffffffffffffff191667ffffffffffffffff191681526018018460ff1660ff1660f81b815260010183805190602001908083835b60208310613c405780518252601f199092019160209182019101613c21565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310613c885780518252601f199092019160209182019101613c69565b6001836020036101000a038019825116818451168082178552505050505050905001955050505050506040516020818303038152906040529350505050610e54565b604080516018808252818301909252606091602082018180388339019050509050613cf78188600c614858565b8351604051600360fb1b6020808301918252772134ba31b7b4b71029b4b3b732b21026b2b9b9b0b3b29d0560411b60218401819052604190940160f881901b6001600160f81b031916603985015288516018959491938a9389938993603a909101918601908083835b60208310613d7f5780518252601f199092019160209182019101613d60565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b60208310613dc75780518252601f199092019160209182019101613da8565b6001836020036101000a03801982511681845116808217855250505050505090500180605f60f81b81525060010182805190602001908083835b60208310613e205780518252601f199092019160209182019101613e01565b6001836020036101000a03801982511681845116808217855250505050505090500196505050505050506040516020818303038152906040529450505050509392505050565b6000600280836040518082805190602001908083835b60208310613e9b5780518252601f199092019160209182019101613e7c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015613eda573d6000803e3d6000fd5b5050506040513d6020811015613eef57600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b60208310613f3b5780518252601f199092019160209182019101613f1c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015613f7a573d6000803e3d6000fd5b5050506040513d6020811015613f8f57600080fd5b505192915050565b606681901c6303ffffff16916607ffffffffffff603383901c8116921690565b600081815b8551811015614056576000868281518110613fd357fe5b602002602001015190508083101561401b578281604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120925061404d565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b50600101613fbc565b509092149392505050565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c08083015164ffffffffff169082015260e08083015190820152610100808301519082015261012091820151910152565b60008083860160026001870104605a8110156140e35750605a5b856141035760006140f58a878b614920565b919091029250614168915050565b858110156141385787810161411a8a878b84614172565b9350600061412a8b888487614172565b850195506141689350505050565b61414489868a85614172565b93508581141561415657839250614165565b858185028161416157fe5b0492505b50505b9550959350505050565b6000825b828110156141b7576000818152600660205260409020546001600160481b03600160481b8204811691168602816141a957fe5b049190910190600101614176565b5061016083118015906141cb575061016082115b15610f1357610160600090815260066020527f5bc747bd71b549e015c2e31a0d21c276f82136338c6c7203a3f9911f7240314a54600160481b90046001600160481b0316856127106305f5e1008004028860e0015102028161422957fe5b04905061423686826149b3565b0101949350505050565b6000848401600e01808411614259576000915050610f13565b6102bc8185038402049695505050505050565b600080600183111561429257610e3883111561428a57610e3861428f565b600183035b90505b600066354a6ba7a180008511156142b05766354a6ba7a180006142b2565b845b670214e8348c4f0000830261071c82020193509050680ecca2d59581a400008584020495945050505050565b8064ffffffffff167f9861fa0ed101659f7a59b4583fcc798dfa4f3b419bea371c8ee2ad0ffe13a31e60288464ffffffffff16901b4264ffffffffff16176040518082815260200191505060405180910390a25050565b60669290921b60339190911b171790565b6040805160e08101825264ffffffffff97881681526001600160481b03968716602080830191825296881692820192835261ffff9586166060830190815294861660808301908152600060a0840181815295151560c085019081528c54600181018e559c8252989020925192909a0180549151935195519a519451975164ffffffffff1990921692909916919091176dffffffffffffffffff00000000001916600160281b928816929092029190911768ffffffffffffffffff60701b1916600160701b93909616929092029490941761ffff60b81b1916600160b81b968316969096029590951761ffff60c81b1916600160c81b938216939093029290921761ffff60d81b1916600160d81b91909216021760ff60e81b1916600160e81b92151592909202919091179055565b64ffffffffff8516337f14872dc760f33532684e68e1b6d5fd3f71ba7b07dee76bdb2b084f28b74233ef836144aa5760006144b0565b600160c81b5b6001600160d01b031660b88661ffff16901b6070886001600160481b0316901b60288a6001600160481b0316901b4264ffffffffff16171717176040518082815260200191505060405180910390a35050505050565b6000610e5483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129ee565b6145538383836149f3565b60409182015160009182526006602052919020805460a084015160e09094015168ffffffffffffffffff199091166001600160481b039384161768ffffffffffffffffff60481b1916600160481b93909416929092029290921766ffffffffffffff60901b1916600160901b66ffffffffffffff90921691909102179055565b337fb8d6eb541ded1720cc657b719f57abcb1fe4711cb7ead82751b135f5d94bc94482614601576000614607565b600160481b5b69ffffffffffffffffffff1660388561ffff16901b60288761ffff16901b4264ffffffffff161717176040518082815260200191505060405180910390a2505050565b6000600188610140015110156146915760405162461bcd60e51b8152600401808060200182810382526024815260200180614fd66024913960400191505060405180910390fd5b61014088015161015f116146ec576040805162461bcd60e51b815260206004820152601a60248201527f4845583a20436c61696d2070686173652068617320656e646564000000000000604482015290519081900360640190fd5b6146f588612d5c565b6301ab362e88610120015110614752576040805162461bcd60e51b815260206004820152601e60248201527f4845583a2043484b3a205f636c61696d656442746341646472436f756e740000604482015290519081900360640190fd5b60008060006147618b8b614a8d565b6101208e0180516001019052919450925090506147848989898d8787878c614b47565b93506064605a85020461479a8c8289600161343f565b6147a68a828703612f28565b50505050979650505050505050565b60408051602880825260608281019093526020820181803883390190505090506147ef816001600160601b0319606086901b166014614858565b811561485257805160208201206000805b601481101561484e57600083826020811061481757fe5b600185019491901a9150614831908690600484901c614bf4565b614845858480600101955083600f16614bf4565b50600101614800565b5050505b92915050565b6000805b8281101561243c57600084826020811061487257fe5b1a90506f181899199a1a9b1b9c1cb0b131b232b360811b600482901c60ff166010811061489b57fe5b1a60f81b8684806001019550815181106148b157fe5b60200101906001600160f81b031916908160001a9053506f181899199a1a9b1b9c1cb0b131b232b360811b600f8216601081106148ea57fe5b1a60f81b86848060010195508151811061490057fe5b60200101906001600160f81b031916908160001a9053505060010161485c565b600061492a614e43565b6149348582614061565b61493c614f27565b8551614946610dc7565b0181526149548282866149f3565b60a082018051860190819052604082015186028161496e57fe5b0492506101608414156149aa5760a082015160e0830151600091908702612710028161499657fe5b0490506149a383826149b3565b0192909201915b50509392505050565b6000806301ab362e8461012001518402816149ca57fe5b049050600066033bb85fc52d998561010001518502816149e657fe5b0491909101949350505050565b81516305fcbae3906127100204604083015261015f811015614a695760e083015160009061015e90612710020490506000614a3485838660400151016149b3565b60208501805191840191820190528451810185526040850151909150614a5b9086906149b3565b604085018051909101905250505b606083015115611be557606083018051604084018051909101905260009052505050565b6000806000614a9b84614c60565b925066033bb85fc52d9983866101000151011115614b00576040805162461bcd60e51b815260206004820152601f60248201527f4845583a2043484b3a205f636c61696d65645361746f73686973546f74616c00604482015290519081900360640190fd5b610100850180518401905261014085015161015f03614b1f8482614cac565b60e0870180518290039052935061271084029250614b3d8382614cbd565b9150509250925092565b828201826001600160a01b038316614b6d57614b688a8a8a8a8a8789614cce565b614bc9565b600a8204918201916005830480820192909201916001600160a01b03858116908d161415614bad5792830192614ba88c8c8c8c8c898b614cce565b614bc6565b614bbc8c8c8c8c8c898b614cce565b614bc68582612f28565b50505b614be7739a6a414d6f3497c05e3b1de90520765fa1e07c0382612f28565b5098975050505050505050565b6000838381518110614c0257fe5b01602001516001600160f81b0319169050606160f81b8110801590614c2b575060088260ff1610155b156115a55780602060f81b18848481518110614c4357fe5b60200101906001600160f81b031916908160001a90535050505050565b600064174876e800821015614c76575080611124565b64e8d4a510008210614c8c575060048104611124565b65034630b8a000826501ba60d3380003830281614ca557fe5b0492915050565b600061015e8383025b049392505050565b60006106d160001983018402614cb5565b6040805164ffffffffff42166bffffffffffffff0000000000602888901b161766ffffffffffffff60601b606087901b161760ff60981b609889901b161768ffffffffffffffffff60a01b60a086901b1617815233602082015281516001600160a01b0380851693908b16926001600160601b03198b16927f41e3c7dc6eebc97a48a437ff2afdc629613f12c48ba37a2c94563f80acba9725929181900390910190a46001600160a01b038716331415614d8757614e3a565b336001600160a01b03167f3a84b2d9dac24683628d63034c6949797f15fab735e16232518ee4e753fd49b760c88666ffffffffffffff16901b60288960601c6001600160a01b0316901b4264ffffffffff16171760d88860ff16901b60388b6001600160a01b0316901b8766ffffffffffffff1617176048856001600160a01b0316901b866001600160481b03161760405180848152602001838152602001828152602001935050505060405180910390a25b50505050505050565b604051806101600160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600064ffffffffff168152602001600081526020016000815260200160008152602001600081525090565b6040518060e00160405280600064ffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b60405180604001604052806002906020820280388339509192915050565b604051806101a00160405280600d906020820280388339509192915050565b6040518060600160405280600081526020016000815260200160008152509056fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573734845583a206265666f72654461792063616e6e6f7420626520696e207468652066757475726545524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f20616464726573734845583a20436c61696d20706861736520686173206e6f742079657420737461727465644845583a206e65775374616b6564486561727473206d757374206265206174206c65617374206d696e696d756d2073686172655261746545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63654845583a204254432061646472657373206f722062616c616e636520756e6b6e6f776e4845583a2042544320616464726573732062616c616e636520616c726561647920636c61696d656445524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654845583a206e65775374616b65644461797320686967686572207468616e206d6178696d756d45524332303a206275726e2066726f6d20746865207a65726f20616464726573734845583a206175746f5374616b6544617973206c6f776572207468616e206d696e696d756d45524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573734845583a206e65775374616b656444617973206c6f776572207468616e206d696e696d756d45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820e1386410ff82a380822a5c5fb950ec31ad42ac34f1e670c4d9b8c7329878472b64736f6c634300050d0032","evm_version":"default","external_libraries":[],"file_path":null,"is_changed_bytecode":false,"is_fully_verified":true,"is_partially_verified":false,"is_self_destructed":false,"is_verified":true,"is_verified_via_eth_bytecode_db":false,"is_verified_via_sourcify":false,"is_vyper_contract":false,"language":"solidity","minimal_proxy_address_hash":null,"name":"HEX","optimization_enabled":true,"optimization_runs":200,"source_code":"/**\n *Submitted for verification at Etherscan.io on 2019-12-03\n*/\n\npragma solidity 0.5.13;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n    // Empty internal constructor, to prevent people from mistakenly deploying\n    // an instance of this contract, which should be used via inheritance.\n    constructor () internal { }\n    // solhint-disable-previous-line no-empty-blocks\n\n    function _msgSender() internal view returns (address payable) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view returns (bytes memory) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c >= a, \"SafeMath: addition overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return sub(a, b, \"SafeMath: subtraction overflow\");\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     *\n     * _Available since v2.4.0._\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b <= a, errorMessage);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return div(a, b, \"SafeMath: division by zero\");\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     *\n     * _Available since v2.4.0._\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        // Solidity only automatically asserts when dividing by 0\n        require(b > 0, errorMessage);\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return mod(a, b, \"SafeMath: modulo by zero\");\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts with custom message when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     *\n     * _Available since v2.4.0._\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b != 0, errorMessage);\n        return a % b;\n    }\n}\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20 {\n    using SafeMath for uint256;\n\n    mapping (address => uint256) private _balances;\n\n    mapping (address => mapping (address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address recipient, uint256 amount) public returns (bool) {\n        _transfer(_msgSender(), recipient, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public returns (bool) {\n        _approve(_msgSender(), spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20};\n     *\n     * Requirements:\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for `sender`'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {\n        _transfer(sender, recipient, amount);\n        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, \"ERC20: transfer amount exceeds allowance\"));\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, \"ERC20: decreased allowance below zero\"));\n        return true;\n    }\n\n    /**\n     * @dev Moves tokens `amount` from `sender` to `recipient`.\n     *\n     * This is internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(address sender, address recipient, uint256 amount) internal {\n        require(sender != address(0), \"ERC20: transfer from the zero address\");\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        _balances[sender] = _balances[sender].sub(amount, \"ERC20: transfer amount exceeds balance\");\n        _balances[recipient] = _balances[recipient].add(amount);\n        emit Transfer(sender, recipient, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements\n     *\n     * - `to` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _totalSupply = _totalSupply.add(amount);\n        _balances[account] = _balances[account].add(amount);\n        emit Transfer(address(0), account, amount);\n    }\n\n     /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n        _totalSupply = _totalSupply.sub(amount);\n        emit Transfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n     *\n     * This is internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(address owner, address spender, uint256 amount) internal {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n     * from the caller's allowance.\n     *\n     * See {_burn} and {_approve}.\n     */\n    function _burnFrom(address account, uint256 amount) internal {\n        _burn(account, amount);\n        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\"));\n    }\n}\n\ncontract GlobalsAndUtility is ERC20 {\n    /*  XfLobbyEnter      (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        address  indexed  memberAddr\n        uint256  indexed  entryId\n        uint96            rawAmount       -->  data0 [135: 40]\n        address  indexed  referrerAddr\n    */\n    event XfLobbyEnter(\n        uint256 data0,\n        address indexed memberAddr,\n        uint256 indexed entryId,\n        address indexed referrerAddr\n    );\n\n    /*  XfLobbyExit       (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        address  indexed  memberAddr\n        uint256  indexed  entryId\n        uint72            xfAmount        -->  data0 [111: 40]\n        address  indexed  referrerAddr\n    */\n    event XfLobbyExit(\n        uint256 data0,\n        address indexed memberAddr,\n        uint256 indexed entryId,\n        address indexed referrerAddr\n    );\n\n    /*  DailyDataUpdate   (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        uint16            beginDay        -->  data0 [ 55: 40]\n        uint16            endDay          -->  data0 [ 71: 56]\n        bool              isAutoUpdate    -->  data0 [ 79: 72]\n        address  indexed  updaterAddr\n    */\n    event DailyDataUpdate(\n        uint256 data0,\n        address indexed updaterAddr\n    );\n\n    /*  Claim             (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        bytes20  indexed  btcAddr\n        uint56            rawSatoshis     -->  data0 [ 95: 40]\n        uint56            adjSatoshis     -->  data0 [151: 96]\n        address  indexed  claimToAddr\n        uint8             claimFlags      -->  data0 [159:152]\n        uint72            claimedHearts   -->  data0 [231:160]\n        address  indexed  referrerAddr\n        address           senderAddr      -->  data1 [159:  0]\n    */\n    event Claim(\n        uint256 data0,\n        uint256 data1,\n        bytes20 indexed btcAddr,\n        address indexed claimToAddr,\n        address indexed referrerAddr\n    );\n\n    /*  ClaimAssist       (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        bytes20           btcAddr         -->  data0 [199: 40]\n        uint56            rawSatoshis     -->  data0 [255:200]\n        uint56            adjSatoshis     -->  data1 [ 55:  0]\n        address           claimToAddr     -->  data1 [215: 56]\n        uint8             claimFlags      -->  data1 [223:216]\n        uint72            claimedHearts   -->  data2 [ 71:  0]\n        address           referrerAddr    -->  data2 [231: 72]\n        address  indexed  senderAddr\n    */\n    event ClaimAssist(\n        uint256 data0,\n        uint256 data1,\n        uint256 data2,\n        address indexed senderAddr\n    );\n\n    /*  StakeStart        (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        address  indexed  stakerAddr\n        uint40   indexed  stakeId\n        uint72            stakedHearts    -->  data0 [111: 40]\n        uint72            stakeShares     -->  data0 [183:112]\n        uint16            stakedDays      -->  data0 [199:184]\n        bool              isAutoStake     -->  data0 [207:200]\n    */\n    event StakeStart(\n        uint256 data0,\n        address indexed stakerAddr,\n        uint40 indexed stakeId\n    );\n\n    /*  StakeGoodAccounting(auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        address  indexed  stakerAddr\n        uint40   indexed  stakeId\n        uint72            stakedHearts    -->  data0 [111: 40]\n        uint72            stakeShares     -->  data0 [183:112]\n        uint72            payout          -->  data0 [255:184]\n        uint72            penalty         -->  data1 [ 71:  0]\n        address  indexed  senderAddr\n    */\n    event StakeGoodAccounting(\n        uint256 data0,\n        uint256 data1,\n        address indexed stakerAddr,\n        uint40 indexed stakeId,\n        address indexed senderAddr\n    );\n\n    /*  StakeEnd          (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        address  indexed  stakerAddr\n        uint40   indexed  stakeId\n        uint72            stakedHearts    -->  data0 [111: 40]\n        uint72            stakeShares     -->  data0 [183:112]\n        uint72            payout          -->  data0 [255:184]\n        uint72            penalty         -->  data1 [ 71:  0]\n        uint16            servedDays      -->  data1 [ 87: 72]\n        bool              prevUnlocked    -->  data1 [ 95: 88]\n    */\n    event StakeEnd(\n        uint256 data0,\n        uint256 data1,\n        address indexed stakerAddr,\n        uint40 indexed stakeId\n    );\n\n    /*  ShareRateChange   (auto-generated event)\n\n        uint40            timestamp       -->  data0 [ 39:  0]\n        uint40            shareRate       -->  data0 [ 79: 40]\n        uint40   indexed  stakeId\n    */\n    event ShareRateChange(\n        uint256 data0,\n        uint40 indexed stakeId\n    );\n\n    /* Origin address */\n    address internal constant ORIGIN_ADDR = 0x9A6a414D6F3497c05E3b1De90520765fA1E07c03;\n\n    /* Flush address */\n    address payable internal constant FLUSH_ADDR = 0xDEC9f2793e3c17cd26eeFb21C4762fA5128E0399;\n\n    /* ERC20 constants */\n    string public constant name = \"HEX\";\n    string public constant symbol = \"HEX\";\n    uint8 public constant decimals = 8;\n\n    /* Hearts per Satoshi = 10,000 * 1e8 / 1e8 = 1e4 */\n    uint256 private constant HEARTS_PER_HEX = 10 ** uint256(decimals); // 1e8\n    uint256 private constant HEX_PER_BTC = 1e4;\n    uint256 private constant SATOSHIS_PER_BTC = 1e8;\n    uint256 internal constant HEARTS_PER_SATOSHI = HEARTS_PER_HEX / SATOSHIS_PER_BTC * HEX_PER_BTC;\n\n    /* Time of contract launch (2019-12-03T00:00:00Z) */\n    uint256 internal constant LAUNCH_TIME = 1575331200;\n\n    /* Size of a Hearts or Shares uint */\n    uint256 internal constant HEART_UINT_SIZE = 72;\n\n    /* Size of a transform lobby entry index uint */\n    uint256 internal constant XF_LOBBY_ENTRY_INDEX_SIZE = 40;\n    uint256 internal constant XF_LOBBY_ENTRY_INDEX_MASK = (1 << XF_LOBBY_ENTRY_INDEX_SIZE) - 1;\n\n    /* Seed for WAAS Lobby */\n    uint256 internal constant WAAS_LOBBY_SEED_HEX = 1e9;\n    uint256 internal constant WAAS_LOBBY_SEED_HEARTS = WAAS_LOBBY_SEED_HEX * HEARTS_PER_HEX;\n\n    /* Start of claim phase */\n    uint256 internal constant PRE_CLAIM_DAYS = 1;\n    uint256 internal constant CLAIM_PHASE_START_DAY = PRE_CLAIM_DAYS;\n\n    /* Length of claim phase */\n    uint256 private constant CLAIM_PHASE_WEEKS = 50;\n    uint256 internal constant CLAIM_PHASE_DAYS = CLAIM_PHASE_WEEKS * 7;\n\n    /* End of claim phase */\n    uint256 internal constant CLAIM_PHASE_END_DAY = CLAIM_PHASE_START_DAY + CLAIM_PHASE_DAYS;\n\n    /* Number of words to hold 1 bit for each transform lobby day */\n    uint256 internal constant XF_LOBBY_DAY_WORDS = (CLAIM_PHASE_END_DAY + 255) >> 8;\n\n    /* BigPayDay */\n    uint256 internal constant BIG_PAY_DAY = CLAIM_PHASE_END_DAY + 1;\n\n    /* Root hash of the UTXO Merkle tree */\n    bytes32 internal constant MERKLE_TREE_ROOT = 0x4e831acb4223b66de3b3d2e54a2edeefb0de3d7916e2886a4b134d9764d41bec;\n\n    /* Size of a Satoshi claim uint in a Merkle leaf */\n    uint256 internal constant MERKLE_LEAF_SATOSHI_SIZE = 45;\n\n    /* Zero-fill between BTC address and Satoshis in a Merkle leaf */\n    uint256 internal constant MERKLE_LEAF_FILL_SIZE = 256 - 160 - MERKLE_LEAF_SATOSHI_SIZE;\n    uint256 internal constant MERKLE_LEAF_FILL_BASE = (1 << MERKLE_LEAF_FILL_SIZE) - 1;\n    uint256 internal constant MERKLE_LEAF_FILL_MASK = MERKLE_LEAF_FILL_BASE << MERKLE_LEAF_SATOSHI_SIZE;\n\n    /* Size of a Satoshi total uint */\n    uint256 internal constant SATOSHI_UINT_SIZE = 51;\n    uint256 internal constant SATOSHI_UINT_MASK = (1 << SATOSHI_UINT_SIZE) - 1;\n\n    /* Total Satoshis from all BTC addresses in UTXO snapshot */\n    uint256 internal constant FULL_SATOSHIS_TOTAL = 1807766732160668;\n\n    /* Total Satoshis from supported BTC addresses in UTXO snapshot after applying Silly Whale */\n    uint256 internal constant CLAIMABLE_SATOSHIS_TOTAL = 910087996911001;\n\n    /* Number of claimable BTC addresses in UTXO snapshot */\n    uint256 internal constant CLAIMABLE_BTC_ADDR_COUNT = 27997742;\n\n    /* Largest BTC address Satoshis balance in UTXO snapshot (sanity check) */\n    uint256 internal constant MAX_BTC_ADDR_BALANCE_SATOSHIS = 25550214098481;\n\n    /* Percentage of total claimed Hearts that will be auto-staked from a claim */\n    uint256 internal constant AUTO_STAKE_CLAIM_PERCENT = 90;\n\n    /* Stake timing parameters */\n    uint256 internal constant MIN_STAKE_DAYS = 1;\n    uint256 internal constant MIN_AUTO_STAKE_DAYS = 350;\n\n    uint256 internal constant MAX_STAKE_DAYS = 5555; // Approx 15 years\n\n    uint256 internal constant EARLY_PENALTY_MIN_DAYS = 90;\n\n    uint256 private constant LATE_PENALTY_GRACE_WEEKS = 2;\n    uint256 internal constant LATE_PENALTY_GRACE_DAYS = LATE_PENALTY_GRACE_WEEKS * 7;\n\n    uint256 private constant LATE_PENALTY_SCALE_WEEKS = 100;\n    uint256 internal constant LATE_PENALTY_SCALE_DAYS = LATE_PENALTY_SCALE_WEEKS * 7;\n\n    /* Stake shares Longer Pays Better bonus constants used by _stakeStartBonusHearts() */\n    uint256 private constant LPB_BONUS_PERCENT = 20;\n    uint256 private constant LPB_BONUS_MAX_PERCENT = 200;\n    uint256 internal constant LPB = 364 * 100 / LPB_BONUS_PERCENT;\n    uint256 internal constant LPB_MAX_DAYS = LPB * LPB_BONUS_MAX_PERCENT / 100;\n\n    /* Stake shares Bigger Pays Better bonus constants used by _stakeStartBonusHearts() */\n    uint256 private constant BPB_BONUS_PERCENT = 10;\n    uint256 private constant BPB_MAX_HEX = 150 * 1e6;\n    uint256 internal constant BPB_MAX_HEARTS = BPB_MAX_HEX * HEARTS_PER_HEX;\n    uint256 internal constant BPB = BPB_MAX_HEARTS * 100 / BPB_BONUS_PERCENT;\n\n    /* Share rate is scaled to increase precision */\n    uint256 internal constant SHARE_RATE_SCALE = 1e5;\n\n    /* Share rate max (after scaling) */\n    uint256 internal constant SHARE_RATE_UINT_SIZE = 40;\n    uint256 internal constant SHARE_RATE_MAX = (1 << SHARE_RATE_UINT_SIZE) - 1;\n\n    /* Constants for preparing the claim message text */\n    uint8 internal constant ETH_ADDRESS_BYTE_LEN = 20;\n    uint8 internal constant ETH_ADDRESS_HEX_LEN = ETH_ADDRESS_BYTE_LEN * 2;\n\n    uint8 internal constant CLAIM_PARAM_HASH_BYTE_LEN = 12;\n    uint8 internal constant CLAIM_PARAM_HASH_HEX_LEN = CLAIM_PARAM_HASH_BYTE_LEN * 2;\n\n    uint8 internal constant BITCOIN_SIG_PREFIX_LEN = 24;\n    bytes24 internal constant BITCOIN_SIG_PREFIX_STR = \"Bitcoin Signed Message:\\n\";\n\n    bytes internal constant STD_CLAIM_PREFIX_STR = \"Claim_HEX_to_0x\";\n    bytes internal constant OLD_CLAIM_PREFIX_STR = \"Claim_BitcoinHEX_to_0x\";\n\n    bytes16 internal constant HEX_DIGITS = \"0123456789abcdef\";\n\n    /* Claim flags passed to btcAddressClaim()  */\n    uint8 internal constant CLAIM_FLAG_MSG_PREFIX_OLD = 1 << 0;\n    uint8 internal constant CLAIM_FLAG_BTC_ADDR_COMPRESSED = 1 << 1;\n    uint8 internal constant CLAIM_FLAG_BTC_ADDR_P2WPKH_IN_P2SH = 1 << 2;\n    uint8 internal constant CLAIM_FLAG_BTC_ADDR_BECH32 = 1 << 3;\n    uint8 internal constant CLAIM_FLAG_ETH_ADDR_LOWERCASE = 1 << 4;\n\n    /* Globals expanded for memory (except _latestStakeId) and compact for storage */\n    struct GlobalsCache {\n        // 1\n        uint256 _lockedHeartsTotal;\n        uint256 _nextStakeSharesTotal;\n        uint256 _shareRate;\n        uint256 _stakePenaltyTotal;\n        // 2\n        uint256 _dailyDataCount;\n        uint256 _stakeSharesTotal;\n        uint40 _latestStakeId;\n        uint256 _unclaimedSatoshisTotal;\n        uint256 _claimedSatoshisTotal;\n        uint256 _claimedBtcAddrCount;\n        //\n        uint256 _currentDay;\n    }\n\n    struct GlobalsStore {\n        // 1\n        uint72 lockedHeartsTotal;\n        uint72 nextStakeSharesTotal;\n        uint40 shareRate;\n        uint72 stakePenaltyTotal;\n        // 2\n        uint16 dailyDataCount;\n        uint72 stakeSharesTotal;\n        uint40 latestStakeId;\n        uint128 claimStats;\n    }\n\n    GlobalsStore public globals;\n\n    /* Claimed BTC addresses */\n    mapping(bytes20 => bool) public btcAddressClaims;\n\n    /* Daily data */\n    struct DailyDataStore {\n        uint72 dayPayoutTotal;\n        uint72 dayStakeSharesTotal;\n        uint56 dayUnclaimedSatoshisTotal;\n    }\n\n    mapping(uint256 => DailyDataStore) public dailyData;\n\n    /* Stake expanded for memory (except _stakeId) and compact for storage */\n    struct StakeCache {\n        uint40 _stakeId;\n        uint256 _stakedHearts;\n        uint256 _stakeShares;\n        uint256 _lockedDay;\n        uint256 _stakedDays;\n        uint256 _unlockedDay;\n        bool _isAutoStake;\n    }\n\n    struct StakeStore {\n        uint40 stakeId;\n        uint72 stakedHearts;\n        uint72 stakeShares;\n        uint16 lockedDay;\n        uint16 stakedDays;\n        uint16 unlockedDay;\n        bool isAutoStake;\n    }\n\n    mapping(address => StakeStore[]) public stakeLists;\n\n    /* Temporary state for calculating daily rounds */\n    struct DailyRoundState {\n        uint256 _allocSupplyCached;\n        uint256 _mintOriginBatch;\n        uint256 _payoutTotal;\n    }\n\n    struct XfLobbyEntryStore {\n        uint96 rawAmount;\n        address referrerAddr;\n    }\n\n    struct XfLobbyQueueStore {\n        uint40 headIndex;\n        uint40 tailIndex;\n        mapping(uint256 => XfLobbyEntryStore) entries;\n    }\n\n    mapping(uint256 => uint256) public xfLobby;\n    mapping(uint256 => mapping(address => XfLobbyQueueStore)) public xfLobbyMembers;\n\n    /**\n     * @dev PUBLIC FACING: Optionally update daily data for a smaller\n     * range to reduce gas cost for a subsequent operation\n     * @param beforeDay Only update days before this day number (optional; 0 for current day)\n     */\n    function dailyDataUpdate(uint256 beforeDay)\n        external\n    {\n        GlobalsCache memory g;\n        GlobalsCache memory gSnapshot;\n        _globalsLoad(g, gSnapshot);\n\n        /* Skip pre-claim period */\n        require(g._currentDay > CLAIM_PHASE_START_DAY, \"HEX: Too early\");\n\n        if (beforeDay != 0) {\n            require(beforeDay <= g._currentDay, \"HEX: beforeDay cannot be in the future\");\n\n            _dailyDataUpdate(g, beforeDay, false);\n        } else {\n            /* Default to updating before current day */\n            _dailyDataUpdate(g, g._currentDay, false);\n        }\n\n        _globalsSync(g, gSnapshot);\n    }\n\n    /**\n     * @dev PUBLIC FACING: External helper to return multiple values of daily data with\n     * a single call. Ugly implementation due to limitations of the standard ABI encoder.\n     * @param beginDay First day of data range\n     * @param endDay Last day (non-inclusive) of data range\n     * @return Fixed array of packed values\n     */\n    function dailyDataRange(uint256 beginDay, uint256 endDay)\n        external\n        view\n        returns (uint256[] memory list)\n    {\n        require(beginDay < endDay && endDay <= globals.dailyDataCount, \"HEX: range invalid\");\n\n        list = new uint256[](endDay - beginDay);\n\n        uint256 src = beginDay;\n        uint256 dst = 0;\n        uint256 v;\n        do {\n            v = uint256(dailyData[src].dayUnclaimedSatoshisTotal) << (HEART_UINT_SIZE * 2);\n            v |= uint256(dailyData[src].dayStakeSharesTotal) << HEART_UINT_SIZE;\n            v |= uint256(dailyData[src].dayPayoutTotal);\n\n            list[dst++] = v;\n        } while (++src < endDay);\n\n        return list;\n    }\n\n    /**\n     * @dev PUBLIC FACING: External helper to return most global info with a single call.\n     * Ugly implementation due to limitations of the standard ABI encoder.\n     * @return Fixed array of values\n     */\n    function globalInfo()\n        external\n        view\n        returns (uint256[13] memory)\n    {\n        uint256 _claimedBtcAddrCount;\n        uint256 _claimedSatoshisTotal;\n        uint256 _unclaimedSatoshisTotal;\n\n        (_claimedBtcAddrCount, _claimedSatoshisTotal, _unclaimedSatoshisTotal) = _claimStatsDecode(\n            globals.claimStats\n        );\n\n        return [\n            // 1\n            globals.lockedHeartsTotal,\n            globals.nextStakeSharesTotal,\n            globals.shareRate,\n            globals.stakePenaltyTotal,\n            // 2\n            globals.dailyDataCount,\n            globals.stakeSharesTotal,\n            globals.latestStakeId,\n            _unclaimedSatoshisTotal,\n            _claimedSatoshisTotal,\n            _claimedBtcAddrCount,\n            //\n            block.timestamp,\n            totalSupply(),\n            xfLobby[_currentDay()]\n        ];\n    }\n\n    /**\n     * @dev PUBLIC FACING: ERC20 totalSupply() is the circulating supply and does not include any\n     * staked Hearts. allocatedSupply() includes both.\n     * @return Allocated Supply in Hearts\n     */\n    function allocatedSupply()\n        external\n        view\n        returns (uint256)\n    {\n        return totalSupply() + globals.lockedHeartsTotal;\n    }\n\n    /**\n     * @dev PUBLIC FACING: External helper for the current day number since launch time\n     * @return Current day number (zero-based)\n     */\n    function currentDay()\n        external\n        view\n        returns (uint256)\n    {\n        return _currentDay();\n    }\n\n    function _currentDay()\n        internal\n        view\n        returns (uint256)\n    {\n        return (block.timestamp - LAUNCH_TIME) / 1 days;\n    }\n\n    function _dailyDataUpdateAuto(GlobalsCache memory g)\n        internal\n    {\n        _dailyDataUpdate(g, g._currentDay, true);\n    }\n\n    function _globalsLoad(GlobalsCache memory g, GlobalsCache memory gSnapshot)\n        internal\n        view\n    {\n        // 1\n        g._lockedHeartsTotal = globals.lockedHeartsTotal;\n        g._nextStakeSharesTotal = globals.nextStakeSharesTotal;\n        g._shareRate = globals.shareRate;\n        g._stakePenaltyTotal = globals.stakePenaltyTotal;\n        // 2\n        g._dailyDataCount = globals.dailyDataCount;\n        g._stakeSharesTotal = globals.stakeSharesTotal;\n        g._latestStakeId = globals.latestStakeId;\n        (g._claimedBtcAddrCount, g._claimedSatoshisTotal, g._unclaimedSatoshisTotal) = _claimStatsDecode(\n            globals.claimStats\n        );\n        //\n        g._currentDay = _currentDay();\n\n        _globalsCacheSnapshot(g, gSnapshot);\n    }\n\n    function _globalsCacheSnapshot(GlobalsCache memory g, GlobalsCache memory gSnapshot)\n        internal\n        pure\n    {\n        // 1\n        gSnapshot._lockedHeartsTotal = g._lockedHeartsTotal;\n        gSnapshot._nextStakeSharesTotal = g._nextStakeSharesTotal;\n        gSnapshot._shareRate = g._shareRate;\n        gSnapshot._stakePenaltyTotal = g._stakePenaltyTotal;\n        // 2\n        gSnapshot._dailyDataCount = g._dailyDataCount;\n        gSnapshot._stakeSharesTotal = g._stakeSharesTotal;\n        gSnapshot._latestStakeId = g._latestStakeId;\n        gSnapshot._unclaimedSatoshisTotal = g._unclaimedSatoshisTotal;\n        gSnapshot._claimedSatoshisTotal = g._claimedSatoshisTotal;\n        gSnapshot._claimedBtcAddrCount = g._claimedBtcAddrCount;\n    }\n\n    function _globalsSync(GlobalsCache memory g, GlobalsCache memory gSnapshot)\n        internal\n    {\n        if (g._lockedHeartsTotal != gSnapshot._lockedHeartsTotal\n            || g._nextStakeSharesTotal != gSnapshot._nextStakeSharesTotal\n            || g._shareRate != gSnapshot._shareRate\n            || g._stakePenaltyTotal != gSnapshot._stakePenaltyTotal) {\n            // 1\n            globals.lockedHeartsTotal = uint72(g._lockedHeartsTotal);\n            globals.nextStakeSharesTotal = uint72(g._nextStakeSharesTotal);\n            globals.shareRate = uint40(g._shareRate);\n            globals.stakePenaltyTotal = uint72(g._stakePenaltyTotal);\n        }\n        if (g._dailyDataCount != gSnapshot._dailyDataCount\n            || g._stakeSharesTotal != gSnapshot._stakeSharesTotal\n            || g._latestStakeId != gSnapshot._latestStakeId\n            || g._unclaimedSatoshisTotal != gSnapshot._unclaimedSatoshisTotal\n            || g._claimedSatoshisTotal != gSnapshot._claimedSatoshisTotal\n            || g._claimedBtcAddrCount != gSnapshot._claimedBtcAddrCount) {\n            // 2\n            globals.dailyDataCount = uint16(g._dailyDataCount);\n            globals.stakeSharesTotal = uint72(g._stakeSharesTotal);\n            globals.latestStakeId = g._latestStakeId;\n            globals.claimStats = _claimStatsEncode(\n                g._claimedBtcAddrCount,\n                g._claimedSatoshisTotal,\n                g._unclaimedSatoshisTotal\n            );\n        }\n    }\n\n    function _stakeLoad(StakeStore storage stRef, uint40 stakeIdParam, StakeCache memory st)\n        internal\n        view\n    {\n        /* Ensure caller's stakeIndex is still current */\n        require(stakeIdParam == stRef.stakeId, \"HEX: stakeIdParam not in stake\");\n\n        st._stakeId = stRef.stakeId;\n        st._stakedHearts = stRef.stakedHearts;\n        st._stakeShares = stRef.stakeShares;\n        st._lockedDay = stRef.lockedDay;\n        st._stakedDays = stRef.stakedDays;\n        st._unlockedDay = stRef.unlockedDay;\n        st._isAutoStake = stRef.isAutoStake;\n    }\n\n    function _stakeUpdate(StakeStore storage stRef, StakeCache memory st)\n        internal\n    {\n        stRef.stakeId = st._stakeId;\n        stRef.stakedHearts = uint72(st._stakedHearts);\n        stRef.stakeShares = uint72(st._stakeShares);\n        stRef.lockedDay = uint16(st._lockedDay);\n        stRef.stakedDays = uint16(st._stakedDays);\n        stRef.unlockedDay = uint16(st._unlockedDay);\n        stRef.isAutoStake = st._isAutoStake;\n    }\n\n    function _stakeAdd(\n        StakeStore[] storage stakeListRef,\n        uint40 newStakeId,\n        uint256 newStakedHearts,\n        uint256 newStakeShares,\n        uint256 newLockedDay,\n        uint256 newStakedDays,\n        bool newAutoStake\n    )\n        internal\n    {\n        stakeListRef.push(\n            StakeStore(\n                newStakeId,\n                uint72(newStakedHearts),\n                uint72(newStakeShares),\n                uint16(newLockedDay),\n                uint16(newStakedDays),\n                uint16(0), // unlockedDay\n                newAutoStake\n            )\n        );\n    }\n\n    /**\n     * @dev Efficiently delete from an unordered array by moving the last element\n     * to the \"hole\" and reducing the array length. Can change the order of the list\n     * and invalidate previously held indexes.\n     * @notice stakeListRef length and stakeIndex are already ensured valid in stakeEnd()\n     * @param stakeListRef Reference to stakeLists[stakerAddr] array in storage\n     * @param stakeIndex Index of the element to delete\n     */\n    function _stakeRemove(StakeStore[] storage stakeListRef, uint256 stakeIndex)\n        internal\n    {\n        uint256 lastIndex = stakeListRef.length - 1;\n\n        /* Skip the copy if element to be removed is already the last element */\n        if (stakeIndex != lastIndex) {\n            /* Copy last element to the requested element's \"hole\" */\n            stakeListRef[stakeIndex] = stakeListRef[lastIndex];\n        }\n\n        /*\n            Reduce the array length now that the array is contiguous.\n            Surprisingly, 'pop()' uses less gas than 'stakeListRef.length = lastIndex'\n        */\n        stakeListRef.pop();\n    }\n\n    function _claimStatsEncode(\n        uint256 _claimedBtcAddrCount,\n        uint256 _claimedSatoshisTotal,\n        uint256 _unclaimedSatoshisTotal\n    )\n        internal\n        pure\n        returns (uint128)\n    {\n        uint256 v = _claimedBtcAddrCount << (SATOSHI_UINT_SIZE * 2);\n        v |= _claimedSatoshisTotal << SATOSHI_UINT_SIZE;\n        v |= _unclaimedSatoshisTotal;\n\n        return uint128(v);\n    }\n\n    function _claimStatsDecode(uint128 v)\n        internal\n        pure\n        returns (uint256 _claimedBtcAddrCount, uint256 _claimedSatoshisTotal, uint256 _unclaimedSatoshisTotal)\n    {\n        _claimedBtcAddrCount = v >> (SATOSHI_UINT_SIZE * 2);\n        _claimedSatoshisTotal = (v >> SATOSHI_UINT_SIZE) & SATOSHI_UINT_MASK;\n        _unclaimedSatoshisTotal = v & SATOSHI_UINT_MASK;\n\n        return (_claimedBtcAddrCount, _claimedSatoshisTotal, _unclaimedSatoshisTotal);\n    }\n\n    /**\n     * @dev Estimate the stake payout for an incomplete day\n     * @param g Cache of stored globals\n     * @param stakeSharesParam Param from stake to calculate bonuses for\n     * @param day Day to calculate bonuses for\n     * @return Payout in Hearts\n     */\n    function _estimatePayoutRewardsDay(GlobalsCache memory g, uint256 stakeSharesParam, uint256 day)\n        internal\n        view\n        returns (uint256 payout)\n    {\n        /* Prevent updating state for this estimation */\n        GlobalsCache memory gTmp;\n        _globalsCacheSnapshot(g, gTmp);\n\n        DailyRoundState memory rs;\n        rs._allocSupplyCached = totalSupply() + g._lockedHeartsTotal;\n\n        _dailyRoundCalc(gTmp, rs, day);\n\n        /* Stake is no longer locked so it must be added to total as if it were */\n        gTmp._stakeSharesTotal += stakeSharesParam;\n\n        payout = rs._payoutTotal * stakeSharesParam / gTmp._stakeSharesTotal;\n\n        if (day == BIG_PAY_DAY) {\n            uint256 bigPaySlice = gTmp._unclaimedSatoshisTotal * HEARTS_PER_SATOSHI * stakeSharesParam\n                / gTmp._stakeSharesTotal;\n            payout += bigPaySlice + _calcAdoptionBonus(gTmp, bigPaySlice);\n        }\n\n        return payout;\n    }\n\n    function _calcAdoptionBonus(GlobalsCache memory g, uint256 payout)\n        internal\n        pure\n        returns (uint256)\n    {\n        /*\n            VIRAL REWARDS: Add adoption percentage bonus to payout\n\n            viral = payout * (claimedBtcAddrCount / CLAIMABLE_BTC_ADDR_COUNT)\n        */\n        uint256 viral = payout * g._claimedBtcAddrCount / CLAIMABLE_BTC_ADDR_COUNT;\n\n        /*\n            CRIT MASS REWARDS: Add adoption percentage bonus to payout\n\n            crit  = payout * (claimedSatoshisTotal / CLAIMABLE_SATOSHIS_TOTAL)\n        */\n        uint256 crit = payout * g._claimedSatoshisTotal / CLAIMABLE_SATOSHIS_TOTAL;\n\n        return viral + crit;\n    }\n\n    function _dailyRoundCalc(GlobalsCache memory g, DailyRoundState memory rs, uint256 day)\n        private\n        pure\n    {\n        /*\n            Calculate payout round\n\n            Inflation of 3.69% inflation per 364 days             (approx 1 year)\n            dailyInterestRate   = exp(log(1 + 3.69%)  / 364) - 1\n                                = exp(log(1 + 0.0369) / 364) - 1\n                                = exp(log(1.0369) / 364) - 1\n                                = 0.000099553011616349            (approx)\n\n            payout  = allocSupply * dailyInterestRate\n                    = allocSupply / (1 / dailyInterestRate)\n                    = allocSupply / (1 / 0.000099553011616349)\n                    = allocSupply / 10044.899534066692            (approx)\n                    = allocSupply * 10000 / 100448995             (* 10000/10000 for int precision)\n        */\n        rs._payoutTotal = rs._allocSupplyCached * 10000 / 100448995;\n\n        if (day < CLAIM_PHASE_END_DAY) {\n            uint256 bigPaySlice = g._unclaimedSatoshisTotal * HEARTS_PER_SATOSHI / CLAIM_PHASE_DAYS;\n\n            uint256 originBonus = bigPaySlice + _calcAdoptionBonus(g, rs._payoutTotal + bigPaySlice);\n            rs._mintOriginBatch += originBonus;\n            rs._allocSupplyCached += originBonus;\n\n            rs._payoutTotal += _calcAdoptionBonus(g, rs._payoutTotal);\n        }\n\n        if (g._stakePenaltyTotal != 0) {\n            rs._payoutTotal += g._stakePenaltyTotal;\n            g._stakePenaltyTotal = 0;\n        }\n    }\n\n    function _dailyRoundCalcAndStore(GlobalsCache memory g, DailyRoundState memory rs, uint256 day)\n        private\n    {\n        _dailyRoundCalc(g, rs, day);\n\n        dailyData[day].dayPayoutTotal = uint72(rs._payoutTotal);\n        dailyData[day].dayStakeSharesTotal = uint72(g._stakeSharesTotal);\n        dailyData[day].dayUnclaimedSatoshisTotal = uint56(g._unclaimedSatoshisTotal);\n    }\n\n    function _dailyDataUpdate(GlobalsCache memory g, uint256 beforeDay, bool isAutoUpdate)\n        private\n    {\n        if (g._dailyDataCount >= beforeDay) {\n            /* Already up-to-date */\n            return;\n        }\n\n        DailyRoundState memory rs;\n        rs._allocSupplyCached = totalSupply() + g._lockedHeartsTotal;\n\n        uint256 day = g._dailyDataCount;\n\n        _dailyRoundCalcAndStore(g, rs, day);\n\n        /* Stakes started during this day are added to the total the next day */\n        if (g._nextStakeSharesTotal != 0) {\n            g._stakeSharesTotal += g._nextStakeSharesTotal;\n            g._nextStakeSharesTotal = 0;\n        }\n\n        while (++day < beforeDay) {\n            _dailyRoundCalcAndStore(g, rs, day);\n        }\n\n        _emitDailyDataUpdate(g._dailyDataCount, day, isAutoUpdate);\n        g._dailyDataCount = day;\n\n        if (rs._mintOriginBatch != 0) {\n            _mint(ORIGIN_ADDR, rs._mintOriginBatch);\n        }\n    }\n\n    function _emitDailyDataUpdate(uint256 beginDay, uint256 endDay, bool isAutoUpdate)\n        private\n    {\n        emit DailyDataUpdate( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint16(beginDay)) << 40)\n                | (uint256(uint16(endDay)) << 56)\n                | (isAutoUpdate ? (1 << 72) : 0),\n            msg.sender\n        );\n    }\n}\n\ncontract StakeableToken is GlobalsAndUtility {\n    /**\n     * @dev PUBLIC FACING: Open a stake.\n     * @param newStakedHearts Number of Hearts to stake\n     * @param newStakedDays Number of days to stake\n     */\n    function stakeStart(uint256 newStakedHearts, uint256 newStakedDays)\n        external\n    {\n        GlobalsCache memory g;\n        GlobalsCache memory gSnapshot;\n        _globalsLoad(g, gSnapshot);\n\n        /* Enforce the minimum stake time */\n        require(newStakedDays >= MIN_STAKE_DAYS, \"HEX: newStakedDays lower than minimum\");\n\n        /* Check if log data needs to be updated */\n        _dailyDataUpdateAuto(g);\n\n        _stakeStart(g, newStakedHearts, newStakedDays, false);\n\n        /* Remove staked Hearts from balance of staker */\n        _burn(msg.sender, newStakedHearts);\n\n        _globalsSync(g, gSnapshot);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Unlocks a completed stake, distributing the proceeds of any penalty\n     * immediately. The staker must still call stakeEnd() to retrieve their stake return (if any).\n     * @param stakerAddr Address of staker\n     * @param stakeIndex Index of stake within stake list\n     * @param stakeIdParam The stake's id\n     */\n    function stakeGoodAccounting(address stakerAddr, uint256 stakeIndex, uint40 stakeIdParam)\n        external\n    {\n        GlobalsCache memory g;\n        GlobalsCache memory gSnapshot;\n        _globalsLoad(g, gSnapshot);\n\n        /* require() is more informative than the default assert() */\n        require(stakeLists[stakerAddr].length != 0, \"HEX: Empty stake list\");\n        require(stakeIndex < stakeLists[stakerAddr].length, \"HEX: stakeIndex invalid\");\n\n        StakeStore storage stRef = stakeLists[stakerAddr][stakeIndex];\n\n        /* Get stake copy */\n        StakeCache memory st;\n        _stakeLoad(stRef, stakeIdParam, st);\n\n        /* Stake must have served full term */\n        require(g._currentDay >= st._lockedDay + st._stakedDays, \"HEX: Stake not fully served\");\n\n        /* Stake must still be locked */\n        require(st._unlockedDay == 0, \"HEX: Stake already unlocked\");\n\n        /* Check if log data needs to be updated */\n        _dailyDataUpdateAuto(g);\n\n        /* Unlock the completed stake */\n        _stakeUnlock(g, st);\n\n        /* stakeReturn value is unused here */\n        (, uint256 payout, uint256 penalty, uint256 cappedPenalty) = _stakePerformance(\n            g,\n            st,\n            st._stakedDays\n        );\n\n        _emitStakeGoodAccounting(\n            stakerAddr,\n            stakeIdParam,\n            st._stakedHearts,\n            st._stakeShares,\n            payout,\n            penalty\n        );\n\n        if (cappedPenalty != 0) {\n            _splitPenaltyProceeds(g, cappedPenalty);\n        }\n\n        /* st._unlockedDay has changed */\n        _stakeUpdate(stRef, st);\n\n        _globalsSync(g, gSnapshot);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Closes a stake. The order of the stake list can change so\n     * a stake id is used to reject stale indexes.\n     * @param stakeIndex Index of stake within stake list\n     * @param stakeIdParam The stake's id\n     */\n    function stakeEnd(uint256 stakeIndex, uint40 stakeIdParam)\n        external\n    {\n        GlobalsCache memory g;\n        GlobalsCache memory gSnapshot;\n        _globalsLoad(g, gSnapshot);\n\n        StakeStore[] storage stakeListRef = stakeLists[msg.sender];\n\n        /* require() is more informative than the default assert() */\n        require(stakeListRef.length != 0, \"HEX: Empty stake list\");\n        require(stakeIndex < stakeListRef.length, \"HEX: stakeIndex invalid\");\n\n        /* Get stake copy */\n        StakeCache memory st;\n        _stakeLoad(stakeListRef[stakeIndex], stakeIdParam, st);\n\n        /* Check if log data needs to be updated */\n        _dailyDataUpdateAuto(g);\n\n        uint256 servedDays = 0;\n\n        bool prevUnlocked = (st._unlockedDay != 0);\n        uint256 stakeReturn;\n        uint256 payout = 0;\n        uint256 penalty = 0;\n        uint256 cappedPenalty = 0;\n\n        if (g._currentDay >= st._lockedDay) {\n            if (prevUnlocked) {\n                /* Previously unlocked in stakeGoodAccounting(), so must have served full term */\n                servedDays = st._stakedDays;\n            } else {\n                _stakeUnlock(g, st);\n\n                servedDays = g._currentDay - st._lockedDay;\n                if (servedDays > st._stakedDays) {\n                    servedDays = st._stakedDays;\n                } else {\n                    /* Deny early-unstake before an auto-stake minimum has been served */\n                    if (servedDays < MIN_AUTO_STAKE_DAYS) {\n                        require(!st._isAutoStake, \"HEX: Auto-stake still locked\");\n                    }\n                }\n            }\n\n            (stakeReturn, payout, penalty, cappedPenalty) = _stakePerformance(g, st, servedDays);\n        } else {\n            /* Deny early-unstake before an auto-stake minimum has been served */\n            require(!st._isAutoStake, \"HEX: Auto-stake still locked\");\n\n            /* Stake hasn't been added to the total yet, so no penalties or rewards apply */\n            g._nextStakeSharesTotal -= st._stakeShares;\n\n            stakeReturn = st._stakedHearts;\n        }\n\n        _emitStakeEnd(\n            stakeIdParam,\n            st._stakedHearts,\n            st._stakeShares,\n            payout,\n            penalty,\n            servedDays,\n            prevUnlocked\n        );\n\n        if (cappedPenalty != 0 && !prevUnlocked) {\n            /* Split penalty proceeds only if not previously unlocked by stakeGoodAccounting() */\n            _splitPenaltyProceeds(g, cappedPenalty);\n        }\n\n        /* Pay the stake return, if any, to the staker */\n        if (stakeReturn != 0) {\n            _mint(msg.sender, stakeReturn);\n\n            /* Update the share rate if necessary */\n            _shareRateUpdate(g, st, stakeReturn);\n        }\n        g._lockedHeartsTotal -= st._stakedHearts;\n\n        _stakeRemove(stakeListRef, stakeIndex);\n\n        _globalsSync(g, gSnapshot);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Return the current stake count for a staker address\n     * @param stakerAddr Address of staker\n     */\n    function stakeCount(address stakerAddr)\n        external\n        view\n        returns (uint256)\n    {\n        return stakeLists[stakerAddr].length;\n    }\n\n    /**\n     * @dev Open a stake.\n     * @param g Cache of stored globals\n     * @param newStakedHearts Number of Hearts to stake\n     * @param newStakedDays Number of days to stake\n     * @param newAutoStake Stake is automatic directly from a new claim\n     */\n    function _stakeStart(\n        GlobalsCache memory g,\n        uint256 newStakedHearts,\n        uint256 newStakedDays,\n        bool newAutoStake\n    )\n        internal\n    {\n        /* Enforce the maximum stake time */\n        require(newStakedDays <= MAX_STAKE_DAYS, \"HEX: newStakedDays higher than maximum\");\n\n        uint256 bonusHearts = _stakeStartBonusHearts(newStakedHearts, newStakedDays);\n        uint256 newStakeShares = (newStakedHearts + bonusHearts) * SHARE_RATE_SCALE / g._shareRate;\n\n        /* Ensure newStakedHearts is enough for at least one stake share */\n        require(newStakeShares != 0, \"HEX: newStakedHearts must be at least minimum shareRate\");\n\n        /*\n            The stakeStart timestamp will always be part-way through the current\n            day, so it needs to be rounded-up to the next day to ensure all\n            stakes align with the same fixed calendar days. The current day is\n            already rounded-down, so rounded-up is current day + 1.\n        */\n        uint256 newLockedDay = g._currentDay < CLAIM_PHASE_START_DAY\n            ? CLAIM_PHASE_START_DAY + 1\n            : g._currentDay + 1;\n\n        /* Create Stake */\n        uint40 newStakeId = ++g._latestStakeId;\n        _stakeAdd(\n            stakeLists[msg.sender],\n            newStakeId,\n            newStakedHearts,\n            newStakeShares,\n            newLockedDay,\n            newStakedDays,\n            newAutoStake\n        );\n\n        _emitStakeStart(newStakeId, newStakedHearts, newStakeShares, newStakedDays, newAutoStake);\n\n        /* Stake is added to total in the next round, not the current round */\n        g._nextStakeSharesTotal += newStakeShares;\n\n        /* Track total staked Hearts for inflation calculations */\n        g._lockedHeartsTotal += newStakedHearts;\n    }\n\n    /**\n     * @dev Calculates total stake payout including rewards for a multi-day range\n     * @param g Cache of stored globals\n     * @param stakeSharesParam Param from stake to calculate bonuses for\n     * @param beginDay First day to calculate bonuses for\n     * @param endDay Last day (non-inclusive) of range to calculate bonuses for\n     * @return Payout in Hearts\n     */\n    function _calcPayoutRewards(\n        GlobalsCache memory g,\n        uint256 stakeSharesParam,\n        uint256 beginDay,\n        uint256 endDay\n    )\n        private\n        view\n        returns (uint256 payout)\n    {\n        for (uint256 day = beginDay; day < endDay; day++) {\n            payout += dailyData[day].dayPayoutTotal * stakeSharesParam\n                / dailyData[day].dayStakeSharesTotal;\n        }\n\n        /* Less expensive to re-read storage than to have the condition inside the loop */\n        if (beginDay <= BIG_PAY_DAY && endDay > BIG_PAY_DAY) {\n            uint256 bigPaySlice = g._unclaimedSatoshisTotal * HEARTS_PER_SATOSHI * stakeSharesParam\n                / dailyData[BIG_PAY_DAY].dayStakeSharesTotal;\n\n            payout += bigPaySlice + _calcAdoptionBonus(g, bigPaySlice);\n        }\n        return payout;\n    }\n\n    /**\n     * @dev Calculate bonus Hearts for a new stake, if any\n     * @param newStakedHearts Number of Hearts to stake\n     * @param newStakedDays Number of days to stake\n     */\n    function _stakeStartBonusHearts(uint256 newStakedHearts, uint256 newStakedDays)\n        private\n        pure\n        returns (uint256 bonusHearts)\n    {\n        /*\n            LONGER PAYS BETTER:\n\n            If longer than 1 day stake is committed to, each extra day\n            gives bonus shares of approximately 0.0548%, which is approximately 20%\n            extra per year of increased stake length committed to, but capped to a\n            maximum of 200% extra.\n\n            extraDays       =  stakedDays - 1\n\n            longerBonus%    = (extraDays / 364) * 20%\n                            = (extraDays / 364) / 5\n                            =  extraDays / 1820\n                            =  extraDays / LPB\n\n            extraDays       =  longerBonus% * 1820\n            extraDaysMax    =  longerBonusMax% * 1820\n                            =  200% * 1820\n                            =  3640\n                            =  LPB_MAX_DAYS\n\n            BIGGER PAYS BETTER:\n\n            Bonus percentage scaled 0% to 10% for the first 150M HEX of stake.\n\n            biggerBonus%    = (cappedHearts /  BPB_MAX_HEARTS) * 10%\n                            = (cappedHearts /  BPB_MAX_HEARTS) / 10\n                            =  cappedHearts / (BPB_MAX_HEARTS * 10)\n                            =  cappedHearts /  BPB\n\n            COMBINED:\n\n            combinedBonus%  =            longerBonus%  +  biggerBonus%\n\n                                      cappedExtraDays     cappedHearts\n                            =         ---------------  +  ------------\n                                            LPB               BPB\n\n                                cappedExtraDays * BPB     cappedHearts * LPB\n                            =   ---------------------  +  ------------------\n                                      LPB * BPB               LPB * BPB\n\n                                cappedExtraDays * BPB  +  cappedHearts * LPB\n                            =   --------------------------------------------\n                                                  LPB  *  BPB\n\n            bonusHearts     = hearts * combinedBonus%\n                            = hearts * (cappedExtraDays * BPB  +  cappedHearts * LPB) / (LPB * BPB)\n        */\n        uint256 cappedExtraDays = 0;\n\n        /* Must be more than 1 day for Longer-Pays-Better */\n        if (newStakedDays > 1) {\n            cappedExtraDays = newStakedDays <= LPB_MAX_DAYS ? newStakedDays - 1 : LPB_MAX_DAYS;\n        }\n\n        uint256 cappedStakedHearts = newStakedHearts <= BPB_MAX_HEARTS\n            ? newStakedHearts\n            : BPB_MAX_HEARTS;\n\n        bonusHearts = cappedExtraDays * BPB + cappedStakedHearts * LPB;\n        bonusHearts = newStakedHearts * bonusHearts / (LPB * BPB);\n\n        return bonusHearts;\n    }\n\n    function _stakeUnlock(GlobalsCache memory g, StakeCache memory st)\n        private\n        pure\n    {\n        g._stakeSharesTotal -= st._stakeShares;\n        st._unlockedDay = g._currentDay;\n    }\n\n    function _stakePerformance(GlobalsCache memory g, StakeCache memory st, uint256 servedDays)\n        private\n        view\n        returns (uint256 stakeReturn, uint256 payout, uint256 penalty, uint256 cappedPenalty)\n    {\n        if (servedDays < st._stakedDays) {\n            (payout, penalty) = _calcPayoutAndEarlyPenalty(\n                g,\n                st._lockedDay,\n                st._stakedDays,\n                servedDays,\n                st._stakeShares\n            );\n            stakeReturn = st._stakedHearts + payout;\n        } else {\n            // servedDays must == stakedDays here\n            payout = _calcPayoutRewards(\n                g,\n                st._stakeShares,\n                st._lockedDay,\n                st._lockedDay + servedDays\n            );\n            stakeReturn = st._stakedHearts + payout;\n\n            penalty = _calcLatePenalty(st._lockedDay, st._stakedDays, st._unlockedDay, stakeReturn);\n        }\n        if (penalty != 0) {\n            if (penalty > stakeReturn) {\n                /* Cannot have a negative stake return */\n                cappedPenalty = stakeReturn;\n                stakeReturn = 0;\n            } else {\n                /* Remove penalty from the stake return */\n                cappedPenalty = penalty;\n                stakeReturn -= cappedPenalty;\n            }\n        }\n        return (stakeReturn, payout, penalty, cappedPenalty);\n    }\n\n    function _calcPayoutAndEarlyPenalty(\n        GlobalsCache memory g,\n        uint256 lockedDayParam,\n        uint256 stakedDaysParam,\n        uint256 servedDays,\n        uint256 stakeSharesParam\n    )\n        private\n        view\n        returns (uint256 payout, uint256 penalty)\n    {\n        uint256 servedEndDay = lockedDayParam + servedDays;\n\n        /* 50% of stakedDays (rounded up) with a minimum applied */\n        uint256 penaltyDays = (stakedDaysParam + 1) / 2;\n        if (penaltyDays < EARLY_PENALTY_MIN_DAYS) {\n            penaltyDays = EARLY_PENALTY_MIN_DAYS;\n        }\n\n        if (servedDays == 0) {\n            /* Fill penalty days with the estimated average payout */\n            uint256 expected = _estimatePayoutRewardsDay(g, stakeSharesParam, lockedDayParam);\n            penalty = expected * penaltyDays;\n            return (payout, penalty); // Actual payout was 0\n        }\n\n        if (penaltyDays < servedDays) {\n            /*\n                Simplified explanation of intervals where end-day is non-inclusive:\n\n                penalty:    [lockedDay  ...  penaltyEndDay)\n                delta:                      [penaltyEndDay  ...  servedEndDay)\n                payout:     [lockedDay  .......................  servedEndDay)\n            */\n            uint256 penaltyEndDay = lockedDayParam + penaltyDays;\n            penalty = _calcPayoutRewards(g, stakeSharesParam, lockedDayParam, penaltyEndDay);\n\n            uint256 delta = _calcPayoutRewards(g, stakeSharesParam, penaltyEndDay, servedEndDay);\n            payout = penalty + delta;\n            return (payout, penalty);\n        }\n\n        /* penaltyDays >= servedDays  */\n        payout = _calcPayoutRewards(g, stakeSharesParam, lockedDayParam, servedEndDay);\n\n        if (penaltyDays == servedDays) {\n            penalty = payout;\n        } else {\n            /*\n                (penaltyDays > servedDays) means not enough days served, so fill the\n                penalty days with the average payout from only the days that were served.\n            */\n            penalty = payout * penaltyDays / servedDays;\n        }\n        return (payout, penalty);\n    }\n\n    function _calcLatePenalty(\n        uint256 lockedDayParam,\n        uint256 stakedDaysParam,\n        uint256 unlockedDayParam,\n        uint256 rawStakeReturn\n    )\n        private\n        pure\n        returns (uint256)\n    {\n        /* Allow grace time before penalties accrue */\n        uint256 maxUnlockedDay = lockedDayParam + stakedDaysParam + LATE_PENALTY_GRACE_DAYS;\n        if (unlockedDayParam <= maxUnlockedDay) {\n            return 0;\n        }\n\n        /* Calculate penalty as a percentage of stake return based on time */\n        return rawStakeReturn * (unlockedDayParam - maxUnlockedDay) / LATE_PENALTY_SCALE_DAYS;\n    }\n\n    function _splitPenaltyProceeds(GlobalsCache memory g, uint256 penalty)\n        private\n    {\n        /* Split a penalty 50:50 between Origin and stakePenaltyTotal */\n        uint256 splitPenalty = penalty / 2;\n\n        if (splitPenalty != 0) {\n            _mint(ORIGIN_ADDR, splitPenalty);\n        }\n\n        /* Use the other half of the penalty to account for an odd-numbered penalty */\n        splitPenalty = penalty - splitPenalty;\n        g._stakePenaltyTotal += splitPenalty;\n    }\n\n    function _shareRateUpdate(GlobalsCache memory g, StakeCache memory st, uint256 stakeReturn)\n        private\n    {\n        if (stakeReturn > st._stakedHearts) {\n            /*\n                Calculate the new shareRate that would yield the same number of shares if\n                the user re-staked this stakeReturn, factoring in any bonuses they would\n                receive in stakeStart().\n            */\n            uint256 bonusHearts = _stakeStartBonusHearts(stakeReturn, st._stakedDays);\n            uint256 newShareRate = (stakeReturn + bonusHearts) * SHARE_RATE_SCALE / st._stakeShares;\n\n            if (newShareRate > SHARE_RATE_MAX) {\n                /*\n                    Realistically this can't happen, but there are contrived theoretical\n                    scenarios that can lead to extreme values of newShareRate, so it is\n                    capped to prevent them anyway.\n                */\n                newShareRate = SHARE_RATE_MAX;\n            }\n\n            if (newShareRate > g._shareRate) {\n                g._shareRate = newShareRate;\n\n                _emitShareRateChange(newShareRate, st._stakeId);\n            }\n        }\n    }\n\n    function _emitStakeStart(\n        uint40 stakeId,\n        uint256 stakedHearts,\n        uint256 stakeShares,\n        uint256 stakedDays,\n        bool isAutoStake\n    )\n        private\n    {\n        emit StakeStart( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint72(stakedHearts)) << 40)\n                | (uint256(uint72(stakeShares)) << 112)\n                | (uint256(uint16(stakedDays)) << 184)\n                | (isAutoStake ? (1 << 200) : 0),\n            msg.sender,\n            stakeId\n        );\n    }\n\n    function _emitStakeGoodAccounting(\n        address stakerAddr,\n        uint40 stakeId,\n        uint256 stakedHearts,\n        uint256 stakeShares,\n        uint256 payout,\n        uint256 penalty\n    )\n        private\n    {\n        emit StakeGoodAccounting( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint72(stakedHearts)) << 40)\n                | (uint256(uint72(stakeShares)) << 112)\n                | (uint256(uint72(payout)) << 184),\n            uint256(uint72(penalty)),\n            stakerAddr,\n            stakeId,\n            msg.sender\n        );\n    }\n\n    function _emitStakeEnd(\n        uint40 stakeId,\n        uint256 stakedHearts,\n        uint256 stakeShares,\n        uint256 payout,\n        uint256 penalty,\n        uint256 servedDays,\n        bool prevUnlocked\n    )\n        private\n    {\n        emit StakeEnd( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint72(stakedHearts)) << 40)\n                | (uint256(uint72(stakeShares)) << 112)\n                | (uint256(uint72(payout)) << 184),\n            uint256(uint72(penalty))\n                | (uint256(uint16(servedDays)) << 72)\n                | (prevUnlocked ? (1 << 88) : 0),\n            msg.sender,\n            stakeId\n        );\n    }\n\n    function _emitShareRateChange(uint256 shareRate, uint40 stakeId)\n        private\n    {\n        emit ShareRateChange( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint40(shareRate)) << 40),\n            stakeId\n        );\n    }\n}\n\n/**\n * @dev These functions deal with verification of Merkle trees (hash trees),\n */\nlibrary MerkleProof {\n    /**\n     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree\n     * defined by `root`. For this, a `proof` must be provided, containing\n     * sibling hashes on the branch from the leaf to the root of the tree. Each\n     * pair of leaves and each pair of pre-images are assumed to be sorted.\n     */\n    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {\n        bytes32 computedHash = leaf;\n\n        for (uint256 i = 0; i < proof.length; i++) {\n            bytes32 proofElement = proof[i];\n\n            if (computedHash < proofElement) {\n                // Hash(current computed hash + current element of the proof)\n                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));\n            } else {\n                // Hash(current element of the proof + current computed hash)\n                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));\n            }\n        }\n\n        // Check if the computed hash (root) is equal to the provided root\n        return computedHash == root;\n    }\n}\n\ncontract UTXOClaimValidation is StakeableToken {\n    /**\n     * @dev PUBLIC FACING: Verify a BTC address and balance are unclaimed and part of the Merkle tree\n     * @param btcAddr Bitcoin address (binary; no base58-check encoding)\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @param proof Merkle tree proof\n     * @return True if can be claimed\n     */\n    function btcAddressIsClaimable(bytes20 btcAddr, uint256 rawSatoshis, bytes32[] calldata proof)\n        external\n        view\n        returns (bool)\n    {\n        uint256 day = _currentDay();\n\n        require(day >= CLAIM_PHASE_START_DAY, \"HEX: Claim phase has not yet started\");\n        require(day < CLAIM_PHASE_END_DAY, \"HEX: Claim phase has ended\");\n\n        /* Don't need to check Merkle proof if UTXO BTC address has already been claimed    */\n        if (btcAddressClaims[btcAddr]) {\n            return false;\n        }\n\n        /* Verify the Merkle tree proof */\n        return _btcAddressIsValid(btcAddr, rawSatoshis, proof);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Verify a BTC address and balance are part of the Merkle tree\n     * @param btcAddr Bitcoin address (binary; no base58-check encoding)\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @param proof Merkle tree proof\n     * @return True if valid\n     */\n    function btcAddressIsValid(bytes20 btcAddr, uint256 rawSatoshis, bytes32[] calldata proof)\n        external\n        pure\n        returns (bool)\n    {\n        return _btcAddressIsValid(btcAddr, rawSatoshis, proof);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Verify a Merkle proof using the UTXO Merkle tree\n     * @param merkleLeaf Leaf asserted to be present in the Merkle tree\n     * @param proof Generated Merkle tree proof\n     * @return True if valid\n     */\n    function merkleProofIsValid(bytes32 merkleLeaf, bytes32[] calldata proof)\n        external\n        pure\n        returns (bool)\n    {\n        return _merkleProofIsValid(merkleLeaf, proof);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Verify that a Bitcoin signature matches the claim message containing\n     * the Ethereum address and claim param hash\n     * @param claimToAddr Eth address within the signed claim message\n     * @param claimParamHash Param hash within the signed claim message\n     * @param pubKeyX First  half of uncompressed ECDSA public key\n     * @param pubKeyY Second half of uncompressed ECDSA public key\n     * @param claimFlags Claim flags specifying address and message formats\n     * @param v v parameter of ECDSA signature\n     * @param r r parameter of ECDSA signature\n     * @param s s parameter of ECDSA signature\n     * @return True if matching\n     */\n    function claimMessageMatchesSignature(\n        address claimToAddr,\n        bytes32 claimParamHash,\n        bytes32 pubKeyX,\n        bytes32 pubKeyY,\n        uint8 claimFlags,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    )\n        public\n        pure\n        returns (bool)\n    {\n        require(v >= 27 && v <= 30, \"HEX: v invalid\");\n\n        /*\n            ecrecover() returns an Eth address rather than a public key, so\n            we must do the same to compare.\n        */\n        address pubKeyEthAddr = pubKeyToEthAddress(pubKeyX, pubKeyY);\n\n        /* Create and hash the claim message text */\n        bytes32 messageHash = _hash256(\n            _claimMessageCreate(claimToAddr, claimParamHash, claimFlags)\n        );\n\n        /* Verify the public key */\n        return ecrecover(messageHash, v, r, s) == pubKeyEthAddr;\n    }\n\n    /**\n     * @dev PUBLIC FACING: Derive an Ethereum address from an ECDSA public key\n     * @param pubKeyX First  half of uncompressed ECDSA public key\n     * @param pubKeyY Second half of uncompressed ECDSA public key\n     * @return Derived Eth address\n     */\n    function pubKeyToEthAddress(bytes32 pubKeyX, bytes32 pubKeyY)\n        public\n        pure\n        returns (address)\n    {\n        return address(uint160(uint256(keccak256(abi.encodePacked(pubKeyX, pubKeyY)))));\n    }\n\n    /**\n     * @dev PUBLIC FACING: Derive a Bitcoin address from an ECDSA public key\n     * @param pubKeyX First  half of uncompressed ECDSA public key\n     * @param pubKeyY Second half of uncompressed ECDSA public key\n     * @param claimFlags Claim flags specifying address and message formats\n     * @return Derived Bitcoin address (binary; no base58-check encoding)\n     */\n    function pubKeyToBtcAddress(bytes32 pubKeyX, bytes32 pubKeyY, uint8 claimFlags)\n        public\n        pure\n        returns (bytes20)\n    {\n        /*\n            Helpful references:\n             - https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses\n             - https://github.com/cryptocoinjs/ecurve/blob/master/lib/point.js\n        */\n        uint8 startingByte;\n        bytes memory pubKey;\n        bool compressed = (claimFlags & CLAIM_FLAG_BTC_ADDR_COMPRESSED) != 0;\n        bool nested = (claimFlags & CLAIM_FLAG_BTC_ADDR_P2WPKH_IN_P2SH) != 0;\n        bool bech32 = (claimFlags & CLAIM_FLAG_BTC_ADDR_BECH32) != 0;\n\n        if (compressed) {\n            /* Compressed public key format */\n            require(!(nested && bech32), \"HEX: claimFlags invalid\");\n\n            startingByte = (pubKeyY[31] & 0x01) == 0 ? 0x02 : 0x03;\n            pubKey = abi.encodePacked(startingByte, pubKeyX);\n        } else {\n            /* Uncompressed public key format */\n            require(!nested && !bech32, \"HEX: claimFlags invalid\");\n\n            startingByte = 0x04;\n            pubKey = abi.encodePacked(startingByte, pubKeyX, pubKeyY);\n        }\n\n        bytes20 pubKeyHash = _hash160(pubKey);\n        if (nested) {\n            return _hash160(abi.encodePacked(hex\"0014\", pubKeyHash));\n        }\n        return pubKeyHash;\n    }\n\n    /**\n     * @dev Verify a BTC address and balance are part of the Merkle tree\n     * @param btcAddr Bitcoin address (binary; no base58-check encoding)\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @param proof Merkle tree proof\n     * @return True if valid\n     */\n    function _btcAddressIsValid(bytes20 btcAddr, uint256 rawSatoshis, bytes32[] memory proof)\n        internal\n        pure\n        returns (bool)\n    {\n        /*\n            Ensure the proof does not attempt to treat a Merkle leaf as if it were an\n            internal Merkle tree node. A leaf will always have the zero-fill. An\n            internal node will never have the zero-fill, as guaranteed by HEX's Merkle\n            tree construction.\n\n            The first element, proof[0], will always be a leaf because it is the pair\n            of the leaf being validated. The rest of the elements, proof[1..length-1],\n            must be internal nodes.\n\n            The number of leaves (CLAIMABLE_BTC_ADDR_COUNT) is even, as guaranteed by\n            HEX's Merkle tree construction, which eliminates the only edge-case where\n            this validation would not apply.\n        */\n        require((uint256(proof[0]) & MERKLE_LEAF_FILL_MASK) == 0, \"HEX: proof invalid\");\n        for (uint256 i = 1; i < proof.length; i++) {\n            require((uint256(proof[i]) & MERKLE_LEAF_FILL_MASK) != 0, \"HEX: proof invalid\");\n        }\n\n        /*\n            Calculate the 32 byte Merkle leaf associated with this BTC address and balance\n                160 bits: BTC address\n                 52 bits: Zero-fill\n                 45 bits: Satoshis (limited by MAX_BTC_ADDR_BALANCE_SATOSHIS)\n        */\n        bytes32 merkleLeaf = bytes32(btcAddr) | bytes32(rawSatoshis);\n\n        /* Verify the Merkle tree proof */\n        return _merkleProofIsValid(merkleLeaf, proof);\n    }\n\n    /**\n     * @dev Verify a Merkle proof using the UTXO Merkle tree\n     * @param merkleLeaf Leaf asserted to be present in the Merkle tree\n     * @param proof Generated Merkle tree proof\n     * @return True if valid\n     */\n    function _merkleProofIsValid(bytes32 merkleLeaf, bytes32[] memory proof)\n        private\n        pure\n        returns (bool)\n    {\n        return MerkleProof.verify(proof, MERKLE_TREE_ROOT, merkleLeaf);\n    }\n\n    function _claimMessageCreate(address claimToAddr, bytes32 claimParamHash, uint8 claimFlags)\n        private\n        pure\n        returns (bytes memory)\n    {\n        bytes memory prefixStr = (claimFlags & CLAIM_FLAG_MSG_PREFIX_OLD) != 0\n            ? OLD_CLAIM_PREFIX_STR\n            : STD_CLAIM_PREFIX_STR;\n\n        bool includeAddrChecksum = (claimFlags & CLAIM_FLAG_ETH_ADDR_LOWERCASE) == 0;\n\n        bytes memory addrStr = _addressStringCreate(claimToAddr, includeAddrChecksum);\n\n        if (claimParamHash == 0) {\n            return abi.encodePacked(\n                BITCOIN_SIG_PREFIX_LEN,\n                BITCOIN_SIG_PREFIX_STR,\n                uint8(prefixStr.length) + ETH_ADDRESS_HEX_LEN,\n                prefixStr,\n                addrStr\n            );\n        }\n\n        bytes memory claimParamHashStr = new bytes(CLAIM_PARAM_HASH_HEX_LEN);\n\n        _hexStringFromData(claimParamHashStr, claimParamHash, CLAIM_PARAM_HASH_BYTE_LEN);\n\n        return abi.encodePacked(\n            BITCOIN_SIG_PREFIX_LEN,\n            BITCOIN_SIG_PREFIX_STR,\n            uint8(prefixStr.length) + ETH_ADDRESS_HEX_LEN + 1 + CLAIM_PARAM_HASH_HEX_LEN,\n            prefixStr,\n            addrStr,\n            \"_\",\n            claimParamHashStr\n        );\n    }\n\n    function _addressStringCreate(address addr, bool includeAddrChecksum)\n        private\n        pure\n        returns (bytes memory addrStr)\n    {\n        addrStr = new bytes(ETH_ADDRESS_HEX_LEN);\n        _hexStringFromData(addrStr, bytes32(bytes20(addr)), ETH_ADDRESS_BYTE_LEN);\n\n        if (includeAddrChecksum) {\n            bytes32 addrStrHash = keccak256(addrStr);\n\n            uint256 offset = 0;\n\n            for (uint256 i = 0; i < ETH_ADDRESS_BYTE_LEN; i++) {\n                uint8 b = uint8(addrStrHash[i]);\n\n                _addressStringChecksumChar(addrStr, offset++, b >> 4);\n                _addressStringChecksumChar(addrStr, offset++, b & 0x0f);\n            }\n        }\n\n        return addrStr;\n    }\n\n    function _addressStringChecksumChar(bytes memory addrStr, uint256 offset, uint8 hashNybble)\n        private\n        pure\n    {\n        bytes1 ch = addrStr[offset];\n\n        if (ch >= \"a\" && hashNybble >= 8) {\n            addrStr[offset] = ch ^ 0x20;\n        }\n    }\n\n    function _hexStringFromData(bytes memory hexStr, bytes32 data, uint256 dataLen)\n        private\n        pure\n    {\n        uint256 offset = 0;\n\n        for (uint256 i = 0; i < dataLen; i++) {\n            uint8 b = uint8(data[i]);\n\n            hexStr[offset++] = HEX_DIGITS[b >> 4];\n            hexStr[offset++] = HEX_DIGITS[b & 0x0f];\n        }\n    }\n\n    /**\n     * @dev sha256(sha256(data))\n     * @param data Data to be hashed\n     * @return 32-byte hash\n     */\n    function _hash256(bytes memory data)\n        private\n        pure\n        returns (bytes32)\n    {\n        return sha256(abi.encodePacked(sha256(data)));\n    }\n\n    /**\n     * @dev ripemd160(sha256(data))\n     * @param data Data to be hashed\n     * @return 20-byte hash\n     */\n    function _hash160(bytes memory data)\n        private\n        pure\n        returns (bytes20)\n    {\n        return ripemd160(abi.encodePacked(sha256(data)));\n    }\n}\n\ncontract UTXORedeemableToken is UTXOClaimValidation {\n    /**\n     * @dev PUBLIC FACING: Claim a BTC address and its Satoshi balance in Hearts\n     * crediting the appropriate amount to a specified Eth address. Bitcoin ECDSA\n     * signature must be from that BTC address and must match the claim message\n     * for the Eth address.\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @param proof Merkle tree proof\n     * @param claimToAddr Destination Eth address to credit Hearts to\n     * @param pubKeyX First  half of uncompressed ECDSA public key for the BTC address\n     * @param pubKeyY Second half of uncompressed ECDSA public key for the BTC address\n     * @param claimFlags Claim flags specifying address and message formats\n     * @param v v parameter of ECDSA signature\n     * @param r r parameter of ECDSA signature\n     * @param s s parameter of ECDSA signature\n     * @param autoStakeDays Number of days to auto-stake, subject to minimum auto-stake days\n     * @param referrerAddr Eth address of referring user (optional; 0x0 for no referrer)\n     * @return Total number of Hearts credited, if successful\n     */\n    function btcAddressClaim(\n        uint256 rawSatoshis,\n        bytes32[] calldata proof,\n        address claimToAddr,\n        bytes32 pubKeyX,\n        bytes32 pubKeyY,\n        uint8 claimFlags,\n        uint8 v,\n        bytes32 r,\n        bytes32 s,\n        uint256 autoStakeDays,\n        address referrerAddr\n    )\n        external\n        returns (uint256)\n    {\n        /* Sanity check */\n        require(rawSatoshis <= MAX_BTC_ADDR_BALANCE_SATOSHIS, \"HEX: CHK: rawSatoshis\");\n\n        /* Enforce the minimum stake time for the auto-stake from this claim */\n        require(autoStakeDays >= MIN_AUTO_STAKE_DAYS, \"HEX: autoStakeDays lower than minimum\");\n\n        /* Ensure signature matches the claim message containing the Eth address and claimParamHash */\n        {\n            bytes32 claimParamHash = 0;\n\n            if (claimToAddr != msg.sender) {\n                /* Claimer did not send this, so claim params must be signed */\n                claimParamHash = keccak256(\n                    abi.encodePacked(MERKLE_TREE_ROOT, autoStakeDays, referrerAddr)\n                );\n            }\n\n            require(\n                claimMessageMatchesSignature(\n                    claimToAddr,\n                    claimParamHash,\n                    pubKeyX,\n                    pubKeyY,\n                    claimFlags,\n                    v,\n                    r,\n                    s\n                ),\n                \"HEX: Signature mismatch\"\n            );\n        }\n\n        /* Derive BTC address from public key */\n        bytes20 btcAddr = pubKeyToBtcAddress(pubKeyX, pubKeyY, claimFlags);\n\n        /* Ensure BTC address has not yet been claimed */\n        require(!btcAddressClaims[btcAddr], \"HEX: BTC address balance already claimed\");\n\n        /* Ensure BTC address is part of the Merkle tree */\n        require(\n            _btcAddressIsValid(btcAddr, rawSatoshis, proof),\n            \"HEX: BTC address or balance unknown\"\n        );\n\n        /* Mark BTC address as claimed */\n        btcAddressClaims[btcAddr] = true;\n\n        return _satoshisClaimSync(\n            rawSatoshis,\n            claimToAddr,\n            btcAddr,\n            claimFlags,\n            autoStakeDays,\n            referrerAddr\n        );\n    }\n\n    function _satoshisClaimSync(\n        uint256 rawSatoshis,\n        address claimToAddr,\n        bytes20 btcAddr,\n        uint8 claimFlags,\n        uint256 autoStakeDays,\n        address referrerAddr\n    )\n        private\n        returns (uint256 totalClaimedHearts)\n    {\n        GlobalsCache memory g;\n        GlobalsCache memory gSnapshot;\n        _globalsLoad(g, gSnapshot);\n\n        totalClaimedHearts = _satoshisClaim(\n            g,\n            rawSatoshis,\n            claimToAddr,\n            btcAddr,\n            claimFlags,\n            autoStakeDays,\n            referrerAddr\n        );\n\n        _globalsSync(g, gSnapshot);\n\n        return totalClaimedHearts;\n    }\n\n    /**\n     * @dev Credit an Eth address with the Hearts value of a raw Satoshis balance\n     * @param g Cache of stored globals\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @param claimToAddr Destination Eth address for the claimed Hearts to be sent\n     * @param btcAddr Bitcoin address (binary; no base58-check encoding)\n     * @param autoStakeDays Number of days to auto-stake, subject to minimum auto-stake days\n     * @param referrerAddr Eth address of referring user (optional; 0x0 for no referrer)\n     * @return Total number of Hearts credited, if successful\n     */\n    function _satoshisClaim(\n        GlobalsCache memory g,\n        uint256 rawSatoshis,\n        address claimToAddr,\n        bytes20 btcAddr,\n        uint8 claimFlags,\n        uint256 autoStakeDays,\n        address referrerAddr\n    )\n        private\n        returns (uint256 totalClaimedHearts)\n    {\n        /* Allowed only during the claim phase */\n        require(g._currentDay >= CLAIM_PHASE_START_DAY, \"HEX: Claim phase has not yet started\");\n        require(g._currentDay < CLAIM_PHASE_END_DAY, \"HEX: Claim phase has ended\");\n\n        /* Check if log data needs to be updated */\n        _dailyDataUpdateAuto(g);\n\n        /* Sanity check */\n        require(\n            g._claimedBtcAddrCount < CLAIMABLE_BTC_ADDR_COUNT,\n            \"HEX: CHK: _claimedBtcAddrCount\"\n        );\n\n        (uint256 adjSatoshis, uint256 claimedHearts, uint256 claimBonusHearts) = _calcClaimValues(\n            g,\n            rawSatoshis\n        );\n\n        /* Increment claim count to track viral rewards */\n        g._claimedBtcAddrCount++;\n\n        totalClaimedHearts = _remitBonuses(\n            claimToAddr,\n            btcAddr,\n            claimFlags,\n            rawSatoshis,\n            adjSatoshis,\n            claimedHearts,\n            claimBonusHearts,\n            referrerAddr\n        );\n\n        /* Auto-stake a percentage of the successful claim */\n        uint256 autoStakeHearts = totalClaimedHearts * AUTO_STAKE_CLAIM_PERCENT / 100;\n        _stakeStart(g, autoStakeHearts, autoStakeDays, true);\n\n        /* Mint remaining claimed Hearts to claim address */\n        _mint(claimToAddr, totalClaimedHearts - autoStakeHearts);\n\n        return totalClaimedHearts;\n    }\n\n    function _remitBonuses(\n        address claimToAddr,\n        bytes20 btcAddr,\n        uint8 claimFlags,\n        uint256 rawSatoshis,\n        uint256 adjSatoshis,\n        uint256 claimedHearts,\n        uint256 claimBonusHearts,\n        address referrerAddr\n    )\n        private\n        returns (uint256 totalClaimedHearts)\n    {\n        totalClaimedHearts = claimedHearts + claimBonusHearts;\n\n        uint256 originBonusHearts = claimBonusHearts;\n\n        if (referrerAddr == address(0)) {\n            /* No referrer */\n            _emitClaim(\n                claimToAddr,\n                btcAddr,\n                claimFlags,\n                rawSatoshis,\n                adjSatoshis,\n                totalClaimedHearts,\n                referrerAddr\n            );\n        } else {\n            /* Referral bonus of 10% of total claimed Hearts to claimer */\n            uint256 referralBonusHearts = totalClaimedHearts / 10;\n\n            totalClaimedHearts += referralBonusHearts;\n\n            /* Then a cumulative referrer bonus of 20% to referrer */\n            uint256 referrerBonusHearts = totalClaimedHearts / 5;\n\n            originBonusHearts += referralBonusHearts + referrerBonusHearts;\n\n            if (referrerAddr == claimToAddr) {\n                /* Self-referred */\n                totalClaimedHearts += referrerBonusHearts;\n                _emitClaim(\n                    claimToAddr,\n                    btcAddr,\n                    claimFlags,\n                    rawSatoshis,\n                    adjSatoshis,\n                    totalClaimedHearts,\n                    referrerAddr\n                );\n            } else {\n                /* Referred by different address */\n                _emitClaim(\n                    claimToAddr,\n                    btcAddr,\n                    claimFlags,\n                    rawSatoshis,\n                    adjSatoshis,\n                    totalClaimedHearts,\n                    referrerAddr\n                );\n                _mint(referrerAddr, referrerBonusHearts);\n            }\n        }\n\n        _mint(ORIGIN_ADDR, originBonusHearts);\n\n        return totalClaimedHearts;\n    }\n\n    function _emitClaim(\n        address claimToAddr,\n        bytes20 btcAddr,\n        uint8 claimFlags,\n        uint256 rawSatoshis,\n        uint256 adjSatoshis,\n        uint256 claimedHearts,\n        address referrerAddr\n    )\n        private\n    {\n        emit Claim( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint56(rawSatoshis)) << 40)\n                | (uint256(uint56(adjSatoshis)) << 96)\n                | (uint256(claimFlags) << 152)\n                | (uint256(uint72(claimedHearts)) << 160),\n            uint256(uint160(msg.sender)),\n            btcAddr,\n            claimToAddr,\n            referrerAddr\n        );\n\n        if (claimToAddr == msg.sender) {\n            return;\n        }\n\n        emit ClaimAssist( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint160(btcAddr)) << 40)\n                | (uint256(uint56(rawSatoshis)) << 200),\n            uint256(uint56(adjSatoshis))\n                | (uint256(uint160(claimToAddr)) << 56)\n                | (uint256(claimFlags) << 216),\n            uint256(uint72(claimedHearts))\n                | (uint256(uint160(referrerAddr)) << 72),\n            msg.sender\n        );\n    }\n\n    function _calcClaimValues(GlobalsCache memory g, uint256 rawSatoshis)\n        private\n        pure\n        returns (uint256 adjSatoshis, uint256 claimedHearts, uint256 claimBonusHearts)\n    {\n        /* Apply Silly Whale reduction */\n        adjSatoshis = _adjustSillyWhale(rawSatoshis);\n        require(\n            g._claimedSatoshisTotal + adjSatoshis <= CLAIMABLE_SATOSHIS_TOTAL,\n            \"HEX: CHK: _claimedSatoshisTotal\"\n        );\n        g._claimedSatoshisTotal += adjSatoshis;\n\n        uint256 daysRemaining = CLAIM_PHASE_END_DAY - g._currentDay;\n\n        /* Apply late-claim reduction */\n        adjSatoshis = _adjustLateClaim(adjSatoshis, daysRemaining);\n        g._unclaimedSatoshisTotal -= adjSatoshis;\n\n        /* Convert to Hearts and calculate speed bonus */\n        claimedHearts = adjSatoshis * HEARTS_PER_SATOSHI;\n        claimBonusHearts = _calcSpeedBonus(claimedHearts, daysRemaining);\n\n        return (adjSatoshis, claimedHearts, claimBonusHearts);\n    }\n\n    /**\n     * @dev Apply Silly Whale adjustment\n     * @param rawSatoshis Raw BTC address balance in Satoshis\n     * @return Adjusted BTC address balance in Satoshis\n     */\n    function _adjustSillyWhale(uint256 rawSatoshis)\n        private\n        pure\n        returns (uint256)\n    {\n        if (rawSatoshis < 1000e8) {\n            /* For < 1,000 BTC: no penalty */\n            return rawSatoshis;\n        }\n        if (rawSatoshis >= 10000e8) {\n            /* For >= 10,000 BTC: penalty is 75%, leaving 25% */\n            return rawSatoshis / 4;\n        }\n        /*\n            For 1,000 <= BTC < 10,000: penalty scales linearly from 50% to 75%\n\n            penaltyPercent  = (btc - 1000) / (10000 - 1000) * (75 - 50) + 50\n                            = (btc - 1000) / 9000 * 25 + 50\n                            = (btc - 1000) / 360 + 50\n\n            appliedPercent  = 100 - penaltyPercent\n                            = 100 - ((btc - 1000) / 360 + 50)\n                            = 100 - (btc - 1000) / 360 - 50\n                            = 50 - (btc - 1000) / 360\n                            = (18000 - (btc - 1000)) / 360\n                            = (18000 - btc + 1000) / 360\n                            = (19000 - btc) / 360\n\n            adjustedBtc     = btc * appliedPercent / 100\n                            = btc * ((19000 - btc) / 360) / 100\n                            = btc * (19000 - btc) / 36000\n\n            adjustedSat     = 1e8 * adjustedBtc\n                            = 1e8 * (btc * (19000 - btc) / 36000)\n                            = 1e8 * ((sat / 1e8) * (19000 - (sat / 1e8)) / 36000)\n                            = 1e8 * (sat / 1e8) * (19000 - (sat / 1e8)) / 36000\n                            = (sat / 1e8) * 1e8 * (19000 - (sat / 1e8)) / 36000\n                            = (sat / 1e8) * (19000e8 - sat) / 36000\n                            = sat * (19000e8 - sat) / 36000e8\n        */\n        return rawSatoshis * (19000e8 - rawSatoshis) / 36000e8;\n    }\n\n    /**\n     * @dev Apply late-claim adjustment to scale claim to zero by end of claim phase\n     * @param adjSatoshis Adjusted BTC address balance in Satoshis (after Silly Whale)\n     * @param daysRemaining Number of reward days remaining in claim phase\n     * @return Adjusted BTC address balance in Satoshis (after Silly Whale and Late-Claim)\n     */\n    function _adjustLateClaim(uint256 adjSatoshis, uint256 daysRemaining)\n        private\n        pure\n        returns (uint256)\n    {\n        /*\n            Only valid from CLAIM_PHASE_DAYS to 1, and only used during that time.\n\n            adjustedSat = sat * (daysRemaining / CLAIM_PHASE_DAYS) * 100%\n                        = sat *  daysRemaining / CLAIM_PHASE_DAYS\n        */\n        return adjSatoshis * daysRemaining / CLAIM_PHASE_DAYS;\n    }\n\n    /**\n     * @dev Calculates speed bonus for claiming earlier in the claim phase\n     * @param claimedHearts Hearts claimed from adjusted BTC address balance Satoshis\n     * @param daysRemaining Number of claim days remaining in claim phase\n     * @return Speed bonus in Hearts\n     */\n    function _calcSpeedBonus(uint256 claimedHearts, uint256 daysRemaining)\n        private\n        pure\n        returns (uint256)\n    {\n        /*\n            Only valid from CLAIM_PHASE_DAYS to 1, and only used during that time.\n            Speed bonus is 20% ... 0% inclusive.\n\n            bonusHearts = claimedHearts  * ((daysRemaining - 1)  /  (CLAIM_PHASE_DAYS - 1)) * 20%\n                        = claimedHearts  * ((daysRemaining - 1)  /  (CLAIM_PHASE_DAYS - 1)) * 20/100\n                        = claimedHearts  * ((daysRemaining - 1)  /  (CLAIM_PHASE_DAYS - 1)) / 5\n                        = claimedHearts  *  (daysRemaining - 1)  / ((CLAIM_PHASE_DAYS - 1)  * 5)\n        */\n        return claimedHearts * (daysRemaining - 1) / ((CLAIM_PHASE_DAYS - 1) * 5);\n    }\n}\n\ncontract TransformableToken is UTXORedeemableToken {\n    /**\n     * @dev PUBLIC FACING: Enter the tranform lobby for the current round\n     * @param referrerAddr Eth address of referring user (optional; 0x0 for no referrer)\n     */\n    function xfLobbyEnter(address referrerAddr)\n        external\n        payable\n    {\n        uint256 enterDay = _currentDay();\n        require(enterDay < CLAIM_PHASE_END_DAY, \"HEX: Lobbies have ended\");\n\n        uint256 rawAmount = msg.value;\n        require(rawAmount != 0, \"HEX: Amount required\");\n\n        XfLobbyQueueStore storage qRef = xfLobbyMembers[enterDay][msg.sender];\n\n        uint256 entryIndex = qRef.tailIndex++;\n\n        qRef.entries[entryIndex] = XfLobbyEntryStore(uint96(rawAmount), referrerAddr);\n\n        xfLobby[enterDay] += rawAmount;\n\n        _emitXfLobbyEnter(enterDay, entryIndex, rawAmount, referrerAddr);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Leave the transform lobby after the round is complete\n     * @param enterDay Day number when the member entered\n     * @param count Number of queued-enters to exit (optional; 0 for all)\n     */\n    function xfLobbyExit(uint256 enterDay, uint256 count)\n        external\n    {\n        require(enterDay < _currentDay(), \"HEX: Round is not complete\");\n\n        XfLobbyQueueStore storage qRef = xfLobbyMembers[enterDay][msg.sender];\n\n        uint256 headIndex = qRef.headIndex;\n        uint256 endIndex;\n\n        if (count != 0) {\n            require(count <= qRef.tailIndex - headIndex, \"HEX: count invalid\");\n            endIndex = headIndex + count;\n        } else {\n            endIndex = qRef.tailIndex;\n            require(headIndex < endIndex, \"HEX: count invalid\");\n        }\n\n        uint256 waasLobby = _waasLobby(enterDay);\n        uint256 _xfLobby = xfLobby[enterDay];\n        uint256 totalXfAmount = 0;\n        uint256 originBonusHearts = 0;\n\n        do {\n            uint256 rawAmount = qRef.entries[headIndex].rawAmount;\n            address referrerAddr = qRef.entries[headIndex].referrerAddr;\n\n            delete qRef.entries[headIndex];\n\n            uint256 xfAmount = waasLobby * rawAmount / _xfLobby;\n\n            if (referrerAddr == address(0)) {\n                /* No referrer */\n                _emitXfLobbyExit(enterDay, headIndex, xfAmount, referrerAddr);\n            } else {\n                /* Referral bonus of 10% of xfAmount to member */\n                uint256 referralBonusHearts = xfAmount / 10;\n\n                xfAmount += referralBonusHearts;\n\n                /* Then a cumulative referrer bonus of 20% to referrer */\n                uint256 referrerBonusHearts = xfAmount / 5;\n\n                if (referrerAddr == msg.sender) {\n                    /* Self-referred */\n                    xfAmount += referrerBonusHearts;\n                    _emitXfLobbyExit(enterDay, headIndex, xfAmount, referrerAddr);\n                } else {\n                    /* Referred by different address */\n                    _emitXfLobbyExit(enterDay, headIndex, xfAmount, referrerAddr);\n                    _mint(referrerAddr, referrerBonusHearts);\n                }\n                originBonusHearts += referralBonusHearts + referrerBonusHearts;\n            }\n\n            totalXfAmount += xfAmount;\n        } while (++headIndex < endIndex);\n\n        qRef.headIndex = uint40(headIndex);\n\n        if (originBonusHearts != 0) {\n            _mint(ORIGIN_ADDR, originBonusHearts);\n        }\n        if (totalXfAmount != 0) {\n            _mint(msg.sender, totalXfAmount);\n        }\n    }\n\n    /**\n     * @dev PUBLIC FACING: Release any value that has been sent to the contract\n     */\n    function xfLobbyFlush()\n        external\n    {\n        require(address(this).balance != 0, \"HEX: No value\");\n\n        FLUSH_ADDR.transfer(address(this).balance);\n    }\n\n    /**\n     * @dev PUBLIC FACING: External helper to return multiple values of xfLobby[] with\n     * a single call\n     * @param beginDay First day of data range\n     * @param endDay Last day (non-inclusive) of data range\n     * @return Fixed array of values\n     */\n    function xfLobbyRange(uint256 beginDay, uint256 endDay)\n        external\n        view\n        returns (uint256[] memory list)\n    {\n        require(\n            beginDay < endDay && endDay <= CLAIM_PHASE_END_DAY && endDay <= _currentDay(),\n            \"HEX: invalid range\"\n        );\n\n        list = new uint256[](endDay - beginDay);\n\n        uint256 src = beginDay;\n        uint256 dst = 0;\n        do {\n            list[dst++] = uint256(xfLobby[src++]);\n        } while (src < endDay);\n\n        return list;\n    }\n\n    /**\n     * @dev PUBLIC FACING: Return a current lobby member queue entry.\n     * Only needed due to limitations of the standard ABI encoder.\n     * @param memberAddr Eth address of the lobby member\n     * @param entryId 49 bit compound value. Top 9 bits: enterDay, Bottom 40 bits: entryIndex\n     * @return 1: Raw amount that was entered with; 2: Referring Eth addr (optional; 0x0 for no referrer)\n     */\n    function xfLobbyEntry(address memberAddr, uint256 entryId)\n        external\n        view\n        returns (uint256 rawAmount, address referrerAddr)\n    {\n        uint256 enterDay = entryId >> XF_LOBBY_ENTRY_INDEX_SIZE;\n        uint256 entryIndex = entryId & XF_LOBBY_ENTRY_INDEX_MASK;\n\n        XfLobbyEntryStore storage entry = xfLobbyMembers[enterDay][memberAddr].entries[entryIndex];\n\n        require(entry.rawAmount != 0, \"HEX: Param invalid\");\n\n        return (entry.rawAmount, entry.referrerAddr);\n    }\n\n    /**\n     * @dev PUBLIC FACING: Return the lobby days that a user is in with a single call\n     * @param memberAddr Eth address of the user\n     * @return Bit vector of lobby day numbers\n     */\n    function xfLobbyPendingDays(address memberAddr)\n        external\n        view\n        returns (uint256[XF_LOBBY_DAY_WORDS] memory words)\n    {\n        uint256 day = _currentDay() + 1;\n\n        if (day > CLAIM_PHASE_END_DAY) {\n            day = CLAIM_PHASE_END_DAY;\n        }\n\n        while (day-- != 0) {\n            if (xfLobbyMembers[day][memberAddr].tailIndex > xfLobbyMembers[day][memberAddr].headIndex) {\n                words[day >> 8] |= 1 << (day & 255);\n            }\n        }\n\n        return words;\n    }\n\n    function _waasLobby(uint256 enterDay)\n        private\n        returns (uint256 waasLobby)\n    {\n        if (enterDay >= CLAIM_PHASE_START_DAY) {\n            GlobalsCache memory g;\n            GlobalsCache memory gSnapshot;\n            _globalsLoad(g, gSnapshot);\n\n            _dailyDataUpdateAuto(g);\n\n            uint256 unclaimed = dailyData[enterDay].dayUnclaimedSatoshisTotal;\n            waasLobby = unclaimed * HEARTS_PER_SATOSHI / CLAIM_PHASE_DAYS;\n\n            _globalsSync(g, gSnapshot);\n        } else {\n            waasLobby = WAAS_LOBBY_SEED_HEARTS;\n        }\n        return waasLobby;\n    }\n\n    function _emitXfLobbyEnter(\n        uint256 enterDay,\n        uint256 entryIndex,\n        uint256 rawAmount,\n        address referrerAddr\n    )\n        private\n    {\n        emit XfLobbyEnter( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint96(rawAmount)) << 40),\n            msg.sender,\n            (enterDay << XF_LOBBY_ENTRY_INDEX_SIZE) | entryIndex,\n            referrerAddr\n        );\n    }\n\n    function _emitXfLobbyExit(\n        uint256 enterDay,\n        uint256 entryIndex,\n        uint256 xfAmount,\n        address referrerAddr\n    )\n        private\n    {\n        emit XfLobbyExit( // (auto-generated event)\n            uint256(uint40(block.timestamp))\n                | (uint256(uint72(xfAmount)) << 40),\n            msg.sender,\n            (enterDay << XF_LOBBY_ENTRY_INDEX_SIZE) | entryIndex,\n            referrerAddr\n        );\n    }\n}\n\ncontract HEX is TransformableToken {\n    constructor()\n        public\n    {\n        /* Initialize global shareRate to 1 */\n        globals.shareRate = uint40(1 * SHARE_RATE_SCALE);\n\n        /* Initialize dailyDataCount to skip pre-claim period */\n        globals.dailyDataCount = uint16(PRE_CLAIM_DAYS);\n\n        /* Add all Satoshis from UTXO snapshot to contract */\n        globals.claimStats = _claimStatsEncode(\n            0, // _claimedBtcAddrCount\n            0, // _claimedSatoshisTotal\n            FULL_SATOSHIS_TOTAL // _unclaimedSatoshisTotal\n        );\n    }\n\n    function() external payable {}\n}","sourcify_repo_url":null,"verified_at":"2024-09-02T02:21:29.281476Z","verified_twin_address_hash":null}