diff --git a/Cargo.lock b/Cargo.lock index a598aae..8e246c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,7 +729,6 @@ dependencies = [ "router-mock", "simple-lock", "utils", - "week-timekeeping", ] [[package]] diff --git a/growth-program/Cargo.toml b/growth-program/Cargo.toml index 26f04cf..4b671ae 100644 --- a/growth-program/Cargo.toml +++ b/growth-program/Cargo.toml @@ -27,10 +27,6 @@ rev = "0c7f45e" git = "https://github.com/multiversx/mx-exchange-sc" rev = "0c7f45e" -[dependencies.week-timekeeping] -git = "https://github.com/multiversx/mx-exchange-sc" -rev = "0c7f45e" - [dependencies.energy-query] git = "https://github.com/multiversx/mx-exchange-sc" rev = "0c7f45e" diff --git a/growth-program/output/growth-program.abi.json b/growth-program/output/growth-program.abi.json index 500f5f3..560eb87 100644 --- a/growth-program/output/growth-program.abi.json +++ b/growth-program/output/growth-program.abi.json @@ -10,7 +10,7 @@ "contractCrate": { "name": "growth-program", "version": "0.0.0", - "gitVersion": "v1.0.2-141-gb83ee58" + "gitVersion": "v1.0.2-154-g37b183a" }, "framework": { "name": "multiversx-sc", @@ -21,14 +21,14 @@ "constructor": { "docs": [ "Arguments:", - "min_energy_per_reward_dollar: Scaled to PRECISION const.", + "min_reward_dollars_per_energy: Scaled to PRECISION const.", "alpha: Percentage, scaled to MAX_PERCENTAGE const.", "beta: Percentage, scaled to MAX_PERCENTAGE const.", "signer: Public key of the signer, used to verify user claims" ], "inputs": [ { - "name": "min_energy_per_reward_dollar", + "name": "min_reward_dollars_per_energy", "type": "BigUint" }, { @@ -153,7 +153,7 @@ "type": "u32" }, { - "name": "initial_energy_per_rew_dollar", + "name": "initial_rewards_dollar_per_energy", "type": "BigUint" } ], @@ -209,7 +209,7 @@ "outputs": [] }, { - "name": "setMinEnergyPerRewardDollar", + "name": "setMinRewardDollarsPerEnergy", "onlyOwner": true, "mutability": "mutable", "inputs": [ @@ -221,7 +221,7 @@ "outputs": [] }, { - "name": "setEnergyPerRewardDollarForWeek", + "name": "setNextWeekRewardDollarsPerEnergy", "onlyOwner": true, "mutability": "mutable", "inputs": [ @@ -260,6 +260,33 @@ ], "outputs": [] }, + { + "name": "setTotalEnergyForCurrentWeek", + "mutability": "mutable", + "inputs": [ + { + "name": "project_ids", + "type": "variadic", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "getTotalEnergyForCurrentWeek", + "mutability": "readonly", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, { "name": "claimRewards", "mutability": "mutable", @@ -277,9 +304,8 @@ "type": "array64" }, { - "name": "opt_lock_option", - "type": "optional", - "multi_arg": true + "name": "claim_type", + "type": "ClaimType" } ], "outputs": [ @@ -427,7 +453,7 @@ ] }, { - "name": "getFirstWeekStartEpoch", + "name": "getFirstWeekStartTimestamp", "mutability": "readonly", "inputs": [], "outputs": [ @@ -483,9 +509,61 @@ ] } ], + "events": [ + { + "identifier": "claimRewardsEvent", + "inputs": [ + { + "name": "caller", + "type": "Address", + "indexed": true + }, + { + "name": "claim_data", + "type": "ClaimRewardsEventData" + } + ] + } + ], "esdtAttributes": [], "hasCallback": false, "types": { + "ClaimRewardsEventData": { + "type": "struct", + "fields": [ + { + "name": "project_id", + "type": "u32" + }, + { + "name": "amount", + "type": "BigUint" + }, + { + "name": "claim_type", + "type": "ClaimType" + } + ] + }, + "ClaimType": { + "type": "enum", + "variants": [ + { + "name": "Exemption", + "discriminant": 0 + }, + { + "name": "Rewards", + "discriminant": 1, + "fields": [ + { + "name": "0", + "type": "LockOption" + } + ] + } + ] + }, "EsdtTokenPayment": { "type": "struct", "fields": [ @@ -535,6 +613,10 @@ "name": "start_week", "type": "u32" }, + { + "name": "last_update_week", + "type": "u32" + }, { "name": "end_week", "type": "u32" diff --git a/growth-program/output/growth-program.imports.json b/growth-program/output/growth-program.imports.json index a10b0b0..d0b6404 100644 --- a/growth-program/output/growth-program.imports.json +++ b/growth-program/output/growth-program.imports.json @@ -15,6 +15,7 @@ "cleanReturnData", "getArgumentLength", "getBlockEpoch", + "getBlockTimestamp", "getGasLeft", "getNumArguments", "isSmartContract", @@ -43,6 +44,7 @@ "managedSCAddress", "managedSignalError", "managedVerifyEd25519", + "managedWriteLog", "signalError", "smallIntFinishSigned", "smallIntFinishUnsigned", diff --git a/growth-program/output/growth-program.mxsc.json b/growth-program/output/growth-program.mxsc.json index 9a3061a..6c38eb1 100644 --- a/growth-program/output/growth-program.mxsc.json +++ b/growth-program/output/growth-program.mxsc.json @@ -21,14 +21,14 @@ "constructor": { "docs": [ "Arguments:", - "min_energy_per_reward_dollar: Scaled to PRECISION const.", + "min_reward_dollars_per_energy: Scaled to PRECISION const.", "alpha: Percentage, scaled to MAX_PERCENTAGE const.", "beta: Percentage, scaled to MAX_PERCENTAGE const.", "signer: Public key of the signer, used to verify user claims" ], "inputs": [ { - "name": "min_energy_per_reward_dollar", + "name": "min_reward_dollars_per_energy", "type": "BigUint" }, { @@ -153,7 +153,7 @@ "type": "u32" }, { - "name": "initial_energy_per_rew_dollar", + "name": "initial_rewards_dollar_per_energy", "type": "BigUint" } ], @@ -209,7 +209,7 @@ "outputs": [] }, { - "name": "setMinEnergyPerRewardDollar", + "name": "setMinRewardDollarsPerEnergy", "onlyOwner": true, "mutability": "mutable", "inputs": [ @@ -221,7 +221,7 @@ "outputs": [] }, { - "name": "setEnergyPerRewardDollarForWeek", + "name": "setNextWeekRewardDollarsPerEnergy", "onlyOwner": true, "mutability": "mutable", "inputs": [ @@ -260,6 +260,33 @@ ], "outputs": [] }, + { + "name": "setTotalEnergyForCurrentWeek", + "mutability": "mutable", + "inputs": [ + { + "name": "project_ids", + "type": "variadic", + "multi_arg": true + } + ], + "outputs": [] + }, + { + "name": "getTotalEnergyForCurrentWeek", + "mutability": "readonly", + "inputs": [ + { + "name": "project_id", + "type": "u32" + } + ], + "outputs": [ + { + "type": "BigUint" + } + ] + }, { "name": "claimRewards", "mutability": "mutable", @@ -277,9 +304,8 @@ "type": "array64" }, { - "name": "opt_lock_option", - "type": "optional", - "multi_arg": true + "name": "claim_type", + "type": "ClaimType" } ], "outputs": [ @@ -427,7 +453,7 @@ ] }, { - "name": "getFirstWeekStartEpoch", + "name": "getFirstWeekStartTimestamp", "mutability": "readonly", "inputs": [], "outputs": [ @@ -483,9 +509,61 @@ ] } ], + "events": [ + { + "identifier": "claimRewardsEvent", + "inputs": [ + { + "name": "caller", + "type": "Address", + "indexed": true + }, + { + "name": "claim_data", + "type": "ClaimRewardsEventData" + } + ] + } + ], "esdtAttributes": [], "hasCallback": false, "types": { + "ClaimRewardsEventData": { + "type": "struct", + "fields": [ + { + "name": "project_id", + "type": "u32" + }, + { + "name": "amount", + "type": "BigUint" + }, + { + "name": "claim_type", + "type": "ClaimType" + } + ] + }, + "ClaimType": { + "type": "enum", + "variants": [ + { + "name": "Exemption", + "discriminant": 0 + }, + { + "name": "Rewards", + "discriminant": 1, + "fields": [ + { + "name": "0", + "type": "LockOption" + } + ] + } + ] + }, "EsdtTokenPayment": { "type": "struct", "fields": [ @@ -535,6 +613,10 @@ "name": "start_week", "type": "u32" }, + { + "name": "last_update_week", + "type": "u32" + }, { "name": "end_week", "type": "u32" @@ -543,6 +625,6 @@ } } }, - "size": 17511, - "code": "0061736d0100000001a1011a60017f017f60000060027f7f017f60027f7f006000017f60017f0060037f7f7f0060037f7f7f017f60047f7f7f7f0060027f7e0060047f7f7f7f017f60017f017e60027f7e017f6000017e60017e0060057f7f7f7f7f0060027f7f017e60057f7f7e7f7f017f60067e7f7f7f7f7f017f60057e7f7f7f7f017f60047f7f7f7e0060017e017f60027e7f0060037f7f7e017f60047f7f7f7e017f60047f7e7f7f00028d093103656e760e626967496e74536574496e743634000903656e7609626967496e74416464000603656e760b7369676e616c4572726f72000303656e760a6d4275666665724e6577000403656e760d6d427566666572417070656e64000203656e76096d4275666665724571000203656e760d6d42756666657246696e697368000003656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465001103656e761b6d616e61676564457865637574654f6e44657374436f6e74657874001203656e760d6d616e6167656443616c6c6572000503656e76106d616e61676564534341646472657373000503656e760f6d4275666665724765744279746573000203656e760f6973536d617274436f6e7472616374000003656e76136d616e616765644f776e657241646472657373000503656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000503656e76106d4275666665724765744c656e677468000003656e76126d427566666572417070656e644279746573000703656e76126d616e616765645369676e616c4572726f72000503656e7611676574417267756d656e744c656e677468000003656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000b03656e7619626967496e74476574556e7369676e6564417267756d656e74000303656e760f6765744e756d417267756d656e7473000403656e7614626967496e7446696e697368556e7369676e6564000503656e7609626967496e74537562000603656e7609626967496e74436d70000203656e760f6d4275666665725365744279746573000703656e760a626967496e7454446976000603656e7609626967496e744d756c000603656e76196d42756666657246726f6d426967496e74556e7369676e6564000203656e76176d427566666572546f426967496e74556e7369676e6564000203656e760a626967496e7453717274000303656e76146d427566666572436f707942797465536c696365000a03656e76126d42756666657253746f726167654c6f6164000203656e76136d42756666657253746f7261676553746f7265000203656e76126d427566666572476574417267756d656e74000203656e760a6765744761734c656674000d03656e760f636c65616e52657475726e44617461000103656e760d676574426c6f636b45706f6368000d03656e761776616c6964617465546f6b656e4964656e746966696572000003656e760e636865636b4e6f5061796d656e74000103656e7609626967496e74506f77000603656e7616736d616c6c496e7446696e697368556e7369676e6564000e03656e76146d616e6167656456657269667945643235353139000703656e761d6d42756666657253746f726167654c6f616446726f6d41646472657373000603656e76156d427566666572546f426967496e745369676e6564000203656e7609626967496e74416273000303656e7614736d616c6c496e7446696e6973685369676e6564000e03656e760a626967496e745369676e000003656e76136d42756666657247657442797465536c696365000a03d001ce0100040f010002050003040305050302000000030003030004031304040105000a02100802070707000000070505050105000600060f00030a08080314090903071008000003060600020302020203000002020200041500000a08080a030605000b000000030303030203000303030300050000020c160c090c09060306060905040700170404041804060b0300050408040205040504050404030819050401020505020202020206040604000402040101010101010101010101010101010101010101010101010101010101010105030100030616037f01418080080b7f004185dd080b7f004190dd080b07f70421066d656d6f7279020004696e697400e001077570677261646500e1010a61646450726f6a65637400e2010f73657450726f6a6563744f776e657200e301137365744d696e52657761726473506572696f6400e401187365744d696e5765656b6c795265776172647356616c756500e501156465706f736974496e697469616c5265776172647300e601186465706f7369744164646974696f6e616c5265776172647300e701146f776e657257697468647261775265776172647300e8010d66696e69736850726f6772616d00e9011b7365744d696e456e65726779506572526577617264446f6c6c617200ea011f736574456e65726779506572526577617264446f6c6c6172466f725765656b00eb0108736574416c70686100ec01077365744265746100ed010c636c61696d5265776172647300ee01176765744578656d707465645061727469636970616e747300ef010e67657455736572436c61696d656400f0010d7570646174655265776172647300f1010e67657452657761726473496e666f00f2011567657452657761726473546f74616c416d6f756e7400f301196765745265776172647352656d61696e696e67416d6f756e7400f4010c6368616e67655369676e657200f5010e67657443757272656e745765656b00f6011667657446697273745765656b537461727445706f636800f70117736574456e65726779466163746f72794164647265737300f80117676574456e65726779466163746f72794164647265737300f90105706175736500fa0107756e706175736500fb0108697350617573656400fc010863616c6c4261636b00fd010a5f5f646174615f656e6403010b5f5f686561705f6261736503020afb68ce011601017f1032220142001000200120012000100120010b1901017f41c48e0841c48e0828020041016b220036020020000b2e000240200120024d0440200220044d0d011034000b1034000b2000200220016b3602042000200120036a3602000b060010fe01000b0f01017f10032201200010041a20010b0b0020002001100541004a0b19002000103845044041f28008410f1039000b103a2000103b0b1400200041e5dc08100b1a41e5dc08100c41004a0b0900200020011002000b0a0041f48908411410540b0900200020011098010b3601027f230041106b22012400200141086a103d20012802082102200020012d000c4101713a000420002002360200200141106a24000b6e01027f230041106b220124002000027f41dcdc082d0000220245044041dcdc0841013a000041d8dc084100360200200141086a4100108d012001280208200128020c419c8e084100108b0110480c010b419c8e08410010540b360200200020024101733a0004200141106a24000b0b0020002001103f10061a0b4901017f230041106b22022400200220013a000c20022000360208200241086a108f01200228020820022d000c044041d8dc08410036020041dcdc0841003a00000b200241106a24000b08002000104110420b6a01047f230041106b220124002001410036020c20002001410c6a2202410410762001200028020820002802002203200241041071a7220210722001280200410147044041d88208410b41e38208410f1053000b20012802042000200220036a360200200141106a24000b0d00200010322200101d1a20000b0a0020001044200110450b0f01017f103222012000101c1a20010bb20101037f230041106b2202240020022000100f220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a410410ad010240024020012d000404402000100f22044190ce0041d8dc0828020022036b4b0d0120022003200320046a220110ae01200041002002280200200228020410681a41d8dc0820013602000c020b20012802002000107a0c010b2001108f0120012802002000107a0b200241106a24000b6902057f017e200128020c220410474504402001290300210710482105104821062001280208230041106b22012400104821031035210220012004103136020c20012007370300200120023602082003200110492000200342002005200610071a200141106a24000b0b0b002000107841ff0171450b1301017f10322200419c8e08410010191a20000bd20102027f017e230041106b2203240020032001280208220241187420024180fe03714108747220024108764180fe0371200241187672723602002003200128020c220241187420024180fe03714108747220024108764180fe03712002411876727236020c20032001290300220442388620044280fe0383422886842004428080fc0783421886200442808080f80f834208868484200442088842808080f80f832004421888428080fc07838420044228884280fe0383200442388884848437020420002003411010101a200341106a24000b1500200020012002200320041032220110081a20010b0c01017f10322200100920000b0c01017f10322200100a20000b1d01017f10322200100d2000104b103604400f0b41e88d0841241002000bfc01020c7f017e230041206b22012400416b2103024041e4dc082d000022020440416b41ffffffff0720021b21030c010b41e4dc0841013a0000416b100e0b4101210402402003104f4101460440410021022003100f2106200141106a2107034020052108200241106a220920064b0d02200742003703002001420037030820032002200141086a2202411010501a2001410036021c41012105200420022001411c6a22041051210b200220041052210d200141086a2001411c6a1051210c20092102410021040d000b1034000b4181810841221002000b200d5004402000200c3602042000200b360200200141206a24000f0b41cc8d08411c1002000b09002000100f4104760b0f00200020012003200210304100470b7301017f230041106b220224002002410036020c2002200020012802002200200041046a2200108a012002410c6a410420022802002002280204108b0120012000360200200228020c2100200241106a2400200041187420004180fe03714108747220004108764180fe0371200041187672720ba70102017e017f230041106b22032400200342003703082003200020012802002200200041086a2200108a01200341086a410820032802002003280204108b012001200036020020032903082102200341106a2400200242388620024280fe0383422886842002428080fc0783421886200242808080f80f834208868484200242088842808080f80f832002421888428080fc07838420024228884280fe038320024238888484840b2e01017f41a381084117105422042000200110101a200441ba8108410310101a20042002200310101a20041011000b1101017f103222022000200110191a20020b2f01017f2000280200220341e0dc082802004e04402001200241bd810841111053000b2000200341016a36020020030b2501017e20001013220342ffffffff0f5804402003a70f0b2001200241998008410e1053000b1f00200010582200100f41204704402001200241a3890841101053000b20000b0d0020001032220010221a20000b0c00200010322200101420000b2601017e2000101322014280808080105a044041838608410a41998008410e1053000b2001a70b0a0020002001200210560b1900200041e0dc082802004e04400f0b41ce810841121002000b1400101520004604400f0b41e0810841191002000b1900200041e0dc082802004c04400f0b41bd810841111002000b0b0041e0dc0810153602000b08002000106110160b0900200010940110420b1f0020002001200210172000106341ff017104400f0b41f9810841301002000b1500410241012000102f22001b4100200041004e1b0b1800200120021054210120001048360204200020013602000b900101037f230041106b220524000240200310660d002002200310672004100f2106410021030340200341046a220720064b0d012005410036020c200420032005410c6a410410681a2002200528020c220341187420034180fe03714108747220034108764180fe0371200341187672721067200721030c000b000b2000200236020420002001360200200541106a24000b07002000100f450b0d0010481a200020011035106b0b0c00200020012002200310500b160020022003106720002002360204200020013602000b1b0010481a200220031044106b20002002360204200020013602000b4601017f230041106b220224002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c20002002410c6a410410101a200241106a24000b160020022003106d20002002360204200020013602000b1201017f104822022001106e20002002106b0b3801017f230041106b2202240020024200370308200220014100200241086a10cc0120002002280200200228020410191a200241106a24000b900101037f230041106b220224002002410036020c024020012002410c6a22034104107022044504402002200128020820012802002204200341041071a7220310722000027f20022802004101460440200020022802043602042001200320046a36020041000c010b2000410f36020441e382080b3602000c010b2000410f360204200020043602000b200241106a24000b3201017f41e382082103200041086a200028020020012002108c01047f41e38208052000200028020020026a36020041000b0b3401017e02402001450d0003402001450d01200141016b210120003100002002420886842102200041016a21000c000b000b20020b1f0020012002200310032201101f21022000200136020420002002453602000b5201047f230041106b22012400200010742102200141086a200028020820002802002203200210722001280208410147044041e38208410f1075000b200128020c2000200220036a360200200141106a24000b5402017f017e230041106b220124002001410036020c200041086a20002802002001410c6a4104108c01044041e38208410f1075000b2000200028020041046a3602002001410c6a41041071200141106a2400a70b1a01017f41e783084116105422022000200110101a20021011000b180020002001200210ba012000200028020020026a3602000b0b0020002001200210101a0b09002000106341016b0b1500417f200020011018220041004720004100481b0b09002000200110041a0b0c00200020002001101a20000b0c00200020002001101b20000b0c00200020002001106220000b0a0020002000200110010b11002000200041a08d06108001101a20000b0b0041722000ad100041720b0f00200020002001108001101b20000b1701017f200110800121011032220220002001101a20020b1701017f200110800121011032220220002001101b20020b0e01017f103222012000101e20010b0e01017f103222004200100020000b1b002000420053044041f2820841111002000b41722000100041720b1900200041feffffff074604404180800841191002000b20000b5f01027f230041206b220124002000100f4120460440200141186a4200370300200141106a4200370300200141086a420037030020014200370300200041002001412010501a2001412041a08308412010890121020b200141206a240020020b5301027f2001200346047f4100210302402001450d00034020002d0000220420022d00002205460440200041016a2100200241016a2102200141016b22010d010c020b0b200420056b21030b20030541010b450b2f000240200220034d0440200341104b0d012000200320026b3602042000200120026a3602000f0b1034000b1034000bb50201067f200120034604402001220341104f04402000410020006b41037122046a210520040440200221010340200020012d00003a0000200141016a2101200041016a22002005490d000b0b2005200320046b2203417c7122066a21000240200220046a22044103710440200641004c0d012004410374220141187121072004417c71220841046a2102410020016b4118712109200828020021010340200520012007762002280200220120097472360200200241046a2102200541046a22052000490d000b0c010b200641004c0d0020042102034020052002280200360200200241046a2102200541046a22052000490d000b0b20034103712103200420066a21020b20030440200020036a21010340200020022d00003a0000200241016a2102200041016a22002001490d000b0b0f0b1034000bb50101037f230041106b22042400027f024020002d000845044020002802002205100f22064190ce004b0d0141dcdc082d00000d0141d8dc08200636020041dcdc0841013a0000200441086a2006108d01200541002004280208200428020c10681a200041013a00080b4101200120036a220041d8dc082802004b0d011a200420012000108e012002200320042802002004280204108b0141000c010b200041003a0008200520012002200310680b200441106a24000b3e01017f230041106b22022400200241086a41c88e084190ce00200110cb01200228020c21012000200228020836020020002001360204200241106a24000b32000240200120024d044020024190ce004d0d011034000b1034000b2000200220016b3602042000200141c88e086a3602000b5801027f230041106b2201240020002d0004200041003a00040440200141086a410041d8dc08280200108e0120002802002001280208200128020c10101a41d8dc08410036020041dcdc0841003a00000b200141106a24000b2101017e200010910122014280808080105a044041998008410e1075000b2001a70b6002027f017e230041106b220124002001420037030820001094012200100f220241094f044041998008410e1075000b2001200141086a4108200210cb0120004100200128020022002001280204220210501a200020021071200141106a24000b1c0020001094012200100f412047044041a3890841101075000b20000b0d002000416710201a4167100f0b0d0020001032220010201a20000b0900200120001096010b4501017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a41041077200241106a24000b0b0020002001104410211a0b09002000200110211a0b1a0020001035220041d18308410510101a2000200110950120000bbb0101047f230041206b2202240020011094012203100f21012002411c6a41003a0000200241186a200136020020022003360214200220013602102002410036020c2002410c6a2204107321012002410c6a1073104221032004107421042002410c6a107421052002280210200228020c46044020022d001c044041d8dc08410036020041dcdc0841003a00000b2000200536020c200020043602082000200336020420002001360200200241206a24000f0b41998008410e1075000b2f01017e027f024020001091012201420158044041002001a741016b0d021a0c010b41b3890841121075000b41010b0b6b01027f230041106b220224002002103d20022002280200360208200220022d00044101713a000c2001280200200241086a2203104520012802042003104320012802082003109d01200128020c2003109d012000200228020820022d000c103f10211a200241106a24000b4601017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a410410ad01200241106a24000b0900200020011097010b080020002001103b0b0d01017f20001061200010a1010b1400416c419c8e08410010191a2000416c10211a0b08002000109301450b130020001035220041968e08410610101a20000b190020001035220041928e08410410101a20002001107a20000b1a00200010352200418c8e08410610101a2001200010a60120000b7701017f230041106b220224002002200042388620004280fe0383422886842000428080fc0783421886200042808080f80f834208868484200042088842808080f80f832000421888428080fc07838420004228884280fe038320004238888484843703082001200241086a41081077200241106a24000b1a0020001035220041e18308410610101a2001200010a60120000b5001037f20002802082203200110a9014504402000280204220210900121042000280200200441016a2200109901200110aa0120022000ad10aa01200210900121002003200110a7012000ad10aa010b0b0f002000200110a7011090014100470b3801017f230041106b2202240020024200370308200220014100200241086a10cc0120002002280200200228020410ab01200241106a24000b0d00200020012002105410211a0b4f01027f230041106b2202240020022000100f220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a4104107720012000107a200241106a24000b810101027f230041106b220324000240024020002d000404404190ce0041d8dc0828020022046b2002490d01200341086a2004200220046a220010ae012003280208200328020c20012002108b0141d8dc0820003602000c020b20002802002001200210101a0c010b2000108f0120002802002001200210101a0b200341106a24000b3f01017f230041106b22032400200341086a2001200241c88e084190ce001033200328020c21012000200328020836020020002001360204200341106a24000b2201017f1032220242001000200010850136020c20002001370300200020023602080b090010b1012000103b0b0a0041a38508410610540b8b0101037f230041106b2203240020001087012104418d8c084107105421051048220020011067200020021067108501210110232004200120052000104a210010242000100f21012003410036020c2003200036020420032001410276360208200341046a10b30110352200100f412047044041d88208410b41a3890841101053000b200341106a240020000b7d01037f230041106b22012400200028020821032001410036020c200028020020034102742001410c6a41041068450440200128020c21022000200341016a360208200241187420024180fe03714108747220024108764180fe0371200241187672721035200141106a24000f0b41d88208410b41bd810841111053000b920101057f20001035210310b501109401210410b601109401210510b70110920122061035200310352004103510b201220710880145044020062004200510b2012203108801044041878408412b1039000b200310b501109401200720002001200210b801200210b8010f0b20062003200510b2012203108801450440200320002001200210b8010f0b41b28408412b1039000b0a0041818b08410c10540b0a0041e98a08410b10540b0a0041f48a08410d10540bd00201047f230041306b2204240010b901109201108701210641d78908411d10542107104822052000106720052003106d200110481035220010ac014200200010a60120021044200010ac0120052000106b108501210010232006200020072005104a210010242000100f210120044100360210200420003602082004200141027636020c200441086a10b3012201100f2100200441246a41003a0000200441206a20003602002004200136021c200420003602182004410036021420044100360228200441146a200441286a410410ba01024020042d002b044020042d0028450d010b200441003a002f200441146a2004412f6a410110760b200441146a220010411a200010bb011a2000104021002004280218200428021446044020042d0024044041d8dc08410036020041dcdc0841003a00000b200441306a240020000f0b41d88208410b41998008410e1053000b0a00418d8b08410d10540b2500200041086a200028020020012002108c01044041d88208410b41e38208410f1053000b0b3002017f017e230041106b22012400200142003703082000200141086a220041081076200041081071200141106a24000b1b002000200110bd01109201103645044041b2850841291039000b0b1300200041aa8a08410c1054220010960120000b170010bf01109001200049044041db850841121039000b0b0a0041b68a08410d10540bac0101037f024010c1012205200328020822044d0d002004200328020c2206460d002005200220046a2202200520022005491b20011b2201200620012006491b22012004200120044b1b210510850121020340200420054604400240200641016b20014d044020032802042002107e0c010b2000200110c2012200106122042002107e20002004109e010b200320013602080520022000200410c20110a001107e200441016a21040c010b0b0b0b2901027e1025220010c901109101220154044041aa8e08411a1039000b200020017d420780a741016a0b1a002000418d8d084116105422001096012000200110950120000b0a0010c4012000109e010b0a0041ac8b08410e10540b0a0010c6012000109e010b0a0041a98508410410540b0a0010c8012000109e010b0a0041ad8508410510540b0a0041c38a08411310540b2e01027f200110352102200110352203419f8908410410101a2000200336020420002001360200200020023602080b3b01017f230041106b22042400200441086a41002003200120021033200428020c21012000200428020836020020002001360204200441106a24000b900202047f017e2003200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc0783842001423888220820014228884280fe038384848437000002402001500440419c8e0821030c010b200204402001427f510440200341076a2103410121040c020b2008a7c022054107752106200541004821050b200641ff0171210603400240024020044108470440200320046a2d000022072006460d02200245200741077620054672450440200441016b220441094f0d020b200320046a2103410820046b21040c040b1034000b10fe01000b200441016a21040c000b000b20002004360204200020033602000b3a01027f230041106b2201240010ce012001420037030820012000ad4101200141086a10cc012001280200200128020410ab01200141106a24000b0a0041d68a08411310540b140010ce01109b01044041c5890841121039000b0b0f0020002001107941ff01714102490b1d0002402000108801450440200010380d010b41888a0841121039000b0b130020001026450440419a8a0841101039000b0b1a002000419a8b084112105422001096012000200110950120000b1a00200041ba8b084112105422001096012000200110950120000b1a00200041cc8b084117105422001096012000200110950120000b1a00200041e38b084114105422001096012000200110950120000b1a00200041f78b084116105422001096012000200110950120000b1f00200141948c08410b10542201109601200120021095012000200110ca010b0a00419f8c08411110540b1f00200141b08c08411410542201109601200120021095012000200110ca010b0a0041c48c08410710540b1300200041cb8c08410b1054220010960120000b0a0041d68c08411010540b1a00200041e68c084112105422001096012000200110950120000b0a0041f88c08411510540bfe01020a7f017e1027410a105d41001059410110592106410210592107410341a38508410610572108410441958508410e10572100410541868508410f10572101410641f0840841161057410741dd8408411310572102410810582103410910582104200010d101200110d101200210d101200310d201200410d20110b7012000109f0110b9012001109f0110d9012002109f0110b601200310980110b5012004109801103710c301200610c701200710c501200810b00110dd01421a10aa011032220042e807100010322201420a10001032220220014106108001102820002002107c210010df012000109e011025210a10c901200a10aa01410110cd010b080010274100105d0b4002027f017e1027104d4101105d410041ed8508410d1057210110bf01109001210010bf01200041016a2200ad220210aa01200010bd012001109f01200210290b2401027f1027104d4102105d4100105a410141fa850841091057210110bd012001109f010b2101017f1027104d4101105d410041bb87084108105b210010dd012000ad10aa010b1a01017f1027104d4101105d41001059210010df012000109e010b8e03010d7f230041306b220024004104105d4100105a2102410141cb8708410a105b2103410241c387084108105b210441031059210810cf01200210be01104b2209200210bc010240024002400240200210dc01220a10a201044020032004492201450d0110dd01109001200420036b22074b0d0210c10120034f0d03200041086a104e20002802082106200028020c220b2007108201210520061035200510314280f52410b40110df01106110d001450d042004200320011b210c2003210103402001200c464504402002200110de0120051097012002200110c2012005109701200141016a21010c010b0b2002200310d4012008109e01200b20052007108301107d21012006103521022000200136021c20004200370310200020023602182009200041106a104610850121012000200436022c200020033602282000200136022420002006360220200a200041206a109c01200041306a24000f0b41d5870841211039000b41f6870841141039000b418a880841141039000b41ba8d0841121039000b418a8708410f1039000bef03010e7f230041306b220024004103105d4100105a2103410141cb8708410a105b2101410241c387084108105b210410cf01200310be01104b220c200310bc010240024002400240024002400240200310dc01220a10a20145044020012004492207450d01200041086a104e200028020c210b20002802082108200041106a2206200a109a01200820002802101036450d0210c1012202200028021c22054f0d03200120024d0d04200120054b0d05200028021820044b0d06200341012002200610c001200b200420016b220d108201210520081035200510314280f52410b40110df01106110d001450d072004200120071b210720012102034020022007464504402003200210de012206106122092005107e20062009109e012003200210c2012206106122092005107e20062009109e01200241016a21020c010b0b2000200b2005200d108301107d36022c2000420037032020002008360228200c200041206a10462000200028021822022001200120024b1b3602182000200028021c22012004200120044b1b36021c200a200041106a109c01200041306a24000f0b41d2880841221039000b41f6870841141039000b419e8808410f1039000b41ad880841151039000b41ba8d0841121039000b41ba8d0841121039000b41c2880841101039000b418a8708410f1039000b9b0201087f230041206b220024001027104d4102105d4100105a2102410141cb8708410a105b2103200210be012000200210dc012205109a01024010c1012204200028020c2201490440200120034d200028020820034f720d01200320044d0d01200241012001200010c0011085012107200028020c21042003210103402006200120044b7245044020072002200110c20110a001107e2002200110de0110a101200120044f2106200120012004496a21010c010b0b104b2000280200103521022000200736021c2000420037031020002002360218200041106a10460240200320002802084704402000200336020c20052000109c010c010b200510a1010b200041206a24000f0b4188890841171039000b41ba8d0841121039000b7701047f230041206b2200240010274101105d4100105a210110cf01104b2202200110bc012000200110dc012203109a01200310a10110c101200028020c49044041f4880841141039000b200141012000200010c00120002000290200370318200042003703102002200041106a1046200041206a24000b11001027104d4101105d4100105910c3010b2d01027f1027104d4102105d4100105a2100410110592101200010be01200010c10141016a10d4012001109e010b11001027104d4101105d4100105910c7010b11001027104d4101105d4100105910c5010bd91502147f037e230041d0016b220024001027105f4103105e4100105a2101410110592106410210582203100f41c00047044041b08608410941a3890841101053000b20032102200041033602b801027f41032103024002400240200041b8016a220528020041e0dc082802004e0d0041002103200541a18608410f105522051012450d002005101322144280025a0d012014a7220341ff017141034f0d020b20030c020b41a18608410f41998008410e1053000b41a18608410f41a78008410d1053000b210820002802b801105c10cf01200110be0110c1012103200041fc006a200110dc01220f109a01024002400240024020002802880120034b04402000418c016a2001200310d801104b210510db012204200510a4011091012214500440200410a30110910121142004200510a401201442017c221410aa012004201410a5012005103b2014500d02200410a301201410aa010b200028029401201410a9010d0310482204200510041a200120041096012003200410960110b10110920120042002102a1a200141012000200041fc006a10c0012000418c016a201410a80110252115103a109301450d0241b08d08410a10542204200510041a103a10920120044167102b41671035220410664504402004100f2102200041c8016a41003a0000200041c4016a2002360200200020043602c001200020023602bc01200041003602b80120004198016a2204200041b8016a2207106f02402000280298010d00200028029c0110322202102c1a200042003703980120072004410810700d00200441081071211620042007106f2000280298010d00200028029c011042210420002802bc0120002802b801470d0020002d00c801044041d8dc08410036020041dcdc0841003a00000b024020152016510d002004107841ff01714101470d0020041031210720152016580d00201520167d108601210a1032220b2007200a101b20022002200b10170b200020043602c401200020023602c001200020153703b8010c060b20002d00c801044041d8dc08410036020041dcdc0841003a00000b41c88008412a1039000b200041b8016a201510af010c040b41c58608412e1039000b41d68308410b1002000b200041b8016a201510af010c010b41ac8708410f1039000b024020002802c0012202106341ff017141014d044010850121040c010b103222042002102d0b02400240024002400240024002402001200310c20122071061220a1047450440200841ff017122024103460d01200241027441a48d086a2802002102200410312002108101107f210b2001200310d6012202106122092004107e20022009109e012001200310d501220410612202200b107e20042002109e012001200310de01106121100240200110c101220310d301220910a2014504402009106121010c010b20004198016a200110dc01109a012001200310de011061210320002802980120034280a30510b4010240200110c101220210d401220e10a201450440200e106121040c010b2001200241016b220310de0110612001200210de011061210d10c4011061210410470d00200d10470d00200041b8016a200110dc01109a012001200310de011061210c20002802b801220d1035200c4280f52410b401200d2001200210de0110614280a30510b4012001200310d30110612001200310d501106121022001200310d6011061221310474504402001200310d7011061220120012002101b20012013107b21012002200210c60110612001107c107f10010b2002107c1084012103107c108401210210c80110612201200142808090bbbad6adf00d108601101b200e20012003107c200241a08d06108101107b2201200420012004107941ff01714101461b22041097010b2004107c2201200142808090bbbad6adf00d108601101a200920011097010b41012104200a2010200b107c2001107b22012001200a107941ff01714101461b2201200610d001450d0220071061220320032001106220072003109e01420021150240027e02400240200841ff017141016b0e020001030b42070c010b420e0b2115410021040b200028027c10352102200020013602a4012000420037039801200020023602a00120040440200520004198016a1046420021140c070b42002114200110470d061025211410d901109201108701210141b48008410a1054210410482206201420157c106d2006200510671048220820004198016a104910850121020240024002402008104f0e020201000b104c200041286a41a982084114106420002802282107200028022c210210481a200220011035106b2008104f2101104822032001ad106e20022003106b2008100f210a200041c0016a210b410021010340200a200141106a22034f0440200b4200370300200042003703b80120082001200041b8016a2201411010501a200041003602ac012001200041ac016a22091051210e20012009105221142001200910512101200041206a20072002200e1069200041186a200028022020002802242014106c200041106a2000280218200028021c2001106a2000280214210220002802102107200321010c010b0b200041086a20072002200420061065200028020c210620002802082104108501210221010c010b200041c0016a4200370300200042003703b80120084100200041b8016a220341101050200041003602ac012003200041ac016a220210512105200320021052211420032002105121020d04027f2014500440200041c8006a41cc8208410c1064200041406b2000280248200028024c20051069200041386a200028024020002802442002106a200041306a2000280238200028023c2004200610652000280234210620002802300c010b104c200041f0006a41bd8208410f1064200041e8006a2000280270200028027420051069200041e0006a2000280268200028026c2014106c200041d8006a200028026020002802642002106a20002802582105200028025c220220011067200041d0006a2005200220042006106520002802542106210120002802500b210410850121020b10232001200220042006104a210110242001100f2103200041003602b401200020013602ac01200020034102763602b001200041ac016a10b3012203100f2101200041c8016a41003a0000200041c4016a2001360200200020033602c001200020013602bc01200041003602b801200041b8016a10412202100f4104460440200041003602cc0120024100200041cc016a2201410410501a41feffffff0720022001410441cd830841041089011b21020b200041b8016a220110bb01211420011040210120002802bc0120002802b801470d0420002d00c801044041d8dc08410036020041dcdc0841003a00000b200241feffffff07470d0641c08308410d1002000b20061047450d042001200310d7012205106122022004107e20052002109e01200041b8016a22052001200341016a10da012005201410a8010c060b41f3860841171039000b418a8708410f1039000b41838308411d1002000b41d88208410b41998008410e1053000b4199870841131039000b200f200041fc006a109c012000103c200020002d00043a009c012000200028020036029801200220004198016a220310452000201442388620144280fe0383422886842014428080fc0783421886201442808080f80f834208868484201442088842808080f80f832014421888428080fc07838420144228884280fe038320144238888484843703b8012003200041b8016a410810ad0120012003104320002802980120002d009c01103e0b200041d0016a24000bee0101087f230041106b2201240010274102105d4100105a21024101418d86084104105b210310db01210610482104200141046a2002200310da012001280208109001210720012802042105410121000340200020074b45044020062005200010990110910110a50122021093010440200210920121030b200420031067200041016a21000c010b0b2004100f2105410021000340200041046a220220054b4504402001410036020420042000200141046a410410501a2001280204220041187420004180fe03714108747220004108764180fe03712000411876727210061a200221000c010b0b200141106a24000b6702047f017e230041106b2200240010274103105d410041b98608410c105721014101105a21024102418d86084104105b210310db01200110a401109101220450047e420005200041046a2002200310d801200028020c200410a901ad0b102e200041106a24000ba50101067f230041206b220024001027105f4101105e4100105a210520004101360210200041086a21020240200041106a2204220128020041e0dc082802004e0440410121030c010b20014191860841101055419186084110105621010b2002200136020420022003360200200028020c2101200028020821022000280210105c2004200510dc012203109a01200520022001200410c00120032004109c01200041206a24000b7801027f230041206b2200240010274101105d200041086a4100105a10dc01109a012000103c200020002d00043a001c200020002802003602182000280208200041186a22011045200028020c2001104320002802102001109d0120002802142001109d01200028021820002d001c103e200041206a24000b1b0010274102105d4100105a4101418d86084104105b10de0110600b1b0010274102105d4100105a4101418d86084104105b10c20110600b17001027104d4101105d410041fd8308410a105710b0010b0e0010274100105d10c101ad10290b100010274100105d10c90110910110290b16001027104d4101105d410041be8008410a105710370b100010274100105d103a10920110061a0b0f001027104d4100105d410110cd010b0f001027104d4100105d410010cd010b110010274100105d10ce01109b01ad102e0b02000b0b00419c8e08410e1002000b0bc00e0300418080080ba003726563697069656e742061646472657373206e6f7420736574696e70757420746f6f206c6f6e67696e76616c69642076616c75656c6f636b546f6b656e7373635f616464726573734661696c6564206465636f64696e6720726573756c742066726f6d20656e6572677920666163746f7279496e76616c69642061646472657373696e636f7272656374206e756d626572206f662045534454207472616e7366657273617267756d656e74206465636f6465206572726f722028293a20746f6f2066657720617267756d656e7473746f6f206d616e7920617267756d656e747377726f6e67206e756d626572206f6620617267756d656e747363616e6e6f74207375627472616374206265636175736520726573756c7420776f756c64206265206e656761746976654d756c7469455344544e46545472616e73666572455344544e46545472616e73666572455344545472616e7366657273796e6320726573756c74696e70757420746f6f2073686f72746361737420746f20693634206572726f724d616e6167656456656320696e646578206f7574206f662072616e67650041c083080b840b4553445420657870656374656445474c442e6974656d4944204f766572666c6f772e696e64657873746f72616765206465636f6465206572726f723a206e65775f7369676e6572496e76616c6964205745474c442d55534443207061697220616464726573732066726f6d20726f75746572496e76616c696420544f4b454e2d55534443207061697220616464726573732066726f6d20726f7574657273696d706c655f6c6f636b5f61646472657373656e657267795f666163746f72795f61646472657373736166655f70726963655f70616972726f757465725f616464726573737369676e657262657461616c7068614f6e6c792070726f6a656374206f776e6572206d61792063616c6c207468697320656e64706f696e74496e76616c69642070726f6a65637420494470726f6a6563745f6f776e65726e65775f6f776e657270726f6a6563745f69647765656b6f70745f6d61785f6e725f7765656b736f70745f6c6f636b5f6f7074696f6e7369676e6174757265757365725f616464726573734d6179206e6f7420636c61696d207265776172647320666f7220746869732070726f6a65637420616e796d6f72654e6f206c6f636b206f7074696f6e2070726f7669646564546f6f206665772072657761726473496e76616c6964206d696e2072657761726473416c726561647920636c61696d65646e725f7765656b73656e645f7765656b73746172745f7765656b496e697469616c207265776172647320616c7265616479206465706f7369746564496e76616c6964207765656b206e756d62657273546f6f2066657720726577617264207765656b73496e76616c6964207061796d656e7450726f6a65637420616c726561647920656e646564496e76616c696420656e64207765656b4d757374206465706f73697420696e697469616c2072657761726473206669727374456e64207765656b206e6f74207265616368656443616e6e6f7420776974686472617720616e796d6f72652e6c656e626164206172726179206c656e677468696e707574206f7574206f662072616e6765436f6e747261637420697320706175736564676574536166655072696365427954696d657374616d704f6666736574656e65726779466163746f727941646472657373496e76616c69642053432061646472657373496e76616c696420746f6b656e20494470726f6a6563744f776e65726c61737450726f6a656374496466697273745765656b537461727445706f636870617573655f6d6f64756c653a70617573656475736463546f6b656e4964726f75746572416464726573737765676c64546f6b656e496473616665507269636550616972746f74616c456e65726779466f725765656b6d696e456e657267795065725244656e657267795065725244466f725765656b696e74456e65726779466f72526577436c61696d657273726567456e65726779526577436c61696d657273726567456e657267794578656d70436c61696d6572736765745061697275736572436c61696d656473696d706c654c6f636b416464726573736578656d707465645061727469636970616e74737573657249647372657761726473496e666f6d696e52657761726473506572696f6472657761726473546f74616c416d6f756e746d696e5765656b6c795265776172647356616c75657265776172647352656d61696e696e67416d6f756e7400a861000050c30000a086010075736572456e65726779496e76616c6964207374617274207765656b66756e6769626c65204553445420746f6b656e206578706563746564456e64706f696e742063616e206f6e6c792062652063616c6c6564206279206f776e6572616464724964616464726c617374496470616e6963206f636375727265645765656b2030206973206e6f7420612076616c6964207765656b0041c48e080b049cffffff" + "size": 18749, + "code": "0061736d0100000001a1011a60017f017f60000060027f7f0060027f7f017f6000017f60017f0060037f7f7f0060037f7f7f017f60047f7f7f7f0060027f7e0060047f7f7f7f017f60057f7f7f7f7f0060017f017e6000017e60027f7e017f60017e0060027f7f017e60057f7f7e7f7f017f60067e7f7f7f7f7f017f60057e7f7f7f7f017f60047f7f7f7e0060017e017f60027e7f0060037f7f7e017f60047f7f7f7e017f60047f7e7f7f0002bb093303656e760e626967496e74536574496e743634000903656e7609626967496e74416464000603656e760b7369676e616c4572726f72000203656e760a6d4275666665724e6577000403656e760d6d427566666572417070656e64000303656e76096d4275666665724571000303656e760d6d42756666657246696e697368000003656e76226d616e616765644d756c74695472616e73666572455344544e465445786563757465001103656e761b6d616e61676564457865637574654f6e44657374436f6e74657874001203656e760d6d616e6167656443616c6c6572000503656e76106d616e61676564534341646472657373000503656e760f6d4275666665724765744279746573000303656e760f6973536d617274436f6e7472616374000003656e76136d616e616765644f776e657241646472657373000503656e761c6d616e616765644765744d756c74694553445443616c6c56616c7565000503656e76106d4275666665724765744c656e677468000003656e76126d427566666572476574417267756d656e74000303656e76126d427566666572417070656e644279746573000703656e76126d616e616765645369676e616c4572726f72000503656e761b736d616c6c496e74476574556e7369676e6564417267756d656e74000c03656e7619626967496e74476574556e7369676e6564417267756d656e74000203656e7611676574417267756d656e744c656e677468000003656e760f6765744e756d417267756d656e7473000403656e7614626967496e7446696e697368556e7369676e6564000503656e7609626967496e74537562000603656e7609626967496e74436d70000303656e760f6d4275666665725365744279746573000703656e760a626967496e7454446976000603656e7609626967496e744d756c000603656e76196d42756666657246726f6d426967496e74556e7369676e6564000303656e76176d427566666572546f426967496e74556e7369676e6564000303656e760a626967496e7453717274000203656e76146d427566666572436f707942797465536c696365000a03656e76126d42756666657253746f726167654c6f6164000303656e76136d42756666657253746f7261676553746f7265000303656e760a6765744761734c656674000d03656e760f636c65616e52657475726e44617461000103656e7611676574426c6f636b54696d657374616d70000d03656e761776616c6964617465546f6b656e4964656e746966696572000003656e760e636865636b4e6f5061796d656e74000103656e7609626967496e74506f77000603656e7616736d616c6c496e7446696e697368556e7369676e6564000f03656e76146d616e6167656456657269667945643235353139000703656e760d676574426c6f636b45706f6368000d03656e761d6d42756666657253746f726167654c6f616446726f6d41646472657373000603656e76156d427566666572546f426967496e745369676e6564000303656e7609626967496e74416273000203656e760f6d616e6167656457726974654c6f67000203656e7614736d616c6c496e7446696e6973685369676e6564000f03656e760a626967496e745369676e000003656e76136d42756666657247657442797465536c696365000a03da01d80100040b0100030500020402050502030000000200020202020004021304040105000a0310000803070207000700070705050501050006000608020b000a081409090b10080207000002060003020303030302000003030300041500000a08080a020605000c000000020202020302000202020200050000030e160e090e0906060609050407071704040418040b0c020005040804030403000003030303030403040505040502020619050401020308050506040604040401010101010101010101010101010101010101010101010101010101010101010105030100030616037f01418080080b7f0041d1dd080b7f0041e0dd080b07be0523066d656d6f7279020004696e697400ea01077570677261646500eb010a61646450726f6a65637400ec010f73657450726f6a6563744f776e657200ed01137365744d696e52657761726473506572696f6400ee01187365744d696e5765656b6c795265776172647356616c756500ef01156465706f736974496e697469616c5265776172647300f001186465706f7369744164646974696f6e616c5265776172647300f101146f776e657257697468647261775265776172647300f2010d66696e69736850726f6772616d00f3011c7365744d696e526577617264446f6c6c617273506572456e6572677900f401217365744e6578745765656b526577617264446f6c6c617273506572456e6572677900f50108736574416c70686100f601077365744265746100f7011c736574546f74616c456e65726779466f7243757272656e745765656b00f8011c676574546f74616c456e65726779466f7243757272656e745765656b00f9010c636c61696d5265776172647300fa01176765744578656d707465645061727469636970616e747300fb010e67657455736572436c61696d656400fc010d7570646174655265776172647300fd010e67657452657761726473496e666f00fe011567657452657761726473546f74616c416d6f756e7400ff01196765745265776172647352656d61696e696e67416d6f756e740080020c6368616e67655369676e65720081020e67657443757272656e745765656b0082021a67657446697273745765656b537461727454696d657374616d7000830217736574456e65726779466163746f72794164647265737300840217676574456e65726779466163746f72794164647265737300850205706175736500860207756e70617573650087020869735061757365640088020863616c6c4261636b0089020a5f5f646174615f656e6403010b5f5f686561705f6261736503020a8871d8011601017f1034220142001000200120012000100120010b1901017f41908f0841908f0828020041016b220036020020000b2e000240200120024d0440200220044d0d011036000b1036000b2000200220016b3602042000200120036a3602000b0600108a02000b0f01017f10032201200010041a20010b0b0020002001100541004a0b19002000103a45044041f58008410f103b000b103c2000103d0b1400200041b1dd08100b1a41b1dd08100c41004a0b0900200020011002000b0a0041848a08411410590b090020002001109d010b3601027f230041106b22012400200141086a103f20012802082102200020012d000c4101713a000420002002360200200141106a24000b6e01027f230041106b220124002000027f41a8dd082d0000220245044041a8dd0841013a000041a4dd084100360200200141086a41001093012001280208200128020c41808f084100109101104c0c010b41808f08410010590b360200200020024101733a0004200141106a24000b0b0020002001104110061a0b4901017f230041106b22022400200220013a000c20022000360208200241086a109501200228020820022d000c044041a4dd08410036020041a8dd0841003a00000b200241106a24000b08002000104310440b7001047f230041106b220124002001410036020c20002001410c6a2202410441db8208410b10742001200028020820002802002203200241041075a7220210762001280200410147044041db8208410b41e68208410f1058000b20012802042000200220036a360200200141106a24000b0d00200010342200101e1a20000b0a0020001046200110470b0f01017f103422012000101d1a20010bb20101037f230041106b2202240020022000100f220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a410410b2010240024020012d000404402000100f22044190ce0041a4dd0828020022036b4b0d0120022003200320046a220110b3012000410020022802002002280204106f1a41a4dd0820013602000c020b20012802002000107f0c010b200110950120012802002000107f0b200241106a24000b0a0020001046200110490b4f01027f230041106b2202240020022000100f220341187420034180fe03714108747220034108764180fe03712003411876727236020c20012002410c6a4104107c20012000107f200241106a24000b6902057f017e200128020c2204104b45044020012903002107104c2105104c21062001280208230041106b22012400104c21031037210220012004103336020c200120073703002001200236020820032001104d2000200342002005200610071a200141106a24000b0b0b002000107d41ff0171450b1301017f1034220041808f084100101a1a20000bd20102027f017e230041106b2203240020032001280208220241187420024180fe03714108747220024108764180fe0371200241187672723602002003200128020c220241187420024180fe03714108747220024108764180fe03712002411876727236020c20032001290300220442388620044280fe0383422886842004428080fc0783421886200442808080f80f834208868484200442088842808080f80f832004421888428080fc07838420044228884280fe0383200442388884848437020420002003411010111a200341106a24000b1500200020012002200320041034220110081a20010b0c01017f10342200100920000b0c01017f10342200100a20000b1d01017f10342200100d2000104f103804400f0b41ca8e0841241002000bfc01020c7f017e230041206b22012400416b2103024041b0dd082d000022020440416b41ffffffff0720021b21030c010b41b0dd0841013a0000416b100e0b410121040240200310534101460440410021022003100f2106200141106a2107034020052108200241106a220920064b0d02200742003703002001420037030820032002200141086a2202411010541a2001410036021c41012105200420022001411c6a22041055210b200220041056210d200141086a2001411c6a1055210c20092102410021040d000b1036000b4184810841221002000b200d5004402000200c3602042000200b360200200141206a24000f0b41ae8e08411c1002000b09002000100f4104760b0f00200020012003200210324100470b7301017f230041106b220224002002410036020c2002200020012802002200200041046a22001090012002410c6a41042002280200200228020410910120012000360200200228020c2100200241106a2400200041187420004180fe03714108747220004108764180fe0371200041187672720ba70102017e017f230041106b22032400200342003703082003200020012802002200200041086a2200109001200341086a4108200328020020032802041091012001200036020020032903082102200341106a2400200242388620024280fe0383422886842002428080fc0783421886200242808080f80f834208868484200242088842808080f80f832002421888428080fc07838420024228884280fe038320024238888484840b0d0020001034220010101a20000b2e01017f41a681084117105922042000200110111a200441bd8108410310111a20042002200310111a20041012000b1101017f1034220220002001101a1a20020b2f01017f2000280200220341acdd082802004e04402001200241c0810841111058000b2000200341016a36020020030b4601017f230041106b220224002002200141187420014180fe03714108747220014108764180fe03712001411876727236020c20002002410c6a410410111a200241106a24000b2501017e20001013220342ffffffff0f5804402003a70f0b2001200241998008410e1058000b2601017e2000101322014280808080105a044041868608410a41998008410e1058000b2001a70b1f00200010572200100f41204704402001200241ab890841101058000b20000b0c00200010342200101420000b2f01017f230041106b22032400200341003a000f20002003410f6a410120012002107420032d000f200341106a24000b0a00200020012002105c0b1900200041acdd082802004e04400f0b41d1810841121002000b1400101620004604400f0b41e3810841191002000b1900200041acdd082802004c04400f0b41c0810841111002000b0b0041acdd0810163602000b08002000106710170b09002000109a0110440b1f0020002001200210182000106941ff017104400f0b41fc810841301002000b1500410241012000103122001b4100200041004e1b0b180020012002105921012000104c360204200020013602000b160020022003106c20002002360204200020013602000b0d00104c1a200020011037105b0b900101037f230041106b2205240002402003106e0d0020022003106c2004100f2106410021030340200341046a220720064b0d012005410036020c200420032005410c6a4104106f1a2002200528020c220341187420034180fe03714108747220034108764180fe037120034118767272106c200721030c000b000b2000200236020420002001360200200541106a24000b07002000100f450b0c00200020012002200310540b1b00104c1a200220031046105b20002002360204200020013602000b160020022003107220002002360204200020013602000b1201017f104c22022001107320002002105b0b3801017f230041106b2202240020024200370308200220014100200241086a10db01200020022802002002280204101a1a200241106a24000b1c002000200120022003200410bf012000200028020020026a3602000b3401017e02402001450d0003402001450d01200141016b210120003100002002420886842102200041016a21000c000b000b20020b1f0020012002200310032201102021022000200136020420002002453602000b900101037f230041106b220224002002410036020c024020012002410c6a22034104107822044504402002200128020820012802002204200341041075a7220310762000027f20022802004101460440200020022802043602042001200320046a36020041000c010b2000410f36020441e682080b3602000c010b2000410f360204200020043602000b200241106a24000b3201017f41e682082103200041086a200028020020012002109201047f41e68208052000200028020020026a36020041000b0b5201047f230041106b220124002000107a2102200141086a200028020820002802002203200210762001280208410147044041e68208410f107b000b200128020c2000200220036a360200200141106a24000b5402017f017e230041106b220124002001410036020c200041086a20002802002001410c6a4104109201044041e68208410f107b000b2000200028020041046a3602002001410c6a41041075200141106a2400a70b1a01017f41ea83084116105922022000200110111a20021012000b0b0020002001200210111a0b09002000106941016b0b1500417f200020011019220041004720004100481b0b09002000200110041a0b0c00200020002001100120000b0c00200020002001101b20000b0c00200020002001101c20000b0c00200020002001106820000b0a0020002000200110010b11002000200041a08d06108601101b20000b0b0041722000ad100041720b0f00200020002001108601101c20000b1701017f200110860121011034220220002001101b20020b1701017f200110860121011034220220002001101c20020b0e01017f103422012000101f20010b0e01017f103422004200100020000b1b002000420053044041f5820841111002000b41722000100041720b1900200041feffffff074604404180800841191002000b20000b5f01027f230041206b220124002000100f4120460440200141186a4200370300200141106a4200370300200141086a420037030020014200370300200041002001412010541a2001412041a383084120108f0121020b200141206a240020020b5301027f2001200346047f4100210302402001450d00034020002d0000220420022d00002205460440200041016a2100200241016a2102200141016b22010d010c020b0b200420056b21030b20030541010b450b2f000240200220034d0440200341104b0d012000200320026b3602042000200120026a3602000f0b1036000b1036000bb50201067f200120034604402001220341104f04402000410020006b41037122046a210520040440200221010340200020012d00003a0000200141016a2101200041016a22002005490d000b0b2005200320046b2203417c7122066a21000240200220046a22044103710440200641004c0d012004410374220141187121072004417c71220841046a2102410020016b4118712109200828020021010340200520012007762002280200220120097472360200200241046a2102200541046a22052000490d000b0c010b200641004c0d0020042102034020052002280200360200200241046a2102200541046a22052000490d000b0b20034103712103200420066a21020b20030440200020036a21010340200020022d00003a0000200241016a2102200041016a22002001490d000b0b0f0b1036000bb50101037f230041106b22042400027f024020002d000845044020002802002205100f22064190ce004b0d0141a8dd082d00000d0141a4dd08200636020041a8dd0841013a0000200441086a2006109301200541002004280208200428020c106f1a200041013a00080b4101200120036a220041a4dd082802004b0d011a200420012000109401200220032004280200200428020410910141000c010b200041003a00082005200120022003106f0b200441106a24000b3e01017f230041106b22022400200241086a41948f084190ce00200110e101200228020c21012000200228020836020020002001360204200241106a24000b32000240200120024d044020024190ce004d0d011036000b1036000b2000200220016b3602042000200141948f086a3602000b5801027f230041106b2201240020002d0004200041003a00040440200141086a410041a4dd0828020010940120002802002001280208200128020c10111a41a4dd08410036020041a8dd0841003a00000b200141106a24000b2101017e200010970122014280808080105a044041998008410e107b000b2001a70b5e02027f017e230041106b22012400200142003703082000109a012200100f220241094f044041998008410e107b000b2001200141086a200210da0120004100200128020022002001280204220210541a200020021075200141106a24000b1c002000109a012200100f412047044041ab89084110107b000b20000b0d002000416710211a4167100f0b0d0020001034220010211a20000b090020012000109c010b4501017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a4104107c200241106a24000b09002000200110221a0b0b0020002001104610221a0b1a0020001037220041d48308410510111a20002001109b0120000bcb0101057f230041206b220224002001109a012203100f21012002411c6a41003a0000200241186a200136020020022003360214200220013602102002410036020c2002410c6a2204107921012002410c6a1079104421032004107a21042002410c6a107a21052002410c6a107a21062002280210200228020c46044020022d001c044041a4dd08410036020041a8dd0841003a00000b200020063602102000200536020c200020043602082000200336020420002001360200200241206a24000f0b41998008410e107b000b2f01017e027f024020001097012201420158044041002001a741016b0d021a0c010b41c389084112107b000b41010b0b080020002001103d0b7501027f230041106b220224002002103f20022002280200360208200220022d00044101713a000c2001280200200241086a220310472001280204200310452001280208200310a401200128020c200310a4012001280210200310a4012000200228020820022d000c104110221a200241106a24000b4601017f230041106b220224002002200041187420004180fe03714108747220004108764180fe03712000411876727236020c20012002410c6a410410b201200241106a24000b090020002001109e010b0d01017f20001067200010a7010b1400416c41808f084100101a1a2000416c10221a0b08002000109901450b130020001037220041f88e08410610111a20000b190020001037220041f48e08410410111a20002001107f20000b1a0020001037220041ee8e08410610111a2001200010ac0120000b7701017f230041106b220224002002200042388620004280fe0383422886842000428080fc0783421886200042808080f80f834208868484200042088842808080f80f832000421888428080fc07838420004228884280fe038320004238888484843703082001200241086a4108107c200241106a24000b1a0020001037220041e48308410610111a2001200010ac0120000b5001037f20002802082203200110af014504402000280204220210960121042000280200200441016a2200109f01200110b00120022000ad10b001200210960121002003200110ad012000ad10b0010b0b0f002000200110ad011096014100470b3801017f230041106b2202240020024200370308200220014100200241086a10db0120002002280200200228020410b101200241106a24000b0d00200020012002105910221a0b810101027f230041106b220324000240024020002d000404404190ce0041a4dd0828020022046b2002490d01200341086a2004200220046a220010b3012003280208200328020c2001200210910141a4dd0820003602000c020b20002802002001200210111a0c010b200010950120002802002001200210111a0b200341106a24000b3f01017f230041106b22032400200341086a2001200241948f084190ce001035200328020c21012000200328020836020020002001360204200341106a24000b2201017f10342202420010002000108b0136020c20002001370300200020023602080b090010b6012000103d0b0a0041a68508410610590b910101037f230041106b220324002000108d01210441b18c08410710592105104c22002001106c20002002106c108b01210110232004200120052000104e210010242000100f21012003410036020c2003200036020420032001410276360208200341046a41db8208410b10b80110372200100f412047044041db8208410b41ab890841101058000b200341106a240020000b7b01027f230041106b22032400200028020821042003410036020c200028020020044102742003410c6a4104106f450440200328020c21012000200441016a360208200141187420014180fe03714108747220014108764180fe0371200141187672721037200341106a24000f0b2001200241c0810841111058000b920101057f20001037210310ba01109a01210410bb01109a01210510bc0110980122061037200310372004103710b7012207108e0145044020062004200510b7012203108e010440418a8408412b103b000b200310ba01109a01200720002001200210bd01200210bd010f0b20062003200510b7012203108e01450440200320002001200210bd010f0b41b58408412b103b000b0a00418f8b08410c10590b0a0041f78a08410b10590b0a0041828b08410d10590bd10201047f230041306b2204240010be01109801108d01210641e78908411d10592107104c22052000106c2005200310722001104c1037220010494200200010ac0120022000104820052000105b108b01210010232006200020072005104e210010242000100f2101200441003602142004200036020c200420014102763602102004410c6a41db8208410b10b8012201100f2100200441286a41003a0000200441246a2000360200200420013602202004200036021c200441003602182004410036022c200441186a2004412c6a410441db8208410b10bf01024020042d002f044020042d002c450d010b200441186a41db8208410b10601a0b200441186a220010431a200010c0011a200010422100200428021c200428021846044020042d0028044041a4dd08410036020041a8dd0841003a00000b200441306a240020000f0b41db8208410b41998008410e1058000b0a00419b8b08410d10590b2300200041086a20002802002001200210920104402003200441e68208410f1058000b0b3602017f017e230041106b22012400200142003703082000200141086a2200410841db8208410b1074200041081075200141106a24000b1b002000200110c201109801103845044041b585084129103b000b0b1300200041cb8a08410c10592200109c0120000b170010c401109601200049044041de85084112103b000b0b0a0041d78a08410d10590baf0101037f024010c6012205200328020c22044d0d00200420032802102206460d002005200220046a2202200520022005491b20011b2201200620012006491b22012004200120044b1b2105108b0121020340200420054604400240200641016b20014d0440200328020420021084010c010b2000200110c70122001067220420021084012000200410a5010b2003200136020c0520022000200410c70110a601108401200441016a21040c010b0b0b0b2b01027e1025220010c801109701220154044041948e08411a103b000b200020017d4280f52480a741016a0b1a00200041b18d08411610592200109c0120002001109b0120000b0a0041c78d08411710590b1b002000200141ff017141027441e08d086a2802001087011085010b970301097f230041306b2205240010c6012101200041a88b08411210592206109c0120062001109b010240200610a8014504402006106721000c010b200541086a200010cb0110a0012000200110cc0110672101200528020820014280a30510b9010240200010c601220310cd01220710a8014504402007106721010c010b2000200341016b220210ce0110672000200210cf01106710800121082000200210d001106721042000200210ce0110672201104b45044020042000200210cf011067200410820120011081011080011a0b10d101106721012008104b0d002004104b0d002005411c6a200010cb0110a0012000200310cc0110672103200528021c20034280a30510b90121032000200210d20110672003108201108a01210220082004108201108a01210410d30110672200200042808090bbbad6adf00d108c01101c200720002002108201200441a08d061087011081012200200120002001107e41ff01714101461b2201109e010b20011082012200200042808090bbbad6adf00d108c01101b20062000109e010b200541306a240020000b1300200041ef8c08410b10592200109c0120000b1a002000418a8d08411210592200109c0120002001109b0120000b1a00200041c78b08411310592200109c0120002001109b0120000b1a00200041878c08411410592200109c0120002001109b0120000b1a002000419b8c08411610592200109c0120002001109b0120000b1a00200041f08b08411710592200109c0120002001109b0120000b0a0041da8b08411610590b1a00200041ba8b08410d10592200109c0120002001109b0120000b0a0041b08508410510590b0a0010d101200010a5010b0a0010d601200010a5010b0a0041ac8508410410590b0a0010d301200010a5010b2e01027f20011037210220011037220341a78908410410111a2000200336020420002001360200200020023602080b2601017f230041106b22022400200220003a000f20012002410f6a4101107c200241106a24000b3a01017f230041106b22032400200341086a20014108200210e101200328020c21012000200328020836020020002001360204200341106a24000b900202047f017e2003200142388620014280fe0383422886842001428080fc0783421886200142808080f80f834208868484200142088842808080f80f832001421888428080fc0783842001423888220820014228884280fe03838484843700000240200150044041808f0821030c010b200204402001427f510440200341076a2103410121040c020b2008a7c022054107752106200541004821050b200641ff0171210603400240024020044108470440200320046a2d000022072006460d02200245200741077620054672450440200441016b220441094f0d020b200320046a2103410820046b21040c040b1036000b108a02000b200441016a21040c000b000b20002004360204200020033602000b3a01027f230041106b2201240010dd012001420037030820012000ad4101200141086a10db012001280200200128020410b101200141106a24000b0a0041e48a08411310590b140010dd0110a101044041d589084112103b000b0b1000104c1a200020012802001037105b0b0f0020002001107e41ff01714102490b3b01017f230041106b22042400200441086a41002003200120021035200428020c21012000200428020836020020002001360204200441106a24000b1d0002402000108e014504402000103a0d010b41a98a084112103b000b0b13002000102645044041bb8a084110103b000b0b1f00200141b88c08410b10592201109c0120012002109b012000200110d8010b0a0041c38c08411110590b1f00200141d48c08411410592201109c0120012002109b012000200110d8010b0a0041e88c08410710590b0a0041fa8c08411010590b0a00419c8d08411510590b8e02020a7f017e1027410a10634100105f4101105f21064102105f2107410341a685084106105e2108410441988508410e105e2100410541898508410f105e2101410641f384084116105e410741e084084113105e2102410810572103410910572104200010e201200110e201200210e201200310e301200410e30110bc01200010a20110be01200110a20110e501200210a20110bb012003109d0110ba012004109d01103910d401200610d701200710d501200810b50110e801421a10b0011034220042e807100010342201420a10001034220220014106108601102820002002108201210010e901200010a5011025210a10c801200a200a4280b4caae067d4280f524827d10b001410110dc010b08001027410010630b4002027f017e1027105141011063410041f08508410d105e210110c401109601210010c401200041016a2200ad220210b001200010c201200110a201200210290b2401027f10271051410210634100105d410141fd85084109105e210110c201200110a2010b2101017f1027105141011063410041c3870841081061210010e8012000ad10b0010b1a01017f10271051410110634100105f210010e901200010a5010b9303010d7f230041306b22002400410410634100105d2102410141d38708410a10612103410241cb87084108106121044103105f210810de01200210c301104f2209200210c1010240024002400240200210cb01220a10a801044020032004492201450d0110e801109601200420036b22074b0d0210c60120034f0d0320001052200028020021062000280204220b2007108801210520061037200510334280f52410b90110e901106710e001450d042004200320011b210c2003210103402001200c464504402002200110cc012005109e012002200110c7012005109e01200141016a21010c010b0b2002200310cd01200810a501200b2005200710890110830121012006103721022000200136021420004200370308200020023602102009200041086a104a108b0121012000200436022c2000200336022820002003360224200020013602202000200636021c200a2000411c6a10a301200041306a24000f0b41dd87084121103b000b41fe87084114103b000b419288084114103b000b41828e084112103b000b419a8708410f103b000bef03010e7f230041306b22002400410310634100105d2103410141d38708410a10612101410241cb870841081061210410de01200310c301104f220c200310c1010240024002400240024002400240200310cb01220a10a80145044020012004492207450d01200010522000280204210b200028020021082000410c6a2206200a10a0012008200028020c1038450d0210c6012202200028021c22054f0d03200120024d0d04200120054b0d05200028021820044b0d06200341012002200610c501200b200420016b220d108801210520081037200510334280f52410b90110e901106710e001450d072004200120071b210720012102034020022007464504402003200210cc0122061067220920051084012006200910a5012003200210c70122061067220920051084012006200910a501200241016a21020c010b0b2000200b2005200d10890110830136022c2000420037032020002008360228200c200041206a104a2000200028021822022001200120024b1b3602182000200028021c22012004200120044b1b36021c200a2000410c6a10a301200041306a24000f0b41da88084122103b000b41fe87084114103b000b41a68808410f103b000b41b588084115103b000b41828e084112103b000b41828e084112103b000b41ca88084110103b000b419a8708410f103b000bae0201087f230041306b2200240010271051410210634100105d2102410141d38708410a10612103200210c3012000410c6a2205200210cb01220610a001024010c6012204200028021c2201490440200120034d200028021820034f720d01200320044d0d01200241012001200510c50141002105108b012107200028021c21042003210103402005200120044b7245044020072002200110c70110a6011084012002200110cc0110a701200120044f2105200120012004496a21010c010b0b200210c201109801200028020c103721022000200736022c2000420037032020002002360228200041206a104a0240200320002802184704402000200336021c20062000410c6a10a3010c010b200610a7010b200041306a24000f0b419089084117103b000b41828e084112103b000b7d01047f230041306b220024001027410110634100105d210110de01104f2202200110c1012000410c6a200110cb01220310a001200310a70110c601200028021c49044041fc88084114103b000b2001410120002000410c6a10c5012000200029020c370328200042003703202002200041206a104a200041306a24000b110010271051410110634100105f10d4010b2d01027f10271051410210634100105d21004101105f2101200010c301200010c60141016a10cd01200110a5010b110010271051410110634100105f10d7010b110010271051410110634100105f10d5010b900202037f017e230041206b2200240010271065410010642000410036020c2000410c6a2102104c21010340200228020041acdd082802004804402001200241b88708410b105a1057105b0c010b0b200028020c10622001100f2102200041003602142000200241027622023602102000200136020c4100210102400340200120024904402000410c6a41bb8908410810b8012101200042003703182001100f220241094f0d022000200041186a200210da0120014100200028020022012000280204220210541a20012002107522034280808080105a0d022003a7220110c301200110ca011a20002802102102200028021421010c010b0b200041206a24000f0b41bb8908410841998008410e1058000b1a01017f1027410110634100105d220010c301200010ca0110170be41502107f037e230041f0016b220024001027410410634100105d21064101105f2107410210572201100f41c00047044041ae8608410941ab890841101058000b20012103027f230041206b220124004103210202400240024041031015450d00410310572204100f21052001411c6a41003a0000200141186a200536020020012004360214200120053602102001410036020c024002402001410c6a41a48608410a106041ff01710e020100040b2001410c6a41a48608410a1060220241ff017141034f0d030b2001280210200128020c470d0120012d001c450d0041a4dd08410036020041a8dd0841003a00000b200141206a240020020c020b41a48608410a41998008410e1058000b41a48608410a41a78008410d1058000b210a10de01200610c30110c601210120004184016a200610cb01220f10a001024002400240024020002802940120014b044020004198016a2006200110e4012000104f22053602a40110e7012202200510aa011097012210500440200210a90110970121102002200510aa01201042017c221010b0012002201010ab012005103d2010500d02200210a901201010b0010b20002802a001201010af010d03104c2202200510041a20062002109c0120012002109c0110b60110980120022003102a1a20064101200020004184016a10c50120004198016a201010ae012006200110c701220910672104200610ca01210b2006200110cc011067210d102b2111103c109901450d0241f88d08410a10592202200510041a103c10980120024167102c416710372202106e4504402002100f2103200041c8016a41003a0000200041c4016a2003360200200020023602c001200020033602bc01200041003602b801200041d8016a2202200041b8016a22081077024020002802d8010d0020002802dc0110342203102d1a200042003703d80120082002410810780d00200241081075211220022008107720002802d8010d0020002802dc011044210220002802bc0120002802b801470d0020002d00c801044041a4dd08410036020041a8dd0841003a00000b024020112012510d002002107d41ff01714101470d0020021033210820112012580d00201120127d108c01210c1034220e2008200c101c20032003200e10180b200020023602c401200020033602c001200020113703b8010c060b20002d00c801044041a4dd08410036020041a8dd0841003a00000b41cb8008412a103b000b200041b8016a201110b4010c040b41c38608412e103b000b41d98308410b1002000b200041b8016a201110b4010c010b41a98708410f103b000b024020002802c0012202106941ff017141014d0440108b0121030c010b103422032002102e0b10d60110672108200d2003108201200b1081012102024002400240024002400240200a41ff0171410346044020042002107e41ff017141ff01470d012007104b450d022006200110cf0122051067220420031084012005200410a5012008200210820110850121022000280284011037200242901c10b90121052006200110d20122031067220220051084012003200210a501200041b8016a22052006200141016a10e6012005201010ae010c060b410121082004200220022004107e41ff01714101461b220b1033200a10c9012202200710e001450d022009106722042004200210682009200410a5012006200110ce0122041067220720031084012004200710a5012003200a10c90121032006200110d00122041067220720031084012004200710a50120002802840122031037200b42901c10b90121042006200110d20122011067220720041084012001200710a501420021110240027e02400240200a41ff017141016b0e020001030b42070c010b420e0b2111410021080b200310372103200020023602b401200042003703a801200020033602b001200804402005200041a8016a104a420021100c060b420021102005103721012002104b0d05102b211010e501109801108d01210541b78008410a10592104104c2207201020117c107220072001106c104c2209200041a8016a104d200020053602c8012000427f3703c001200020073602bc01200020043602b8012000108b0122013602d00102400240024002400240200910530e020301000b10502105200041306a41ac82084114106a2000280230210320002802342208200041c8016a10df01200910532101104c22022001ad107320082002105b2009100f210b200041e0016a210d410021010340200141106a2202200b4b0d02200d4200370300200042003703d80120092001200041d8016a2201411010541a200041003602ec012001200041ec016a220c1055210e2001200c105621102001200c10552101200041286a20032008200e106b200041206a2000280228200028022c20101071200041186a2000280220200028022420011070200028021c210820002802182103200221010c000b000b200041e0016a4200370300200042003703d80120094100200041d8016a220141101054200041003602ec012001200041ec016a220310552102200120031056211020012003105521030d06027f2010500440200041d0006a41cf8208410c106a200041c8006a200028025020002802542002106b200041406b2000280248200028024c20031070200041386a2000280240200028024420042007106d20002802382104200028023c0c010b1050200041f8006a41c08208410f106a200041f0006a2000280278200028027c2002106b200041e8006a2000280270200028027420101071200041e0006a2000280268200028026c2003107020002802602102200028026422032005106c200041d8006a2002200320042007106d200028025821042105200028025c0b2107108b0121010c010b200041106a2003200820042007106d20002903c00121102000280214210720002802102104108b0121012010427f520d010b102321100b20102005200120042007104e210110242001100f2102200041003602e001200020013602d801200020024102763602dc01200041d8016a41db8208410b10b8012202100f2101200041c8016a41003a0000200041c4016a2001360200200020023602c001200020013602bc01200041003602b801200041b8016a10432203100f4104460440200041003602ec0120034100200041ec016a2201410410541a41feffffff0720032001410441d083084104108f011b21030b200041b8016a220110c001211020011042210220002802bc0120002802b801470d0420002d00c801044041a4dd08410036020041a8dd0841003a00000b200341feffffff07470d0541c38308410d1002000b41f186084116103b000b418787084113103b000b419a8708410f103b000b41868308411d1002000b41db8208410b41998008410e1058000b200f20004184016a10a301027f200a41ff01714103470440200210330c010b108b010b104c220541988a0841111059105b2005200041a4016a10df012006104c10372201109c01200110480240200a41ff0171220641034704404101200110d901200641027441ec8d086a2802002d0000200110d90120052001102f200041086a103e200020002d000c3a0088012000200028020836028401200320004184016a220110472000201042388620104280fe0383422886842010428080fc0783421886201042808080f80f834208868484201042088842808080f80f832010421888428080fc07838420104228884280fe038320104238888484843703b8012001200041b8016a410810b20120022001104520002802840120002d00880110400c010b4100200110d90120052001102f0b200041f0016a24000bee0101087f230041106b220124001027410210634100105d210241014190860841041061210310e7012106104c2104200141046a2002200310e6012001280208109601210720012802042105410121000340200020074b450440200620052000109f0110970110ab0122021099010440200210980121030b20042003106c200041016a21000c010b0b2004100f2105410021000340200041046a220220054b4504402001410036020420042000200141046a410410541a2001280204220041187420004180fe03714108747220004108764180fe03712000411876727210061a200221000c010b0b200141106a24000b6702047f017e230041106b22002400102741031063410041b78608410c105e21014101105d210241024190860841041061210310e701200110aa01109701220450047e420005200041046a2002200310e401200028020c200410af01ad0b1030200041106a24000b9e0101067f230041206b2200240010271065410110644100105d21042000410136020c02402000410c6a2203220128020041acdd082802004e0440410121020c010b2001419486084110105a419486084110105c21010b20002001360204200020023602002000280204210520002802002101200028020c10622003200410cb01220210a001200420012005200310c5012002200310a301200041206a24000b850101027f230041306b22002400102741011063200041146a4100105d10cb0110a001200041086a103e200020002d000c3a002c200020002802083602282000280214200041286a22011047200028021820011045200028021c200110a4012000280220200110a4012000280224200110a401200028022820002d002c1040200041306a24000b1b001027410210634100105d4101419086084104106110cc0110660b1b001027410210634100105d4101419086084104106110c70110660b17001027105141011063410041808408410a105e10b5010b0e0010274100106310c601ad10290b100010274100106310c80110970110290b16001027105141011063410041c18008410a105e10390b1000102741001063103c10980110061a0b0f001027105141001063410110dc010b0f001027105141001063410010dc010b110010274100106310dd0110a101ad10300b02000b0b0041808f08410e1002000b0b8a0f0300418080080ba303726563697069656e742061646472657373206e6f7420736574696e70757420746f6f206c6f6e67696e76616c69642076616c75650001026c6f636b546f6b656e7373635f616464726573734661696c6564206465636f64696e6720726573756c742066726f6d20656e6572677920666163746f7279496e76616c69642061646472657373696e636f7272656374206e756d626572206f662045534454207472616e7366657273617267756d656e74206465636f6465206572726f722028293a20746f6f2066657720617267756d656e7473746f6f206d616e7920617267756d656e747377726f6e67206e756d626572206f6620617267756d656e747363616e6e6f74207375627472616374206265636175736520726573756c7420776f756c64206265206e656761746976654d756c7469455344544e46545472616e73666572455344544e46545472616e73666572455344545472616e7366657273796e6320726573756c74696e70757420746f6f2073686f72746361737420746f20693634206572726f724d616e6167656456656320696e646578206f7574206f662072616e67650041c383080bcb0b4553445420657870656374656445474c442e6974656d4944204f766572666c6f772e696e64657873746f72616765206465636f6465206572726f723a206e65775f7369676e6572496e76616c6964205745474c442d55534443207061697220616464726573732066726f6d20726f75746572496e76616c696420544f4b454e2d55534443207061697220616464726573732066726f6d20726f7574657273696d706c655f6c6f636b5f61646472657373656e657267795f666163746f72795f61646472657373736166655f70726963655f70616972726f757465725f616464726573737369676e657262657461616c7068614f6e6c792070726f6a656374206f776e6572206d61792063616c6c207468697320656e64706f696e74496e76616c69642070726f6a65637420494470726f6a6563745f6f776e65726e65775f6f776e657270726f6a6563745f69647765656b6f70745f6d61785f6e725f7765656b73636c61696d5f747970657369676e6174757265757365725f616464726573734d6179206e6f7420636c61696d207265776172647320666f7220746869732070726f6a65637420616e796d6f726543616e20636c61696d2066756c6c2072657761726473496e76616c6964206d696e2072657761726473546f6f206665772072657761726473416c726561647920636c61696d656470726f6a6563745f6964736e725f7765656b73656e645f7765656b73746172745f7765656b496e697469616c207265776172647320616c7265616479206465706f7369746564496e76616c6964207765656b206e756d62657273546f6f2066657720726577617264207765656b73496e76616c6964207061796d656e7450726f6a65637420616c726561647920656e646564496e76616c696420656e64207765656b4d757374206465706f73697420696e697469616c2072657761726473206669727374456e64207765656b206e6f74207265616368656443616e6e6f7420776974686472617720616e796d6f72652e6c656e626164206172726179206c656e6774687661722061726773696e707574206f7574206f662072616e6765436f6e747261637420697320706175736564676574536166655072696365427954696d657374616d704f6666736574656e65726779466163746f727941646472657373636c61696d526577617264734576656e74496e76616c69642053432061646472657373496e76616c696420746f6b656e20494470726f6a6563744f776e65726c61737450726f6a656374496470617573655f6d6f64756c653a70617573656475736463546f6b656e4964726f75746572416464726573737765676c64546f6b656e496473616665507269636550616972746f74616c456e65726779466f725765656b726567526577446f6c6c617273726577446f6c6c617273506572456e657267796d696e526577446f6c6c617273506572456e65726779696e74456e65726779466f72526577436c61696d657273726567456e65726779526577436c61696d657273726567456e657267794578656d70436c61696d6572736765745061697275736572436c61696d656473696d706c654c6f636b416464726573736578656d707465645061727469636970616e74737573657249647372657761726473496e666f6d696e52657761726473506572696f6472657761726473546f74616c416d6f756e746d696e5765656b6c795265776172647356616c75657265776172647352656d61696e696e67416d6f756e7466697273745765656b537461727454696d657374616d700000a861000050c30000a086010034000200350002003600020075736572456e65726779496e76616c6964207374617274207765656b5765656b2030206973206e6f7420612076616c6964207765656b66756e6769626c65204553445420746f6b656e206578706563746564456e64706f696e742063616e206f6e6c792062652063616c6c6564206279206f776e6572616464724964616464726c6173744964000070616e6963206f636375727265640041908f080b049cffffff" } diff --git a/growth-program/output/growth-program.wasm b/growth-program/output/growth-program.wasm index 79eed4f..f273212 100755 Binary files a/growth-program/output/growth-program.wasm and b/growth-program/output/growth-program.wasm differ diff --git a/growth-program/src/events.rs b/growth-program/src/events.rs new file mode 100644 index 0000000..8676d60 --- /dev/null +++ b/growth-program/src/events.rs @@ -0,0 +1,36 @@ +use crate::{project::ProjectId, rewards::claim::ClaimType}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] +pub struct ClaimRewardsEventData { + pub project_id: ProjectId, + pub amount: BigUint, + pub claim_type: ClaimType, +} + +#[multiversx_sc::module] +pub trait EventsModule { + fn emit_claim_rewards_event( + &self, + caller: &ManagedAddress, + project_id: ProjectId, + rewards_amount: BigUint, + claim_type: ClaimType, + ) { + let claim_data = ClaimRewardsEventData { + amount: rewards_amount, + project_id, + claim_type, + }; + self.claim_rewards_event(caller, &claim_data); + } + + #[event("claimRewardsEvent")] + fn claim_rewards_event( + &self, + #[indexed] caller: &ManagedAddress, + claim_data: &ClaimRewardsEventData, + ); +} diff --git a/growth-program/src/lib.rs b/growth-program/src/lib.rs index 2ba5231..3d3e9a5 100644 --- a/growth-program/src/lib.rs +++ b/growth-program/src/lib.rs @@ -1,9 +1,10 @@ #![no_std] -use week_timekeeping::Week; +use rewards::week_timekeeping::{Week, MONDAY_19_02_2024_GMT_TIMESTAMP}; multiversx_sc::imports!(); +pub mod events; pub mod price_query; pub mod project; pub mod rewards; @@ -12,6 +13,7 @@ pub mod validation; pub type Timestamp = u64; pub const MAX_PERCENTAGE: u32 = 100_000; +pub const HOUR_IN_SECONDS: Timestamp = 60 * 60; pub const DAY_IN_SECONDS: Timestamp = 24 * 60 * 60; pub const WEEK_IN_SECONDS: Timestamp = 7 * DAY_IN_SECONDS; pub const PRECISION: u64 = 1_000_000_000_000_000_000; @@ -30,20 +32,21 @@ pub trait GrowthProgram: + rewards::common_rewards::CommonRewardsModule + price_query::PriceQueryModule + validation::ValidationModule - + week_timekeeping::WeekTimekeepingModule + + rewards::week_timekeeping::WeekTimekeepingModule + + events::EventsModule + utils::UtilsModule + energy_query::EnergyQueryModule + multiversx_sc_modules::pause::PauseModule { /// Arguments: - /// min_energy_per_reward_dollar: Scaled to PRECISION const. + /// min_reward_dollars_per_energy: Scaled to PRECISION const. /// alpha: Percentage, scaled to MAX_PERCENTAGE const. /// beta: Percentage, scaled to MAX_PERCENTAGE const. /// signer: Public key of the signer, used to verify user claims #[init] fn init( &self, - min_energy_per_reward_dollar: BigUint, + min_reward_dollars_per_energy: BigUint, alpha: BigUint, beta: BigUint, signer: ManagedAddress, @@ -67,7 +70,7 @@ pub trait GrowthProgram: self.wegld_token_id().set(wegld_token_id); self.set_energy_factory_address(energy_factory_address); - self.set_min_energy_per_reward_dollar(min_energy_per_reward_dollar); + self.set_min_reward_dollars_per_energy(min_reward_dollars_per_energy); self.set_alpha(alpha); self.set_beta(beta); self.change_signer(signer); @@ -80,8 +83,12 @@ pub trait GrowthProgram: self.min_weekly_rewards_value() .set(default_min_weekly_rewards_value); - let current_epoch = self.blockchain().get_block_epoch(); - self.first_week_start_epoch().set(current_epoch); + let current_timestamp = self.blockchain().get_block_timestamp(); + let first_week_start_timestamp = MONDAY_19_02_2024_GMT_TIMESTAMP + + (current_timestamp - MONDAY_19_02_2024_GMT_TIMESTAMP) / WEEK_IN_SECONDS + * WEEK_IN_SECONDS; + self.first_week_start_timestamp() + .set(first_week_start_timestamp); self.set_paused(true); } diff --git a/growth-program/src/rewards/claim.rs b/growth-program/src/rewards/claim.rs index 9aa82f0..e54ba00 100644 --- a/growth-program/src/rewards/claim.rs +++ b/growth-program/src/rewards/claim.rs @@ -1,6 +1,6 @@ -use week_timekeeping::{Epoch, Week, EPOCHS_IN_WEEK}; +use super::week_timekeeping::{Epoch, Week}; -use crate::{project::ProjectId, validation::Signature, MAX_PERCENTAGE}; +use crate::{project::ProjectId, validation::Signature, HOUR_IN_SECONDS, MAX_PERCENTAGE}; multiversx_sc::imports!(); multiversx_sc::derive_imports!(); @@ -12,6 +12,12 @@ pub enum LockOption { TwoWeeks, } +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, Copy)] +pub enum ClaimType { + Exemption, + Rewards(LockOption), +} + impl LockOption { pub fn get_lock_period(&self) -> Epoch { match *self { @@ -26,18 +32,20 @@ pub const NONE_PERCENTAGE: u32 = 25 * MAX_PERCENTAGE / 100; // 25% pub const ONE_WEEK_PERCENTAGE: u32 = 50 * MAX_PERCENTAGE / 100; // 50% pub const TWO_WEEKS_PERCENTAGE: u32 = 100 * MAX_PERCENTAGE / 100; // 100% +pub const EPOCHS_IN_WEEK: Epoch = 7; pub const NO_LOCK_PERIOD: Epoch = 0; pub const ONE_WEEK_LOCK_PERIOD: Epoch = EPOCHS_IN_WEEK; pub const TWO_WEEKS_LOCK_PERIOD: Epoch = 2 * EPOCHS_IN_WEEK; #[multiversx_sc::module] pub trait ClaimRewardsModule: - week_timekeeping::WeekTimekeepingModule + super::week_timekeeping::WeekTimekeepingModule + crate::price_query::PriceQueryModule + crate::project::ProjectsModule + super::energy::EnergyModule + super::common_rewards::CommonRewardsModule + crate::validation::ValidationModule + + crate::events::EventsModule + energy_query::EnergyQueryModule + multiversx_sc_modules::pause::PauseModule { @@ -47,7 +55,7 @@ pub trait ClaimRewardsModule: project_id: ProjectId, min_rewards: BigUint, signature: Signature, - opt_lock_option: OptionalValue, + claim_type: ClaimType, ) -> OptionalValue { self.require_not_paused(); self.require_valid_project_id(project_id); @@ -68,56 +76,90 @@ pub trait ClaimRewardsModule: self.verify_signature(&caller, project_id, current_week, &signature); self.update_rewards(project_id, OptionalValue::None, &mut rewards_info); - claimed_user_mapper.insert(user_id); + let _ = claimed_user_mapper.insert(user_id); - let user_original_energy = self.get_energy_amount(&caller); let rem_rewards_mapper = self.rewards_remaining_amount(project_id, current_week); let remaining_rewards = rem_rewards_mapper.get(); - if remaining_rewards == 0 { - require!(min_rewards == 0, "Invalid min rewards"); - - self.registered_energy_exemption_claimers(project_id, current_week) - .update(|reg_energy| *reg_energy += user_original_energy); - let _ = self - .exempted_participants(project_id, current_week + 1) - .insert(user_id); - - return OptionalValue::None; - } - - require!(opt_lock_option.is_some(), "No lock option provided"); - let lock_option = unsafe { opt_lock_option.into_option().unwrap_unchecked() }; - let user_adjusted_energy = - self.adjust_energy_to_lock_option(user_original_energy.clone(), lock_option); - self.registered_energy_rewards_claimers(project_id, current_week) - .update(|reg_energy| *reg_energy += user_original_energy); - self.interested_energy_rewards_claimers(project_id, current_week) - .update(|int_energy| *int_energy += &user_adjusted_energy); - - let total_rewards = self.rewards_total_amount(project_id, current_week).get(); let total_energy = self.get_total_energy_for_current_week(project_id); - let max_rewards = total_rewards * user_adjusted_energy / total_energy; - let user_rewards = core::cmp::min(max_rewards, remaining_rewards); - require!(user_rewards >= min_rewards, "Too few rewards"); - - rem_rewards_mapper.update(|rem_rew| *rem_rew -= &user_rewards); - - let lock_period = lock_option.get_lock_period(); - let unlocked_payment = - EsdtTokenPayment::new(rewards_info.reward_token_id.clone(), 0, user_rewards); - let output_payment = if lock_period > 0 { - self.lock_tokens(unlocked_payment, lock_period, caller) - } else { - self.send() - .direct_non_zero_esdt_payment(&caller, &unlocked_payment); - - unlocked_payment + let total_rewards = self.rewards_total_amount(project_id, current_week).get(); + let user_original_energy = self.get_energy_amount(&caller); + let beta = self.beta().get(); + + let rew_advertised = total_rewards * &user_original_energy / total_energy; + let opt_rewards = match claim_type { + ClaimType::Exemption => { + require!(remaining_rewards < rew_advertised, "Can claim full rewards"); + require!(min_rewards == 0, "Invalid min rewards"); + + self.registered_energy_exemption_claimers(project_id, current_week) + .update(|reg_energy| *reg_energy += user_original_energy); + + let rew_available = beta * rew_advertised / MAX_PERCENTAGE; + let rew_available_dollar_value = self.get_dollar_value( + rewards_info.reward_token_id.clone(), + rew_available, + HOUR_IN_SECONDS, + ); + self.registered_rewards_dollars(project_id, current_week) + .update(|reg_rew_dollars| *reg_rew_dollars += rew_available_dollar_value); + + let _ = self + .exempted_participants(project_id, current_week + 1) + .insert(user_id); + + OptionalValue::None + } + ClaimType::Rewards(lock_option) => { + let rew_available = core::cmp::min(rew_advertised, remaining_rewards); + let user_rewards = + self.adjust_amount_to_lock_option(rew_available.clone(), lock_option); + require!(user_rewards >= min_rewards, "Too few rewards"); + + rem_rewards_mapper.update(|rem_rew| *rem_rew -= &user_rewards); + + self.registered_energy_rewards_claimers(project_id, current_week) + .update(|reg_energy| *reg_energy += &user_original_energy); + + let user_adjusted_energy = + self.adjust_amount_to_lock_option(user_original_energy, lock_option); + self.interested_energy_rewards_claimers(project_id, current_week) + .update(|int_energy| *int_energy += &user_adjusted_energy); + + let rew_available_dollar_value = self.get_dollar_value( + rewards_info.reward_token_id.clone(), + rew_available, + HOUR_IN_SECONDS, + ); + self.registered_rewards_dollars(project_id, current_week) + .update(|reg_rew_dollars| *reg_rew_dollars += rew_available_dollar_value); + + let lock_period = lock_option.get_lock_period(); + let unlocked_payment = + EsdtTokenPayment::new(rewards_info.reward_token_id.clone(), 0, user_rewards); + let output_payment = if lock_period > 0 { + self.lock_tokens(unlocked_payment, lock_period, caller.clone()) + } else { + self.send() + .direct_non_zero_esdt_payment(&caller, &unlocked_payment); + + unlocked_payment + }; + + OptionalValue::Some(output_payment) + } }; info_mapper.set(rewards_info); - OptionalValue::Some(output_payment) + let total_rewards = match &opt_rewards { + OptionalValue::Some(payment) => payment.amount.clone(), + OptionalValue::None => BigUint::zero(), + }; + + self.emit_claim_rewards_event(&caller, project_id, total_rewards, claim_type); + + opt_rewards } #[view(getExemptedParticipants)] @@ -152,7 +194,7 @@ pub trait ClaimRewardsModule: self.user_claimed(project_id, week).contains(&user_id) } - fn adjust_energy_to_lock_option(&self, amount: BigUint, lock_option: LockOption) -> BigUint { + fn adjust_amount_to_lock_option(&self, amount: BigUint, lock_option: LockOption) -> BigUint { match lock_option { LockOption::None => amount * NONE_PERCENTAGE / MAX_PERCENTAGE, LockOption::OneWeek => amount * ONE_WEEK_PERCENTAGE / MAX_PERCENTAGE, diff --git a/growth-program/src/rewards/common_rewards.rs b/growth-program/src/rewards/common_rewards.rs index f84c165..3849a5e 100644 --- a/growth-program/src/rewards/common_rewards.rs +++ b/growth-program/src/rewards/common_rewards.rs @@ -1,4 +1,4 @@ -use week_timekeeping::Week; +use super::week_timekeeping::Week; use crate::project::ProjectId; @@ -10,11 +10,12 @@ pub struct RewardsInfo { pub reward_token_id: TokenIdentifier, pub undistributed_rewards: BigUint, pub start_week: Week, + pub last_update_week: Week, pub end_week: Week, } #[multiversx_sc::module] -pub trait CommonRewardsModule: week_timekeeping::WeekTimekeepingModule { +pub trait CommonRewardsModule: super::week_timekeeping::WeekTimekeepingModule { #[endpoint(updateRewards)] fn update_rewards_endpoint( &self, @@ -33,25 +34,25 @@ pub trait CommonRewardsModule: week_timekeeping::WeekTimekeepingModule { rewards_info: &mut RewardsInfo, ) { let current_week = self.get_current_week(); - if rewards_info.start_week >= current_week { + if rewards_info.last_update_week >= current_week { return; } - if rewards_info.start_week == rewards_info.end_week { + if rewards_info.last_update_week == rewards_info.end_week { return; } let last_week = match opt_max_nr_weeks { OptionalValue::Some(max_nr_weeks) => { let first_cmp_result = - core::cmp::min(rewards_info.start_week + max_nr_weeks, current_week); + core::cmp::min(rewards_info.last_update_week + max_nr_weeks, current_week); core::cmp::min(first_cmp_result, rewards_info.end_week) } OptionalValue::None => core::cmp::min(current_week, rewards_info.end_week), }; let mut total_undistributed_rewards = BigUint::zero(); - for week in rewards_info.start_week..last_week { + for week in rewards_info.last_update_week..last_week { let undistributed_rewards = self.rewards_remaining_amount(project_id, week).take(); total_undistributed_rewards += undistributed_rewards; } @@ -63,7 +64,7 @@ pub trait CommonRewardsModule: week_timekeeping::WeekTimekeepingModule { rewards_info.undistributed_rewards += total_undistributed_rewards; } - rewards_info.start_week = last_week; + rewards_info.last_update_week = last_week; } #[storage_mapper("minRewardsPeriod")] diff --git a/growth-program/src/rewards/deposit.rs b/growth-program/src/rewards/deposit.rs index b6bba38..929060c 100644 --- a/growth-program/src/rewards/deposit.rs +++ b/growth-program/src/rewards/deposit.rs @@ -1,4 +1,4 @@ -use week_timekeeping::Week; +use super::week_timekeeping::Week; use crate::{project::ProjectId, rewards::common_rewards::RewardsInfo, WEEK_IN_SECONDS}; @@ -12,7 +12,7 @@ pub trait DepositRewardsModule: + crate::price_query::PriceQueryModule + super::common_rewards::CommonRewardsModule + super::energy::EnergyModule - + week_timekeeping::WeekTimekeepingModule + + super::week_timekeeping::WeekTimekeepingModule + multiversx_sc_modules::pause::PauseModule { #[only_owner] @@ -34,7 +34,7 @@ pub trait DepositRewardsModule: project_id: ProjectId, start_week: Week, end_week: Week, - initial_energy_per_rew_dollar: BigUint, + initial_rewards_dollar_per_energy: BigUint, ) { self.require_not_paused(); self.require_valid_project_id(project_id); @@ -67,8 +67,8 @@ pub trait DepositRewardsModule: .set(&rewards_per_week); } - self.energy_per_reward_dollar_for_week(project_id, start_week) - .set(initial_energy_per_rew_dollar); + self.rewards_dollars_per_energy(project_id, start_week) + .set(initial_rewards_dollar_per_energy); let surplus_amount = amount - &rewards_per_week * week_diff as u32; let surplus_payment = EsdtTokenPayment::new(token_id.clone(), 0, surplus_amount); @@ -79,6 +79,7 @@ pub trait DepositRewardsModule: reward_token_id: token_id, undistributed_rewards: BigUint::zero(), start_week, + last_update_week: start_week, end_week, }; info_mapper.set(rewards_info); @@ -114,7 +115,10 @@ pub trait DepositRewardsModule: rewards_info.end_week >= start_week, INVALID_START_WEEK_ERR_MSG ); - require!(end_week >= rewards_info.start_week, "Invalid end week"); + require!( + end_week >= rewards_info.last_update_week, + "Invalid end week" + ); self.update_rewards(project_id, OptionalValue::None, &mut rewards_info); @@ -137,7 +141,7 @@ pub trait DepositRewardsModule: self.send() .direct_non_zero_esdt_payment(&caller, &surplus_payment); - rewards_info.start_week = core::cmp::min(rewards_info.start_week, start_week); + rewards_info.last_update_week = core::cmp::min(rewards_info.last_update_week, start_week); rewards_info.end_week = core::cmp::max(rewards_info.end_week, end_week); info_mapper.set(rewards_info); diff --git a/growth-program/src/rewards/energy.rs b/growth-program/src/rewards/energy.rs index 118047c..a271585 100644 --- a/growth-program/src/rewards/energy.rs +++ b/growth-program/src/rewards/energy.rs @@ -1,6 +1,6 @@ -use week_timekeeping::Week; +use super::week_timekeeping::Week; -use crate::{project::ProjectId, DAY_IN_SECONDS, MAX_PERCENTAGE, PRECISION, WEEK_IN_SECONDS}; +use crate::{project::ProjectId, DAY_IN_SECONDS, MAX_PERCENTAGE, PRECISION}; multiversx_sc::imports!(); multiversx_sc::derive_imports!(); @@ -10,21 +10,21 @@ pub trait EnergyModule: super::common_rewards::CommonRewardsModule + crate::price_query::PriceQueryModule + crate::project::ProjectsModule - + week_timekeeping::WeekTimekeepingModule + + super::week_timekeeping::WeekTimekeepingModule { #[only_owner] - #[endpoint(setMinEnergyPerRewardDollar)] - fn set_min_energy_per_reward_dollar(&self, min_value: BigUint) { - self.min_energy_per_reward_dollar().set(min_value); + #[endpoint(setMinRewardDollarsPerEnergy)] + fn set_min_reward_dollars_per_energy(&self, min_value: BigUint) { + self.min_reward_dollars_per_energy().set(min_value); } #[only_owner] - #[endpoint(setEnergyPerRewardDollarForWeek)] - fn set_energy_per_reward_dollar_for_week(&self, project_id: ProjectId, new_min: BigUint) { + #[endpoint(setNextWeekRewardDollarsPerEnergy)] + fn set_next_week_reward_dollars_per_energy(&self, project_id: ProjectId, new_min: BigUint) { self.require_valid_project_id(project_id); let week = self.get_current_week() + 1; - self.energy_per_reward_dollar_for_week(project_id, week) + self.rewards_dollars_per_energy(project_id, week) .set(new_min); } @@ -40,6 +40,22 @@ pub trait EnergyModule: self.beta().set(beta); } + #[endpoint(setTotalEnergyForCurrentWeek)] + fn set_total_energy_for_current_week(&self, project_ids: MultiValueEncoded) { + for project_id in project_ids { + self.require_valid_project_id(project_id); + + let _ = self.get_total_energy_for_current_week(project_id); + } + } + + #[view(getTotalEnergyForCurrentWeek)] + fn get_total_energy_for_current_week_view(&self, project_id: ProjectId) -> BigUint { + self.require_valid_project_id(project_id); + + self.get_total_energy_for_current_week(project_id) + } + fn get_total_energy_for_current_week(&self, project_id: ProjectId) -> BigUint { let current_week = self.get_current_week(); let mapper = self.total_energy_for_week(project_id, current_week); @@ -51,36 +67,37 @@ pub trait EnergyModule: let total_rewards = self.rewards_total_amount(project_id, current_week).get(); let rewards_value = self.get_dollar_value(rewards_info.reward_token_id, total_rewards, DAY_IN_SECONDS); - let energy_per_rew_dollar = self.get_energy_per_rew_dollar(project_id); + let energy_per_rew_dollar = self.get_reward_dollar_per_energy(project_id); let total_energy = rewards_value * energy_per_rew_dollar / PRECISION; mapper.set(&total_energy); total_energy } - fn get_energy_per_rew_dollar(&self, project_id: ProjectId) -> BigUint { + fn get_reward_dollar_per_energy(&self, project_id: ProjectId) -> BigUint { let current_week = self.get_current_week(); - let mapper = self.energy_per_reward_dollar_for_week(project_id, current_week); + let mapper = self.rewards_dollars_per_energy(project_id, current_week); if !mapper.is_empty() { return mapper.get(); } let previous_week = current_week - 1; - let rew_prev_week = self.rewards_total_amount(project_id, previous_week).get(); - let rew_current_week = self.rewards_total_amount(project_id, current_week).get(); - let min_energy_per_reward_dollar = self.min_energy_per_reward_dollar().get(); - if rew_prev_week == 0 || rew_current_week == 0 { - return min_energy_per_reward_dollar; + let registered_energy_rewards_claimers_prev_week = self + .registered_energy_rewards_claimers(project_id, previous_week) + .get(); + let registered_energy_exemption_claimers_prev_week = self + .registered_energy_exemption_claimers(project_id, previous_week) + .get(); + let registered_energy_prev_week = registered_energy_rewards_claimers_prev_week + + registered_energy_exemption_claimers_prev_week; + let interested_energy_prev_week = self.get_interested_energy(project_id, previous_week); + + let min_reward_dollar_per_energy = self.min_reward_dollars_per_energy().get(); + if registered_energy_prev_week == 0 || interested_energy_prev_week == 0 { + return min_reward_dollar_per_energy; } let rewards_info = self.rewards_info(project_id).get(); - let total_rewards_prev_week = self.rewards_total_amount(project_id, previous_week).get(); - let rewards_value_prev_week = self.get_dollar_value( - rewards_info.reward_token_id.clone(), - total_rewards_prev_week, - WEEK_IN_SECONDS, - ); - let total_rewards_current_week = self.rewards_total_amount(project_id, current_week).get(); let rewards_value_current_week = self.get_dollar_value( rewards_info.reward_token_id, @@ -88,17 +105,18 @@ pub trait EnergyModule: DAY_IN_SECONDS, ); - let total_energy_prev_week = self.total_energy_for_week(project_id, previous_week).get(); - let interested_energy = self.get_interested_energy(project_id, previous_week); - let num = (total_energy_prev_week * interested_energy).sqrt(); - let den = (rewards_value_prev_week * rewards_value_current_week).sqrt(); + let registered_rewards_dollars_prev_week = self + .registered_rewards_dollars(project_id, previous_week) + .get(); + let num = (registered_rewards_dollars_prev_week * rewards_value_current_week).sqrt(); + let den = (registered_energy_prev_week * interested_energy_prev_week).sqrt(); let alpha = self.alpha().get(); let calculated_value = alpha * PRECISION * num / (den * MAX_PERCENTAGE); - let eprd_for_week = core::cmp::max(calculated_value, min_energy_per_reward_dollar); - mapper.set(&eprd_for_week); + let rdpe_for_week = core::cmp::max(calculated_value, min_reward_dollar_per_energy); + mapper.set(&rdpe_for_week); - eprd_for_week + rdpe_for_week } fn get_interested_energy(&self, project_id: ProjectId, previous_week: Week) -> BigUint { @@ -118,9 +136,8 @@ pub trait EnergyModule: let interested_energy_exemption = registered_energy_exemption_claimers * &interested_energy_rewards / registered_energy_rewards_claimers; - let beta = self.beta().get(); - interested_energy_rewards + beta * interested_energy_exemption / MAX_PERCENTAGE + interested_energy_rewards + interested_energy_exemption } #[storage_mapper("totalEnergyForWeek")] @@ -137,6 +154,13 @@ pub trait EnergyModule: week: Week, ) -> SingleValueMapper; + #[storage_mapper("regRewDollars")] + fn registered_rewards_dollars( + &self, + project_id: ProjectId, + week: Week, + ) -> SingleValueMapper; + #[storage_mapper("regEnergyRewClaimers")] fn registered_energy_rewards_claimers( &self, @@ -151,15 +175,15 @@ pub trait EnergyModule: week: Week, ) -> SingleValueMapper; - #[storage_mapper("energyPerRDForWeek")] - fn energy_per_reward_dollar_for_week( + #[storage_mapper("rewDollarsPerEnergy")] + fn rewards_dollars_per_energy( &self, project_id: ProjectId, week: Week, ) -> SingleValueMapper; - #[storage_mapper("minEnergyPerRD")] - fn min_energy_per_reward_dollar(&self) -> SingleValueMapper; + #[storage_mapper("minRewDollarsPerEnergy")] + fn min_reward_dollars_per_energy(&self) -> SingleValueMapper; #[storage_mapper("alpha")] fn alpha(&self) -> SingleValueMapper; diff --git a/growth-program/src/rewards/mod.rs b/growth-program/src/rewards/mod.rs index b9656a4..003f61f 100644 --- a/growth-program/src/rewards/mod.rs +++ b/growth-program/src/rewards/mod.rs @@ -2,4 +2,5 @@ pub mod claim; pub mod common_rewards; pub mod deposit; pub mod energy; +pub mod week_timekeeping; pub mod withdraw; diff --git a/growth-program/src/rewards/week_timekeeping.rs b/growth-program/src/rewards/week_timekeeping.rs new file mode 100644 index 0000000..2af367a --- /dev/null +++ b/growth-program/src/rewards/week_timekeeping.rs @@ -0,0 +1,42 @@ +use crate::{Timestamp, WEEK_IN_SECONDS}; + +multiversx_sc::imports!(); + +pub const FIRST_WEEK: Week = 1; +pub const MONDAY_19_02_2024_GMT_TIMESTAMP: u64 = 1_708_300_800; +static INVALID_WEEK_ERR_MSG: &[u8] = b"Week 0 is not a valid week"; + +pub type Week = usize; +pub type Epoch = u64; + +#[multiversx_sc::module] +pub trait WeekTimekeepingModule { + /// Week starts from 1 + #[view(getCurrentWeek)] + fn get_current_week(&self) -> Week { + let current_timestamp = self.blockchain().get_block_timestamp(); + self.get_week_for_timestamp(current_timestamp) + } + + fn get_week_for_timestamp(&self, timestamp: Timestamp) -> Week { + let first_week_start_timestamp = self.first_week_start_timestamp().get(); + require!( + timestamp >= first_week_start_timestamp, + INVALID_WEEK_ERR_MSG + ); + + unsafe { + // will never overflow usize + let zero_based_week: Week = ((timestamp - first_week_start_timestamp) + / WEEK_IN_SECONDS) + .try_into() + .unwrap_unchecked(); + + zero_based_week + 1 + } + } + + #[view(getFirstWeekStartTimestamp)] + #[storage_mapper("firstWeekStartTimestamp")] + fn first_week_start_timestamp(&self) -> SingleValueMapper; +} diff --git a/growth-program/src/rewards/withdraw.rs b/growth-program/src/rewards/withdraw.rs index 3d80e91..41c66d1 100644 --- a/growth-program/src/rewards/withdraw.rs +++ b/growth-program/src/rewards/withdraw.rs @@ -1,4 +1,4 @@ -use week_timekeeping::Week; +use super::week_timekeeping::Week; use crate::{project::ProjectId, rewards::deposit::INVALID_START_WEEK_ERR_MSG}; @@ -8,7 +8,7 @@ multiversx_sc::imports!(); pub trait WithdrawRewardsModule: super::common_rewards::CommonRewardsModule + crate::project::ProjectsModule - + week_timekeeping::WeekTimekeepingModule + + super::week_timekeeping::WeekTimekeepingModule + multiversx_sc_modules::pause::PauseModule { #[only_owner] @@ -24,7 +24,7 @@ pub trait WithdrawRewardsModule: "Cannot withdraw anymore" ); require!( - start_week > rewards_info.start_week, + start_week > rewards_info.last_update_week, INVALID_START_WEEK_ERR_MSG ); require!( @@ -43,11 +43,12 @@ pub trait WithdrawRewardsModule: self.rewards_total_amount(project_id, week).clear(); } - let caller = self.blockchain().get_caller(); + let project_owner = self.project_owner(project_id).get(); let payment = EsdtTokenPayment::new(rewards_info.reward_token_id.clone(), 0, total_amount); - self.send().direct_non_zero_esdt_payment(&caller, &payment); + self.send() + .direct_non_zero_esdt_payment(&project_owner, &payment); - if start_week == rewards_info.start_week { + if start_week == rewards_info.last_update_week { info_mapper.clear(); } else { rewards_info.end_week = start_week; diff --git a/growth-program/src/validation.rs b/growth-program/src/validation.rs index 10eb715..097f320 100644 --- a/growth-program/src/validation.rs +++ b/growth-program/src/validation.rs @@ -1,6 +1,4 @@ -use week_timekeeping::Week; - -use crate::project::ProjectId; +use crate::{project::ProjectId, rewards::week_timekeeping::Week}; multiversx_sc::imports!(); diff --git a/growth-program/tests/growth_program_setup/mod.rs b/growth-program/tests/growth_program_setup/mod.rs index c0a6ca7..80931d1 100644 --- a/growth-program/tests/growth_program_setup/mod.rs +++ b/growth-program/tests/growth_program_setup/mod.rs @@ -4,10 +4,12 @@ use energy_factory::SimpleLockEnergy; use growth_program::{ project::{ProjectId, ProjectsModule}, rewards::{ - claim::{ClaimRewardsModule, LockOption}, + claim::{ClaimRewardsModule, ClaimType, LockOption}, deposit::DepositRewardsModule, + week_timekeeping::{Epoch, MONDAY_19_02_2024_GMT_TIMESTAMP}, }, - GrowthProgram, DEFAULT_MIN_REWARDS_PERIOD, MAX_PERCENTAGE, PRECISION, + GrowthProgram, Timestamp, DEFAULT_MIN_REWARDS_PERIOD, MAX_PERCENTAGE, PRECISION, + WEEK_IN_SECONDS, }; use multiversx_sc::{ api::ManagedTypeApi, @@ -25,7 +27,6 @@ use multiversx_sc_scenario::{ use pair_mock::PairMock; use router_mock::RouterMock; use simple_lock::{locked_token::LockedTokenModule, SimpleLock}; -use week_timekeeping::Epoch; // associated private key - used for generating the signatures (please don't steal my funds) // 3eb200ef228e593d49a522f92587889fedfc091629d175873b64ca0ab3b4514d52773868c13654355cca16adb389b09201fabf5d9d4b795ebbdae5b361b46f20 @@ -82,6 +83,7 @@ pub struct GrowthProgramSetup< ContractObjWrapper, SimpleLockBuilder>, pub energy_factory_wrapper: ContractObjWrapper, EnergyFactoryBuilder>, + pub current_timestamp: Timestamp, pub current_epoch: Epoch, } @@ -292,6 +294,8 @@ where ) .assert_ok(); + b_mock.set_block_timestamp(MONDAY_19_02_2024_GMT_TIMESTAMP); + // Growth Program SC init let gp_wrapper = b_mock.create_sc_account( @@ -333,6 +337,7 @@ where router_wrapper, simple_lock_wrapper, energy_factory_wrapper, + current_timestamp: MONDAY_19_02_2024_GMT_TIMESTAMP, current_epoch, } } @@ -401,7 +406,9 @@ where } pub fn advance_week(&mut self) { - self.current_epoch += EPOCHS_IN_WEEK; + self.current_timestamp += WEEK_IN_SECONDS; + self.b_mock.set_block_timestamp(self.current_timestamp); + self.current_epoch += 7; self.b_mock.set_block_epoch(self.current_epoch); } @@ -419,7 +426,7 @@ where project_id, managed_biguint!(min_rewards), ManagedByteArray::new_from_bytes(signature), - OptionalValue::Some(lock_option), + ClaimType::Rewards(lock_option), ); }) } diff --git a/growth-program/tests/test.rs b/growth-program/tests/test.rs index b8089cc..ad6cdce 100644 --- a/growth-program/tests/test.rs +++ b/growth-program/tests/test.rs @@ -185,6 +185,7 @@ fn deposit_additional_rewards_ok_test() { reward_token_id: managed_token_id!(FIRST_PROJ_TOKEN), undistributed_rewards: managed_biguint!(0), start_week: 2, + last_update_week: 2, end_week: 30, }; assert_eq!(rewards_info, expected_rewards_info); diff --git a/growth-program/wasm/Cargo.lock b/growth-program/wasm/Cargo.lock index cb8fc91..122b14e 100644 --- a/growth-program/wasm/Cargo.lock +++ b/growth-program/wasm/Cargo.lock @@ -125,7 +125,6 @@ dependencies = [ "router", "simple-lock", "utils", - "week-timekeeping", ] [[package]] diff --git a/growth-program/wasm/src/lib.rs b/growth-program/wasm/src/lib.rs index 286b0ed..73013cf 100644 --- a/growth-program/wasm/src/lib.rs +++ b/growth-program/wasm/src/lib.rs @@ -5,9 +5,9 @@ //////////////////////////////////////////////////// // Init: 1 -// Endpoints: 28 +// Endpoints: 30 // Async Callback (empty): 1 -// Total number of exported functions: 30 +// Total number of exported functions: 32 #![no_std] #![allow(internal_features)] @@ -29,10 +29,12 @@ multiversx_sc_wasm_adapter::endpoints! { depositAdditionalRewards => deposit_additional_rewards ownerWithdrawRewards => owner_withdraw_rewards finishProgram => finish_program - setMinEnergyPerRewardDollar => set_min_energy_per_reward_dollar - setEnergyPerRewardDollarForWeek => set_energy_per_reward_dollar_for_week + setMinRewardDollarsPerEnergy => set_min_reward_dollars_per_energy + setNextWeekRewardDollarsPerEnergy => set_next_week_reward_dollars_per_energy setAlpha => set_alpha setBeta => set_beta + setTotalEnergyForCurrentWeek => set_total_energy_for_current_week + getTotalEnergyForCurrentWeek => get_total_energy_for_current_week_view claimRewards => claim_rewards getExemptedParticipants => get_exempted_participants getUserClaimed => get_user_claimed @@ -42,7 +44,7 @@ multiversx_sc_wasm_adapter::endpoints! { getRewardsRemainingAmount => rewards_remaining_amount changeSigner => change_signer getCurrentWeek => get_current_week - getFirstWeekStartEpoch => first_week_start_epoch + getFirstWeekStartTimestamp => first_week_start_timestamp setEnergyFactoryAddress => set_energy_factory_address getEnergyFactoryAddress => energy_factory_address pause => pause_endpoint