Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x9A1d5103Ef765a3EdE26d5757353DF2Af0dd3856
Balance 0 ETH
Nonce 1
Code Size 16563 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

16563 bytes
0x608060405234801561001057600080fd5b50600436106101d95760003560e01c806387e3dfe211610104578063c211acf2116100a2578063e3adffab11610071578063e3adffab14610405578063e640207714610418578063f550810114610438578063f56033171461044b576101d9565b8063c211acf2146103c4578063c7c13b3a146103d7578063cc297ab1146103ea578063d8359117146103f2576101d9565b8063a834f5b7116100de578063a834f5b714610381578063ad6de44514610396578063b6932914146103a9578063bace1a36146103bc576101d9565b806387e3dfe21461033b5780639c1857d41461035b5780639fa8f0131461036e576101d9565b806338309b851161017c578063470c23821161014b578063470c2382146102de578063497cb411146103005780636f73ae00146103155780638719bfb114610328576101d9565b806338309b85146102755780633a64ebec146102955780633daa551c146102a85780633dd8fe11146102be576101d9565b80630faf728a116101b85780630faf728a14610232578063119577a41461024557806312efe4b31461025a5780632ef3da231461026d576101d9565b806223de29146101de5780630696ecaa146101f35780630a28b8a91461021d575b600080fd5b6101f16101ec36600461324d565b61045e565b005b61020661020136600461340d565b610628565b6040516102149291906137e3565b60405180910390f35b61022561075a565b604051610214919061385c565b6101f1610240366004613394565b610769565b61024d6107e7565b6040516102149190613f48565b6101f1610268366004613231565b61087a565b610225610904565b610288610283366004613231565b610913565b6040516102149190613747565b6101f16102a33660046134c9565b610ae8565b6102b0610c5d565b6040516102149291906136f2565b6102d16102cc3660046133f5565b610cb1565b6040516102149190613ff4565b6102f16102ec366004613231565b610cda565b6040516102149392919061375a565b610308610edf565b60405161021491906136df565b6101f16103233660046133f5565b611044565b6101f16103363660046134c9565b6110f8565b61034e610349366004613359565b611188565b6040516102149190613870565b6101f16103693660046133f5565b611238565b6102d161037c3660046133f5565b611281565b610389611299565b6040516102149190613eba565b6101f16103a4366004613231565b6113ec565b6101f16103b7366004613231565b611473565b6102256114f6565b6101f16103d2366004613470565b611505565b6101f16103e536600461343c565b611559565b6102d161160c565b6101f16104003660046132fb565b611612565b6101f161041336600461331c565b61168e565b61042b6104263660046133f5565b611747565b6040516102149190613691565b6101f16104463660046133f5565b611817565b6101f16104593660046133f5565b61189d565b6002600054141561048a5760405162461bcd60e51b815260040161048190613e4c565b60405180910390fd5b6002600055826104ac5760405162461bcd60e51b815260040161048190613b91565b600080806104bc86880188613491565b919450925090506001600160a01b038a166104e95760405162461bcd60e51b815260040161048190613dd6565b8260051415610501576104fc8a89611988565b610615565b8260041415610514576104fc8a89611bb7565b8260031415610580576000881161053d5760405162461bcd60e51b815260040161048190613c6a565b6022546001600160a01b031633146105675760405162461bcd60e51b815260040161048190613b3b565b6018546105749089611963565b60185550610619915050565b82600214156105ec57600088116105a95760405162461bcd60e51b815260040161048190613c6a565b6023546001600160a01b031633146105d35760405162461bcd60e51b815260040161048190613cbd565b6017546105e09089611963565b60175550610619915050565b826105fd576104fc8a83838b611d86565b60405162461bcd60e51b815260040161048190613d87565b5050505b50506001600055505050505050565b6000610632612eab565b83610653576001600160a01b03831660009081526012602052604090205493505b836106a3576001600160a01b0383161561069e576013546001600160a01b038481169116148061069b57506001600160a01b03831660009081526014602052604090205460ff165b91505b610753565b600084815260116020526040902060018101546013546001600160a01b03908116911614806106ee575060018101546001600160a01b031660009081526014602052604090205460ff165b60018201546001600160a01b0316835260028201546020840152600382015460408401526008820154606084015260098201546080840152600a82015460a0840152600b82015460c0840152600c82015460e0840152600d9091015461010083015291505b9250929050565b6023546001600160a01b031681565b6013546001600160a01b031633148061079157503360009081526014602052604090205460ff165b6107ad5760405162461bcd60e51b815260040161048190613bb7565b806002601f01836040516107c1919061364d565b908152602001604051809103902090805190602001906107e2929190612f00565b505050565b6107ef612f88565b600354815260045460208083019190915260055460408301526010546060830152601554608083015260165460a083015260175460c083015260185460e0830152601954610100830152601a54610120830152601b54610140830152601c54610160830152601d54610180830152601e546101a0830152601f546101c0830152546101e08201525b90565b6013546001600160a01b031633146108a45760405162461bcd60e51b815260040161048190613ab2565b6001600160a01b0381166108ca5760405162461bcd60e51b815260040161048190613a4c565b6013546001600160a01b03828116911614156108e557610901565b601380546001600160a01b0319166001600160a01b0383161790555b50565b6022546001600160a01b031681565b6001600160a01b0381166000908152601260205260409020546060908061093a5750610ae3565b600081815260116020526040812090805b60025481101561097e5760008181526020849052604090206002810154610973908490611963565b92505060010161094b565b508067ffffffffffffffff8111801561099657600080fd5b506040519080825280602002602001820160405280156109d057816020015b6109bd613005565b8152602001906001900390816109b55790505b5093506000805b600254811015610add57600081815260208590526040902060028101546109fe5750610ad5565b6000610a0b600c8361213d565b90505b60408051610120810190915260038201805482526004830154602083019060ff166001811115610a3a57fe5b6001811115610a4557fe5b8152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050888581518110610a9b57fe5b6020908102919091010152600190930192610ab7600c82612187565b610ac057610ad2565b610acb600c826121a1565b9050610a0e565b50505b6001016109d7565b50505050505b919050565b6013546001600160a01b0316331480610b1057503360009081526014602052604090205460ff165b610b2c5760405162461bcd60e51b815260040161048190613bb7565b6002548310610b4d5760405162461bcd60e51b8152600401610481906138f8565b610b556121e9565b600060026000018481548110610b6757fe5b906000526020600020906009020190508281600201819055506000670de0b6b3a7640000610ba6836005015484600801546118f890919063ffffffff16565b81610bad57fe5b0490506000825460ff166001811115610bc257fe5b1415610bdd57601d54610bd5908261193b565b601d55610bee565b601c54610bea908261193b565b601c555b600582018390556008820154670de0b6b3a764000090610c0e90856118f8565b81610c1557fe5b0490506000825460ff166001811115610c2a57fe5b1415610c4557601d54610c3d9082611963565b601d55610c56565b601c54610c529082611963565b601c555b5050505050565b6060610c67613052565b610c6f610edf565b6040805160c08101825260065481526007546020820152600854918101919091526009546060820152600a546080820152600b5460a082015290925090509091565b600754600090670de0b6b3a764000090610ccc9084906118f8565b81610cd357fe5b0492915050565b6060610ce4613088565b6001600160a01b03831660009081526012602052604090205460609080610d0b5750610ed8565b6000818152601160205260409020610d2286610913565b9450845160010167ffffffffffffffff81118015610d3f57600080fd5b50604051908082528060200260200182016040528015610d7957816020015b610d666130b0565b815260200190600190039081610d5e5790505b50925060005b8551811015610e2e57610df1868281518110610d9757fe5b602002602001015160400151878381518110610daf57fe5b602002602001015160c00151888481518110610dc757fe5b602002602001015160e00151898581518110610ddf57fe5b6020026020010151610100015161223b565b858381518110610dfd57fe5b6020026020010151600001868481518110610e1457fe5b602090810291909101810151019190915252600101610d7f565b610e37826122c4565b848281518110610e4357fe5b60200260200101516020018181525050610e848260040160030154858381518110610e6a57fe5b60200260200101516020015161196390919063ffffffff16565b848281518110610e9057fe5b60209081029190910181015181019190915260408051608081018252600485015481526005850154928101929092526006840154908201526007909201546060830152509250505b9193909250565b60025460609067ffffffffffffffff81118015610efb57600080fd5b50604051908082528060200260200182016040528015610f3557816020015b610f226130ca565b815260200190600190039081610f1a5790505b50905060005b600254811015611040576002805482908110610f5357fe5b600091825260209091206040805161012081019091526009909202018054829060ff166001811115610f8157fe5b6001811115610f8c57fe5b815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815260200160078201548152602001600882015481525050828281518110610fec57fe5b602002602001018190525061101d6002600001828154811061100a57fe5b9060005260206000209060090201612334565b82828151811061102957fe5b602090810291909101015160600152600101610f3b565b5090565b6013546001600160a01b031633148061106c57503360009081526014602052604090205460ff165b6110885760405162461bcd60e51b815260040161048190613bb7565b601754611095908261193b565b601755602354604051634decdde360e11b81526001600160a01b0390911690639bd9bbc6906110ca9033908590600401613669565b600060405180830381600087803b1580156110e457600080fd5b505af1158015610c56573d6000803e3d6000fd5b6013546001600160a01b031633148061112057503360009081526014602052604090205460ff165b61113c5760405162461bcd60e51b815260040161048190613bb7565b6000821161115c5760405162461bcd60e51b8152600401610481906139f1565b60068390556007829055600881905560646111788260636118f8565b8161117f57fe5b04600955505050565b60606002601f018260405161119d919061364d565b9081526040805160209281900383018120805460026001821615610100026000190190911604601f8101859004850283018501909352828252909290919083018282801561122c5780601f106112015761010080835404028352916020019161122c565b820191906000526020600020905b81548152906001019060200180831161120f57829003601f168201915b50505050509050919050565b6013546001600160a01b031633148061126057503360009081526014602052604090205460ff165b61127c5760405162461bcd60e51b815260040161048190613bb7565b600355565b600754600090610ccc83670de0b6b3a76400006118f8565b6112a1613117565b60408051600c80546060602082028401810185529383018181529293919284929091849160009085015b828210156113ad57838290600052602060002090600c02016040518060800160405290816000820154815260200160018201548152602001600282015481526020016003820160405180610120016040529081600082015481526020016001820160009054906101000a900460ff16600181111561134557fe5b600181111561135057fe5b815260200160028201548152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820154815260200160088201548152505081525050815260200190600101906112cb565b50505050815260200160018201604051806060016040529081600082015481526020016001820154815260200160028201548152505081525050905090565b6013546001600160a01b031633146114165760405162461bcd60e51b815260040161048190613ab2565b6001600160a01b03811660009081526014602052604090205460ff161561144f5760405162461bcd60e51b815260040161048190613adc565b6001600160a01b03166000908152601460205260409020805460ff19166001179055565b6013546001600160a01b0316331461149d5760405162461bcd60e51b815260040161048190613ab2565b6001600160a01b03811660009081526014602052604090205460ff166114d55760405162461bcd60e51b815260040161048190613c8d565b6001600160a01b03166000908152601460205260409020805460ff19169055565b6024546001600160a01b031681565b6013546001600160a01b031633148061152d57503360009081526014602052604090205460ff165b6115495760405162461bcd60e51b815260040161048190613bb7565b6115516121e9565b601e55601f55565b6002600054141561157c5760405162461bcd60e51b815260040161048190613e4c565b6002600090815560118161158f336123f1565b815260200190815260200160002090506000806000806115b18589898961246d565b9096509450909250905081156115d657600c8501546115d0908361193b565b600c8601555b83156115f157600d8501546115eb908561193b565b600d8601555b6001850154610619906001600160a01b0316838387876126b7565b60015481565b6013546001600160a01b031633148061163a57503360009081526014602052604090205460ff165b6116565760405162461bcd60e51b815260040161048190613bb7565b8080156116635750600554155b15611672576001600555610901565b80158015611681575060055415155b1561090157600060055550565b6013546001600160a01b03163314806116b657503360009081526014602052604090205460ff165b6116d25760405162461bcd60e51b815260040161048190613bb7565b6116da6121e9565b60028054600181018083556000838152919290839081106116f757fe5b6000918252602090912060099091020180549091508690829060ff19166001838181111561172157fe5b021790555060018101949094556005840191909155600283019190915560049091015550565b60008181526011602052604090206002546060919067ffffffffffffffff8111801561177257600080fd5b506040519080825280602002602001820160405280156117ac57816020015b611799613136565b8152602001906001900390816117915790505b50915060005b6002548110156118105760008181526020838152604091829020825160608101845281548152600182015492810192909252600201549181019190915283518490839081106117fd57fe5b60209081029190910101526001016117b2565b5050919050565b6013546001600160a01b031633148061183f57503360009081526014602052604090205460ff165b61185b5760405162461bcd60e51b815260040161048190613bb7565b601854611868908261193b565b601855602254604051634decdde360e11b81526001600160a01b0390911690639bd9bbc6906110ca9033908590600401613669565b6013546001600160a01b03163314806118c557503360009081526014602052604090205460ff165b6118e15760405162461bcd60e51b815260040161048190613bb7565b600455565b80546109015780546001018155600052565b60008261190757506000611935565b8282028284828161191457fe5b04146119325760405162461bcd60e51b815260040161048190613ce7565b90505b92915050565b60008282111561195d5760405162461bcd60e51b815260040161048190613bdb565b50900390565b6000828201838110156119325760405162461bcd60e51b815260040161048190613a7b565b600081116119a85760405162461bcd60e51b815260040161048190613d28565b6023546001600160a01b031633146119d25760405162461bcd60e51b815260040161048190613c12565b60006011816119e0856123f1565b815260200190815260200160002090506119f9816128c7565b60078101548290811115611a0e575060078101545b6007820154611a1d908261193b565b6007830155601754611a2f9082611963565b601755611a3c838261193b565b925082611a4a575050611bb3565b60048201548390811115611a5f575060048201545b6004830154600584015460009190611a789084906118f8565b81611a7f57fe5b60048601549190049150611a93908361193b565b60048501556005840154611aa7908261193b565b6005850155601954611ab9908361193b565b601955601b54611ac99083611963565b601b55611ad6858361193b565b94508015611b4357602454604051634decdde360e11b81526001600160a01b0390911690639bd9bbc690611b109089908590600401613669565b600060405180830381600087803b158015611b2a57600080fd5b505af1158015611b3e573d6000803e3d6000fd5b505050505b8415611bae57602354604051634decdde360e11b81526001600160a01b0390911690639bd9bbc690611b7b9089908990600401613669565b600060405180830381600087803b158015611b9557600080fd5b505af1158015611ba9573d6000803e3d6000fd5b505050505b505050505b5050565b60008111611bd75760405162461bcd60e51b815260040161048190613dfc565b6024546001600160a01b03163314611c015760405162461bcd60e51b815260040161048190613a20565b6000611c0c82610cb1565b601b54909150811115611c315760405162461bcd60e51b815260040161048190613e83565b600954811015611c535760405162461bcd60e51b815260040161048190613d50565b6000601181611c61866123f1565b81526020019081526020016000209050611c7a816128c7565b600b5460068201541015611c9157600b5460068201555b6004810154611ca09083611963565b60048201556005810154611cb49084611963565b6005820155601954611cc69083611963565b601955601b54611cd6908361193b565b601b55602354604051634decdde360e11b81526001600160a01b0390911690639bd9bbc690611d0b9087908690600401613669565b600060405180830381600087803b158015611d2557600080fd5b505af1158015611d39573d6000803e3d6000fd5b50505050836001600160a01b03167fad9d68f84b5df48e48651913515b1d6bed12ed9f20dea3d9771f5328526196958385604051611d78929190613ffd565b60405180910390a250505050565b60008111611da65760405162461bcd60e51b815260040161048190613c6a565b6002548310611dc75760405162461bcd60e51b815260040161048190613dab565b600060026000018481548110611dd957fe5b6000918252602082206009909102019150815460ff166001811115611dfa57fe5b1415611e2f576022546001600160a01b03163314611e2a5760405162461bcd60e51b815260040161048190613b65565b611e89565b6001815460ff166001811115611e4157fe5b1415611e71576023546001600160a01b03163314611e2a5760405162461bcd60e51b815260040161048190613c3e565b60405162461bcd60e51b815260040161048190613958565b611e916121e9565b6000601181611e9f886123f1565b81526020810191909152604001600020600381015490915080158015611ed75750866001600160a01b0316856001600160a01b031614155b8015611eeb57506001600160a01b03851615155b15611f0357611ef9856123f1565b6003830181905590505b6001830154611f10575060005b8015611f8357600081815260116020526040908190206009810180546001019081905591519091906001600160a01b03808b1691908916907f7e1c35b2764f73a1364fed3bf30d5061c05022f93703cd0ca9404df72b0f48b390611f79908a908d90429061400b565b60405180910390a4505b6004830154600090815260208390526040812090611fa1600c612907565b855460048201805492935060ff9091169160ff191660018381811115611fc357fe5b021790555060048501546005820155600180860154600683018190559054611ff591611fee916118f8565b4290611963565b60078083019190915560088201849055600982018790556006860154600a830155850154600b82015561202a600c8383612976565b60088501546120399087611963565b60088601556000855460ff16600181111561205057fe5b14156120b257600c8401546120659087611963565b600c8501556015546120779087611963565b60155560058501546120aa90670de0b6b3a7640000906120989089906118f8565b8161209f57fe5b601d54919004611963565b601d55612132565b6001855460ff1660018111156120c457fe5b141561213257600d8401546120d99087611963565b600d8501556016546120eb9087611963565b601655601b546120fb9087611963565b601b55600585015461212e90670de0b6b3a76400009061211c9089906118f8565b8161212357fe5b601c54919004611963565b601c555b505050505050505050565b6000808260020154116121625760405162461bcd60e51b815260040161048190613e24565b81548354849190811061217157fe5b90600052602060002090600c0201905092915050565b805460009061219857506000611935565b50600192915050565b8054600090806121c35760405162461bcd60e51b8152600401610481906138a3565b8360000181815481106121d257fe5b90600052602060002090600c020191505092915050565b6020544214156121f857612239565b60005b6002548110156122335761222b6002600001828154811061221857fe5b90600052602060002090600902016129e1565b6001016121fb565b50426020555b565b60008060006002600001878154811061225057fe5b9060005260206000209060090201905060008061226c836129f7565b9092509050670de0b6b3a764000061228e612287848a61193b565b8a906118f8565b8161229557fe5b049450670de0b6b3a76400006122ae612287838961193b565b816122b557fe5b04935050505094509492505050565b60048101546000906122d857506000610ae3565b60006122e2612a86565b9050808360040160020154106122fc576000915050610ae3565b6006830154670de0b6b3a7640000906123259061231a90849061193b565b6004860154906118f8565b8161232c57fe5b049392505050565b600081600801546000141561234b57506000610ae3565b6000612368836005015484600801546118f890919063ffffffff16565b90506000835460ff16600181111561237c57fe5b14156123b357601d54612393576000915050610ae3565b601d54601f546123a49083906118f8565b816123ab57fe5b0491506123e0565b601c546123c4576000915050610ae3565b601c54601e546123d59083906118f8565b816123dc57fe5b0491505b60088301546123258361016d6118f8565b6001600160a01b038116600090815260126020526040902054801561241557610ae3565b5060108054600190810191829055600082815260116020908152604080832093840180546001600160a01b0388166001600160a01b031990911681179091556002949094018590559282526012905220819055919050565b60008060008061247b6121e9565b8561248557600096505b84612491576001850394505b60008060006124a08b8b612adc565b9250925092505b8080156124b45750600088115b80156124c757508815806124c757508983145b156126a957600582015460028054600019909a019960038501926000929181106124ed57fe5b9060005260206000209060090201905060008061250984612b46565b90925090506125188a83611963565b99506125248882611963565b97506125328f858484612b6e565b836004015442118015612549575060008460030154115b8061255e5750600384015415801561255e57508c5b1561267757600684015460088401546125769161193b565b600884015560018481015460ff168181111561258e57fe5b14156125e75760068401546125a4908a90611963565b98506125df670de0b6b3a76400006125cd856005015487600601546118f890919063ffffffff16565b816125d457fe5b601c5491900461193b565b601c55612636565b60068401546125f7908c90611963565b9a50612632670de0b6b3a7640000612620856005015487600601546118f890919063ffffffff16565b8161262757fe5b601d5491900461193b565b601d555b6126618f60000160008981526020019081526020016000206002600a01612cd890919063ffffffff16565b61266b8f88612adc565b919850965094506126a0565b600683015460078086019190915583015460088501556126988f8888612cf0565b919850965094505b505050506124a7565b505050945094509450949050565b6016548211156126d95760405162461bcd60e51b8152600401610481906138c9565b601b548211156126fb5760405162461bcd60e51b815260040161048190613921565b60155484111561271d5760405162461bcd60e51b815260040161048190613b0c565b811561274457601654612730908361193b565b601655601b54612740908361193b565b601b555b831561275b57601554612757908561193b565b6015555b80156127a0576017548111156127835760405162461bcd60e51b8152600401610481906139bc565b601754612790908261193b565b60175561279d8282611963565b91505b82156127f6576018548311156127c85760405162461bcd60e51b815260040161048190613987565b6018546127d5908461193b565b6018556127e28484611963565b601a549094506127f29084611963565b601a555b811561286157602354604051634decdde360e11b81526001600160a01b0390911690639bd9bbc69061282e9088908690600401613669565b600060405180830381600087803b15801561284857600080fd5b505af115801561285c573d6000803e3d6000fd5b505050505b8315610c5657602254604051634decdde360e11b81526001600160a01b0390911690639bd9bbc6906128999088908890600401613669565b600060405180830381600087803b1580156128b357600080fd5b505af1158015612132573d6000803e3d6000fd5b6128cf612d54565b60006128da826122c4565b9050806128e75750610901565b600b54600683015560078201546128fe9082611963565b60078301555050565b6003810154600090612969578154612926578154600101825560008290525b815460018101808455600084905283908290811061294057fe5b600091825260208220600c90910201818155600181019190915560028101919091559050610ae3565b6119358283600101612d79565b6001808301549082015560008155600282015461299f57600281015480835560018301556129d3565b8060020154836000018360010154815481106129b757fe5b60009182526020909120600c9091020155600281015460018301555b506002018054600101905550565b6129ea816129f7565b6007830155600690910155565b6000806000612a146002601e01544261193b90919063ffffffff16565b905080612a2d5750505060068101546007820154612a81565b612a52612a47670de0b6b3a7640000866002015484612e2f565b600786015490611963565b9150612a7d612a72670de0b6b3a7640000612a6c87612334565b84612e2f565b600686015490611963565b9250505b915091565b600a54600090421415612a9c5750600b54610877565b600a54600090612aad90429061193b565b9050612ad6612acd670de0b6b3a764000060026004016000015484612e2f565b600b5490611963565b91505090565b60008060005b600254841015612b2a5760008481526020869052604090206002810154612b0f5750600190930192612ae2565b612b1a600c8261213d565b859450925060019150612b3f9050565b6000612b36600c612e76565b60009250925092505b9250925092565b600080612b65836002015484600601548560070154866008015461223b565b91509150915091565b6003830154612b7c57612cd2565b600583015480612b8c5750612cd2565b6000818152601160205260409020600454600d8201541015612baf575050612cd2565b600354600090670de0b6b3a764000090612bca9087906118f8565b81612bd157fe5b0490506000808215612bf65750600a830154600190612bf09084611963565b600a8501555b60055415612c3f57600354670de0b6b3a764000090612c169088906118f8565b81612c1d57fe5b0491508115612c3f5750600b830154600190612c399083611963565b600b8501555b80612c4e575050505050612cd2565b6008840180546001908101918290558a8101549086015460028b01546040516001600160a01b0393841693909216917fafe38f267ece28b49c2765a03daf360a7bf79bd1cd7e664ffe93d2c05f76e03991612cae91899189914290614021565b60405180910390a46001840154612132906001600160a01b031660008581866126b7565b50505050565b6000612ce48383612d79565b90506107e28382612e9d565b600254600090819081908510612d0e57506000915082905081612d4b565b612d19600c85612187565b15612d375784612d2a600c866121a1565b6001925092509250612d4b565b612d448686600101612adc565b9250925092505b93509350939050565b6000612d5e612a86565b600b549091508111612d705750612239565b600b5542600a55565b600080826002015411612d9e5760405162461bcd60e51b815260040161048190613e24565b81548354849082908110612dae57fe5b60009182526020909120600c909102015480845515612df2578254845460009186918110612dd857fe5b90600052602060002090600c020160010181905550612dfa565b600060018401555b6002830180546000190190558354849082908110612e1457fe5b600091825260208220600c9091020190815591505092915050565b600154600090670de0b6b3a76400009061016d612e5685612e5089896118f8565b906118f8565b81612e5d57fe5b0481612e6557fe5b0481612e6d57fe5b04949350505050565b600081600001600081548110612e8857fe5b90600052602060002090600c02019050919050565b611bb3828360010183612976565b60405180610120016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612f365760008555612f7c565b82601f10612f4f57805160ff1916838001178555612f7c565b82800160010185558215612f7c579182015b82811115612f7c578251825591602001919060010190612f61565b50611040929150613157565b604051806102000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604080516101208101909152600080825260208201908152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604080516101208101909152806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806040016040528060608152602001613131613136565b905290565b60405180606001604052806000815260200160008152602001600081525090565b5b808211156110405760008155600101613158565b80358015158114610ae357600080fd5b60008083601f84011261318d578182fd5b50813567ffffffffffffffff8111156131a4578182fd5b60208301915083602082850101111561075357600080fd5b600082601f8301126131cc578081fd5b813567ffffffffffffffff808211156131e157fe5b604051601f8301601f1916810160200182811182821017156131ff57fe5b604052828152848301602001861015613216578384fd5b82602086016020830137918201602001929092529392505050565b600060208284031215613242578081fd5b813561193281614068565b60008060008060008060008060c0898b031215613268578384fd5b883561327381614068565b9750602089013561328381614068565b9650604089013561329381614068565b955060608901359450608089013567ffffffffffffffff808211156132b6578586fd5b6132c28c838d0161317c565b909650945060a08b01359150808211156132da578384fd5b506132e78b828c0161317c565b999c989b5096995094979396929594505050565b60006020828403121561330c578081fd5b6133158261316c565b9392505050565b60008060008060808587031215613331578384fd5b84356002811061333f578485fd5b966020860135965060408601359560600135945092505050565b60006020828403121561336a578081fd5b813567ffffffffffffffff811115613380578182fd5b61338c848285016131bc565b949350505050565b600080604083850312156133a6578182fd5b823567ffffffffffffffff808211156133bd578384fd5b6133c9868387016131bc565b935060208501359150808211156133de578283fd5b506133eb858286016131bc565b9150509250929050565b600060208284031215613406578081fd5b5035919050565b6000806040838503121561341f578182fd5b82359150602083013561343181614068565b809150509250929050565b600080600060608486031215613450578283fd5b833592506134606020850161316c565b9150604084013590509250925092565b60008060408385031215613482578182fd5b50508035926020909101359150565b6000806000606084860312156134a5578283fd5b833592506020840135915060408401356134be81614068565b809150509250925092565b6000806000606084860312156134dd578283fd5b505081359360208301359350604090920135919050565b6000815180845260208085019450808401835b8381101561357e57815161351c8882516135c3565b808401518885015260408082015190890152606080820151908901526080808201519089015260a0808201519089015260c0808201519089015260e0808201519089015261010090810151908801526101209096019590820190600101613507565b509495945050505050565b6000815180845260208085019450808401835b8381101561357e576135af8783516135ea565b61012096909601959082019060010161359c565b600281106135cd57fe5b9052565b8051825260208082015190830152604090810151910152565b80518252602081015161360060208401826135c3565b5060408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b6000825161365f81846020870161403c565b9190910192915050565b6001600160a01b03929092168252602082015260606040820181905260009082015260800190565b6020808252825182820181905260009190848201906040850190845b818110156136d3576136c08385516135d1565b92840192606092909201916001016136ad565b50909695505050505050565b60006020825261331560208301846134f4565b600060e0825261370560e08301856134f4565b905082516020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c08301529392505050565b6000602082526133156020830184613589565b600060c0825261376d60c0830186613589565b602085518185015280860151604081818701528088015160608701526060880151608087015285840360a0870152839150865180855283850192508388019450855b818110156137d4578551805185528501518585015294840194928201926001016137af565b50919998505050505050505050565b600061014082019050831515825260018060a01b038351166020830152602083015160408301526040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010081818501528085015161012085015250509392505050565b6001600160a01b0391909116815260200190565b600060208252825180602084015261388f81604085016020870161403c565b601f01601f19169190910160400192915050565b6020808252600c908201526b6e6f206e657874206974656d60a01b604082015260600190565b60208082526015908201527431b334b61034b73b32b9ba103737bb9032b93937b960591b604082015260600190565b6020808252600f908201526e3830b1b5b0b3b2a4a21032b93937b960891b604082015260600190565b6020808252601b908201527f6e6f7420656e6f756768206366696c20746f2077697468647261770000000000604082015260600190565b6020808252601590820152746e6f742061766169207061636b616765207479706560581b604082015260600190565b6020808252818101527f6372666920696e74657265737420706f6f6c206973206e6f7420656e6f756768604082015260600190565b6020808252818101527f6366696c20696e74657265737420706f6f6c206973206e6f7420656e6f756768604082015260600190565b6020808252601590820152740706c6564676520726174652063616e2774203d203605c1b604082015260600190565b6020808252601290820152716e6f74207366696c20636f696e207479706560701b604082015260600190565b60208082526015908201527432b6b83a3c903732bb9039bab832b91030b236b4b760591b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526010908201526f37b7363c9039bab832b91030b236b4b760811b604082015260600190565b60208082526016908201527530b63932b0b23c9030b232103a3434b99030b236b4b760511b604082015260600190565b60208082526015908201527431b933349034b73b32b9ba103737bb9032b93937b960591b604082015260600190565b60208082526010908201526f6f6e6c7920636861726765206372666960801b604082015260600190565b6020808252601290820152716e6f74204352464920636f696e207479706560701b604082015260600190565b6020808252600c908201526b6e6f2075736572206461746160a01b604082015260600190565b6020808252600a908201526937b7363c9030b236b4b760b11b604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252601290820152716e6f74206366696c20636f696e207479706560701b604082015260600190565b6020808252601290820152716e6f74204346696c20636f696e207479706560701b604082015260600190565b6020808252600990820152681b9bc8185b5bdd5b9d60ba1b604082015260600190565b6020808252601690820152753a3434b99030b232391034b9903737ba1030b236b4b760511b604082015260600190565b60208082526010908201526f1bdb9b1e4818da185c99d94818d99a5b60821b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600e908201526d1b9bc818d99a5b08185b5bdd5b9d60921b604082015260600190565b60208082526018908201527f6366696c20616d6f756e7420697320746f6f20736d616c6c0000000000000000604082015260600190565b6020808252600a908201526936b7b2329032b93937b960b11b604082015260600190565b6020808252601190820152701a5b9d985b1a59081c1858dad859d95251607a1b604082015260600190565b6020808252600c908201526b66726f6d206973207a65726f60a01b604082015260600190565b6020808252600e908201526d1b9bc81cd99a5b08185b5bdd5b9d60921b604082015260600190565b6020808252600e908201526d636861696e20697320656d70747960901b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526017908201527f6e6f7420656e6f756768206366696c20746f206c6f616e000000000000000000604082015260600190565b60208082528251608083830152805160a0840181905260009291820190839060c08601905b80831015613f2b5783518051835285810151868401526040808201519084015260609081015190613f12818501836135ea565b5050610180820191508484019350600183019250613edf565b509286015192613f3e60408701856135d1565b9695505050505050565b815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c0808301519082015260e08083015190820152610100808301519082015261012080830151908201526101408083015190820152610160808301519082015261018080830151908201526101a080830151908201526101c080830151908201526101e091820151918101919091526102000190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b60005b8381101561405757818101518382015260200161403f565b83811115612cd25750506000910152565b6001600160a01b038116811461090157600080fdfea2646970667358221220e41164bdf8c9a4db6120b097c47392ab0b27dfdcd74414380c0b5555653ad6a964736f6c63430007060033

Verified Source Code Full Match

Compiler: v0.7.6+commit.7338295f EVM: istanbul Optimization: Yes (200 runs)
all_main.sol 2087 lines
// File: @openzeppelin/contracts/token/ERC777/IERC777.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC777Token standard as defined in the EIP.
 *
 * This contract uses the
 * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let
 * token holders and recipients react to token movements by using setting implementers
 * for the associated interfaces in said registry. See {IERC1820Registry} and
 * {ERC1820Implementer}.
 */
interface IERC777 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the smallest part of the token that is not divisible. This
     * means all token operations (creation, movement and destruction) must have
     * amounts that are a multiple of this number.
     *
     * For most token contracts, this value will equal 1.
     */
    function granularity() external view returns (uint256);

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

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * If send or receive hooks are registered for the caller and `recipient`,
     * the corresponding functions will be called with `data` and empty
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function send(address recipient, uint256 amount, bytes calldata data) external;

    /**
     * @dev Destroys `amount` tokens from the caller's account, reducing the
     * total supply.
     *
     * If a send hook is registered for the caller, the corresponding function
     * will be called with `data` and empty `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - the caller must have at least `amount` tokens.
     */
    function burn(uint256 amount, bytes calldata data) external;

    /**
     * @dev Returns true if an account is an operator of `tokenHolder`.
     * Operators can send and burn tokens on behalf of their owners. All
     * accounts are their own operator.
     *
     * See {operatorSend} and {operatorBurn}.
     */
    function isOperatorFor(address operator, address tokenHolder) external view returns (bool);

    /**
     * @dev Make an account an operator of the caller.
     *
     * See {isOperatorFor}.
     *
     * Emits an {AuthorizedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function authorizeOperator(address operator) external;

    /**
     * @dev Revoke an account's operator status for the caller.
     *
     * See {isOperatorFor} and {defaultOperators}.
     *
     * Emits a {RevokedOperator} event.
     *
     * Requirements
     *
     * - `operator` cannot be calling address.
     */
    function revokeOperator(address operator) external;

    /**
     * @dev Returns the list of default operators. These accounts are operators
     * for all token holders, even if {authorizeOperator} was never called on
     * them.
     *
     * This list is immutable, but individual holders may revoke these via
     * {revokeOperator}, in which case {isOperatorFor} will return false.
     */
    function defaultOperators() external view returns (address[] memory);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must
     * be an operator of `sender`.
     *
     * If send or receive hooks are registered for `sender` and `recipient`,
     * the corresponding functions will be called with `data` and
     * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
     *
     * Emits a {Sent} event.
     *
     * Requirements
     *
     * - `sender` cannot be the zero address.
     * - `sender` must have at least `amount` tokens.
     * - the caller must be an operator for `sender`.
     * - `recipient` cannot be the zero address.
     * - if `recipient` is a contract, it must implement the {IERC777Recipient}
     * interface.
     */
    function operatorSend(
        address sender,
        address recipient,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the total supply.
     * The caller must be an operator of `account`.
     *
     * If a send hook is registered for `account`, the corresponding function
     * will be called with `data` and `operatorData`. See {IERC777Sender}.
     *
     * Emits a {Burned} event.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     * - the caller must be an operator for `account`.
     */
    function operatorBurn(
        address account,
        uint256 amount,
        bytes calldata data,
        bytes calldata operatorData
    ) external;

    event Sent(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 amount,
        bytes data,
        bytes operatorData
    );

    event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData);

    event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData);

    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    event RevokedOperator(address indexed operator, address indexed tokenHolder);
}

// File: @openzeppelin/contracts/token/ERC777/IERC777Recipient.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.
 *
 * Accounts can be notified of {IERC777} tokens being sent to them by having a
 * contract implement this interface (contract holders can be their own
 * implementer) and registering it on the
 * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
 *
 * See {IERC1820Registry} and {ERC1820Implementer}.
 */
interface IERC777Recipient {
    /**
     * @dev Called by an {IERC777} token contract whenever tokens are being
     * moved or created into a registered account (`to`). The type of operation
     * is conveyed by `from` being the zero address or not.
     *
     * This call occurs _after_ the token contract's state is updated, so
     * {IERC777-balanceOf}, etc., can be used to query the post-operation state.
     *
     * This function may revert to prevent the operation from being executed.
     */
    function tokensReceived(
        address operator,
        address from,
        address to,
        uint256 amount,
        bytes calldata userData,
        bytes calldata operatorData
    ) external;
}

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


pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// File: @openzeppelin/contracts/introspection/IERC1820Registry.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the global ERC1820 Registry, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register
 * implementers for interfaces in this registry, as well as query support.
 *
 * Implementers may be shared by multiple accounts, and can also implement more
 * than a single interface for each account. Contracts can implement interfaces
 * for themselves, but externally-owned accounts (EOA) must delegate this to a
 * contract.
 *
 * {IERC165} interfaces can also be queried via the registry.
 *
 * For an in-depth explanation and source code analysis, see the EIP text.
 */
interface IERC1820Registry {
    /**
     * @dev Sets `newManager` as the manager for `account`. A manager of an
     * account is able to set interface implementers for it.
     *
     * By default, each account is its own manager. Passing a value of `0x0` in
     * `newManager` will reset the manager to this initial state.
     *
     * Emits a {ManagerChanged} event.
     *
     * Requirements:
     *
     * - the caller must be the current manager for `account`.
     */
    function setManager(address account, address newManager) external;

    /**
     * @dev Returns the manager for `account`.
     *
     * See {setManager}.
     */
    function getManager(address account) external view returns (address);

    /**
     * @dev Sets the `implementer` contract as ``account``'s implementer for
     * `interfaceHash`.
     *
     * `account` being the zero address is an alias for the caller's address.
     * The zero address can also be used in `implementer` to remove an old one.
     *
     * See {interfaceHash} to learn how these are created.
     *
     * Emits an {InterfaceImplementerSet} event.
     *
     * Requirements:
     *
     * - the caller must be the current manager for `account`.
     * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not
     * end in 28 zeroes).
     * - `implementer` must implement {IERC1820Implementer} and return true when
     * queried for support, unless `implementer` is the caller. See
     * {IERC1820Implementer-canImplementInterfaceForAddress}.
     */
    function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external;

    /**
     * @dev Returns the implementer of `interfaceHash` for `account`. If no such
     * implementer is registered, returns the zero address.
     *
     * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28
     * zeroes), `account` will be queried for support of it.
     *
     * `account` being the zero address is an alias for the caller's address.
     */
    function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address);

    /**
     * @dev Returns the interface hash for an `interfaceName`, as defined in the
     * corresponding
     * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].
     */
    function interfaceHash(string calldata interfaceName) external pure returns (bytes32);

    /**
     *  @notice Updates the cache with whether the contract implements an ERC165 interface or not.
     *  @param account Address of the contract for which to update the cache.
     *  @param interfaceId ERC165 interface for which to update the cache.
     */
    function updateERC165Cache(address account, bytes4 interfaceId) external;

    /**
     *  @notice Checks whether a contract implements an ERC165 interface or not.
     *  If the result is not cached a direct lookup on the contract address is performed.
     *  If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
     *  {updateERC165Cache} with the contract address.
     *  @param account Address of the contract to check.
     *  @param interfaceId ERC165 interface to check.
     *  @return True if `account` implements `interfaceId`, false otherwise.
     */
    function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);

    /**
     *  @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.
     *  @param account Address of the contract to check.
     *  @param interfaceId ERC165 interface to check.
     *  @return True if `account` implements `interfaceId`, false otherwise.
     */
    function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);

    event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);

    event ManagerChanged(address indexed account, address indexed newManager);
}

// File: @openzeppelin/contracts/math/SafeMath.sol


pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

// File: crosslend/data.sol

pragma solidity >=0.6.2 <0.8.0;

enum FinancialType{CRFI, CFil}

struct FinancialPackage {
  FinancialType Type;
  
  uint256 Days;
  uint256 CFilInterestRate;
  uint256 CRFIInterestRateDyn;
  uint256 ID;

  uint256 Weight;
  uint256 ParamCRFI;
  uint256 ParamCFil;
  uint256 Total;
}

struct LoanCFilPackage {
  uint256 APY;
  uint256 PledgeRate;
  uint256 PaymentDue;
  uint256 PaymentDue99;

  uint256 UpdateTime;
  uint256 Param;
}

struct ViewSystemInfo{
  FinancialPackage[] Packages;
  uint256 AffRate;
  uint256 AffRequire;
  uint256 EnableAffCFil;
  
  LoanCFilPackage LoanCFil;

  ChainManager ChainM;

  // invest
  uint256 NewInvestID;
  mapping(uint256 => InvestInfo) Invests;
  mapping(address => uint256) InvestAddrID;
        
  // setting power
  address SuperAdmin;
  mapping(address => bool) Admins;

  // statistic
  uint256 nowInvestCRFI;
  uint256 nowInvestCFil; 
  uint256 cfilInterestPool;
  uint256 crfiInterestPool;

  uint256 cfilLendingTotal;
  uint256 crfiRewardTotal;
  uint256 avaiCFilAmount;
  
  uint256 totalWeightCFil;
  uint256 totalWeightCRFI;
  uint256 crfiMinerPerDayCFil;
  uint256 crfiMinerPerDayCRFI;
  
  uint256 ParamUpdateTime;
}

struct SystemInfoView {
  uint256 AffRate;
  uint256 AffRequire;
  uint256 EnableAffCFil;
  
  // invest
  uint256 NewInvestID;

  // statistic
  uint256 nowInvestCRFI;
  uint256 nowInvestCFil; 
  uint256 cfilInterestPool;
  uint256 crfiInterestPool;

  uint256 cfilLendingTotal;
  uint256 crfiRewardTotal;
  uint256 avaiCFilAmount;
  
  uint256 totalWeightCFil;
  uint256 totalWeightCRFI;
  uint256 crfiMinerPerDayCFil;
  uint256 crfiMinerPerDayCRFI;
  
  uint256 ParamUpdateTime;
}

struct SystemInfo {

  FinancialPackage[] Packages;
  uint256 AffRate;
  uint256 AffRequire;
  uint256 EnableAffCFil;
  
  LoanCFilPackage LoanCFil;

  ChainManager ChainM;

  // invest
  uint256 NewInvestID;
  mapping(uint256 => InvestInfo) Invests;
  mapping(address => uint256) InvestAddrID;
        
  // setting power
  address SuperAdmin;
  mapping(address => bool) Admins;

  // statistic
  uint256 nowInvestCRFI;
  uint256 nowInvestCFil; 
  uint256 cfilInterestPool;
  uint256 crfiInterestPool;

  uint256 cfilLendingTotal;
  uint256 crfiRewardTotal;
  uint256 avaiCFilAmount;
  
  uint256 totalWeightCFil;
  uint256 totalWeightCRFI;
  uint256 crfiMinerPerDayCFil;
  uint256 crfiMinerPerDayCRFI;
  
  uint256 ParamUpdateTime;

  mapping(string => string) kvMap;
}

struct InterestDetail{
  uint256 crfiInterest;
  uint256 cfilInterest;
}

struct LoanInvest{
  uint256 Lending;
  uint256 Pledge;
  uint256 Param;
  uint256 NowInterest;
}

struct InvestInfoView {
  address Addr;
  uint256 ID;

  uint256 affID;

  // statistic for financial
  uint256 totalAffTimes;
  uint256 totalAffPackageTimes;
  
  uint256 totalAffCRFI;
  uint256 totalAffCFil;
  
  uint256 nowInvestFinCRFI;
  uint256 nowInvestFinCFil;
}

struct InvestInfo {
  mapping(uint256 => ChainQueue) InvestRecords;

  address Addr;
  uint256 ID;

  uint256 affID;

  LoanInvest LoanCFil;

  // statistic for financial
  uint256 totalAffTimes;
  uint256 totalAffPackageTimes;
  
  uint256 totalAffCRFI;
  uint256 totalAffCFil;
  
  uint256 nowInvestFinCRFI;
  uint256 nowInvestFinCFil;
}


//////////////////// queue

struct QueueData {
  uint256 RecordID;
  
  FinancialType Type;
  uint256 PackageID;
  uint256 Days;
  uint256 EndTime;
  uint256 AffID;
  uint256 Amount;

  uint256 ParamCRFI;
  uint256 ParamCFil;
}

struct ChainItem {
  uint256 Next;
  uint256 Prev;
  uint256 My;
  
  QueueData Data;
}

struct ChainQueue{
  uint256 First;
  uint256 End;

  uint256 Size;
}


struct ChainManager{
  ChainItem[] rawQueue;

  ChainQueue avaiQueue;
}

library ChainQueueLib{

  //////////////////// item
  function GetNullItem(ChainManager storage chainM)
    internal
    view
    returns(ChainItem storage item){
    return chainM.rawQueue[0];
  }

  function HasNext(ChainManager storage chainM,
                   ChainItem storage item)
    internal
    view
    returns(bool has){

    if(item.Next == 0){
      return false;
    }

    return true;
  }

  function Next(ChainManager storage chainM,
                ChainItem storage item)
    internal
    view
    returns(ChainItem storage nextItem){

    uint256 nextIdx = item.Next;
    require(nextIdx > 0, "no next item");

    return chainM.rawQueue[uint256(nextIdx)];
  }

  //////////////////// chain
  function GetFirstItem(ChainManager storage chainM,
                        ChainQueue storage chain)
    internal
    view
    returns(ChainItem storage item){

    require(chain.Size > 0, "chain is empty");

    return chainM.rawQueue[chain.First];
  }

  function GetEndItem(ChainManager storage chainM,
                      ChainQueue storage chain)
    internal
    view
    returns(ChainItem storage item){

    require(chain.Size > 0, "chain is empty");

    return chainM.rawQueue[chain.End];
  }

  // need ensure the item is in chain
  function DeleteItem(ChainManager storage chainM,
                      ChainQueue storage chain,
                      ChainItem storage item)
    internal{

    if(chain.First == item.My){
      PopPutFirst(chainM, chain);
      return;
    } else if (chain.End == item.My){
      PopPutEnd(chainM, chain);
      return;
    }

    ChainItem storage next = chainM.rawQueue[item.Next];
    ChainItem storage prev = chainM.rawQueue[item.Prev];

    next.Prev = item.Prev;
    prev.Next = item.Next;

    item.Prev = 0;
    item.Next = 0;

    chain.Size--;

    PutItem(chainM, item);
  }

  function PopPutFirst(ChainManager storage chainM,
                       ChainQueue storage chain)
    internal{

    ChainItem storage item = PopFirstItem(chainM, chain);
    PutItem(chainM, item);
  }

  function PopPutEnd(ChainManager storage chainM,
                     ChainQueue storage chain)
    internal{

    ChainItem storage item = PopEndItem(chainM, chain);
    PutItem(chainM, item);
  }

  function PopEndItem(ChainManager storage chainM,
                        ChainQueue storage chain)
    internal
    returns(ChainItem storage item){
    
    require(chain.Size >0, "chain is empty");
    
    uint256 itemIdx = chain.End;
    chain.End = chainM.rawQueue[itemIdx].Prev;
    if(chain.End > 0){
      chainM.rawQueue[chain.End].Next = 0;
    } else {
      chain.First = 0;
    }
    chain.Size--;
    item = chainM.rawQueue[itemIdx];
    item.Prev = 0;
    return item;
  }

  function PopFirstItem(ChainManager storage chainM,
                        ChainQueue storage chain)
    internal
    returns(ChainItem storage item){

    require(chain.Size > 0, "chain is empty");

    uint256 itemIdx = chain.First;
    chain.First = chainM.rawQueue[itemIdx].Next;
    if(chain.First > 0){
      chainM.rawQueue[chain.First].Prev = 0;
    } else {
      chain.End = 0;
    }
    chain.Size--;

    item = chainM.rawQueue[itemIdx];
    item.Next = 0;

    return item;
  }

  function PushEndItem(ChainManager storage chainM,
                       ChainQueue storage chain,
                       ChainItem storage item)
    internal{

    item.Prev = chain.End;
    item.Next = 0;

    if(chain.Size == 0){
      chain.First = item.My;
      chain.End = item.My;
    } else {
      chainM.rawQueue[chain.End].Next = item.My;
      chain.End = item.My;
    }
    chain.Size++;
  }

  //////////////////// chain manager
  function InitChainManager(ChainManager storage chainM)
    internal{
    if(chainM.rawQueue.length == 0){
      chainM.rawQueue.push();
    }
  }
  
  function GetAvaiItem(ChainManager storage chainM)
    internal
    returns(ChainItem storage item){
    
    if(chainM.avaiQueue.Size == 0){
      if(chainM.rawQueue.length == 0){
        chainM.rawQueue.push();
      }
      
      uint256 itemIdx = chainM.rawQueue.length;
      chainM.rawQueue.push();

      item = chainM.rawQueue[itemIdx];
      item.Next = 0;
      item.Prev = 0;
      item.My = itemIdx;
      
      return item;
    }

    return PopFirstItem(chainM, chainM.avaiQueue);
  }

  function PutItem(ChainManager storage chainM,
                   ChainItem storage item)
    internal{
    
    PushEndItem(chainM, chainM.avaiQueue, item);
  }
}

// File: crosslend/main.sol

pragma solidity >=0.7.0 <0.8.0;
pragma abicoder v2;







contract CrossLend is IERC777Recipient, ReentrancyGuard{
  //////////////////// for using
  using ChainQueueLib for ChainManager;
  using SafeMath for uint256;

  //////////////////// constant
  IERC1820Registry constant internal _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);

  bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");

  uint256 constant Decimal = 1e18;

  uint256 public OneDayTime;

  //////////////////// var
  SystemInfo internal SInfo;
  
  IERC777 public CRFI;
  IERC777 public CFil;
  IERC777 public SFil;

  //////////////////// modifier
  modifier IsAdmin() {
    require(msg.sender == SInfo.SuperAdmin || SInfo.Admins[msg.sender], "only admin");
    _;
  }

  modifier IsSuperAdmin() {
    require(SInfo.SuperAdmin == msg.sender, "only super admin");
    _;
  }

  //////////////////// event
  event AffEvent(address indexed receiver, address indexed sender, uint256 indexed affTimes, uint256 crfiInterest, uint256 cfilInterest, uint256 packageID, uint256 timestamp);

  event AffBought(address indexed affer, address indexed sender, uint256 indexed affPackageTimes, uint256 amount, uint256 packageID, uint256 timestamp);
  
  event loanCFilEvent(address indexed addr, uint256 cfilAmount, uint256 sfilAmount);

  //////////////////// constructor
  constructor(address crfiAddr, address cfilAddr, address sfilAddr) {
    CRFI = IERC777(crfiAddr);
    CFil = IERC777(cfilAddr);
    SFil = IERC777(sfilAddr);
    OneDayTime = 60 * 60 * 24;

    SInfo.SuperAdmin = msg.sender;

    SInfo.AffRate = Decimal / 10;
    SInfo.EnableAffCFil = 1;

    SInfo.ChainM.InitChainManager();
    
    ////////// add package

    SInfo.crfiMinerPerDayCFil = 1917808 * Decimal / 100;
    SInfo.crfiMinerPerDayCRFI = 821918 * Decimal / 100;

    SInfo.ParamUpdateTime = block.timestamp;
    
    // loan CFil
    ChangeLoanRate(201 * Decimal / 1000,
                   56 * Decimal / 100,
                   2300 * Decimal);
    SInfo.LoanCFil.UpdateTime = block.timestamp;

    // add crfi
    AddPackage(FinancialType.CRFI,
               0,
               (20 * Decimal) / 1000,
               Decimal);
    
    AddPackage(FinancialType.CRFI,
               90,
               (32 * Decimal) / 1000,
               (15 * Decimal) / 10);

    AddPackage(FinancialType.CRFI,
               180,
               (34 * Decimal) / 1000,
               2 * Decimal);

    AddPackage(FinancialType.CRFI,
               365,
               (36 * Decimal) / 1000,
               (25 * Decimal) / 10);
                   
    AddPackage(FinancialType.CRFI,
               540,
               (40 * Decimal) / 1000,
               3 * Decimal);
    
    // add cfil
    AddPackage(FinancialType.CFil,
               0,
               (20 * Decimal) / 1000,
               Decimal);
    
    AddPackage(FinancialType.CFil,
               90,
               (33 * Decimal) / 1000,
               (15 * Decimal) / 10);

    AddPackage(FinancialType.CFil,
               180, 
               (35 * Decimal) / 1000,
               2 * Decimal);

    AddPackage(FinancialType.CFil,
               365,
               (37 * Decimal) / 1000,
               (25 * Decimal) / 10);
                   
    AddPackage(FinancialType.CFil,
               540,
               (41 * Decimal) / 1000,
               3 * Decimal);
    
    // register interfaces
    _ERC1820_REGISTRY.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, address(this));
  }
  
  //////////////////// super admin func
  function AddAdmin(address admin)
    public
    IsSuperAdmin(){
    require(!SInfo.Admins[admin], "already add this admin");
    SInfo.Admins[admin] = true;
  }

  function DelAdmin(address admin)
    public
    IsSuperAdmin(){
    require(SInfo.Admins[admin], "this addr is not admin");
    SInfo.Admins[admin] = false;
  }

  function ChangeSuperAdmin(address suAdmin)
    public
    IsSuperAdmin(){
    require(suAdmin != address(0x0), "empty new super admin");

    if(suAdmin == SInfo.SuperAdmin){
      return;
    }
    
    SInfo.SuperAdmin = suAdmin;
  }

  //////////////////// admin func
  function SetMap(string memory key,
                  string memory value)
    public
    IsAdmin(){

    SInfo.kvMap[key] = value;
  }
  
  function ChangePackageRate(uint256 packageID,
                             uint256 cfilInterestRate,
                             uint256 weight)
    public
    IsAdmin(){
    
    require(packageID < SInfo.Packages.length, "packageID error");

    updateAllParam();
    
    FinancialPackage storage package = SInfo.Packages[packageID];
    package.CFilInterestRate = cfilInterestRate;

    uint256 nowTotal = package.Total.mul(package.Weight) / Decimal;
    if(package.Type == FinancialType.CRFI){
      SInfo.totalWeightCRFI = SInfo.totalWeightCRFI.sub(nowTotal);
    } else {
      SInfo.totalWeightCFil = SInfo.totalWeightCFil.sub(nowTotal);
    }

    package.Weight = weight;

    nowTotal = package.Total.mul(package.Weight) / Decimal;
    if(package.Type == FinancialType.CRFI){
      SInfo.totalWeightCRFI = SInfo.totalWeightCRFI.add(nowTotal);
    } else {
      SInfo.totalWeightCFil = SInfo.totalWeightCFil.add(nowTotal);
    }
  }

  function AddPackage(FinancialType _type,
                      uint256 dayTimes,
                      uint256 cfilInterestRate,
                      uint256 weight)
    public
    IsAdmin(){

    updateAllParam();
    
    uint256 idx = SInfo.Packages.length;
    SInfo.Packages.push();
    FinancialPackage storage package = SInfo.Packages[idx];

    package.Type = _type;
    package.Days = dayTimes;
    package.Weight = weight;
    package.CFilInterestRate = cfilInterestRate;
    package.ID = idx;
  }

  function ChangeCRFIMinerPerDay(uint256 crfi, uint256 cfil)
    public
    IsAdmin(){

    updateAllParam();

    SInfo.crfiMinerPerDayCFil = cfil;
    SInfo.crfiMinerPerDayCRFI = crfi;
  }

  function ChangeLoanRate(uint256 apy, uint256 pledgeRate, uint256 paymentDue)
    public
    IsAdmin(){

    require(pledgeRate > 0, "pledge rate can't = 0");

    SInfo.LoanCFil.APY = apy;
    SInfo.LoanCFil.PledgeRate = pledgeRate;
    SInfo.LoanCFil.PaymentDue = paymentDue;
    SInfo.LoanCFil.PaymentDue99 = paymentDue.mul(99) / 100;
  }

  function ChangeAffCFil(bool enable)
    public
    IsAdmin(){
    if(enable && SInfo.EnableAffCFil == 0){
      SInfo.EnableAffCFil = 1;
    } else if(!enable && SInfo.EnableAffCFil > 0){
      SInfo.EnableAffCFil = 0;
    }
  }

  function ChangeAffRate(uint256 rate)
    public
    IsAdmin(){
    
    SInfo.AffRate = rate;
  }

  function ChangeAffRequire(uint256 amount)
    public
    IsAdmin(){
    SInfo.AffRequire = amount;
  }

  function WithdrawCRFIInterestPool(uint256 amount)
    public
    IsAdmin(){
    SInfo.crfiInterestPool = SInfo.crfiInterestPool.sub(amount);
    CRFI.send(msg.sender, amount, "");
  }

  function WithdrawCFilInterestPool(uint256 amount)
    public
    IsAdmin(){
    SInfo.cfilInterestPool = SInfo.cfilInterestPool.sub(amount);
    CFil.send(msg.sender, amount, "");
  }
  
  //////////////////// public
  function tokensReceived(
        address operator,
        address from,
        address to,
        uint256 amount,
        bytes calldata userData,
        bytes calldata operatorData)
    public
    override
    nonReentrant(){

    ////////// check
    require(userData.length > 0, "no user data");
    
    // mode = 0, normal bought financial package
    // mode = 2, charge cfil interest pool
    // mode = 3, charge crfi interest pool
    // mode = 4, loan cfil
    // mode = 5, repay cfil by loan
    (uint256 mode, uint256 param, address addr) = abi.decode(userData, (uint256,uint256, address));
    require(from != address(0x0), "from is zero");

    if(mode == 5){
      _repayLoanCFil(from, amount);
    }else if(mode == 4){
      _loanCFil(from, amount);
    }else if(mode == 3){
      require(amount > 0, "no amount");
      require(msg.sender == address(CRFI), "only charge crfi");
      SInfo.crfiInterestPool = SInfo.crfiInterestPool.add(amount);
      return;
    }else if(mode == 2){
      require(amount > 0, "no amount");
      require(msg.sender == address(CFil), "only charge cfil");
      SInfo.cfilInterestPool = SInfo.cfilInterestPool.add(amount);
      
      return;
    } else if (mode == 0){
      _buyFinancialPackage(from, param, addr, amount);
    } else {
      revert("mode error");
    }
  }
  
  function Withdraw(uint256 packageID, bool only, uint256 maxNum)
    public
    nonReentrant(){

    InvestInfo storage uInfo = SInfo.Invests[getUID(msg.sender)];
    
    uint256 cfil;
    uint256 cfilInterest;
    uint256 crfi;
    uint256 crfiInterest;

    (crfi, crfiInterest, cfil, cfilInterest) = _withdrawFinancial(uInfo, packageID, only, maxNum);

    if(crfi > 0){
      uInfo.nowInvestFinCRFI = uInfo.nowInvestFinCRFI.sub(crfi);
    }
    if(cfil > 0){
      uInfo.nowInvestFinCFil = uInfo.nowInvestFinCFil.sub(cfil);
    }

    withdrawCoin(uInfo.Addr, crfi, crfiInterest, cfil, cfilInterest);
  }

  //////////////////// view func

  function GetMap(string memory key)
    public
    view
    returns(string memory value){

    return SInfo.kvMap[key];
  }

  function GetFinancialPackage()
    public
    view
    returns(FinancialPackage[] memory packages){

    packages = new FinancialPackage[](SInfo.Packages.length);
    for(uint256 packageID = 0; packageID < SInfo.Packages.length; packageID++){
      packages[packageID] = SInfo.Packages[packageID];
      packages[packageID].CRFIInterestRateDyn = getFinancialCRFIRate(SInfo.Packages[packageID]);
    }
    
    return packages;
  }

  function GetInvesterFinRecords(address addr)
    public
    view
    returns(QueueData[] memory records){

    uint256 uid = SInfo.InvestAddrID[addr];
    if(uid == 0){
      return records;
    }

    InvestInfo storage uInfo = SInfo.Invests[uid];

    uint256 recordSize = 0;

    for(uint256 packageID = 0; packageID < SInfo.Packages.length; packageID++){
      ChainQueue storage chain = uInfo.InvestRecords[packageID];
      recordSize = recordSize.add(chain.Size);
    }

    records = new QueueData[](recordSize);
    uint256 id = 0;
    
    for(uint256 packageID = 0; packageID < SInfo.Packages.length; packageID++){
      ChainQueue storage chain = uInfo.InvestRecords[packageID];
      if(chain.Size == 0){
        continue;
      }

      ChainItem storage item = SInfo.ChainM.GetFirstItem(chain);
      for(;;){
        records[id] = item.Data;
        id++;

        if(!SInfo.ChainM.HasNext(item)){
          break;
        }

        item = SInfo.ChainM.Next(item);
      }
    }
    
    return records;
  }


  function GetSystemInfo()
    public
    view
    returns(SystemInfoView memory sInfoView){

    sInfoView.AffRate = SInfo.AffRate;
    sInfoView.AffRequire = SInfo.AffRequire;
    sInfoView.EnableAffCFil = SInfo.EnableAffCFil;
    sInfoView.NewInvestID = SInfo.NewInvestID;
    sInfoView.nowInvestCRFI = SInfo.nowInvestCRFI;
    sInfoView.nowInvestCFil = SInfo.nowInvestCFil;
    sInfoView.cfilInterestPool = SInfo.cfilInterestPool;
    sInfoView.crfiInterestPool = SInfo.crfiInterestPool;

    sInfoView.cfilLendingTotal = SInfo.cfilLendingTotal;
    sInfoView.crfiRewardTotal = SInfo.crfiRewardTotal;
    sInfoView.avaiCFilAmount = SInfo.avaiCFilAmount;
  
    sInfoView.totalWeightCFil = SInfo.totalWeightCFil;
    sInfoView.totalWeightCRFI = SInfo.totalWeightCRFI;
    sInfoView.crfiMinerPerDayCFil = SInfo.crfiMinerPerDayCFil;
    sInfoView.crfiMinerPerDayCRFI = SInfo.crfiMinerPerDayCRFI;
  
    sInfoView.ParamUpdateTime = SInfo.ParamUpdateTime;

    return sInfoView;
  }

  function GetPackages()
    public
    view
    returns(FinancialPackage[] memory financialPackages,
            LoanCFilPackage memory loanCFil){

    return (GetFinancialPackage(),
            SInfo.LoanCFil);
  }


  function GetInvestRecords(address addr)
    public
    view
    returns(QueueData[] memory records,
            LoanInvest memory loanInvest,
            InterestDetail[] memory interestDetail){

    uint256 uid = SInfo.InvestAddrID[addr];
    if(uid == 0){
      return (records, loanInvest, interestDetail);
    }

    InvestInfo storage uInfo = SInfo.Invests[uid];

    records = GetInvesterFinRecords(addr);
    interestDetail = new InterestDetail[](records.length+1);

    uint256 id = 0;
    for(; id < records.length; id++){
      (interestDetail[id].crfiInterest, interestDetail[id].cfilInterest) = _calcInvestFinancial(records[id].PackageID, records[id].Amount, records[id].ParamCRFI, records[id].ParamCFil);
    }

    interestDetail[id].cfilInterest = calcInvestLoanStatus(uInfo);
    interestDetail[id].cfilInterest = interestDetail[id].cfilInterest.add(uInfo.LoanCFil.NowInterest);

    return(records,
           uInfo.LoanCFil,
           interestDetail);
  }

  function GetInvestInfo(uint256 uid, address addr)
    public
    view
    returns(bool admin,
            InvestInfoView memory uInfoView){
    if(uid == 0){
      uid = SInfo.InvestAddrID[addr];
    }

    if(uid == 0){
      if(addr != address(0x0)){
        admin = (SInfo.SuperAdmin == addr) || (SInfo.Admins[addr]);
      }
      return (admin,
              uInfoView);
    }
    
    InvestInfo storage uInfo = SInfo.Invests[uid];

    admin = (SInfo.SuperAdmin == uInfo.Addr) || (SInfo.Admins[uInfo.Addr]);

    uInfoView.Addr = uInfo.Addr;
    uInfoView.ID = uInfo.ID;
    uInfoView.affID = uInfo.affID;
    uInfoView.totalAffTimes = uInfo.totalAffTimes;
    uInfoView.totalAffPackageTimes = uInfo.totalAffPackageTimes;
    uInfoView.totalAffCRFI = uInfo.totalAffCRFI;
    uInfoView.totalAffCFil = uInfo.totalAffCFil;
    uInfoView.nowInvestFinCRFI = uInfo.nowInvestFinCRFI;
    uInfoView.nowInvestFinCFil = uInfo.nowInvestFinCFil;

    return (admin,
            uInfoView);
  }

  function calcSFilToCFil(uint256 sfil)
    public
    view
    returns(uint256 cfil){
    cfil = sfil.mul(SInfo.LoanCFil.PledgeRate) / Decimal;
    return cfil;
  }

  function calcCFilToSFil(uint256 cfil)
    public
    view
    returns(uint256 sfil){

    sfil = cfil.mul(Decimal) / SInfo.LoanCFil.PledgeRate;
    return sfil;
  }
  
  //////////////////// for debug

  function getChainMDetail()
    public
    view
    returns(ChainManager memory chaimM){

    return SInfo.ChainM;
  }

  function getInvestChainDetail(uint256 id)
    public
    view
    returns(ChainQueue[] memory chains){

    InvestInfo storage uInfo = SInfo.Invests[id];

    chains = new ChainQueue[](SInfo.Packages.length);

    for(uint256 packageID = 0; packageID < SInfo.Packages.length; packageID++){
      chains[packageID] = uInfo.InvestRecords[packageID];
    }

    return chains;
  }
  
  //////////////////// internal func
  function _repayLoanCFil(address from,
                          uint256 cfilAmount)
    internal{
    require(cfilAmount > 0, "no cfil amount");
    require(msg.sender == address(CFil), "not cfil coin type");

    InvestInfo storage uInfo = SInfo.Invests[getUID(from)];
    updateInvesterLoanCFil(uInfo);

    // deal interest
    uint256 repayInterest = cfilAmount;
    if(uInfo.LoanCFil.NowInterest < cfilAmount){
      repayInterest = uInfo.LoanCFil.NowInterest;
    }

    uInfo.LoanCFil.NowInterest = uInfo.LoanCFil.NowInterest.sub(repayInterest);
    SInfo.cfilInterestPool = SInfo.cfilInterestPool.add(repayInterest);
    cfilAmount = cfilAmount.sub(repayInterest);

    // deal lending
    if(cfilAmount == 0){
      return;
    }

    uint256 repayLending = cfilAmount;
    if(uInfo.LoanCFil.Lending < cfilAmount){
      repayLending = uInfo.LoanCFil.Lending;
    }

    uint256 pledge = repayLending.mul(uInfo.LoanCFil.Pledge) / uInfo.LoanCFil.Lending;
    uInfo.LoanCFil.Lending = uInfo.LoanCFil.Lending.sub(repayLending);
    uInfo.LoanCFil.Pledge = uInfo.LoanCFil.Pledge.sub(pledge);
    SInfo.cfilLendingTotal = SInfo.cfilLendingTotal.sub(repayLending);
    SInfo.avaiCFilAmount = SInfo.avaiCFilAmount.add(repayLending);
    cfilAmount = cfilAmount.sub(repayLending);

    if(pledge > 0){
      SFil.send(from, pledge, "");
    }
    
    if(cfilAmount > 0){
      CFil.send(from, cfilAmount, "");
    }
  }
  
  function _loanCFil(address from,
                     uint256 sfilAmount)
    internal{

    require(sfilAmount > 0, "no sfil amount");
    require(msg.sender == address(SFil), "not sfil coin type");

    uint256 cfilAmount = calcSFilToCFil(sfilAmount);
    require(cfilAmount <= SInfo.avaiCFilAmount, "not enough cfil to loan");
    require(cfilAmount >= SInfo.LoanCFil.PaymentDue99, "cfil amount is too small");

    InvestInfo storage uInfo = SInfo.Invests[getUID(from)];
    updateInvesterLoanCFil(uInfo);
    
    if(uInfo.LoanCFil.Param < SInfo.LoanCFil.Param){
      uInfo.LoanCFil.Param = SInfo.LoanCFil.Param;
    }
    uInfo.LoanCFil.Lending = uInfo.LoanCFil.Lending.add(cfilAmount);
    uInfo.LoanCFil.Pledge = uInfo.LoanCFil.Pledge.add(sfilAmount);

    SInfo.cfilLendingTotal = SInfo.cfilLendingTotal.add(cfilAmount);
    SInfo.avaiCFilAmount = SInfo.avaiCFilAmount.sub(cfilAmount);

    CFil.send(from, cfilAmount, "");
    emit loanCFilEvent(from, cfilAmount, sfilAmount);
  }
  
  function _buyFinancialPackage(address from,
                                uint256 packageID,
                                address affAddr,
                                uint256 amount)
    internal{
    // check
    require(amount > 0, "no amount");
    require(packageID < SInfo.Packages.length, "invalid packageID");
    FinancialPackage storage package = SInfo.Packages[packageID];
    if(package.Type == FinancialType.CRFI){
      require(msg.sender == address(CRFI), "not CRFI coin type");
    }else if(package.Type == FinancialType.CFil){
      require(msg.sender == address(CFil), "not CFil coin type");
    } else {
      revert("not avai package type");
    }

    updateAllParam();
    
    // exec
    InvestInfo storage uInfo = SInfo.Invests[getUID(from)];    

    uint256 affID = uInfo.affID;

    if(affID == 0 && affAddr != from && affAddr != address(0x0)){
      uInfo.affID = getUID(affAddr);
      affID = uInfo.affID;
    }

    if(package.Days == 0){
      affID = 0;
    }

    if(affID != 0){
      InvestInfo storage affInfo = SInfo.Invests[affID];
      affInfo.totalAffPackageTimes++;      
      emit AffBought(affAddr, from, affInfo.totalAffPackageTimes, amount, packageID, block.timestamp); 
    }

    ChainQueue storage recordQ = uInfo.InvestRecords[package.ID];

    ChainItem storage item = SInfo.ChainM.GetAvaiItem();

    item.Data.Type = package.Type;
    item.Data.PackageID = package.ID;
    item.Data.Days = package.Days;
    item.Data.EndTime = block.timestamp.add(package.Days.mul(OneDayTime));
    item.Data.AffID = affID;
    item.Data.Amount = amount;
    item.Data.ParamCRFI = package.ParamCRFI;
    item.Data.ParamCFil = package.ParamCFil;

    SInfo.ChainM.PushEndItem(recordQ, item);

    ////////// for statistic
    package.Total = package.Total.add(amount);
    if(package.Type == FinancialType.CRFI){
      uInfo.nowInvestFinCRFI = uInfo.nowInvestFinCRFI.add(amount);
      SInfo.nowInvestCRFI = SInfo.nowInvestCRFI.add(amount);
      SInfo.totalWeightCRFI = SInfo.totalWeightCRFI.add(amount.mul(package.Weight) / Decimal);
    } else if(package.Type == FinancialType.CFil){
      uInfo.nowInvestFinCFil = uInfo.nowInvestFinCFil.add(amount);
      SInfo.nowInvestCFil = SInfo.nowInvestCFil.add(amount);
      SInfo.avaiCFilAmount = SInfo.avaiCFilAmount.add(amount);
      SInfo.totalWeightCFil = SInfo.totalWeightCFil.add(amount.m...

// [truncated — 59665 bytes total]

Read Contract

CFil 0x0a28b8a9 → address
CRFI 0x2ef3da23 → address
GetFinancialPackage 0x497cb411 → tuple[]
GetInvestInfo 0x0696ecaa → bool, tuple
GetInvestRecords 0x470c2382 → tuple[], tuple, tuple[]
GetInvesterFinRecords 0x38309b85 → tuple[]
GetMap 0x87e3dfe2 → string
GetPackages 0x3daa551c → tuple[], tuple
GetSystemInfo 0x119577a4 → tuple
OneDayTime 0xcc297ab1 → uint256
SFil 0xbace1a36 → address
calcCFilToSFil 0x9fa8f013 → uint256
calcSFilToCFil 0x3dd8fe11 → uint256
getChainMDetail 0xa834f5b7 → tuple
getInvestChainDetail 0xe6402077 → tuple[]

Write Contract 15 functions

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

AddAdmin 0xad6de445
address admin
AddPackage 0xe3adffab
uint8 _type
uint256 dayTimes
uint256 cfilInterestRate
uint256 weight
ChangeAffCFil 0xd8359117
bool enable
ChangeAffRate 0x9c1857d4
uint256 rate
ChangeAffRequire 0xf5603317
uint256 amount
ChangeCRFIMinerPerDay 0xc211acf2
uint256 crfi
uint256 cfil
ChangeLoanRate 0x8719bfb1
uint256 apy
uint256 pledgeRate
uint256 paymentDue
ChangePackageRate 0x3a64ebec
uint256 packageID
uint256 cfilInterestRate
uint256 weight
ChangeSuperAdmin 0x12efe4b3
address suAdmin
DelAdmin 0xb6932914
address admin
SetMap 0x0faf728a
string key
string value
Withdraw 0xc7c13b3a
uint256 packageID
bool only
uint256 maxNum
WithdrawCFilInterestPool 0x6f73ae00
uint256 amount
WithdrawCRFIInterestPool 0xf5508101
uint256 amount
tokensReceived 0x0023de29
address operator
address from
address to
uint256 amount
bytes userData
bytes operatorData

Recent Transactions

No transactions found for this address